Modified: bloodhound/vendor/trac/current/trac/templates/error.html
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/templates/error.html?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/templates/error.html (original)
+++ bloodhound/vendor/trac/current/trac/templates/error.html Fri Nov 14 
11:06:23 2014
@@ -1,3 +1,13 @@
+<!--!  Copyright (C) 2006-2014 Edgewall Software
+
+  This software is licensed as described in the file COPYING, which
+  you should have received as part of this distribution. The terms
+  are also available at http://trac.edgewall.com/license.html.
+
+  This software consists of voluntary contributions made by many
+  individuals. For the exact contribution history, see the revision
+  history and logs, available at http://trac.edgewall.org/.
+-->
 <!DOCTYPE html
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
@@ -39,7 +49,9 @@
        $("#traceback pre").hide();
        $("#tbtoggle").parent().show();
 
-       $("#systeminfo").append("<tr><th>jQuery</th><td>" + $().jquery + 
"</td></tr>");
+       
$("#systeminfo").append("<tr><th>jQuery</th><td>"+$().jquery+"</td></tr>" +
+                               "<tr><th>jQuery 
UI</th><td>"+$.ui.version+"</td></tr>" +
+                               "<tr><th>jQuery 
Timepicker</th><td>"+$.timepicker.version+"</td></tr>");
        $("#systeminfo").before("<p>User Agent: <tt>" + navigator.userAgent + 
"</tt></p>");
       });
     /*]]>*/</script>
@@ -48,7 +60,9 @@
         $("form.newticket textarea").each(function() {
           $(this).val($(this).val()
                              .replace(/#USER_AGENT#/m, navigator.userAgent)
-                             .replace(/#JQUERY#/m, $().jquery));
+                             .replace(/#JQUERY#/m, $().jquery)
+                             .replace(/#JQUERYUI#/m, $.ui.version)
+                             .replace(/#JQUERYTP#/m, $.timepicker.version));
         });
       });
     /*]]>*/</script>
@@ -98,13 +112,17 @@ ${description_en if url else description
               <p>The action that triggered the error was:</p>
               <pre>${req.method}: ${req.path_info}</pre>
             </py:when>
-            <py:otherwise>
-              <form class="newticket" method="get" 
action="${project.admin_href.newticket()}#">
+            <py:otherwise py:choose="">
+              <p py:when="not project.admin_href or project.admin_trac_url == 
'.'">
+                This is probably a local installation issue.
+              </p>
+              <form py:otherwise=""
+                    class="newticket" method="get" 
action="${project.admin_href.newticket()}#">
                 <p>This is probably a local installation issue.
-                  <py:if test="project.admin_href and project.admin_trac_url 
!= '.'"><i18n:msg params="create">
+                  <i18n:msg params="create">
                     You should ${create_ticket()} a ticket at the admin Trac 
to report
                     the issue.
-                  </i18n:msg></py:if>
+                  </i18n:msg>
                 </p>
               </form>
               <h2>Found a bug in Trac?</h2>
@@ -140,7 +158,7 @@ ${description_en if url else description
                     <li class="frame" py:for="idx, frame in enumerate(frames)">
                       <a href="#frame${idx}" id="frame${idx}"><span 
i18n:msg="file, line, function" py:strip="">
                         <span class="file">File "${frame.filename}",
-                        line <b>${frame.lineno + 1}</b>, in</span>
+                        line <strong>${frame.lineno + 1}</strong>, in</span>
                         <var>${frame.function}</var></span>
                       </a>
                       <div py:if="frame.line" class="source" style="display: 
none">

Modified: bloodhound/vendor/trac/current/trac/templates/history_view.html
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/templates/history_view.html?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/templates/history_view.html (original)
+++ bloodhound/vendor/trac/current/trac/templates/history_view.html Fri Nov 14 
11:06:23 2014
@@ -1,3 +1,13 @@
+<!--!  Copyright (C) 2006-2014 Edgewall Software
+
+  This software is licensed as described in the file COPYING, which
+  you should have received as part of this distribution. The terms
+  are also available at http://trac.edgewall.com/license.html.
+
+  This software consists of voluntary contributions made by many
+  individuals. For the exact contribution history, see the revision
+  history and logs, available at http://trac.edgewall.org/.
+-->
 <!DOCTYPE html
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
@@ -15,7 +25,7 @@
     <div id="content" class="ticket">
       <h1 i18n:msg="name">Change History for <a href="${url or 
url_of(resource)}">${name or name_of(resource)}</a></h1>
 
-      <form py:if="history" class="printableform" method="get" action="">
+      <form py:if="history" id="history" class="printableform" method="get" 
action="">
         <div class="buttons">
           <input type="hidden" name="action" value="${diff_action or 'diff'}" 
/>
           <input py:for="k, v in diff_args or []" type="hidden" name="$k" 
value="$v"/>

Modified: bloodhound/vendor/trac/current/trac/templates/index.html
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/templates/index.html?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/templates/index.html (original)
+++ bloodhound/vendor/trac/current/trac/templates/index.html Fri Nov 14 
11:06:23 2014
@@ -1,3 +1,13 @@
+<!--!  Copyright (C) 2006-2014 Edgewall Software
+
+  This software is licensed as described in the file COPYING, which
+  you should have received as part of this distribution. The terms
+  are also available at http://trac.edgewall.com/license.html.
+
+  This software consists of voluntary contributions made by many
+  individuals. For the exact contribution history, see the revision
+  history and logs, available at http://trac.edgewall.org/.
+-->
 <!DOCTYPE html
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>

Modified: bloodhound/vendor/trac/current/trac/templates/layout.html
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/templates/layout.html?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/templates/layout.html (original)
+++ bloodhound/vendor/trac/current/trac/templates/layout.html Fri Nov 14 
11:06:23 2014
@@ -1,3 +1,13 @@
+<!--!  Copyright (C) 2006-2014 Edgewall Software
+
+  This software is licensed as described in the file COPYING, which
+  you should have received as part of this distribution. The terms
+  are also available at http://trac.edgewall.com/license.html.
+
+  This software consists of voluntary contributions made by many
+  individuals. For the exact contribution history, see the revision
+  history and logs, available at http://trac.edgewall.org/.
+-->
 <!DOCTYPE html
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>

Modified: bloodhound/vendor/trac/current/trac/templates/list_of_attachments.html
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/templates/list_of_attachments.html?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/templates/list_of_attachments.html 
(original)
+++ bloodhound/vendor/trac/current/trac/templates/list_of_attachments.html Fri 
Nov 14 11:06:23 2014
@@ -1,4 +1,13 @@
-<!--!
+<!--!  Copyright (C) 2010-2014 Edgewall Software
+
+  This software is licensed as described in the file COPYING, which
+  you should have received as part of this distribution. The terms
+  are also available at http://trac.edgewall.com/license.html.
+
+  This software consists of voluntary contributions made by many
+  individuals. For the exact contribution history, see the revision
+  history and logs, available at http://trac.edgewall.org/.
+
 Display a list of attachments.
 
 Arguments:

Modified: bloodhound/vendor/trac/current/trac/templates/macros.html
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/templates/macros.html?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/templates/macros.html (original)
+++ bloodhound/vendor/trac/current/trac/templates/macros.html Fri Nov 14 
11:06:23 2014
@@ -1,3 +1,13 @@
+<!--!  Copyright (C) 2006-2014 Edgewall Software
+
+  This software is licensed as described in the file COPYING, which
+  you should have received as part of this distribution. The terms
+  are also available at http://trac.edgewall.com/license.html.
+
+  This software consists of voluntary contributions made by many
+  individuals. For the exact contribution history, see the revision
+  history and logs, available at http://trac.edgewall.org/.
+-->
 <div xmlns="http://www.w3.org/1999/xhtml";
      xmlns:py="http://genshi.edgewall.org/";
      xmlns:xi="http://www.w3.org/2001/XInclude";

Modified: bloodhound/vendor/trac/current/trac/templates/page_index.html
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/templates/page_index.html?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/templates/page_index.html (original)
+++ bloodhound/vendor/trac/current/trac/templates/page_index.html Fri Nov 14 
11:06:23 2014
@@ -1,6 +1,17 @@
-<!--!  Display a page index.
+<!--!  Copyright (C) 2008-2014 Edgewall Software
 
-  `paginator` must be a trac.util.presentation.Paginator instance
+  This software is licensed as described in the file COPYING, which
+  you should have received as part of this distribution. The terms
+  are also available at http://trac.edgewall.com/license.html.
+
+  This software consists of voluntary contributions made by many
+  individuals. For the exact contribution history, see the revision
+  history and logs, available at http://trac.edgewall.org/.
+
+Display a page index.
+
+Arguments:
+ - `paginator` must be a trac.util.presentation.Paginator instance
 
   -->
 <div xmlns="http://www.w3.org/1999/xhtml";

Modified: bloodhound/vendor/trac/current/trac/templates/preview_file.html
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/templates/preview_file.html?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/templates/preview_file.html (original)
+++ bloodhound/vendor/trac/current/trac/templates/preview_file.html Fri Nov 14 
11:06:23 2014
@@ -1,4 +1,13 @@
-<!--!
+<!--!  Copyright (C) 2010-2014 Edgewall Software
+
+  This software is licensed as described in the file COPYING, which
+  you should have received as part of this distribution. The terms
+  are also available at http://trac.edgewall.com/license.html.
+
+  This software consists of voluntary contributions made by many
+  individuals. For the exact contribution history, see the revision
+  history and logs, available at http://trac.edgewall.org/.
+
 Display a div for visualizing a preview of a file content.
 
 Arguments:

Modified: bloodhound/vendor/trac/current/trac/templates/progress_bar.html
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/templates/progress_bar.html?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/templates/progress_bar.html (original)
+++ bloodhound/vendor/trac/current/trac/templates/progress_bar.html Fri Nov 14 
11:06:23 2014
@@ -1,4 +1,13 @@
-<!--!
+<!--!  Copyright (C) 2010-2014 Edgewall Software
+
+  This software is licensed as described in the file COPYING, which
+  you should have received as part of this distribution. The terms
+  are also available at http://trac.edgewall.com/license.html.
+
+  This software consists of voluntary contributions made by many
+  individuals. For the exact contribution history, see the revision
+  history and logs, available at http://trac.edgewall.org/.
+
 Display groups of tickets in a progress bar.
 
 Arguments:

Modified: 
bloodhound/vendor/trac/current/trac/templates/progress_bar_grouped.html
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/templates/progress_bar_grouped.html?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/templates/progress_bar_grouped.html 
(original)
+++ bloodhound/vendor/trac/current/trac/templates/progress_bar_grouped.html Fri 
Nov 14 11:06:23 2014
@@ -1,4 +1,13 @@
-<!--!
+<!--!  Copyright (C) 2011-2014 Edgewall Software
+
+  This software is licensed as described in the file COPYING, which
+  you should have received as part of this distribution. The terms
+  are also available at http://trac.edgewall.com/license.html.
+
+  This software consists of voluntary contributions made by many
+  individuals. For the exact contribution history, see the revision
+  history and logs, available at http://trac.edgewall.org/.
+
 Display a table of progress bars for ticket groups
 
 Arguments:

Modified: bloodhound/vendor/trac/current/trac/templates/theme.html
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/templates/theme.html?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/templates/theme.html (original)
+++ bloodhound/vendor/trac/current/trac/templates/theme.html Fri Nov 14 
11:06:23 2014
@@ -1,3 +1,13 @@
+<!--!  Copyright (C) 2006-2014 Edgewall Software
+
+  This software is licensed as described in the file COPYING, which
+  you should have received as part of this distribution. The terms
+  are also available at http://trac.edgewall.com/license.html.
+
+  This software consists of voluntary contributions made by many
+  individuals. For the exact contribution history, see the revision
+  history and logs, available at http://trac.edgewall.org/.
+-->
 <!DOCTYPE html
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>

Modified: bloodhound/vendor/trac/current/trac/test.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/test.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/test.py (original)
+++ bloodhound/vendor/trac/current/trac/test.py Fri Nov 14 11:06:23 2014
@@ -144,7 +144,8 @@ class TestSetup(unittest.TestSuite):
         return result
 
     def _wrapped_run(self, *args, **kwargs):
-        "Python 2.7 / unittest2 compatibility - there must be a better way..."
+        """Python 2.7 / unittest2 compatibility - there must be a better
+        way..."""
         self.setUp()
         if hasattr(self, 'fixture'):
             for test in self._tests:
@@ -153,6 +154,7 @@ class TestSetup(unittest.TestSuite):
         unittest.TestSuite._wrapped_run(self, *args, **kwargs)
         self.tearDown()
 
+
 class TestCaseSetup(unittest.TestCase):
     def setFixture(self, fixture):
         self.fixture = fixture
@@ -164,7 +166,7 @@ def get_dburi():
     dburi = os.environ.get('TRAC_TEST_DB_URI')
     if dburi:
         scheme, db_prop = _parse_db_str(dburi)
-        # Assume the schema 'tractest' for Postgres
+        # Assume the schema 'tractest' for PostgreSQL
         if scheme == 'postgres' and \
                 not db_prop.get('params', {}).get('schema'):
             if '?' in dburi:
@@ -176,9 +178,8 @@ def get_dburi():
 
 
 def reset_sqlite_db(env, db_prop):
-    dbname = os.path.basename(db_prop['path'])
     with env.db_transaction as db:
-        tables = db("SELECT name FROM sqlite_master WHERE type='table'")
+        tables = db.get_table_names()
         for table in tables:
             db("DELETE FROM %s" % table)
         return tables
@@ -189,24 +190,24 @@ def reset_postgres_db(env, db_prop):
         dbname = db.schema
         if dbname:
             # reset sequences
-            # information_schema.sequences view is available in PostgreSQL 8.2+
-            # however Trac supports PostgreSQL 8.0+, uses
+            # information_schema.sequences view is available in
+            # PostgreSQL 8.2+ however Trac supports PostgreSQL 8.0+, uses
             # pg_get_serial_sequence()
-            for seq in db("""
-                    SELECT sequence_name FROM (
-                        SELECT pg_get_serial_sequence(%s||table_name,
-                                                      column_name)
-                               AS sequence_name
-                        FROM information_schema.columns
-                        WHERE table_schema=%s) AS tab
-                    WHERE sequence_name IS NOT NULL""",
-                    (dbname + '.', dbname)):
+            seqs = [seq for seq, in db("""
+                SELECT sequence_name
+                FROM (
+                    SELECT pg_get_serial_sequence(
+                        quote_ident(table_schema) || '.' ||
+                        quote_ident(table_name), column_name) AS sequence_name
+                    FROM information_schema.columns
+                    WHERE table_schema=%s) AS tab
+                WHERE sequence_name IS NOT NULL""", (dbname,))]
+            for seq in seqs:
                 db("ALTER SEQUENCE %s RESTART WITH 1" % seq)
             # clear tables
-            tables = db("""SELECT table_name FROM information_schema.tables
-                           WHERE table_schema=%s""", (dbname,))
+            tables = db.get_table_names()
             for table in tables:
-                db("DELETE FROM %s" % table)
+                db("DELETE FROM %s" % db.quote(table))
             # PostgreSQL supports TRUNCATE TABLE as well
             # (see http://www.postgresql.org/docs/8.1/static/sql-truncate.html)
             # but on the small tables used here, DELETE is actually much faster
@@ -217,12 +218,18 @@ def reset_mysql_db(env, db_prop):
     dbname = os.path.basename(db_prop['path'])
     if dbname:
         with env.db_transaction as db:
-            tables = db("""SELECT table_name FROM information_schema.tables
+            tables = db("""SELECT table_name, auto_increment
+                           FROM information_schema.tables
                            WHERE table_schema=%s""", (dbname,))
-            for table in tables:
-                # TRUNCATE TABLE is prefered to DELETE FROM, as we need to 
reset
-                # the auto_increment in MySQL.
-                db("TRUNCATE TABLE %s" % table)
+            for table, auto_increment in tables:
+                if auto_increment is None or auto_increment == 1:
+                    # DELETE FROM is preferred to TRUNCATE TABLE, as the
+                    # auto_increment is not used or it is 1.
+                    db("DELETE FROM %s" % table)
+                else:
+                    # TRUNCATE TABLE is preferred to DELETE FROM, as we
+                    # need to reset the auto_increment in MySQL.
+                    db("TRUNCATE TABLE %s" % table)
             return tables
 
 
@@ -245,6 +252,12 @@ class EnvironmentStub(Environment):
                        activate in the stub environment.
         :param disable: A list of component classes or name globs to
                         deactivate in the stub environment.
+        :param path: The location of the environment in the file system.
+                     No files or directories are created when specifying
+                     this parameter.
+        :param destroying: If True, the database will not be reset. This is
+                           useful for cases when the object is being
+                           constructed in order to call `destroy_db`.
         """
         if enable is not None and not isinstance(enable, (list, tuple)):
             raise TypeError('Keyword argument "enable" must be a list')
@@ -323,28 +336,26 @@ class EnvironmentStub(Environment):
         remove_sqlite_db = False
         try:
             with self.db_transaction as db:
-                db.rollback() # make sure there's no transaction in progress
+                db.rollback()  # make sure there's no transaction in progress
                 # check the database version
-                database_version = db(
-                    "SELECT value FROM system WHERE name='database_version'")
-                if database_version:
-                    database_version = int(database_version[0][0])
-                if database_version == db_default.db_version:
-                    # same version, simply clear the tables (faster)
-                    m = sys.modules[__name__]
-                    reset_fn = 'reset_%s_db' % scheme
-                    if hasattr(m, reset_fn):
-                        tables = getattr(m, reset_fn)(self, db_prop)
-                else:
-                    # different version or version unknown, drop the tables
-                    remove_sqlite_db = True
-                    self.destroy_db(scheme, db_prop)
-        except Exception, e:
+                database_version = self.get_version()
+        except Exception:
             # "Database not found ...",
             # "OperationalError: no such table: system" or the like
             pass
+        else:
+            if database_version == db_default.db_version:
+                # same version, simply clear the tables (faster)
+                m = sys.modules[__name__]
+                reset_fn = 'reset_%s_db' % scheme
+                if hasattr(m, reset_fn):
+                    tables = getattr(m, reset_fn)(self, db_prop)
+            else:
+                # different version or version unknown, drop the tables
+                remove_sqlite_db = True
+                self.destroy_db(scheme, db_prop)
 
-        db = None # as we might shutdown the pool     FIXME no longer needed!
+        db = None  # as we might shutdown the pool    FIXME no longer needed!
 
         if scheme == 'sqlite' and remove_sqlite_db:
             path = db_prop['path']
@@ -362,12 +373,14 @@ class EnvironmentStub(Environment):
                 self.global_databasemanager.shutdown()
 
         with self.db_transaction as db:
+            if scheme == 'sqlite':
+                # Speed-up tests with SQLite database
+                db("PRAGMA synchronous = OFF")
             if default_data:
                 for table, cols, vals in db_default.get_data(db):
                     db.executemany("INSERT INTO %s (%s) VALUES (%s)"
                                    % (table, ','.join(cols),
-                                      ','.join(['%s' for c in cols])),
-                                   vals)
+                                      ','.join(['%s'] * len(cols))), vals)
             else:
                 db("INSERT INTO system (name, value) VALUES (%s, %s)",
                    ('database_version', str(db_default.db_version)))
@@ -378,12 +391,9 @@ class EnvironmentStub(Environment):
         try:
             with self.db_transaction as db:
                 if scheme == 'postgres' and db.schema:
-                    db('DROP SCHEMA "%s" CASCADE' % db.schema)
+                    db('DROP SCHEMA %s CASCADE' % db.quote(db.schema))
                 elif scheme == 'mysql':
-                    dbname = os.path.basename(db_prop['path'])
-                    for table in db("""
-                          SELECT table_name FROM information_schema.tables
-                          WHERE table_schema=%s""", (dbname,)):
+                    for table in db.get_table_names():
                         db("DROP TABLE IF EXISTS `%s`" % table)
         except Exception:
             # "TracError: Database not found...",
@@ -391,7 +401,7 @@ class EnvironmentStub(Environment):
             pass
         return False
 
-    # overriden
+    # overridden
 
     def is_component_enabled(self, cls):
         if self._component_name(cls).startswith('__main__.'):
@@ -418,6 +428,7 @@ def locate(fn):
 
 INCLUDE_FUNCTIONAL_TESTS = True
 
+
 def suite():
     import trac.tests
     import trac.admin.tests

Modified: bloodhound/vendor/trac/current/trac/tests/config.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/config.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/config.py (original)
+++ bloodhound/vendor/trac/current/trac/tests/config.py Fri Nov 14 11:06:23 2014
@@ -19,10 +19,10 @@ import tempfile
 import time
 import unittest
 
+import trac.tests.compat
 from trac.config import *
 from trac.core import Component, Interface, implements
 from trac.test import Configuration, EnvironmentStub
-from trac.tests import compat
 from trac.util import create_file
 
 

Modified: bloodhound/vendor/trac/current/trac/tests/core.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/core.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/core.py (original)
+++ bloodhound/vendor/trac/current/trac/tests/core.py Fri Nov 14 11:06:23 2014
@@ -14,9 +14,9 @@
 #
 # Author: Christopher Lenz <cml...@gmx.de>
 
+import trac.tests.compat
 from trac.core import *
 from trac.core import ComponentManager
-from trac.tests import compat
 
 import unittest
 

Modified: bloodhound/vendor/trac/current/trac/tests/env.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/env.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/env.py (original)
+++ bloodhound/vendor/trac/current/trac/tests/env.py Fri Nov 14 11:06:23 2014
@@ -13,11 +13,12 @@
 
 from __future__ import with_statement
 
+from ConfigParser import RawConfigParser
 import shutil
 import tempfile
 import unittest
 
-from trac.tests import compat
+import trac.tests.compat
 from trac import db_default
 from trac.core import ComponentManager
 from trac.env import Environment
@@ -85,6 +86,8 @@ class EnvironmentTestCase(unittest.TestC
     def test_get_version(self):
         """Testing env.get_version"""
         self.assertEqual(db_default.db_version, self.env.get_version())
+        self.assertEqual(db_default.db_version, self.env.database_version)
+        self.assertEqual(db_default.db_version, 
self.env.database_initial_version)
 
     def test_get_known_users(self):
         """Testing env.get_known_users"""
@@ -112,6 +115,24 @@ class EnvironmentTestCase(unittest.TestC
         self.assertEqual(False, EnvironmentStub.required)
         self.assertEqual(None, self.env.is_component_enabled(EnvironmentStub))
 
+    def test_dumped_values_in_tracini(self):
+        parser = RawConfigParser()
+        filename = self.env.config.filename
+        self.assertEqual([filename], parser.read(filename))
+        self.assertEqual('#cc0,#0c0,#0cc,#00c,#c0c,#c00',
+                         parser.get('revisionlog', 'graph_colors'))
+        self.assertEqual('disabled', parser.get('trac', 'secure_cookies'))
+
+    def test_dumped_values_in_tracini_sample(self):
+        parser = RawConfigParser()
+        filename = self.env.config.filename + '.sample'
+        self.assertEqual([filename], parser.read(filename))
+        self.assertEqual('#cc0,#0c0,#0cc,#00c,#c0c,#c00',
+                         parser.get('revisionlog', 'graph_colors'))
+        self.assertEqual('disabled', parser.get('trac', 'secure_cookies'))
+        self.assertTrue(parser.has_option('logging', 'log_format'))
+        self.assertEqual('', parser.get('logging', 'log_format'))
+
 
 def suite():
     suite = unittest.TestSuite()

Modified: bloodhound/vendor/trac/current/trac/tests/functional/__init__.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/functional/__init__.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/functional/__init__.py (original)
+++ bloodhound/vendor/trac/current/trac/tests/functional/__init__.py Fri Nov 14 
11:06:23 2014
@@ -123,22 +123,33 @@ if twill:
         else:
             env_class = FunctionalTestEnvironment
 
+        tester_class = FunctionalTester
+
         def setUp(self, port=None):
             """If no port is specified, use a semi-random port and subdirectory
             'testenv'; but if a port is specified, use that port and
             subdirectory 'testenv<portnum>'.
             """
             if port is None:
-                port = 8000 + os.getpid() % 1000
-                dirname = "testenv"
+                try:
+                    port = int(os.getenv('TRAC_TEST_PORT'))
+                except (TypeError, ValueError):
+                    pass
+
+            env_path = os.getenv('TRAC_TEST_ENV_PATH')
+            if not env_path:
+                env_name = 'testenv%s' % (port or '')
+                env_path = os.path.join(trac_source_tree, env_name)
             else:
-                dirname = "testenv%s" % port
-            dirname = os.path.join(trac_source_tree, dirname)
+                env_path += str(port or '')
+
+            if port is None:
+                port = 8000 + os.getpid() % 1000
 
             baseurl = "http://127.0.0.1:%s"; % port
-            self._testenv = self.env_class(dirname, port, baseurl)
+            self._testenv = self.env_class(env_path, port, baseurl)
             self._testenv.start()
-            self._tester = FunctionalTester(baseurl)
+            self._tester = self.tester_class(baseurl)
             self.fixture = (self._testenv, self._tester)
 
         def tearDown(self):

Modified: bloodhound/vendor/trac/current/trac/tests/functional/better_twill.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/functional/better_twill.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/functional/better_twill.py 
(original)
+++ bloodhound/vendor/trac/current/trac/tests/functional/better_twill.py Fri 
Nov 14 11:06:23 2014
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2008-2013 Edgewall Software
+# Copyright (C) 2008-2014 Edgewall Software
 # All rights reserved.
 #
 # This software is licensed as described in the file COPYING, which
@@ -17,8 +17,10 @@ It also handles twill's absense.
 """
 
 import os
-from os.path import abspath, dirname, join
 import sys
+import urllib
+import urlparse
+from os.path import abspath, dirname, join
 from pkg_resources import parse_version as pv
 try:
     from cStringIO import StringIO
@@ -160,7 +162,7 @@ if twill:
         html_file.write(b.get_html())
         html_file.close()
 
-        return filename
+        return urlparse.urljoin('file:', urllib.pathname2url(filename))
 
     # Twill isn't as helpful with errors as I'd like it to be, so we replace
     # the formvalue function.  This would be better done as a patch to Twill.
@@ -170,8 +172,8 @@ if twill:
         except (twill.errors.TwillAssertionError,
                 twill.utils.ClientForm.ItemNotFoundError), e:
             filename = twill_write_html()
-            args = e.args + (filename,)
-            raise twill.errors.TwillAssertionError(*args)
+            raise twill.errors.TwillAssertionError('%s at %s' %
+                                                   (unicode(e), filename))
     tc.formvalue = better_formvalue
     tc.fv = better_formvalue
 
@@ -221,8 +223,8 @@ if twill:
             tcfind(what, flags)
         except twill.errors.TwillAssertionError, e:
             filename = twill_write_html()
-            args = e.args + (filename,)
-            raise twill.errors.TwillAssertionError(*args)
+            raise twill.errors.TwillAssertionError('%s at %s' %
+                                                   (unicode(e), filename))
     tc.find = better_find
 
     def better_notfind(what, flags='', tcnotfind=tc.notfind):
@@ -230,8 +232,8 @@ if twill:
             tcnotfind(what, flags)
         except twill.errors.TwillAssertionError, e:
             filename = twill_write_html()
-            args = e.args + (filename,)
-            raise twill.errors.TwillAssertionError(*args)
+            raise twill.errors.TwillAssertionError('%s at %s' %
+                                                   (unicode(e), filename))
     tc.notfind = better_notfind
 
     # Same for tc.url - no hint about what went wrong!
@@ -240,8 +242,8 @@ if twill:
             tcurl(should_be)
         except twill.errors.TwillAssertionError, e:
             filename = twill_write_html()
-            args = e.args + (filename,)
-            raise twill.errors.TwillAssertionError(*args)
+            raise twill.errors.TwillAssertionError('%s at %s' %
+                                                   (unicode(e), filename))
     tc.url = better_url
 else:
     b = tc = None

Modified: bloodhound/vendor/trac/current/trac/tests/functional/compat.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/functional/compat.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/functional/compat.py (original)
+++ bloodhound/vendor/trac/current/trac/tests/functional/compat.py Fri Nov 14 
11:06:23 2014
@@ -11,5 +11,5 @@
 # individuals. For the exact contribution history, see the revision
 # history and logs, available at http://trac.edgewall.org/log/.
 
-from trac.util.compat import close_fds
 from trac.tests.compat import rmtree
+from trac.util.compat import close_fds

Modified: bloodhound/vendor/trac/current/trac/tests/functional/svntestenv.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/functional/svntestenv.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/functional/svntestenv.py 
(original)
+++ bloodhound/vendor/trac/current/trac/tests/functional/svntestenv.py Fri Nov 
14 11:06:23 2014
@@ -24,16 +24,17 @@ class SvnFunctionalTestEnvironment(Funct
     def work_dir(self):
         return os.path.join(self.dirname, 'workdir')
 
+    def repo_path(self, filename):
+        return os.path.join(self.dirname, filename)
+
     def repo_path_for_initenv(self):
-        return os.path.join(self.dirname, 'repo')
+        return self.repo_path('repo')
 
     def create_repo(self):
         """
         Initialize a repo of the type :attr:`self.repotype`.
         """
-        if call(["svnadmin", "create", self.repo_path_for_initenv()],
-                stdout=logfile, stderr=logfile, close_fds=close_fds):
-            raise Exception('unable to create subversion repository')
+        self.svnadmin_create()
         if call(['svn', 'co', self.repo_url(), self.work_dir()],
                 stdout=logfile, stderr=logfile, close_fds=close_fds):
             raise Exception('Checkout from %s failed.' % self.repo_url())
@@ -53,6 +54,18 @@ class SvnFunctionalTestEnvironment(Funct
         else:
             return 'file://' + repodir
 
+    def svnadmin_create(self, filename=None):
+        """Subversion helper to create a new repository."""
+        if filename is None:
+            path = self.repo_path_for_initenv()
+        else:
+            path = self.repo_path(filename)
+        if call(["svnadmin", "create", path],
+                stdout=logfile, stderr=logfile, close_fds=close_fds):
+            raise Exception('unable to create subversion repository: %r' %
+                            path)
+        return path
+
     def svn_mkdir(self, paths, msg, username='admin'):
         """Subversion helper to create a new directory within the main
         repository.  Operates directly on the repository url, so a working

Modified: bloodhound/vendor/trac/current/trac/tests/functional/testcases.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/functional/testcases.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/functional/testcases.py (original)
+++ bloodhound/vendor/trac/current/trac/tests/functional/testcases.py Fri Nov 
14 11:06:23 2014
@@ -32,11 +32,61 @@ class TestAttachmentNonexistentParent(Fu
                 'Parent resource NonexistentPage doesn\'t exist</p>')
 
 
+class TestErrorPage(FunctionalTwillTestCaseSetup):
+    """Validate the error page.
+    Defects reported to trac-hacks should use the Component defined in the
+    plugin's URL (#11434).
+    """
+    def runTest(self):
+        env = self._testenv.get_trac_environment()
+        env.config.set('components', 'RaiseExceptionPlugin.*', 'enabled')
+        env.config.save()
+        create_file(os.path.join(env.path, 'plugins',
+                                 'RaiseExceptionPlugin.py'),
+"""\
+from trac.core import Component, implements
+from trac.web.api import IRequestHandler
+
+url = None
+
+class RaiseExceptionPlugin(Component):
+    implements(IRequestHandler)
+
+    def match_request(self, req):
+        if req.path_info.startswith('/raise-exception'):
+            return True
+
+    def process_request(self, req):
+        print 'maybe?'
+        if req.args.get('report') == 'tho':
+            global url
+            url = 'http://trac-hacks.org/wiki/HelloWorldMacro'
+        raise Exception
+
+""")
+        self._testenv.restart()
+
+        try:
+            tc.go(self._tester.url + '/raise-exception')
+            tc.find(internal_error)
+            tc.find('<form class="newticket" method="get" '
+                    'action="http://trac.edgewall.org/newticket";>')
+
+            tc.go(self._tester.url + '/raise-exception?report=tho')
+            tc.find(internal_error)
+            tc.find('<form class="newticket" method="get" '
+                    'action="http://trac-hacks.org/newticket";>')
+            tc.find('<input type="hidden" name="component" '
+                    'value="HelloWorldMacro" />')
+        finally:
+            env.config.set('components', 'RaiseExceptionPlugin.*', 'disabled')
+
+
 class RegressionTestRev6017(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Test for regression of the plugin reload fix in r6017"""
         # Setup the DeleteTicket plugin
-        plugin = open(os.path.join(self._testenv.command_cwd,
+        plugin = open(os.path.join(self._testenv.trac_src,
                                    'sample-plugins', 'workflow',
                                    'DeleteTicket.py')).read()
         open(os.path.join(self._testenv.tracdir, 'plugins',
@@ -198,17 +248,6 @@ See also http://bugs.python.org/issue155
 """)
 
 
-class ErrorPageValidation(FunctionalTwillTestCaseSetup):
-    def runTest(self):
-        """Validate the error page"""
-        url = self._tester.url + '/wiki/WikiStart'
-        tc.go(url + '?version=bug')
-        tc.url(url)
-        tc.find(internal_error)
-        tc.find('<form class="newticket" method="get" '
-                'action="http://trac.edgewall.org/newticket";>')
-
-
 class RegressionTestTicket3663(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Regression test for non-UTF-8 PATH_INFO (#3663)
@@ -297,6 +336,7 @@ def functionalSuite(suite=None):
         import trac.tests.functional
         suite = trac.tests.functional.functionalSuite()
     suite.addTest(TestAttachmentNonexistentParent())
+    suite.addTest(TestErrorPage())
     suite.addTest(RegressionTestRev6017())
     suite.addTest(RegressionTestTicket3833a())
     suite.addTest(RegressionTestTicket3833b())
@@ -304,7 +344,6 @@ def functionalSuite(suite=None):
     suite.addTest(RegressionTestTicket5572())
     suite.addTest(RegressionTestTicket7209())
     suite.addTest(RegressionTestTicket9880())
-    suite.addTest(ErrorPageValidation())
     suite.addTest(RegressionTestTicket3663())
     suite.addTest(RegressionTestTicket6318())
     suite.addTest(RegressionTestTicket11434())

Modified: bloodhound/vendor/trac/current/trac/tests/functional/testenv.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/functional/testenv.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/functional/testenv.py (original)
+++ bloodhound/vendor/trac/current/trac/tests/functional/testenv.py Fri Nov 14 
11:06:23 2014
@@ -25,7 +25,7 @@ from subprocess import call, Popen, PIPE
 from trac.env import open_environment
 from trac.test import EnvironmentStub, get_dburi
 from trac.tests.compat import rmtree
-from trac.tests.functional import logfile
+from trac.tests.functional import logfile, trac_source_tree
 from trac.tests.functional.better_twill import tc, ConnectError
 from trac.util import terminate
 from trac.util.compat import close_fds, wait_for_file_mtime_change
@@ -64,6 +64,7 @@ class FunctionalTestEnvironment(object):
     def __init__(self, dirname, port, url):
         """Create a :class:`FunctionalTestEnvironment`, see the class itself
         for parameter information."""
+        self.trac_src = trac_source_tree
         self.url = url
         self.command_cwd = os.path.normpath(os.path.join(dirname, '..'))
         self.dirname = os.path.abspath(dirname)
@@ -77,8 +78,6 @@ class FunctionalTestEnvironment(object):
         self.create()
         locale.setlocale(locale.LC_ALL, '')
 
-    trac_src = '.'
-
     @property
     def dburi(self):
         dburi = get_dburi()
@@ -114,11 +113,13 @@ class FunctionalTestEnvironment(object):
 
     def post_create(self, env):
         """Hook for modifying the environment after creation.  For example, to
-        set configuration like::
+        set configuration like:
+        ::
 
             def post_create(self, env):
                 env.config.set('git', 'path', '/usr/bin/git')
                 env.config.save()
+
         """
         pass
 
@@ -310,21 +311,24 @@ class FunctionalTestEnvironment(object):
     def enable_authz_permpolicy(self, authz_content, filename=None):
         """Enables the Authz permissions policy. The `authz_content` will
         be written to `filename`, and may be specified in a triple-quoted
-        string.
-            '''
-            [wiki:WikiStart@*]
-            * = WIKI_VIEW
-            [wiki:PrivatePage@*]
-            john = WIKI_VIEW
-            * = !WIKI_VIEW
-            '''
+        string.::
+
+           [wiki:WikiStart@*]
+           * = WIKI_VIEW
+           [wiki:PrivatePage@*]
+           john = WIKI_VIEW
+           * = !WIKI_VIEW
+
         `authz_content` may also be a dictionary of dictionaries specifying
         the sections and key/value pairs of each section, however this form
         should only be used when the order of the entries in the file is not
-        important, as the order cannot be known.
-            {'wiki:WikiStart@*': {'*': 'WIKI_VIEW'},
-             'wiki:PrivatePage@*': {'john': 'WIKI_VIEW', '*': '!WIKI_VIEW'},
-            }
+        important, as the order cannot be known.::
+
+           {
+            'wiki:WikiStart@*': {'*': 'WIKI_VIEW'},
+            'wiki:PrivatePage@*': {'john': 'WIKI_VIEW', '*': '!WIKI_VIEW'},
+           }
+
         The `filename` parameter is optional, and if omitted a filename will
         be generated by computing a hash of `authz_content`, prefixed with
         "authz-".

Modified: bloodhound/vendor/trac/current/trac/tests/functional/tester.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/functional/tester.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/functional/tester.py (original)
+++ bloodhound/vendor/trac/current/trac/tests/functional/tester.py Fri Nov 14 
11:06:23 2014
@@ -20,7 +20,7 @@ import re
 from trac.tests.functional import internal_error
 from trac.tests.functional.better_twill import tc, b
 from trac.tests.contentgen import random_page, random_sentence, random_word, \
-    random_unique_camel
+                                  random_unique_camel
 from trac.util.text import to_utf8, unicode_quote
 
 try:

Modified: bloodhound/vendor/trac/current/trac/tests/perm.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/perm.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/perm.py (original)
+++ bloodhound/vendor/trac/current/trac/tests/perm.py Fri Nov 14 11:06:23 2014
@@ -11,18 +11,20 @@
 # individuals. For the exact contribution history, see the revision
 # history and logs, available at http://trac.edgewall.org/log/.
 
+import unittest
+
 from trac import perm
 from trac.core import *
+from trac.resource import Resource
 from trac.test import EnvironmentStub
 
-import unittest
-
 
 class DefaultPermissionStoreTestCase(unittest.TestCase):
 
     def setUp(self):
-        self.env = EnvironmentStub(enable=[perm.DefaultPermissionStore,
-                                           
perm.DefaultPermissionGroupProvider])
+        self.env = \
+            EnvironmentStub(enable=[perm.DefaultPermissionStore,
+                                    perm.DefaultPermissionGroupProvider])
         self.store = perm.DefaultPermissionStore(self.env)
 
     def tearDown(self):
@@ -102,6 +104,48 @@ class TestPermissionRequestor(Component)
                 ('TEST_ADMIN', ['TEST_MODIFY'])]
 
 
+class PermissionErrorTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.env = EnvironmentStub()
+
+    def test_default_message(self):
+        permission_error = perm.PermissionError()
+        self.assertEqual(None, permission_error.action)
+        self.assertEqual(None, permission_error.resource)
+        self.assertEqual(None, permission_error.env)
+        self.assertEqual("Insufficient privileges to perform this operation.",
+                         unicode(permission_error))
+        self.assertEqual("Forbidden", permission_error.title)
+        self.assertEqual(unicode(permission_error), permission_error.msg)
+
+    def test_message_specified(self):
+        message = "The message."
+        permission_error = perm.PermissionError(msg=message)
+        self.assertEqual(message, unicode(permission_error))
+
+    def test_message_from_action(self):
+        action = 'WIKI_VIEW'
+        permission_error = perm.PermissionError(action)
+        self.assertEqual(action, permission_error.action)
+        self.assertEqual(None, permission_error.resource)
+        self.assertEqual(None, permission_error.env)
+        self.assertEqual("WIKI_VIEW privileges are required to perform this "
+                         "operation. You don't have the required "
+                         "permissions.", unicode(permission_error))
+
+    def test_message_from_action_and_resource(self):
+        action = 'WIKI_VIEW'
+        resource = Resource('wiki', 'WikiStart')
+        permission_error = perm.PermissionError(action, resource, self.env)
+        self.assertEqual(action, permission_error.action)
+        self.assertEqual(resource, permission_error.resource)
+        self.assertEqual(self.env, permission_error.env)
+        self.assertEqual("WIKI_VIEW privileges are required to perform this "
+                         "operation on WikiStart. You don't have the "
+                         "required permissions.", unicode(permission_error))
+
+
 class PermissionSystemTestCase(unittest.TestCase):
 
     def setUp(self):
@@ -184,7 +228,8 @@ class PermissionCacheTestCase(unittest.T
     def test_require(self):
         self.perm.require('TEST_MODIFY')
         self.perm.require('TEST_ADMIN')
-        self.assertRaises(perm.PermissionError, self.perm.require, 
'TRAC_ADMIN')
+        self.assertRaises(perm.PermissionError,
+                          self.perm.require, 'TRAC_ADMIN')
 
     def test_assert_permission(self):
         self.perm.assert_permission('TEST_MODIFY')
@@ -231,12 +276,14 @@ class TestPermissionPolicy(Component):
 
 
 class PermissionPolicyTestCase(unittest.TestCase):
+
     def setUp(self):
         self.env = EnvironmentStub(enable=[perm.DefaultPermissionStore,
                                            perm.DefaultPermissionPolicy,
                                            TestPermissionPolicy,
                                            TestPermissionRequestor])
-        self.env.config.set('trac', 'permission_policies', 
'TestPermissionPolicy')
+        self.env.config.set('trac', 'permission_policies',
+                            'TestPermissionPolicy')
         self.policy = TestPermissionPolicy(self.env)
         self.perm = perm.PermissionCache(self.env, 'testuser')
 
@@ -261,7 +308,8 @@ class PermissionPolicyTestCase(unittest.
                           ('testuser', 'TEST_ADMIN'): True})
 
     def test_policy_chaining(self):
-        self.env.config.set('trac', 'permission_policies', 
'TestPermissionPolicy,DefaultPermissionPolicy')
+        self.env.config.set('trac', 'permission_policies',
+                            'TestPermissionPolicy,DefaultPermissionPolicy')
         self.policy.grant('testuser', ['TEST_MODIFY'])
         system = perm.PermissionSystem(self.env)
         system.grant_permission('testuser', 'TEST_ADMIN')
@@ -279,6 +327,7 @@ class PermissionPolicyTestCase(unittest.
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(DefaultPermissionStoreTestCase))
+    suite.addTest(unittest.makeSuite(PermissionErrorTestCase))
     suite.addTest(unittest.makeSuite(PermissionSystemTestCase))
     suite.addTest(unittest.makeSuite(PermissionCacheTestCase))
     suite.addTest(unittest.makeSuite(PermissionPolicyTestCase))

Modified: bloodhound/vendor/trac/current/trac/tests/wikisyntax.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/tests/wikisyntax.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/tests/wikisyntax.py (original)
+++ bloodhound/vendor/trac/current/trac/tests/wikisyntax.py Fri Nov 14 11:06:23 
2014
@@ -25,6 +25,7 @@ from trac.test import MockPerm
 from trac.web.href import Href
 from trac.wiki.tests import formatter
 
+
 SEARCH_TEST_CASES = u"""
 ============================== search: link resolver
 search:foo

Modified: bloodhound/vendor/trac/current/trac/ticket/admin.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/ticket/admin.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/ticket/admin.py (original)
+++ bloodhound/vendor/trac/current/trac/ticket/admin.py Fri Nov 14 11:06:23 2014
@@ -395,10 +395,11 @@ class MilestoneAdminPanel(TicketAdminPan
             return self.get_milestone_list()
 
     def _do_list(self):
-        print_table([(m.name, m.due and
-                        format_date(m.due, console_date_format),
-                      m.completed and
-                        format_datetime(m.completed, console_datetime_format))
+        print_table([(m.name,
+                      format_date(m.due, console_date_format)
+                      if m.due else None,
+                      format_datetime(m.completed, console_datetime_format)
+                      if m.completed else None)
                      for m in model.Milestone.select(self.env)],
                     [_("Name"), _("Due"), _("Completed")])
 
@@ -417,15 +418,16 @@ class MilestoneAdminPanel(TicketAdminPan
 
     def _do_due(self, name, due):
         milestone = model.Milestone(self.env, name)
-        milestone.due = due and parse_date(due, hint='datetime',
-                                           locale=get_console_locale(self.env))
+        milestone.due = parse_date(due, hint='datetime',
+                                   locale=get_console_locale(self.env)) \
+                        if due else None
         milestone.update()
 
     def _do_completed(self, name, completed):
         milestone = model.Milestone(self.env, name)
-        milestone.completed = completed and \
-                              parse_date(completed, hint='datetime',
-                                         locale=get_console_locale(self.env))
+        milestone.completed = parse_date(completed, hint='datetime',
+                                         locale=get_console_locale(self.env)) \
+                              if completed else None
         milestone.update()
 
     def _do_remove(self, name):
@@ -566,17 +568,18 @@ class VersionAdminPanel(TicketAdminPanel
 
     def _do_list(self):
         print_table([(v.name,
-                      v.time and format_date(v.time, console_date_format))
-                     for v in model.Version.select(self.env)],
+                      format_date(v.time, console_date_format)
+                      if v.time else None)
+                    for v in model.Version.select(self.env)],
                     [_("Name"), _("Time")])
 
     def _do_add(self, name, time=None):
         version = model.Version(self.env)
         version.name = name
         if time is not None:
-            version.time = time and \
-                           parse_date(time, hint='datetime',
-                                      locale=get_console_locale(self.env))
+            version.time = parse_date(time, hint='datetime',
+                                      locale=get_console_locale(self.env)) \
+                           if time else None
         version.insert()
 
     def _do_rename(self, name, newname):
@@ -586,9 +589,9 @@ class VersionAdminPanel(TicketAdminPanel
 
     def _do_time(self, name, time):
         version = model.Version(self.env, name)
-        version.time = time and \
-                       parse_date(time, hint='datetime',
-                                  locale=get_console_locale(self.env))
+        version.time = parse_date(time, hint='datetime',
+                                  locale=get_console_locale(self.env)) \
+                       if time else None
         version.update()
 
     def _do_remove(self, name):

Modified: bloodhound/vendor/trac/current/trac/ticket/api.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/ticket/api.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/ticket/api.py (original)
+++ bloodhound/vendor/trac/current/trac/ticket/api.py Fri Nov 14 11:06:23 2014
@@ -122,6 +122,15 @@ class ITicketChangeListener(Interface):
     def ticket_deleted(ticket):
         """Called when a ticket is deleted."""
 
+    def ticket_comment_modified(ticket, cdate, author, comment, old_comment):
+        """Called when a ticket comment is modified."""
+
+    def ticket_change_deleted(ticket, cdate, changes):
+        """Called when a ticket change is deleted.
+
+        `changes` is a dictionary of tuple `(oldvalue, newvalue)`
+        containing the ticket change of the fields that have changed."""
+
 
 class ITicketManipulator(Interface):
     """Miscellaneous manipulation of ticket workflow features."""

Modified: bloodhound/vendor/trac/current/trac/ticket/batch.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/ticket/batch.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/ticket/batch.py (original)
+++ bloodhound/vendor/trac/current/trac/ticket/batch.py Fri Nov 14 11:06:23 2014
@@ -29,6 +29,7 @@ from trac.util.translation import _, tag
 from trac.web import IRequestHandler
 from trac.web.chrome import add_warning, add_script_data
 
+
 class BatchModifyModule(Component):
     """Ticket batch modification module.
 

Modified: bloodhound/vendor/trac/current/trac/ticket/default_workflow.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/ticket/default_workflow.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/ticket/default_workflow.py (original)
+++ bloodhound/vendor/trac/current/trac/ticket/default_workflow.py Fri Nov 14 
11:06:23 2014
@@ -20,6 +20,7 @@ import pkg_resources
 
 from ConfigParser import RawConfigParser
 from StringIO import StringIO
+from functools import partial
 
 from genshi.builder import tag
 
@@ -98,10 +99,12 @@ class ConfigurableTicketWorkflow(Compone
     """Ticket action controller which provides actions according to a
     workflow defined in trac.ini.
 
-    The workflow is idefined in the `[ticket-workflow]` section of the
+    The workflow is defined in the `[ticket-workflow]` section of the
     [wiki:TracIni#ticket-workflow-section trac.ini] configuration file.
     """
 
+    implements(IEnvironmentSetupParticipant, ITicketActionController)
+
     ticket_workflow_section = ConfigSection('ticket-workflow',
         """The workflow for tickets is controlled by plugins. By default,
         there's only a `ConfigurableTicketWorkflow` component in charge.
@@ -129,7 +132,6 @@ class ConfigurableTicketWorkflow(Compone
                 self.log.warning("Ticket workflow action '%s' doesn't define "
                                  "any transitions", name)
 
-    implements(ITicketActionController, IEnvironmentSetupParticipant)
 
     # IEnvironmentSetupParticipant methods
 
@@ -226,19 +228,14 @@ Read TracWorkflow for more information (
         this_action = self.actions[action]
         status = this_action['newstate']
         operations = this_action['operations']
-        current_owner_or_empty = ticket._old.get('owner', ticket['owner'])
-        current_owner = current_owner_or_empty or '(none)'
-        if not (Chrome(self.env).show_email_addresses
-                or 'EMAIL_VIEW' in req.perm(ticket.resource)):
-            format_user = obfuscate_email_address
-        else:
-            format_user = lambda address: address
-        current_owner = format_user(current_owner)
+        current_owner = ticket._old.get('owner', ticket['owner'])
+        format_author = partial(Chrome(self.env).format_author, req)
+        formatted_current_owner = format_author(current_owner or _("(none)"))
 
         control = [] # default to nothing
         hints = []
         if 'reset_workflow' in operations:
-            control.append(tag("from invalid state "))
+            control.append(_("from invalid state"))
             hints.append(_("Current state no longer exists"))
         if 'del_owner' in operations:
             hints.append(_("The ticket will be disowned"))
@@ -256,39 +253,40 @@ Read TracWorkflow for more information (
             else:
                 owners = None
 
-            if owners == None:
+            if owners is None:
                 owner = req.args.get(id, req.authname)
-                control.append(tag_('to %(owner)s',
+                control.append(tag_("to %(owner)s",
                                     owner=tag.input(type='text', id=id,
                                                     name=id, value=owner)))
                 hints.append(_("The owner will be changed from "
                                "%(current_owner)s to the specified user",
-                               current_owner=current_owner))
+                               current_owner=formatted_current_owner))
             elif len(owners) == 1:
                 owner = tag.input(type='hidden', id=id, name=id,
                                   value=owners[0])
-                formatted_owner = format_user(owners[0])
-                control.append(tag_('to %(owner)s ',
-                                    owner=tag(formatted_owner, owner)))
+                formatted_new_owner = format_author(owners[0])
+                control.append(tag_("to %(owner)s",
+                                    owner=tag(formatted_new_owner, owner)))
                 if ticket['owner'] != owners[0]:
                     hints.append(_("The owner will be changed from "
                                    "%(current_owner)s to %(selected_owner)s",
-                                   current_owner=current_owner,
-                                   selected_owner=formatted_owner))
+                                   current_owner=formatted_current_owner,
+                                   selected_owner=formatted_new_owner))
             else:
-                control.append(tag_('to %(owner)s', owner=tag.select(
+                control.append(tag_("to %(owner)s", owner=tag.select(
                     [tag.option(x, value=x,
                                 selected=(x == selected_owner or None))
                      for x in owners],
                     id=id, name=id)))
                 hints.append(_("The owner will be changed from "
                                "%(current_owner)s to the selected user",
-                               current_owner=current_owner))
+                               current_owner=formatted_current_owner))
         elif 'set_owner_to_self' in operations and \
                 ticket._old.get('owner', ticket['owner']) != req.authname:
             hints.append(_("The owner will be changed from %(current_owner)s "
-                           "to %(authname)s", current_owner=current_owner,
-                           authname=req.authname))
+                           "to %(authname)s",
+                           current_owner=formatted_current_owner,
+                           authname=format_author(req.authname)))
         if 'set_resolution' in operations:
             if 'set_resolution' in this_action:
                 resolutions = [x.strip() for x in
@@ -303,7 +301,7 @@ Read TracWorkflow for more information (
             if len(resolutions) == 1:
                 resolution = tag.input(type='hidden', id=id, name=id,
                                        value=resolutions[0])
-                control.append(tag_('as %(resolution)s',
+                control.append(tag_("as %(resolution)s",
                                     resolution=tag(resolutions[0],
                                                    resolution)))
                 hints.append(_("The resolution will be set to %(name)s",
@@ -311,7 +309,7 @@ Read TracWorkflow for more information (
             else:
                 selected_option = req.args.get(id,
                         TicketSystem(self.env).default_resolution)
-                control.append(tag_('as %(resolution)s',
+                control.append(tag_("as %(resolution)s",
                                     resolution=tag.select(
                     [tag.option(x, value=x,
                                 selected=(x == selected_option or None))
@@ -321,19 +319,20 @@ Read TracWorkflow for more information (
         if 'del_resolution' in operations:
             hints.append(_("The resolution will be deleted"))
         if 'leave_status' in operations:
-            control.append(_('as %(status)s ',
+            control.append(_("as %(status)s",
                              status= ticket._old.get('status',
                                                      ticket['status'])))
             if len(operations) == 1:
                 hints.append(_("The owner will remain %(current_owner)s",
-                               current_owner=current_owner)
-                             if current_owner_or_empty else
+                               current_owner=formatted_current_owner)
+                             if current_owner else
                              _("The ticket will remain with no owner"))
         else:
             if status != '*':
                 hints.append(_("Next status will be '%(name)s'", name=status))
-        return (this_action['name'], tag(*control), '. '.join(hints) + '.'
-                if hints else '')
+        return (this_action['name'],
+                tag((' ' if i else None, c) for i, c in enumerate(control)),
+                '. '.join(hints) + '.' if hints else '')
 
     def get_ticket_changes(self, req, ticket, action):
         this_action = self.actions[action]

Modified: bloodhound/vendor/trac/current/trac/ticket/model.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/ticket/model.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/ticket/model.py (original)
+++ bloodhound/vendor/trac/current/trac/ticket/model.py Fri Nov 14 11:06:23 2014
@@ -507,6 +507,12 @@ class Ticket(object):
 
         self._fetch_ticket(self.id)
 
+        changes = dict((field, (oldvalue, newvalue))
+                       for field, oldvalue, newvalue in fields)
+        for listener in TicketSystem(self.env).change_listeners:
+            if hasattr(listener, 'ticket_change_deleted'):
+                listener.ticket_change_deleted(self, cdate, changes)
+
     def modify_comment(self, cdate, author, comment, when=None):
         """Modify a ticket comment specified by its date, while keeping a
         history of edits.
@@ -531,8 +537,8 @@ class Ticket(object):
             # Find the next edit number
             fields = db("""SELECT field FROM ticket_change
                            WHERE ticket=%%s AND time=%%s AND field %s
-                           """ % db.like(),
-                           (self.id, ts, db.like_escape('_comment') + '%'))
+                           """ % db.prefix_match(),
+                           (self.id, ts, db.prefix_match_value('_comment')))
             rev = max(int(field[8:]) for field, in fields) + 1 if fields else 0
             db("""INSERT INTO ticket_change
                     (ticket,time,author,field,oldvalue,newvalue)
@@ -546,8 +552,8 @@ class Ticket(object):
                 for old_author, in db("""
                         SELECT author FROM ticket_change
                         WHERE ticket=%%s AND time=%%s AND NOT field %s LIMIT 1
-                        """ % db.like(),
-                        (self.id, ts, db.like_escape('_') + '%')):
+                        """ % db.prefix_match(),
+                        (self.id, ts, db.prefix_match_value('_'))):
                     db("""INSERT INTO ticket_change
                             (ticket,time,author,field,oldvalue,newvalue)
                           VALUES (%s,%s,%s,'comment','',%s)
@@ -563,6 +569,12 @@ class Ticket(object):
 
         self.values['changetime'] = when
 
+        old_comment = old_comment or ''
+        for listener in TicketSystem(self.env).change_listeners:
+            if hasattr(listener, 'ticket_comment_modified'):
+                listener.ticket_comment_modified(self, cdate, author, comment,
+                                                 old_comment)
+
     def get_comment_history(self, cnum=None, cdate=None, db=None):
         """Retrieve the edit history of a comment identified by its number or
         date.
@@ -590,8 +602,8 @@ class Ticket(object):
                 for author0, last_comment in db("""
                         SELECT author, newvalue FROM ticket_change
                         WHERE ticket=%%s AND time=%%s AND NOT field %s LIMIT 1
-                        """ % db.like(),
-                        (self.id, ts0, db.like_escape('_') + '%')):
+                        """ % db.prefix_match(),
+                        (self.id, ts0, db.prefix_match_value('_'))):
                     break
                 else:
                     return
@@ -600,8 +612,8 @@ class Ticket(object):
             rows = db("""SELECT field, author, oldvalue, newvalue
                          FROM ticket_change
                          WHERE ticket=%%s AND time=%%s AND field %s
-                         """ % db.like(),
-                         (self.id, ts0, db.like_escape('_comment') + '%'))
+                         """ % db.prefix_match(),
+                         (self.id, ts0, db.prefix_match_value('_comment')))
             rows = sorted((int(field[8:]), author, old, new)
                           for field, author, old, new in rows)
             history = []
@@ -653,8 +665,8 @@ class Ticket(object):
                 for author, in db("""
                         SELECT author FROM ticket_change
                         WHERE ticket=%%s AND time=%%s AND NOT field %s LIMIT 1
-                        """ % db.like(),
-                        (self.id, ts, db.like_escape('_') + '%')):
+                        """ % db.prefix_match(),
+                        (self.id, ts, db.prefix_match_value('_'))):
                     break
             return (ts, author, comment)
 
@@ -1003,11 +1015,10 @@ class Milestone(object):
     def delete(self, retarget_to=None, author=None, db=None):
         """Delete the milestone.
 
-        :param author: the author of the change
-
-        :since 1.0.2: the `retarget_to` parameter is deprecated and tickets
-        should moved to another milestone by calling `move_tickets` before
-        `delete`.
+        :since 1.0.2: the `retarget_to` and `author` parameters are
+                      deprecated and will be removed in Trac 1.3.1. Tickets
+                      should be moved to another milestone by calling
+                      `move_tickets` before `delete`.
 
         :since 1.0: the `db` parameter is no longer needed and will be removed
         in version 1.1.1
@@ -1015,6 +1026,7 @@ class Milestone(object):
         with self.env.db_transaction as db:
             self.env.log.info("Deleting milestone %s", self.name)
             db("DELETE FROM milestone WHERE name=%s", (self.name,))
+            Attachment.delete_all(self.env, 'milestone', self.name)
             # Don't translate ticket comment (comment:40:ticket:5658)
             self.move_tickets(retarget_to, author, "Milestone deleted")
             self._old['name'] = None

Modified: bloodhound/vendor/trac/current/trac/ticket/notification.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/ticket/notification.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/ticket/notification.py (original)
+++ bloodhound/vendor/trac/current/trac/ticket/notification.py Fri Nov 14 
11:06:23 2014
@@ -26,6 +26,7 @@ from trac.core import *
 from trac.config import *
 from trac.notification import NotifyEmail
 from trac.ticket.api import TicketSystem
+from trac.ticket.model import Ticket
 from trac.util.datefmt import to_utimestamp
 from trac.util.text import obfuscate_email_address, shorten_line, \
                            text_width, wrap
@@ -75,65 +76,69 @@ class TicketNotificationSystem(Component
         0.12.2)''""")
 
 
-def get_ticket_notification_recipients(env, config, tktid, prev_cc):
-    """Returns the notifications recipients.
+def get_ticket_notification_recipients(env, config, tktid, prev_cc=None,
+                                       modtime=None):
+    """Returns notifications recipients.
 
-    :since 1.0.3: the `config` parameter is no longer used.
+    :since 1.0.2: the `config` parameter is no longer used.
+    :since 1.0.2: the `prev_cc` parameter is deprecated.
     """
     section = env.config['notification']
-    notify_reporter = section.getbool('always_notify_reporter')
-    notify_owner = section.getbool('always_notify_owner')
-    notify_updater = section.getbool('always_notify_updater')
-
-    ccrecipients = prev_cc
-    torecipients = []
-    with env.db_query as db:
-        # Harvest email addresses from the cc, reporter, and owner fields
-        for row in db("SELECT cc, reporter, owner FROM ticket WHERE id=%s",
-                      (tktid,)):
-            if row[0]:
-                ccrecipients += row[0].replace(',', ' ').split()
-            reporter = row[1]
-            owner = row[2]
-            if notify_reporter:
-                torecipients.append(row[1])
-            if notify_owner:
-                torecipients.append(row[2])
-            break
-
-        # Harvest email addresses from the author field of ticket_change(s)
-        if notify_updater:
-            for author, ticket in db("""
-                    SELECT DISTINCT author, ticket FROM ticket_change
-                    WHERE ticket=%s
-                    """, (tktid,)):
-                torecipients.append(author)
-
-        # Suppress the updater from the recipients
-        updater = None
-        for updater, in db("""
-                SELECT author FROM ticket_change WHERE ticket=%s
-                ORDER BY time DESC LIMIT 1
-                """, (tktid,)):
-            break
-        else:
-            for updater, in db("SELECT reporter FROM ticket WHERE id=%s",
-                               (tktid,)):
-                break
-
-        if not notify_updater:
-            filter_out = True
-            if notify_reporter and (updater == reporter):
-                filter_out = False
-            if notify_owner and (updater == owner):
-                filter_out = False
-            if filter_out:
-                torecipients = [r for r in torecipients
-                                if r and r != updater]
-        elif updater:
-            torecipients.append(updater)
+    always_notify_reporter = section.getbool('always_notify_reporter')
+    always_notify_owner = section.getbool('always_notify_owner')
+    always_notify_updater = section.getbool('always_notify_updater')
+
+    cc_recipients = set(prev_cc or [])
+    to_recipients = set()
+    tkt = Ticket(env, tktid)
+
+    # CC field is stored as comma-separated string. Parse to list.
+    to_list = lambda cc: cc.replace(',', ' ').split()
+
+    # Backward compatibility
+    if not modtime:
+        modtime = tkt['changetime']
+
+    # Harvest email addresses from the cc, reporter, and owner fields
+    if tkt['cc']:
+        cc_recipients.update(to_list(tkt['cc']))
+    if always_notify_reporter:
+        to_recipients.add(tkt['reporter'])
+    if always_notify_owner:
+        to_recipients.add(tkt['owner'])
+
+    # Harvest email addresses from the author field of ticket_change(s)
+    if always_notify_updater:
+        for author, ticket in env.db_query("""
+                SELECT DISTINCT author, ticket FROM ticket_change
+                WHERE ticket=%s
+                """, (tktid, )):
+            to_recipients.add(author)
+
+    # Harvest previous owner and cc list
+    author = None
+    for changelog in tkt.get_changelog(modtime):
+        author, field, old = changelog[1:4]
+        if field == 'owner' and always_notify_owner:
+            to_recipients.add(old)
+        elif field == 'cc':
+            cc_recipients.update(to_list(old))
+
+    # Suppress the updater from the recipients if necessary
+    updater = author or tkt['reporter']
+    if not always_notify_updater:
+        filter_out = True
+        if always_notify_reporter and updater == tkt['reporter']:
+            filter_out = False
+        if always_notify_owner and updater == tkt['owner']:
+            filter_out = False
+        if filter_out:
+            to_recipients.discard(updater)
+    elif updater:
+        to_recipients.add(updater)
 
-    return (torecipients, ccrecipients, reporter, owner)
+    return list(to_recipients), list(cc_recipients), \
+           tkt['reporter'], tkt['owner']
 
 
 class TicketNotifyEmail(NotifyEmail):
@@ -148,7 +153,6 @@ class TicketNotifyEmail(NotifyEmail):
 
     def __init__(self, env):
         NotifyEmail.__init__(self, env)
-        self.prev_cc = []
         ambiguous_char_width = env.config.get('notification',
                                               'ambiguous_char_width',
                                               'single')
@@ -226,7 +230,6 @@ class TicketNotifyEmail(NotifyEmail):
                                           self.ambiwidth) + '\n'
                         if chgcc:
                             changes_body += chgcc
-                        self.prev_cc += self.parse_cc(old) if old else []
                     else:
                         if field in ['owner', 'reporter']:
                             old = self.obfuscate_email(old)
@@ -411,9 +414,9 @@ class TicketNotifyEmail(NotifyEmail):
         return template.generate(**data).render('text', encoding=None).strip()
 
     def get_recipients(self, tktid):
-        (torecipients, ccrecipients, reporter, owner) = \
-            get_ticket_notification_recipients(self.env, self.config,
-                                               tktid, self.prev_cc)
+        torecipients, ccrecipients, reporter, owner = \
+            get_ticket_notification_recipients(self.env, self.config, tktid,
+                                               modtime=self.modtime)
         self.reporter = reporter
         self.owner = owner
         return (torecipients, ccrecipients)
@@ -507,12 +510,11 @@ class BatchTicketNotifyEmail(NotifyEmail
         return shorten_line(subj)
 
     def get_recipients(self, tktids):
-        alltorecipients = []
-        allccrecipients = []
+        alltorecipients = set()
+        allccrecipients = set()
         for t in tktids:
-            (torecipients, ccrecipients, reporter, owner) = \
-                get_ticket_notification_recipients(self.env, self.config,
-                                                   t, [])
-            alltorecipients.extend(torecipients)
-            allccrecipients.extend(ccrecipients)
-        return (list(set(alltorecipients)), list(set(allccrecipients)))
+            torecipients, ccrecipients, reporter, owner = \
+                get_ticket_notification_recipients(self.env, self.config, t)
+            alltorecipients.update(torecipients)
+            allccrecipients.update(ccrecipients)
+        return list(alltorecipients), list(allccrecipients)

Modified: bloodhound/vendor/trac/current/trac/ticket/query.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/ticket/query.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/ticket/query.py (original)
+++ bloodhound/vendor/trac/current/trac/ticket/query.py Fri Nov 14 11:06:23 2014
@@ -32,14 +32,14 @@ from trac.db import get_column_names
 from trac.mimeview.api import IContentConverter, Mimeview
 from trac.resource import Resource
 from trac.ticket.api import TicketSystem
-from trac.ticket.model import Milestone, group_milestones, Ticket
+from trac.ticket.model import Milestone, group_milestones
 from trac.util import Ranges, as_bool
 from trac.util.compat import any
 from trac.util.datefmt import format_datetime, from_utimestamp, parse_date, \
                               to_timestamp, to_utimestamp, utc, user_time
 from trac.util.presentation import Paginator
 from trac.util.text import empty, shorten_line, quote_query_string
-from trac.util.translation import _, tag_, cleandoc_
+from trac.util.translation import _, tag_, cleandoc_, ngettext
 from trac.web import arg_list_to_args, parse_arg_list, IRequestHandler
 from trac.web.href import Href
 from trac.web.chrome import (INavigationContributor, Chrome,
@@ -1165,7 +1165,7 @@ class QueryModule(Component):
                 values = []
                 for col in cols:
                     value = result[col]
-                    if col in ('cc', 'reporter'):
+                    if col in ('cc', 'owner', 'reporter'):
                         value = Chrome(self.env).format_emails(
                                     context.child(ticket), value)
                     elif col in query.time_fields:
@@ -1267,6 +1267,9 @@ class TicketQueryMacro(WikiMacroBase):
     The `rows` parameter can be used to specify which field(s) should
     be viewed as a row, e.g. `rows=description|summary`
 
+    The `col` parameter can be used to specify which fields should
+    be viewed as columns. For '''table''' format only.
+
     For compatibility with Trac 0.10, if there's a last positional parameter
     given to the macro, it will be used to specify the `format`.
     Also, using "&" as a field separator still works (except for `order`)
@@ -1327,8 +1330,10 @@ class TicketQueryMacro(WikiMacroBase):
 
         if format == 'count':
             cnt = query.count(req)
-            return tag.span(cnt, title='%d tickets for which %s' %
-                            (cnt, query_string), class_='query_count')
+            title = ngettext("%(num)d ticket for which %(query)s",
+                             "%(num)d tickets for which %(query)s",
+                             cnt, query=query_string)
+            return tag.span(cnt, title=title, class_='query_count')
 
         tickets = query.execute(req)
 
@@ -1350,14 +1355,21 @@ class TicketQueryMacro(WikiMacroBase):
             add_stylesheet(req, 'common/css/roadmap.css')
 
             def query_href(extra_args, group_value = None):
-                q = Query.from_string(self.env, query_string)
+                q = query_string + ''.join('&%s=%s' % (kw, v)
+                                           for kw in extra_args
+                                           if kw not in ['group', 'status']
+                                           for v in extra_args[kw])
+                q = Query.from_string(self.env, q)
+                args = {}
                 if q.group:
-                    extra_args[q.group] = group_value
-                    q.group = None
+                    args[q.group] = group_value
+                q.group = extra_args.get('group')
+                if 'status' in extra_args:
+                    args['status'] = extra_args['status']
                 for constraint in q.constraints:
-                    constraint.update(extra_args)
+                    constraint.update(args)
                 if not q.constraints:
-                    q.constraints.append(extra_args)
+                    q.constraints.append(args)
                 return q.get_href(formatter.context)
             chrome = Chrome(self.env)
             tickets = apply_ticket_permissions(self.env, req, tickets)

Modified: bloodhound/vendor/trac/current/trac/ticket/report.py
URL: 
http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/ticket/report.py?rev=1639602&r1=1639601&r2=1639602&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/ticket/report.py (original)
+++ bloodhound/vendor/trac/current/trac/ticket/report.py Fri Nov 14 11:06:23 
2014
@@ -186,17 +186,19 @@ class ReportModule(Component):
             if content_type: # i.e. alternate format
                 return template, data, content_type
 
+        from trac.ticket.query import QueryModule
+        show_query_link = 'TICKET_VIEW' in req.perm and \
+                          self.env.is_component_enabled(QueryModule)
+
         if id != -1 or action == 'new':
             add_ctxtnav(req, _('Available Reports'), href=req.href.report())
             add_link(req, 'up', req.href.report(), _('Available Reports'))
-        else:
+        elif show_query_link:
             add_ctxtnav(req, _('Available Reports'))
 
         # Kludge: only show link to custom query if the query module
         # is actually enabled
-        from trac.ticket.query import QueryModule
-        if 'TICKET_VIEW' in req.perm and \
-                self.env.is_component_enabled(QueryModule):
+        if show_query_link:
             add_ctxtnav(req, _('Custom Query'), href=req.href.query())
             data['query_href'] = req.href.query()
             data['saved_query_href'] = req.session.get('query_href')
@@ -680,6 +682,9 @@ class ReportModule(Component):
             try:
                 cursor.execute(count_sql, args)
             except Exception, e:
+                self.log.warn('Exception caught while executing report: %r, '
+                              'args %r%s', count_sql, args,
+                              exception_to_unicode(e, traceback=True))
                 return e, count_sql
             num_items = cursor.fetchone()[0]
 
@@ -689,6 +694,9 @@ class ReportModule(Component):
             try:
                 cursor.execute(colnames_sql, args)
             except Exception, e:
+                self.log.warn('Exception caught while executing report: %r, '
+                              'args %r%s', colnames_sql, args,
+                              exception_to_unicode(e, traceback=True))
                 return e, colnames_sql
             cols = get_column_names(cursor)
 
@@ -740,6 +748,9 @@ class ReportModule(Component):
         try:
             cursor.execute(sql, args)
         except Exception, e:
+            self.log.warn('Exception caught while executing report: %r, args '
+                          '%r%s',
+                          sql, args, exception_to_unicode(e, traceback=True))
             if order_by or limit_offset:
                 add_notice(req, _("Hint: if the report failed due to automatic"
                                   " modification of the ORDER BY clause or the"
@@ -755,14 +766,18 @@ class ReportModule(Component):
         return cols, rows, num_items, missing_args, limit_offset
 
     def get_report(self, id):
-        for title, description, sql in self.env.db_query("""
-                SELECT title, description, query from report WHERE id=%s
-                """, (id,)):
-            break
+        try:
+            number = int(id)
+        except (ValueError, TypeError):
+            pass
         else:
-            raise ResourceNotFound(_("Report {%(num)s} does not exist.",
-                                     num=id), _("Invalid Report Number"))
-        return title, description, sql
+            for title, description, sql in self.env.db_query("""
+                    SELECT title, description, query from report WHERE id=%s
+                    """, (number,)):
+                return title, description, sql
+
+        raise ResourceNotFound(_("Report {%(num)s} does not exist.", num=id),
+                               _("Invalid Report Number"))
 
     def get_var_args(self, req):
         # reuse somehow for #9574 (wiki vars)


Reply via email to