You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by tv...@apache.org on 2013/05/08 17:34:58 UTC

[01/50] git commit: [#5294] ticket:320 Check permissions on project REST controller

Updated Branches:
  refs/heads/tv/docs a83b4baff -> e64a52ede (forced update)


[#5294] ticket:320 Check permissions on project REST controller


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/c8311bbe
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/c8311bbe
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/c8311bbe

Branch: refs/heads/tv/docs
Commit: c8311bbe6cec1b58edfc8ef577e0c1f992f45ac5
Parents: 974fa9f
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon Apr 22 09:26:53 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Apr 26 20:31:33 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/rest.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c8311bbe/Allura/allura/controllers/rest.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/rest.py b/Allura/allura/controllers/rest.py
index c90a1ef..cf03733 100644
--- a/Allura/allura/controllers/rest.py
+++ b/Allura/allura/controllers/rest.py
@@ -281,5 +281,5 @@ class ProjectRestController(object):
         return dict(
             name=c.project.shortname,
             tools=[dict(name=t.tool_name, mount_point=t.options.mount_point, label=t.options.mount_label)
-                   for t in c.project.app_configs]
+                   for t in c.project.app_configs if h.has_access(t, 'read')]
         )


[31/50] git commit: add newrelic to requirements-sf.txt

Posted by tv...@apache.org.
add newrelic to requirements-sf.txt


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/a9b5b119
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/a9b5b119
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/a9b5b119

Branch: refs/heads/tv/docs
Commit: a9b5b119b611b712e5ae9f656a647b7bcee41a1d
Parents: 17617e6
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu May 2 20:13:54 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu May 2 20:13:54 2013 +0000

----------------------------------------------------------------------
 requirements-sf.txt |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a9b5b119/requirements-sf.txt
----------------------------------------------------------------------
diff --git a/requirements-sf.txt b/requirements-sf.txt
index 351f054..939dca3 100644
--- a/requirements-sf.txt
+++ b/requirements-sf.txt
@@ -8,6 +8,7 @@ ForgeHg==0.1.9
 ForgePastebin==0.2.6
 mechanize==0.2.4
 MySQL-python==1.2.3c1
+newrelic==1.11.0.55
 phpserialize==1.2
 psycopg2==2.2.2
 sf.phpsession==0.1


[06/50] git commit: [#5332] Restrict project name length to 15 chars

Posted by tv...@apache.org.
[#5332] Restrict project name length to 15 chars

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/f8475cd4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/f8475cd4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/f8475cd4

Branch: refs/heads/tv/docs
Commit: f8475cd4ade6176edcf20be1cf07a0d8c57bf6fc
Parents: cec8151
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Mon Apr 29 14:33:13 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Apr 29 14:44:08 2013 +0000

----------------------------------------------------------------------
 .../allura/ext/admin/templates/project_tools.html  |    2 +-
 Allura/allura/lib/helpers.py                       |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f8475cd4/Allura/allura/ext/admin/templates/project_tools.html
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/templates/project_tools.html b/Allura/allura/ext/admin/templates/project_tools.html
index a607cfd..0c8046d 100644
--- a/Allura/allura/ext/admin/templates/project_tools.html
+++ b/Allura/allura/ext/admin/templates/project_tools.html
@@ -64,7 +64,7 @@
         </span>
         <span class="mount-point-name-rules subproject">
           A valid subproject mount point must begin with a letter, contain only letters,
-          numbers, and dashes, and be from 3-63 characters in length.
+          numbers, and dashes, and be from 3-15 characters in length.
         </span>
       </small>
     </div>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f8475cd4/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 691204a..9ddad18 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -54,7 +54,7 @@ from .security import has_access
 
 
 # validates project, subproject, and user names
-re_project_name = re.compile(r'^[a-z][-a-z0-9]{2,62}$')
+re_project_name = re.compile(r'^[a-z][-a-z0-9]{2,14}$')
 
 # validates tool mount point names
 re_tool_mount_point = re.compile(r'^[a-z][-a-z0-9]{0,62}$')


[43/50] git commit: [#6133] ticket solved values are percentages, so *100

Posted by tv...@apache.org.
[#6133] ticket solved values are percentages, so *100


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/47e7e084
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/47e7e084
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/47e7e084

Branch: refs/heads/tv/docs
Commit: 47e7e084e97edadfea372dffb27d07f936140dd2
Parents: 59ea05c
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Sat May 4 22:46:19 2013 -0400
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon May 6 21:34:31 2013 +0000

----------------------------------------------------------------------
 ForgeUserStats/forgeuserstats/templates/index.html |   22 +++++++-------
 1 files changed, 11 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/47e7e084/ForgeUserStats/forgeuserstats/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/index.html b/ForgeUserStats/forgeuserstats/templates/index.html
index ceb3f81..bc23ec0 100644
--- a/ForgeUserStats/forgeuserstats/templates/index.html
+++ b/ForgeUserStats/forgeuserstats/templates/index.html
@@ -45,10 +45,10 @@
           <th>Time interval</th>
         </tr>
       </thead>
-      <tbody> 
+      <tbody>
         <tr>
           <td>Registration date</td>
-          <td>{{registration_date.strftime("%d %b %Y, %H:%M:%S (UTC)")}}</td> 
+          <td>{{registration_date.strftime("%d %b %Y, %H:%M:%S (UTC)")}}</td>
            <td>{{days}} day{% if days != 1 %}s{% endif %} ago</td>
         </tr>
         {% if last_login %}
@@ -187,7 +187,7 @@
             </td>
           {% endif %}
         </tr>
-        
+
         {% for key, value in artifacts_by_type.items() %}
           <tr>
             <td>
@@ -332,7 +332,7 @@
           </td>
           <td>
             {% if tottickets.averagesolvingtime %}
-              {{tottickets.averagesolvingtime.days}} days, 
+              {{tottickets.averagesolvingtime.days}} days,
               {{tottickets.averagesolvingtime.hours}} hours,
               {{tottickets.averagesolvingtime.minutes}} min
             {% else %}n/a{% endif %}
@@ -340,7 +340,7 @@
           <td>n/a</td>
           <td>
             {% if lastmonthtickets.averagesolvingtime %}
-              {{lastmonthtickets.averagesolvingtime.days}} days, 
+              {{lastmonthtickets.averagesolvingtime.days}} days,
               {{lastmonthtickets.averagesolvingtime.hours}} hours,
               {{lastmonthtickets.averagesolvingtime.minutes}} min
             {% else %}n/a{% endif %}
@@ -381,7 +381,7 @@
             {% endfor %}
           </tbody>
         </table>
-         
+
         {% if categories|length > 1 %}
           <p>
             The same data listed in the previous table is graphically presented by the following histogram.
@@ -420,9 +420,9 @@
           </tr>
           <tr>
             <td>Solved issues</td>
-            <td>{{ticketcontribution}} %</td>
-            <td>{{averageticketcontrib}} %</td>
-            <td>{{maxticketcontrib}} %</td>
+            <td>{{ticketcontribution*100}} %</td>
+            <td>{{averageticketcontrib*100}} %</td>
+            <td>{{maxticketcontrib*100}} %</td>
             <td><img src="{{c.project.url()}}userstats/tickets_ranking_bar"/> {{ticketspercentage}} %</td>
           </tr>
         </tbody>
@@ -438,13 +438,13 @@
   {% else %}
     {% if user %}
       <h2>Statistics not available</h2>
-      <div class="grid-20"> 
+      <div class="grid-20">
         This user has set his or her preferences so that personal statistics are not visible
         to other users of the forge.
       </div>
     {% else %}
       <h2>Invalid user</h2>
-      <div class="grid-20"> 
+      <div class="grid-20">
         You are looking for personal statistics of a user which doesn't exist on this forge. Check your url.
       </div>
     {% endif %}


[50/50] git commit: setup.py proxy script for RTD

Posted by tv...@apache.org.
setup.py proxy script for RTD

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/e64a52ed
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/e64a52ed
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/e64a52ed

Branch: refs/heads/tv/docs
Commit: e64a52ededdea4b4954271c14e7728eab12cbbef
Parents: 8e9c17d
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Wed May 8 15:34:18 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Wed May 8 15:34:18 2013 +0000

----------------------------------------------------------------------
 setup.py |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/e64a52ed/setup.py
----------------------------------------------------------------------
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..78c6258
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+"""
+This file is here exclusively for readthedocs.org support. RTD expects
+a setup.py file in the root of the project.
+"""
+
+import os
+import subprocess
+
+os.chdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Allura'))
+subprocess.call(["python", "setup.py", "develop"])


[33/50] git commit: [#5773] ticket:314 Move commit message back to the bottom

Posted by tv...@apache.org.
[#5773] ticket:314 Move commit message back to the bottom


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/d7bcc228
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/d7bcc228
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/d7bcc228

Branch: refs/heads/tv/docs
Commit: d7bcc2286ea81d13dab8019df40db657531e83c6
Parents: 94b70ce
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Apr 19 14:15:14 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu May 2 20:37:04 2013 +0000

----------------------------------------------------------------------
 Allura/allura/templates/widgets/repo/log.html |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d7bcc228/Allura/allura/templates/widgets/repo/log.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/repo/log.html b/Allura/allura/templates/widgets/repo/log.html
index 086b0b3..bdeeda2 100644
--- a/Allura/allura/templates/widgets/repo/log.html
+++ b/Allura/allura/templates/widgets/repo/log.html
@@ -34,7 +34,6 @@
         <tr class="rev">
           <td>
             <div class="grid-14">
-                {{g.markdown.convert(commit.message)}}
                 {%if is_file%}
                     <div class="grid-1"><input type="checkbox" class="revision" revision="{{commit._id.split(':')[-1]}}" url_commit="{{commit.url()}}"></div>
                 {%endif%}
@@ -59,6 +58,7 @@
                 {%if is_file%}
                     ({{commit.tree.get_obj_by_path(request.params.get('path')).size|filesizeformat}})
                 {%endif%}
+                {{g.markdown.convert(commit.message)}}
             </div>
           </td>
           <td style="vertical-align: text-top">


[24/50] git commit: [#5913] change id back to top_nav

Posted by tv...@apache.org.
[#5913] change id back to top_nav


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/22df7b42
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/22df7b42
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/22df7b42

Branch: refs/heads/tv/docs
Commit: 22df7b4299e2c7ff5ae0dfd56b465c545c0f4de2
Parents: c853c46
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Apr 1 19:05:33 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Wed May 1 20:38:37 2013 +0000

----------------------------------------------------------------------
 Allura/allura/templates/jinja_master/master.html |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/22df7b42/Allura/allura/templates/jinja_master/master.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/master.html b/Allura/allura/templates/jinja_master/master.html
index 00052c1..11482a7 100644
--- a/Allura/allura/templates/jinja_master/master.html
+++ b/Allura/allura/templates/jinja_master/master.html
@@ -82,7 +82,7 @@
             {% include g.theme.nav_menu %}
             {% endblock %}
       </div>
-      <div id="main_nav" class="">
+      <div id="top_nav" class="">
         {% block top_nav %}
         {% include g.theme.top_nav %}
         {% endblock %}


[05/50] git commit: [#5332] Miscellaneous code cleanup

Posted by tv...@apache.org.
[#5332] Miscellaneous code cleanup

- Rename project name regex to something logical
- Update make_safe_path_portion() to work in strict and relaxed modes

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/cec8151f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/cec8151f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/cec8151f

Branch: refs/heads/tv/docs
Commit: cec8151f3d2a9a7a9602816e7f9eb6d3b7a70359
Parents: ba32ac7
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Fri Apr 26 20:37:36 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Apr 29 14:44:07 2013 +0000

----------------------------------------------------------------------
 .../controllers/basetest_neighborhood_root.py      |    2 +-
 Allura/allura/controllers/basetest_project_root.py |    2 +-
 Allura/allura/controllers/project.py               |    4 +-
 Allura/allura/controllers/rest.py                  |    2 +-
 .../allura/ext/admin/templates/project_tools.html  |    2 +-
 Allura/allura/lib/helpers.py                       |   27 +++++++++---
 Allura/allura/lib/plugin.py                        |    4 +-
 Allura/allura/lib/widgets/forms.py                 |    2 +-
 Allura/allura/model/project.py                     |    2 +-
 Allura/allura/tests/test_helpers.py                |   33 +++++++++++---
 10 files changed, 56 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec8151f/Allura/allura/controllers/basetest_neighborhood_root.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/basetest_neighborhood_root.py b/Allura/allura/controllers/basetest_neighborhood_root.py
index cf36aed..b4ef16b 100644
--- a/Allura/allura/controllers/basetest_neighborhood_root.py
+++ b/Allura/allura/controllers/basetest_neighborhood_root.py
@@ -88,7 +88,7 @@ class BasetestNeighborhoodRootController(WsgiDispatchController, NeighborhoodCon
     @expose()
     def _lookup(self, pname, *remainder):
         pname = unquote(pname)
-        if not h.re_path_portion.match(pname):
+        if not h.re_project_name.match(pname):
             raise exc.HTTPNotFound, pname
         project = M.Project.query.get(shortname=self.prefix + pname, neighborhood_id=self.neighborhood._id)
         if project is None:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec8151f/Allura/allura/controllers/basetest_project_root.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/basetest_project_root.py b/Allura/allura/controllers/basetest_project_root.py
index 359984c..f9ec3d5 100644
--- a/Allura/allura/controllers/basetest_project_root.py
+++ b/Allura/allura/controllers/basetest_project_root.py
@@ -99,7 +99,7 @@ class BasetestProjectRootController(WsgiDispatchController, ProjectController):
 
     @expose()
     def _lookup(self, name, *remainder):
-        if not h.re_path_portion.match(name):
+        if not h.re_project_name.match(name):
             raise exc.HTTPNotFound, name
         subproject = M.Project.query.get(shortname=c.project.shortname + '/' + name,
                                          neighborhood_id=self.p_nbhd._id)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec8151f/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index 75e7792..4f02632 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -79,7 +79,7 @@ class NeighborhoodController(object):
     @expose()
     def _lookup(self, pname, *remainder):
         pname = unquote(pname)
-        if not h.re_path_portion.match(pname):
+        if not h.re_project_name.match(pname):
             raise exc.HTTPNotFound, pname
         project = M.Project.query.get(shortname=self.prefix + pname, neighborhood_id=self.neighborhood._id)
         if project is None and self.prefix == 'u/':
@@ -185,7 +185,7 @@ class NeighborhoodController(object):
             W.add_project.fields['project_name'].validate(project_name, '')
         except Invalid as e:
             result['name_message'] = str(e)
-        if not h.re_path_portion.match(unix_name) or not (3 <= len(unix_name) <= 15):
+        if not h.re_project_name.match(unix_name) or not (3 <= len(unix_name) <= 15):
             result['unixname_message'] = 'Please use only letters, numbers, and dashes 3-15 characters long.'
         else:
             result['unixname_message'] = plugin.ProjectRegistrationProvider.get().name_taken(unix_name, self.neighborhood)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec8151f/Allura/allura/controllers/rest.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/rest.py b/Allura/allura/controllers/rest.py
index 8ae0c70..c976c21 100644
--- a/Allura/allura/controllers/rest.py
+++ b/Allura/allura/controllers/rest.py
@@ -243,7 +243,7 @@ class NeighborhoodRestController(object):
 
     @expose()
     def _lookup(self, name, *remainder):
-        if not h.re_path_portion.match(name):
+        if not h.re_project_name.match(name):
             raise exc.HTTPNotFound, name
         name = self._neighborhood.shortname_prefix + name
         project = M.Project.query.get(shortname=name, neighborhood_id=self._neighborhood._id, deleted=False)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec8151f/Allura/allura/ext/admin/templates/project_tools.html
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/templates/project_tools.html b/Allura/allura/ext/admin/templates/project_tools.html
index dc7646c..a607cfd 100644
--- a/Allura/allura/ext/admin/templates/project_tools.html
+++ b/Allura/allura/ext/admin/templates/project_tools.html
@@ -30,7 +30,7 @@
   <div class="nested-grid-container">
     {% for tool in installable_tools %}
       <span class="tcenter grid-4 installable_tool">
-        <a class="install_trig" data-tool="{{ tool['name'] }}" data-relaxed-mount-points="{{ tool.app.relaxed_mount_points and 'true' or 'false' }}">
+        <a class="install_trig" data-tool="{{ tool['name'] }}" data-relaxed-mount-points="{{ 'true' if tool.app.relaxed_mount_points else 'false' }}">
           <span class="tool_title">{{ tool['app'].tool_label }}{{' (%s)' % tool.app.status if tool.app.status != 'production' else ''}}</span><br />
           <img src="{{ g.theme.app_icon_url(tool['app'], 32) or 'unk.png' }}" alt="">
         </a>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec8151f/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index b118efe..691204a 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -52,10 +52,16 @@ from allura.lib.decorators import exceptionless
 from allura.lib import AsciiDammit
 from .security import has_access
 
-re_path_portion_fragment = re.compile(r'[a-z][-a-z0-9]*')
-re_path_portion = re.compile(r'^[a-z][-a-z0-9]{2,62}$')
+
+# validates project, subproject, and user names
+re_project_name = re.compile(r'^[a-z][-a-z0-9]{2,62}$')
+
+# validates tool mount point names
 re_tool_mount_point = re.compile(r'^[a-z][-a-z0-9]{0,62}$')
+re_tool_mount_point_fragment = re.compile(r'[a-z][-a-z0-9]*')
 re_relaxed_tool_mount_point = re.compile(r'^[a-z0-9][-a-z0-9_\.\+]{0,62}$')
+re_relaxed_tool_mount_point_fragment = re.compile(r'[a-z0-9][-a-z0-9_\.\+]*')
+
 re_clean_vardec_key = re.compile(r'''\A
 ( # first part
 \w+# name...
@@ -67,17 +73,24 @@ re_clean_vardec_key = re.compile(r'''\A
 )+
 \Z''', re.VERBOSE)
 
-def make_safe_path_portion(ustr):
-    """Return an ascii representation of `ustr`
+def make_safe_path_portion(ustr, relaxed=True):
+    """Return an ascii representation of ``ustr`` that conforms to mount point
+    naming :attr:`rules <re_tool_mount_point_fragment>`.
+
+    Will return an empty string if no char in ``ustr`` is latin1-encodable.
+
+    :param relaxed: Use relaxed mount point naming rules (allows more
+        characters. See :attr:`re_relaxed_tool_mount_point_fragment`.
+    :returns: The converted string.
 
-    Will return an empty string if no char in `ustr`
-    is latin1-encodable.
     """
+    regex = (re_relaxed_tool_mount_point_fragment if relaxed else
+                re_tool_mount_point_fragment)
     ustr = really_unicode(ustr)
     s = ustr.encode('latin1', 'ignore')
     s = AsciiDammit.asciiDammit(s)
     s = s.lower()
-    s = '-'.join(re_path_portion_fragment.findall(s))
+    s = '-'.join(regex.findall(s))
     s = s.replace('--', '-')
     return s
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec8151f/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 48aa04b..b7722d2 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -464,7 +464,7 @@ class ProjectRegistrationProvider(object):
 
         self.rate_limit(user, neighborhood)
 
-        if not h.re_path_portion.match(shortname.replace('/', '')):
+        if not h.re_project_name.match(shortname.replace('/', '')):
             raise ValueError('Invalid project shortname: %s' % shortname)
 
         p = M.Project.query.get(shortname=shortname, neighborhood_id=neighborhood._id)
@@ -582,7 +582,7 @@ class ProjectRegistrationProvider(object):
 
     def register_subproject(self, project, name, user, install_apps):
         from allura import model as M
-        assert h.re_path_portion.match(name), 'Invalid subproject shortname'
+        assert h.re_project_name.match(name), 'Invalid subproject shortname'
         shortname = project.shortname + '/' + name
         sp = M.Project(
             parent_id=project._id,

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec8151f/Allura/allura/lib/widgets/forms.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/forms.py b/Allura/allura/lib/widgets/forms.py
index 43c6dd4..9501b70 100644
--- a/Allura/allura/lib/widgets/forms.py
+++ b/Allura/allura/lib/widgets/forms.py
@@ -618,7 +618,7 @@ class RegistrationForm(ForgeForm):
         username = ew.TextField(
             label='Desired Username',
             validator=fev.Regex(
-                h.re_path_portion))
+                h.re_project_name))
         username.validator._messages['invalid'] = (
             'Usernames must include only letters, numbers, and dashes.'
             ' They must also start with a letter and be at least 3 characters'

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec8151f/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index b3f1131..350f353 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -606,7 +606,7 @@ class Project(MappedClass, ActivityNode, ActivityObject):
                 return ac
 
     def new_subproject(self, name, install_apps=True, user=None):
-        if not h.re_path_portion.match(name):
+        if not h.re_project_name.match(name):
             raise exceptions.ToolError, 'Mount point "%s" is invalid' % name
         provider = plugin.ProjectRegistrationProvider.get()
         return provider.register_subproject(self, name, user or c.user, install_apps)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec8151f/Allura/allura/tests/test_helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index 2b8e179..ed40cfc 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -17,6 +17,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+from unittest import TestCase
 from os import path
 from mock import Mock, patch
 
@@ -34,13 +35,31 @@ def setUp(self):
     """Method called by nose before running each test"""
     setup_basic_test()
 
-def test_make_safe_path_portion():
-    s = u'Задачи'
-    new_s = h.make_safe_path_portion(s)
-    assert len(new_s) == 0
-    s = 'åß∂ƒ'
-    new_s = h.make_safe_path_portion(s)
-    assert new_s == 'ab'
+
+class TestMakeSafePathPortion(TestCase):
+    def setUp(self):
+        self.f = h.make_safe_path_portion
+
+    def test_no_latin1_chars(self):
+        s = self.f(u'Задачи')
+        self.assertEqual(s, '')
+
+    def test_some_latin1_chars(self):
+        s = self.f('åß∂ƒ')
+        self.assertEqual(s, 'ab')
+
+    def test_strict_mount_point_names(self):
+        s = self.f('1this+is.illegal', relaxed=False)
+        self.assertEqual(s, 'this-is-illegal')
+        s = self.f('this-1-is-legal', relaxed=False)
+        self.assertEqual(s, 'this-1-is-legal')
+
+    def test_relaxed_mount_point_names(self):
+        s = self.f('1_this+is.legal')
+        self.assertEqual(s, '1_this+is.legal')
+        s = self.f('not*_legal')
+        self.assertEqual(s, 'not-legal')
+
 
 def test_really_unicode():
     here_dir = path.dirname(__file__)


[37/50] git commit: [#5773] ticket:328 fixed authored.name and committed name

Posted by tv...@apache.org.
[#5773]  ticket:328  fixed authored.name and committed name


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/ba100cc3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/ba100cc3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/ba100cc3

Branch: refs/heads/tv/docs
Commit: ba100cc3fa89641552ec2618d97bbe6d1cf25acd
Parents: 5a51840
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Thu May 2 09:53:31 2013 +0400
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu May 2 20:37:06 2013 +0000

----------------------------------------------------------------------
 Allura/allura/templates/widgets/repo/log.html |   16 ++++++----------
 1 files changed, 6 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ba100cc3/Allura/allura/templates/widgets/repo/log.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/repo/log.html b/Allura/allura/templates/widgets/repo/log.html
index c46b425..1d2c24d 100644
--- a/Allura/allura/templates/widgets/repo/log.html
+++ b/Allura/allura/templates/widgets/repo/log.html
@@ -43,23 +43,19 @@
                         <a href="{{c.app.repo.url_for_commit(tag)}}">{{tag}}</a>{% if not loop.last %}&nbsp;{% endif %}
                     {%- endfor %})
                 {% endif %}
-                {% if commit.committed.email != commit.authored.email %}
-                {% if commit.committer_url %}
+                {%if is_file%}
+                    ({{commit.tree.get_obj_by_path(request.params.get('path')).size|filesizeformat}})
+                {%endif%}
                 by
+                {{email_gravatar(commit.authored.email, title=commit.authored.name, size=16)}} {{commit.authored.name}}{%if commit.committed.email != commit.authored.email %}, pushed by
+                {% if commit.committer_url %}
                 <a href="{{commit.committer_url}}">{{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}}
                     {{commit.committed.name}}</a>,
                 pushed
                 {% else %}
-                by
-                {{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}} {{commit.committed.name}},
-                pushed
+                {{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}} {{commit.committed.name}}
                 {% endif %}
                 {% endif %}
-                by
-                {{email_gravatar(commit.authored.email, title=commit.authored.name, size=16)}} {{commit.authored.name}}
-                {%if is_file%}
-                    ({{commit.tree.get_obj_by_path(request.params.get('path')).size|filesizeformat}})
-                {%endif%}
                 {{g.markdown.convert(commit.message)}}
             </div>
           </td>


[45/50] git commit: [#6133] remove histogram, and matplotlib & numpy dependences

Posted by tv...@apache.org.
[#6133] remove histogram, and matplotlib & numpy dependences

Only remaining use of matplotlib was a histogram (bar chart)
of a user's projects per trove category.  This is a simple chart
and the data is available in a table, so not worth the very big
and complex dependencies of matplotlib and numpy and associated
workarounds due to them.  So removing the histogram, dependencies,
and workarounds.


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/3e12f6d5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/3e12f6d5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/3e12f6d5

Branch: refs/heads/tv/docs
Commit: 3e12f6d574d4685c0bed84e3ae95772b24cd6425
Parents: b21778f
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Sat May 4 23:03:06 2013 -0400
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon May 6 21:34:31 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/graphics/__init__.py             |   16 ---
 Allura/allura/lib/graphics/graphic_methods.py      |   86 ---------------
 Allura/docs/conf.py                                |   25 ----
 .../forgeuserstats/controllers/userstats.py        |   30 -----
 ForgeUserStats/forgeuserstats/templates/index.html |    9 --
 requirements-common.txt                            |    2 -
 vagrant/manifests/ubuntu-1204-server-amd64.pp      |   14 ---
 7 files changed, 0 insertions(+), 182 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/Allura/allura/lib/graphics/__init__.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/graphics/__init__.py b/Allura/allura/lib/graphics/__init__.py
deleted file mode 100644
index 144e298..0000000
--- a/Allura/allura/lib/graphics/__init__.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/Allura/allura/lib/graphics/graphic_methods.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/graphics/graphic_methods.py b/Allura/allura/lib/graphics/graphic_methods.py
deleted file mode 100644
index 777cfc0..0000000
--- a/Allura/allura/lib/graphics/graphic_methods.py
+++ /dev/null
@@ -1,86 +0,0 @@
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.
-
-import StringIO
-
-from matplotlib.backends.backend_agg import FigureCanvasAgg
-from matplotlib.figure import Figure
-import Image
-
-
-def create_histogram(data, tick_labels, y_label, title):
-    fig = Figure(figsize=(10,5), dpi=80, facecolor='white')
-    ax = fig.add_subplot(111, axisbg='#EEEEFF')
-
-    canvas = FigureCanvasAgg(fig)
-    n, bins, patches = ax.hist(data, facecolor='#330099', edgecolor='white')
-    ax.set_ylabel(y_label)
-    ax.set_title(title)
-
-    ax.set_xticks(range(len(tick_labels)+1))
-    ax.get_xaxis().set_ticklabels(tick_labels, rotation=45, va='top', ha='right')
-    ax.get_xaxis().set_ticks_position('none')
-    ax.set_autoscalex_on(False)
-
-    ax.set_xlim((-1, len(tick_labels)))
-    ax.set_ylim((0, 1+max([data.count(el) for el in data])))
-    fig.subplots_adjust(bottom=0.3)
-
-    canvas.draw()
-
-    s = canvas.tostring_rgb()
-    l,b,w,h = fig.bbox.bounds
-    w, h = int(w), int(h)
-
-    output = StringIO.StringIO()
-    im = Image.fromstring( "RGB", (w,h), s)
-    im.save(output, 'PNG')
-
-    return output.getvalue()
-
-def create_progress_bar(value):
-    value = value / 100.0
-    if value < 1 / 5.0:
-        color = 'red'
-    elif value < 2 / 5.0:
-        color = 'orange'
-    elif value < 3 / 5.0:
-        color = 'yellow'
-    elif value < 4 / 5.0:
-        color = 'lightgreen'
-    else:
-        color = 'green'
-
-    fig = Figure(figsize=(3,0.5), dpi=40, facecolor='gray')
-    canvas = FigureCanvasAgg(fig)
-    canvas.draw()
-
-    from matplotlib.patches import Rectangle
-    from matplotlib.axes import Axes
-
-    fig.draw_artist(Rectangle((0,0), int(value * 120), 20, color=color))
-    fig.draw_artist(Rectangle((1,0), 119, 19, fill=False, ec='black'))
-
-    l,b,w,h = fig.bbox.bounds
-    s = canvas.tostring_rgb()
-    w, h = int(w), int(h)
-
-    output = StringIO.StringIO()
-    im = Image.fromstring( "RGB", (w,h), s)
-    im.save(output, 'PNG')
-
-    return output.getvalue()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/Allura/docs/conf.py
----------------------------------------------------------------------
diff --git a/Allura/docs/conf.py b/Allura/docs/conf.py
index 81c0e1f..f7d8757 100644
--- a/Allura/docs/conf.py
+++ b/Allura/docs/conf.py
@@ -30,31 +30,6 @@
 
 import sys, os
 
-class Mock(object):
-    def __init__(self, *args, **kwargs):
-        pass
-
-    def __call__(self, *args, **kwargs):
-        return Mock()
-
-    @classmethod
-    def __getattr__(cls, name):
-        if name in ('__file__', '__path__'):
-            return '/dev/null'
-        elif name[0] == name[0].upper():
-            mockType = type(name, (), {})
-            mockType.__module__ = __name__
-            return mockType
-        else:
-            return Mock()
-
-MOCK_MODULES = ['matplotlib', 'matplotlib.axes',
-        'matplotlib.backends', 'matplotlib.backends.backend_agg',
-        'matplotlib.figure', 'matplotlib.patches']
-
-for mod_name in MOCK_MODULES:
-    sys.modules[mod_name] = Mock()
-
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/ForgeUserStats/forgeuserstats/controllers/userstats.py
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/controllers/userstats.py b/ForgeUserStats/forgeuserstats/controllers/userstats.py
index 1cb5505..85b26df 100644
--- a/ForgeUserStats/forgeuserstats/controllers/userstats.py
+++ b/ForgeUserStats/forgeuserstats/controllers/userstats.py
@@ -20,7 +20,6 @@ from tg.decorators import with_trailing_slash
 from datetime import datetime
 from allura.controllers import BaseController
 import allura.model as M
-from allura.lib.graphics.graphic_methods import create_histogram, create_progress_bar
 from forgeuserstats.model.stats import UserStats
 from pylons import tmpl_context as c
 from allura.lib.security import require_access
@@ -195,35 +194,6 @@ class ForgeUserStatsController(BaseController):
             user=self.user,
             data=artifacts)
 
-    @expose()
-    def categories_graph(self):
-        self.user = c.project.user_project_of
-        if not self.user:
-            return None
-
-        categories = {}
-        for p in self.user.my_projects():
-            for cat in p.trove_topic:
-                cat = M.TroveCategory.query.get(_id = cat)
-                if categories.get(cat):
-                    categories[cat] += 1
-                else:
-                    categories[cat] = 1
-        data = []
-        labels = []
-        i = 0
-        for cat in sorted(categories.keys(), key=lambda x:x.fullname):
-            n = categories[cat]
-            data = data + [i] * n
-            label = cat.fullname
-            if len(label) > 15:
-                label = label[:15] + "..."
-            labels.append(label)
-            i += 1
-
-        return create_histogram(data, labels,
-            'Number of projects', 'Projects by category')
-
 
 def _getDataForCategory(category, stats):
     totcommits = stats.getCommits(category)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/ForgeUserStats/forgeuserstats/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/index.html b/ForgeUserStats/forgeuserstats/templates/index.html
index 2bb6314..406fb20 100644
--- a/ForgeUserStats/forgeuserstats/templates/index.html
+++ b/ForgeUserStats/forgeuserstats/templates/index.html
@@ -381,15 +381,6 @@
             {% endfor %}
           </tbody>
         </table>
-
-        {% if categories|length > 1 %}
-          <p>
-            The same data listed in the previous table is graphically presented by the following histogram.
-          </p>
-          <p>
-            <img src="{{c.project.url()}}userstats/categories_graph"/>
-          </p>
-        {% endif %}
     {% endif %}
   {% else %}
     {% if user %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/requirements-common.txt
----------------------------------------------------------------------
diff --git a/requirements-common.txt b/requirements-common.txt
index 75f4541..21ea929 100644
--- a/requirements-common.txt
+++ b/requirements-common.txt
@@ -47,8 +47,6 @@ TurboGears2==2.1.5
 WebOb==1.0.8
 # part of the stdlib, but with a version number.  see http://guide.python-distribute.org/pip.html#listing-installed-packages
 wsgiref==0.1.2
-numpy==1.6.1
-matplotlib==1.1.1
 
 # tg2 deps (not used directly)
 Babel==0.9.6

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/vagrant/manifests/ubuntu-1204-server-amd64.pp
----------------------------------------------------------------------
diff --git a/vagrant/manifests/ubuntu-1204-server-amd64.pp b/vagrant/manifests/ubuntu-1204-server-amd64.pp
index 1feb18e..4031084 100644
--- a/vagrant/manifests/ubuntu-1204-server-amd64.pp
+++ b/vagrant/manifests/ubuntu-1204-server-amd64.pp
@@ -107,19 +107,6 @@ file { '/home/vagrant/src/allura':
   require => [ File['/home/vagrant/src'], Exec['clone repo'] ],
 }
 
-# HACK to get numpy installed in the venv before installing
-# remaining dependencies via requirements file
-exec { "pip install numpy":
-  command => "/home/vagrant/env-allura/bin/pip install numpy==1.6.1",
-  cwd     => "/vagrant/allura",
-  timeout => 0,
-  logoutput => true,
-  returns => 0,
-  tries => 3,
-  require => [ Exec[ "clone repo"], Exec[ "create allura venv" ],
-               ],
-}
-
 # install Allura dependencies
 exec { "pip install":
   command => "/home/vagrant/env-allura/bin/pip install -r requirements.txt",
@@ -132,7 +119,6 @@ exec { "pip install":
   tries => 3,
   require => [ Exec[ "clone repo"], Exec[ "create allura venv" ],
                File["/usr/lib/libjpeg.so"], File["/usr/lib/libz.so"],
-               Exec["pip install numpy"],
                ],
 }
 


[17/50] git commit: [#6172] Rename new Feed object to FeedArgs

Posted by tv...@apache.org.
[#6172] Rename new Feed object to FeedArgs

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/d34331e8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/d34331e8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/d34331e8

Branch: refs/heads/tv/docs
Commit: d34331e8d500e77a8f390222606e62758b10638a
Parents: 391aa92
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Tue Apr 30 19:44:46 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Apr 30 19:45:59 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/discuss.py               |   10 +++++-----
 Allura/allura/controllers/feed.py                  |    8 ++++----
 Allura/allura/controllers/project.py               |    6 +++---
 Allura/allura/ext/user_profile/user_main.py        |    6 +++---
 ForgeBlog/forgeblog/main.py                        |    6 +++---
 .../forgediscussion/controllers/root.py            |    6 +++---
 ForgeTracker/forgetracker/tracker_main.py          |    6 +++---
 ForgeWiki/forgewiki/wiki_main.py                   |    6 +++---
 8 files changed, 27 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d34331e8/Allura/allura/controllers/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index b37d880..96f8979 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -38,7 +38,7 @@ from allura.lib.helpers import DateTimeConverter
 
 from allura.lib.widgets import discuss as DW
 from .attachments import AttachmentsController, AttachmentController
-from .feed import Feed, FeedController
+from .feed import FeedArgs, FeedController
 
 log = logging.getLogger(__name__)
 
@@ -106,13 +106,13 @@ class DiscussionController(BaseController, FeedController):
         redirect(request.referer)
 
     def get_feed(self, project, app, user):
-        """Return a :class:`allura.controllers.feed.Feed` object describing
+        """Return a :class:`allura.controllers.feed.FeedArgs` object describing
         the xml feed for this controller.
 
         Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
 
         """
-        return Feed(
+        return FeedArgs(
             dict(ref_id={'$in': [t.index_id() for t in self.discussion.threads]}),
             'Recent posts to %s' % self.discussion.name,
             self.discussion.url())
@@ -224,13 +224,13 @@ class ThreadController(BaseController, FeedController):
         redirect(self.discussion.url())
 
     def get_feed(self, project, app, user):
-        """Return a :class:`allura.controllers.feed.Feed` object describing
+        """Return a :class:`allura.controllers.feed.FeedArgs` object describing
         the xml feed for this controller.
 
         Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
 
         """
-        return Feed(
+        return FeedArgs(
             dict(ref_id=self.thread.index_id()),
             'Recent posts to %s' % (self.thread.subject or '(no subject)'),
             self.thread.url())

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d34331e8/Allura/allura/controllers/feed.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/feed.py b/Allura/allura/controllers/feed.py
index f014b21..9be693d 100644
--- a/Allura/allura/controllers/feed.py
+++ b/Allura/allura/controllers/feed.py
@@ -25,7 +25,7 @@ from allura import model as M
 from allura.lib import helpers as h
 
 
-class Feed(object):
+class FeedArgs(object):
     """A facade for the arguments required by
     :meth:`allura.model.artifact.Feed.feed`.
 
@@ -92,17 +92,17 @@ class FeedController(object):
         return feed.writeString('utf-8')
 
     def get_feed(self, project, app, user):
-        """Return a default :class:`Feed` for this controller.
+        """Return a default :class:`FeedArgs` for this controller.
 
         Subclasses should override to customize the feed.
 
         :param project: :class:`allura.model.project.Project`
         :param app: :class:`allura.app.Application`
         :param user: :class:`allura.model.auth.User`
-        :rtype: :class:`Feed`
+        :rtype: :class:`FeedArgs`
 
         """
-        return Feed(
+        return FeedArgs(
             dict(project_id=project._id, app_config_id=app.config._id),
             'Recent changes to %s' % app.config.options.mount_point,
             app.url)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d34331e8/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index 3bfe0ca..e60b494 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -40,7 +40,7 @@ from allura.lib import helpers as h
 from allura.lib import utils
 from allura.lib.decorators import require_post
 from allura.controllers.error import ErrorController
-from allura.controllers.feed import Feed, FeedController
+from allura.controllers.feed import FeedArgs, FeedController
 from allura.lib.security import require_access, has_access
 from allura.lib.security import RoleCache
 from allura.lib.widgets import forms as ff
@@ -367,13 +367,13 @@ class ProjectController(FeedController):
             redirect(c.project.app_configs[0].options.mount_point + '/')
 
     def get_feed(self, project, app, user):
-        """Return a :class:`allura.controllers.feed.Feed` object describing
+        """Return a :class:`allura.controllers.feed.FeedArgs` object describing
         the xml feed for this controller.
 
         Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
 
         """
-        return Feed(
+        return FeedArgs(
             dict(project_id=project._id),
             'Recent changes to Project %s' % project.name,
             project.url())

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d34331e8/Allura/allura/ext/user_profile/user_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/user_profile/user_main.py b/Allura/allura/ext/user_profile/user_main.py
index c6e2402..54baebf 100644
--- a/Allura/allura/ext/user_profile/user_main.py
+++ b/Allura/allura/ext/user_profile/user_main.py
@@ -32,7 +32,7 @@ from allura.lib.helpers import DateTimeConverter
 from allura.lib.security import require_access
 from allura.model import User, Feed, ACE
 from allura.controllers import BaseController
-from allura.controllers.feed import Feed, FeedController
+from allura.controllers.feed import FeedArgs, FeedController
 from allura.lib.decorators import require_post
 
 log = logging.getLogger(__name__)
@@ -93,14 +93,14 @@ class UserProfileController(BaseController, FeedController):
         return dict(user=user)
 
     def get_feed(self, project, app, user):
-        """Return a :class:`allura.controllers.feed.Feed` object describing
+        """Return a :class:`allura.controllers.feed.FeedArgs` object describing
         the xml feed for this controller.
 
         Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
 
         """
         user = project.user_project_of
-        return Feed(
+        return FeedArgs(
             {'author_link': user.url()},
             'Recent posts by %s' % user.display_name,
             project.url())

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d34331e8/ForgeBlog/forgeblog/main.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index 0c7af13..24b0bf2 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -46,7 +46,7 @@ from allura.lib.widgets import form_fields as ffw
 from allura.lib.widgets.search import SearchResults, SearchHelp
 from allura import model as M
 from allura.controllers import BaseController, AppDiscussionController
-from allura.controllers.feed import Feed, FeedController
+from allura.controllers.feed import FeedArgs, FeedController
 
 # Local imports
 from forgeblog import model as BM
@@ -354,13 +354,13 @@ class PostController(BaseController, FeedController):
         redirect(h.really_unicode(request.referer).encode('utf-8'))
 
     def get_feed(self, project, app, user):
-        """Return a :class:`allura.controllers.feed.Feed` object describing
+        """Return a :class:`allura.controllers.feed.FeedArgs` object describing
         the xml feed for this controller.
 
         Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
 
         """
-        return Feed(
+        return FeedArgs(
             dict(ref_id=self.post.index_id()),
             'Recent changes to %s' % self.post.title,
             self.post.url())

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d34331e8/ForgeDiscussion/forgediscussion/controllers/root.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/controllers/root.py b/ForgeDiscussion/forgediscussion/controllers/root.py
index f731da3..8e074aa 100644
--- a/ForgeDiscussion/forgediscussion/controllers/root.py
+++ b/ForgeDiscussion/forgediscussion/controllers/root.py
@@ -33,7 +33,7 @@ from allura.lib import helpers as h
 from allura.lib.utils import AntiSpam
 from allura.lib.decorators import require_post
 from allura.controllers import BaseController, DispatchIndex
-from allura.controllers.feed import Feed, FeedController
+from allura.controllers.feed import FeedArgs, FeedController
 
 from .forum import ForumController
 from forgediscussion import import_support
@@ -187,13 +187,13 @@ class RootController(BaseController, DispatchIndex, FeedController):
         redirect(request.referer)
 
     def get_feed(self, project, app, user):
-        """Return a :class:`allura.controllers.feed.Feed` object describing
+        """Return a :class:`allura.controllers.feed.FeedArgs` object describing
         the xml feed for this controller.
 
         Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
 
         """
-        return Feed(
+        return FeedArgs(
             dict(project_id=project._id, app_config_id=app.config._id),
              'Recent posts to %s' % app.config.options.mount_label,
             app.url)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d34331e8/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 6270e96..0f266aa 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -61,7 +61,7 @@ from allura.lib.zarkov_helpers import zero_fill_zarkov_result
 from allura.controllers import AppDiscussionController, AppDiscussionRestController
 from allura.controllers import attachments as ac
 from allura.controllers import BaseController
-from allura.controllers.feed import Feed, FeedController
+from allura.controllers.feed import FeedArgs, FeedController
 from allura.tasks import mail_tasks
 
 # Local imports
@@ -1259,7 +1259,7 @@ class TicketController(BaseController, FeedController):
             raise exc.HTTPNotFound, 'Ticket #%s does not exist.' % self.ticket_num
 
     def get_feed(self, project, app, user):
-        """Return a :class:`allura.controllers.feed.Feed` object describing
+        """Return a :class:`allura.controllers.feed.FeedArgs` object describing
         the xml feed for this controller.
 
         Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
@@ -1267,7 +1267,7 @@ class TicketController(BaseController, FeedController):
         """
         title = 'Recent changes to %d: %s' % (
             self.ticket.ticket_num, self.ticket.summary)
-        return Feed(
+        return FeedArgs(
             {'ref_id': self.ticket.index_id()},
             title,
             self.ticket.url())

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d34331e8/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index dfb982b..0f5151e 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -41,7 +41,7 @@ from allura.lib.security import require_access, has_access
 from allura.controllers import AppDiscussionController, BaseController
 from allura.controllers import DispatchIndex
 from allura.controllers import attachments as ac
-from allura.controllers.feed import Feed, FeedController
+from allura.controllers.feed import FeedArgs, FeedController
 from allura.lib import widgets as w
 from allura.lib.widgets import form_fields as ffw
 from allura.lib.widgets.subscriptions import SubscribeForm
@@ -558,7 +558,7 @@ class PageController(BaseController, FeedController):
         return pformat(self.page)
 
     def get_feed(self, project, app, user):
-        """Return a :class:`allura.controllers.feed.Feed` object describing
+        """Return a :class:`allura.controllers.feed.FeedArgs` object describing
         the xml feed for this controller.
 
         Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
@@ -566,7 +566,7 @@ class PageController(BaseController, FeedController):
         """
         if not self.page:
             return None
-        return Feed(
+        return FeedArgs(
             {'ref_id': self.page.index_id()},
             'Recent changes to %s' % self.page.title,
             self.page.url())


[13/50] git commit: [#5891] ticket:327 removed add_attach from helpers, and put it to Post

Posted by tv...@apache.org.
[#5891]  ticket:327  removed add_attach from helpers, and put it to Post


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/5c8db545
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/5c8db545
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/5c8db545

Branch: refs/heads/tv/docs
Commit: 5c8db5459133394fbfe82828fcab82d42bd785ad
Parents: c40773b
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Tue Apr 30 15:10:11 2013 +0400
Committer: Yuriy Arhipov <yu...@yandex.ru>
Committed: Tue Apr 30 15:10:11 2013 +0400

----------------------------------------------------------------------
 Allura/allura/controllers/discuss.py         |    8 ++++----
 Allura/allura/lib/helpers.py                 |   15 +--------------
 Allura/allura/model/discuss.py               |   12 ++++++++++++
 Allura/allura/tests/model/test_discussion.py |    7 +++++--
 4 files changed, 22 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5c8db545/Allura/allura/controllers/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index eb34981..218f9b4 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -211,7 +211,7 @@ class ThreadController(BaseController):
         file_info = kw.get('file_info', None)
         p = self.thread.add_post(**kw)
         is_spam = g.spam_checker.check(kw['text'], artifact=p, user=c.user)
-        h.attach_to_post(p, file_info)
+        p.add_attachment(file_info)
         if self.thread.artifact:
             self.thread.artifact.mod_date = datetime.utcnow()
         flash('Message posted')
@@ -294,7 +294,7 @@ class PostController(BaseController):
             require_access(self.post, 'moderate')
             post_fields = self.W.edit_post.to_python(kw, None)
             file_info = post_fields.pop('file_info', None)
-            h.attach_to_post(self.post, file_info)
+            self.post.add_attachment(file_info)
             for k,v in post_fields.iteritems():
                 try:
                     setattr(self.post, k, v)
@@ -339,7 +339,7 @@ class PostController(BaseController):
         kw = self.W.edit_post.to_python(kw, None)
         p = self.thread.add_post(parent_id=self.post._id, **kw)
         is_spam = g.spam_checker.check(kw['text'], artifact=p, user=c.user)
-        h.attach_to_post(p, file_info)
+        p.add_attachment(file_info)
         redirect(request.referer)
 
     @h.vardec
@@ -373,7 +373,7 @@ class PostController(BaseController):
     @require_post()
     def attach(self, file_info=None):
         require_access(self.post, 'moderate')
-        h.attach_to_post(self.post, file_info)
+        self.post.add_attachment(file_info)
         redirect(request.referer)
 
     @expose()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5c8db545/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index deed268..29cf44e 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -51,7 +51,6 @@ from allura.lib import exceptions as exc
 from allura.lib.decorators import exceptionless
 from allura.lib import AsciiDammit
 from .security import has_access
-from allura.lib import utils
 
 
 # validates project, subproject, and user names
@@ -702,16 +701,4 @@ def get_first(d, key):
     v = d.get(key)
     if isinstance(v, list):
         return v[0] if len(v) > 0 else None
-    return v
-
-
-def attach_to_post(post, file_info):
-    if hasattr(file_info, 'file'):
-        mime_type = file_info.type
-        if not mime_type or '/' not in mime_type:
-            mime_type = utils.guess_mime_type(file_info.filename)
-        post.attach(
-            file_info.filename, file_info.file, content_type=mime_type,
-            post_id=post._id,
-            thread_id=post.thread_id,
-            discussion_id=post.discussion_id)
+    return v
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5c8db545/Allura/allura/model/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/discuss.py b/Allura/allura/model/discuss.py
index d169e1b..4375077 100644
--- a/Allura/allura/model/discuss.py
+++ b/Allura/allura/model/discuss.py
@@ -31,6 +31,7 @@ from ming.utils import LazyProperty
 from allura.lib import helpers as h
 from allura.lib import security
 from allura.lib.security import require_access, has_access
+from allura.lib import utils
 from allura.model.notification import Notification, Mailbox
 from .artifact import Artifact, ArtifactReference, VersionedArtifact, Snapshot, Message, Feed
 from .attachments import BaseAttachment
@@ -513,6 +514,17 @@ class Post(Message, VersionedArtifact, ActivityObject):
         return self.attachment_class().query.find(dict(
             post_id=self._id, type='attachment'))
 
+    def add_attachment(self, file_info):
+        if hasattr(file_info, 'file'):
+            mime_type = file_info.type
+            if not mime_type or '/' not in mime_type:
+                mime_type = utils.guess_mime_type(file_info.filename)
+            self.attach(
+                file_info.filename, file_info.file, content_type=mime_type,
+                post_id=self._id,
+                thread_id=self.thread_id,
+                discussion_id=self.discussion_id)
+
     def last_edit_by(self):
         return User.query.get(_id=self.last_edit_by_id) or User.anonymous()
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5c8db545/Allura/allura/tests/model/test_discussion.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_discussion.py b/Allura/allura/tests/model/test_discussion.py
index 2ab4b2a..35c5594 100644
--- a/Allura/allura/tests/model/test_discussion.py
+++ b/Allura/allura/tests/model/test_discussion.py
@@ -206,7 +206,7 @@ def test_attachment_methods():
     assert '\nAttachment: fake.txt (37 Bytes; text/plain)' in n.text
 
 @with_setup(setUp, tearDown)
-def test_attach_to_post():
+def test_add_attachment():
     test_file = FieldStorage()
     test_file.name = 'file_info'
     test_file.filename = 'test.txt'
@@ -215,9 +215,12 @@ def test_attach_to_post():
     d = M.Discussion(shortname='test', name='test')
     t = M.Thread.new(discussion_id=d._id, subject='Test Thread')
     test_post = t.post('test post')
-    h.attach_to_post(test_post, test_file)
+    test_post.add_attachment(test_file)
     ThreadLocalORMSession.flush_all()
     assert test_post.attachments.count() == 1, test_post.attachments.count()
+    attach = test_post.attachments.first()
+    assert attach.filename == 'test.txt', attach.filename
+    assert attach.content_type == 'text/plain', attach.content_type
 
 @with_setup(setUp, tearDown)
 def test_discussion_delete():


[48/50] git commit: remove duplicate "pushed" word

Posted by tv...@apache.org.
remove duplicate "pushed" word


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/87a89b2b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/87a89b2b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/87a89b2b

Branch: refs/heads/tv/docs
Commit: 87a89b2b32234e6de64f9790fbab1d9c48c099cc
Parents: 9bfc415
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue May 7 19:53:59 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue May 7 19:53:59 2013 +0000

----------------------------------------------------------------------
 Allura/allura/templates/widgets/repo/log.html |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/87a89b2b/Allura/allura/templates/widgets/repo/log.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/repo/log.html b/Allura/allura/templates/widgets/repo/log.html
index 1d2c24d..7afac6c 100644
--- a/Allura/allura/templates/widgets/repo/log.html
+++ b/Allura/allura/templates/widgets/repo/log.html
@@ -49,9 +49,8 @@
                 by
                 {{email_gravatar(commit.authored.email, title=commit.authored.name, size=16)}} {{commit.authored.name}}{%if commit.committed.email != commit.authored.email %}, pushed by
                 {% if commit.committer_url %}
-                <a href="{{commit.committer_url}}">{{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}}
-                    {{commit.committed.name}}</a>,
-                pushed
+                    <a href="{{commit.committer_url}}">{{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}}
+                    {{commit.committed.name}}</a>
                 {% else %}
                 {{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}} {{commit.committed.name}}
                 {% endif %}


[19/50] git commit: [#6172] Remove default TG file extension handling.

Posted by tv...@apache.org.
[#6172] Remove default TG file extension handling.

Repo names can now have dots in them, and TG was stripping the
dot and everything after it from the repo name in the url.
Rather than adding another hack to piece the URL back
together, we're turning off this behavior.

Some controllers were relying on the extension stripping to
automatically forward `feed.{rss|atom}` -> `feed`. In these cases,
explicit attrs for rss and atom were added to the controller.

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/7244932d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/7244932d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/7244932d

Branch: refs/heads/tv/docs
Commit: 7244932d5eee45ec5289b90b78c8b3d98df22226
Parents: 50f9a49
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Tue Apr 30 13:45:41 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Apr 30 19:45:59 2013 +0000

----------------------------------------------------------------------
 Allura/allura/config/app_cfg.py                    |    1 +
 Allura/allura/controllers/discuss.py               |    4 ++++
 Allura/allura/controllers/repository.py            |   10 ++++------
 Allura/allura/ext/user_profile/user_main.py        |    4 ++++
 Allura/allura/lib/base.py                          |   15 +++++++++++++++
 Allura/allura/lib/patches.py                       |    8 ++++++--
 .../allura/tests/functional/test_user_profile.py   |    7 ++++---
 .../forgediscussion/controllers/root.py            |    4 ++++
 .../forgediscussion/tests/functional/test_forum.py |    4 +++-
 .../forgegit/tests/functional/test_controllers.py  |    3 ++-
 ForgeLink/forgelink/link_main.py                   |    5 -----
 ForgeSVN/forgesvn/svn_main.py                      |    2 ++
 .../forgesvn/tests/functional/test_controllers.py  |    4 ++--
 .../forgetracker/tests/functional/test_root.py     |    7 +++----
 ForgeTracker/forgetracker/tracker_main.py          |    2 ++
 ForgeWiki/forgewiki/tests/functional/test_root.py  |    4 ++++
 ForgeWiki/forgewiki/wiki_main.py                   |    5 -----
 17 files changed, 60 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/Allura/allura/config/app_cfg.py
----------------------------------------------------------------------
diff --git a/Allura/allura/config/app_cfg.py b/Allura/allura/config/app_cfg.py
index c947fe1..f6b11e4 100644
--- a/Allura/allura/config/app_cfg.py
+++ b/Allura/allura/config/app_cfg.py
@@ -61,6 +61,7 @@ class ForgeConfig(AppConfig):
         self.use_transaction_manager = False
         # self.handle_status_codes = [ 403, 404 ]
         self.handle_status_codes = [ 403, 404 ]
+        self.disable_request_extensions = True
 
     def after_init_config(self):
         config['pylons.strict_c'] = True

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/Allura/allura/controllers/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index 218f9b4..5abb3a2 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -73,6 +73,8 @@ class DiscussionController(BaseController):
     W=WidgetConfig
 
     def __init__(self):
+        setattr(self, 'feed.rss', self.feed)
+        setattr(self, 'feed.atom', self.feed)
         if not hasattr(self, 'ThreadController'):
             self.ThreadController = ThreadController
         if not hasattr(self, 'PostController'):
@@ -168,6 +170,8 @@ class ThreadController(BaseController):
             require_access(self.thread.ref.artifact, 'read')
 
     def __init__(self, discussion_controller, thread_id):
+        setattr(self, 'feed.rss', self.feed)
+        setattr(self, 'feed.atom', self.feed)
         self._discussion_controller = discussion_controller
         self.discussion = discussion_controller.discussion
         self.thread = self.M.Thread.query.get(_id=thread_id)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/Allura/allura/controllers/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index 319506e..5e006ba 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -65,6 +65,10 @@ class RepoRootController(BaseController):
     _discuss = AppDiscussionController()
     commit_browser_widget=SCMCommitBrowserWidget()
 
+    def __init__(self):
+        setattr(self, 'feed.atom', self.feed)
+        setattr(self, 'feed.rss', self.feed)
+
     def _check_security(self):
         security.require(security.has_access(c.app, 'read'))
 
@@ -538,12 +542,6 @@ class TreeBrowser(BaseController, DispatchIndex):
 
     @expose()
     def _lookup(self, next, *rest):
-        if not rest and request.response_ext:
-            # Directory name may ends with file extension (e.g. `dir.rdf`)
-            # dispatching system will cut extension, so we need to restore it
-            next = "%s%s" % (next, request.response_ext)
-            request.response_ext = None
-            request.response_type = None
         next = h.really_unicode(unquote(next))
         if not rest:
             # Might be a file rather than a dir

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/Allura/allura/ext/user_profile/user_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/user_profile/user_main.py b/Allura/allura/ext/user_profile/user_main.py
index bc2b942..0491199 100644
--- a/Allura/allura/ext/user_profile/user_main.py
+++ b/Allura/allura/ext/user_profile/user_main.py
@@ -81,6 +81,10 @@ class UserProfileApp(Application):
 
 class UserProfileController(BaseController):
 
+    def __init__(self):
+        setattr(self, 'feed.rss', self.feed)
+        setattr(self, 'feed.atom', self.feed)
+
     def _check_security(self):
         require_access(c.project, 'read')
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/Allura/allura/lib/base.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/base.py b/Allura/allura/lib/base.py
index 4bd5a63..409b77c 100644
--- a/Allura/allura/lib/base.py
+++ b/Allura/allura/lib/base.py
@@ -19,6 +19,7 @@
 
 """The base Controller API."""
 from webob import exc
+import pylons
 from tg import TGController, config
 
 __all__ = ['WsgiDispatchController']
@@ -51,4 +52,18 @@ class WsgiDispatchController(TGController):
         for chunk in response: yield chunk
         self._cleanup_request()
 
+    def _get_dispatchable(self, url_path):
+        """Patch ``TGController._get_dispatchable`` by overriding.
 
+        This fixes a bug in TG 2.1.5 that causes ``request.response_type``
+        to not be created if ``disable_request_extensions = True`` (see
+        allura/config/app_cfg.py).
+
+        ``request.response_type`` must be set because the "trailing slash"
+        decorators use it (see allura/lib/patches.py).
+
+        This entire method can be removed if/when we upgrade to TG >= 2.2.1
+
+        """
+        pylons.request.response_type = None
+        return super(WsgiDispatchController, self)._get_dispatchable(url_path)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/Allura/allura/lib/patches.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/patches.py b/Allura/allura/lib/patches.py
index adbc4bc..ef6fba5 100644
--- a/Allura/allura/lib/patches.py
+++ b/Allura/allura/lib/patches.py
@@ -61,7 +61,9 @@ def apply():
     @decorator
     def without_trailing_slash(func, *args, **kwargs):
         '''Monkey-patched to use 301 redirects for SEO'''
-        if request.method == 'GET' and request.path.endswith('/') and not(request.response_type) and len(request.params)==0:
+        response_type = getattr(request, 'response_type', None)
+        if (request.method == 'GET' and request.path.endswith('/')
+                and not response_type and len(request.params)==0):
             raise webob.exc.HTTPMovedPermanently(location=request.url[:-1])
         return func(*args, **kwargs)
 
@@ -69,7 +71,9 @@ def apply():
     @decorator
     def with_trailing_slash(func, *args, **kwargs):
         '''Monkey-patched to use 301 redirects for SEO'''
-        if request.method == 'GET' and not(request.path.endswith('/')) and not(request.response_type) and len(request.params)==0:
+        response_type = getattr(request, 'response_type', None)
+        if (request.method == 'GET' and not(request.path.endswith('/'))
+                and not response_type and len(request.params)==0):
             raise webob.exc.HTTPMovedPermanently(location=request.url+'/')
         return func(*args, **kwargs)
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/Allura/allura/tests/functional/test_user_profile.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_user_profile.py b/Allura/allura/tests/functional/test_user_profile.py
index a8d724a..e5a9aef 100644
--- a/Allura/allura/tests/functional/test_user_profile.py
+++ b/Allura/allura/tests/functional/test_user_profile.py
@@ -53,6 +53,7 @@ class TestUserProfile(TestController):
     @td.with_user_project('test-admin')
     @td.with_wiki
     def test_feed(self):
-        response = self.app.get('/u/test-admin/profile/feed')
-        assert 'Recent posts by Test Admin' in response
-        assert 'Home modified by Test Admin' in response
+        for ext in ['', '.rss', '.atom']:
+            r = self.app.get('/u/test-admin/profile/feed%s' % ext, status=200)
+            assert 'Recent posts by Test Admin' in r
+            assert 'Home modified by Test Admin' in r

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/ForgeDiscussion/forgediscussion/controllers/root.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/controllers/root.py b/ForgeDiscussion/forgediscussion/controllers/root.py
index d9058fb..02c3cde 100644
--- a/ForgeDiscussion/forgediscussion/controllers/root.py
+++ b/ForgeDiscussion/forgediscussion/controllers/root.py
@@ -58,6 +58,10 @@ class RootController(BaseController, DispatchIndex):
         search_results = SearchResults()
         search_help = SearchHelp(comments=False, history=False)
 
+    def __init__(self):
+        setattr(self, 'feed.rss', self.feed)
+        setattr(self, 'feed.atom', self.feed)
+
     def _check_security(self):
         require_access(c.app, 'read')
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py b/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
index e408189..73b6682 100644
--- a/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
+++ b/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
@@ -730,4 +730,6 @@ class TestForum(TestController):
         assert '<a href="flag_as_spam" class="sidebar_thread_spam"><b data-icon="^" class="ico ico-flag"></b> <span>Mark as Spam</span></a>' not in thread_sidebarmenu
 
     def test_feed(self):
-        r = self.app.get('/discussion/general/feed', status=200)
+        for ext in ['', '.rss', '.atom']:
+            self.app.get('/discussion/feed%s' % ext, status=200)
+            self.app.get('/discussion/general/feed%s' % ext, status=200)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/ForgeGit/forgegit/tests/functional/test_controllers.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/tests/functional/test_controllers.py b/ForgeGit/forgegit/tests/functional/test_controllers.py
index 78a8d7e..186b46a 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -156,7 +156,8 @@ class TestRootController(_TestCase):
         assert 'Rick' in resp, resp.showbrowser()
 
     def test_feed(self):
-        assert 'Add README' in self.app.get('/feed')
+        for ext in ['', '.rss', '.atom']:
+            assert 'Add README' in self.app.get('/feed%s' % ext)
 
     def test_tree(self):
         ci = self._get_ci()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/ForgeLink/forgelink/link_main.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/link_main.py b/ForgeLink/forgelink/link_main.py
index 121c8cf..1f5fb2e 100644
--- a/ForgeLink/forgelink/link_main.py
+++ b/ForgeLink/forgelink/link_main.py
@@ -104,11 +104,6 @@ class RootController(BaseController):
     @expose()
     def _lookup(self, *remainder):
         path = "/".join(remainder)
-        # HACK: The TG request extension machinery will strip off the end of
-        # a dotted wiki page name if it matches a known file extension. Here,
-        # we reassemble the original page name.
-        if request.response_ext:
-            path += request.response_ext
         url = c.app.config.options.get('url')
         if url:
             permanent_redirect(url + h.really_unicode(path).encode('utf-8'))

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/ForgeSVN/forgesvn/svn_main.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/svn_main.py b/ForgeSVN/forgesvn/svn_main.py
index cca94f7..ef7d008 100644
--- a/ForgeSVN/forgesvn/svn_main.py
+++ b/ForgeSVN/forgesvn/svn_main.py
@@ -65,6 +65,8 @@ class ForgeSVNApp(RepositoryApp):
         default_root = RepoRootController()
         self.root.refresh = default_root.refresh
         self.root.feed = default_root.feed
+        setattr(self.root, 'feed.rss', self.root.feed)
+        setattr(self.root, 'feed.atom', self.root.feed)
         self.root.commit_browser = default_root.commit_browser
         self.root.commit_browser_data = default_root.commit_browser_data
         self.root.status = default_root.status

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/ForgeSVN/forgesvn/tests/functional/test_controllers.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/tests/functional/test_controllers.py b/ForgeSVN/forgesvn/tests/functional/test_controllers.py
index c5d340c..90af545 100644
--- a/ForgeSVN/forgesvn/tests/functional/test_controllers.py
+++ b/ForgeSVN/forgesvn/tests/functional/test_controllers.py
@@ -90,8 +90,8 @@ class TestRootController(SVNTestController):
                 assert val['message'] == 'Create readme'
 
     def test_feed(self):
-        r = self.app.get('/src/feed.rss')
-        assert 'Remove hello.txt' in str(r), r
+        for ext in ['', '.rss', '.atom']:
+            assert 'Remove hello.txt' in self.app.get('/src/feed%s' % ext)
 
     def test_commit(self):
         resp = self.app.get('/src/3/tree/')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/ForgeTracker/forgetracker/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py
index e193a10..dfaaba1 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -828,10 +828,9 @@ class TestFunctionalController(TrackerTestController):
         ThreadLocalORMSession.flush_all()
         M.MonQTask.run_ready()
         ThreadLocalORMSession.flush_all()
-        response = self.app.get('/p/test/bugs/search_feed?q=test')
-        assert '<title>test first ticket</title>' in response
-        response = self.app.get('/p/test/bugs/search_feed.atom?q=test')
-        assert '<title>test first ticket</title>' in response
+        for ext in ['', '.rss', '.atom']:
+            assert '<title>test first ticket</title>' in \
+                    self.app.get('/p/test/bugs/search_feed%s?q=test' % ext)
 
     def test_search_current_user(self):
         self.new_ticket(summary='test first ticket')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 8d786d9..349ef1e 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -472,6 +472,8 @@ class RootController(BaseController):
     def __init__(self):
         setattr(self, 'feed.atom', self.feed)
         setattr(self, 'feed.rss', self.feed)
+        setattr(self, 'search_feed.atom', self.search_feed)
+        setattr(self, 'search_feed.rss', self.search_feed)
         self._discuss = AppDiscussionController()
 
     def _check_security(self):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/ForgeWiki/forgewiki/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/tests/functional/test_root.py b/ForgeWiki/forgewiki/tests/functional/test_root.py
index 14e70c6..d928e70 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_root.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_root.py
@@ -80,6 +80,10 @@ class TestRootController(TestController):
         response = self.app.get('/wiki/search?q=tést')
         assert 'Search wiki: tést' in response
 
+    def test_feed(self):
+        for ext in ['', '.rss', '.atom']:
+            self.app.get('/wiki/feed%s' % ext, status=200)
+
     @patch('allura.lib.search.search')
     def test_search(self, search):
         r = self.app.get('/wiki/search?q=test')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7244932d/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index 23ca7f2..b923350 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -296,11 +296,6 @@ class RootController(BaseController, DispatchIndex):
     @expose()
     def _lookup(self, pname, *remainder):
         """Instantiate a Page object, and continue dispatch there."""
-        # HACK: The TG request extension machinery will strip off the end of
-        # a dotted wiki page name if it matches a known file extension. Here,
-        # we reassemble the original page name.
-        if request.response_ext and not remainder:
-            pname += request.response_ext
         return PageController(pname), remainder
 
     @expose()


[26/50] git commit: [#5599] ticket:296 fixed css

Posted by tv...@apache.org.
[#5599] ticket:296 fixed css


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/be11653c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/be11653c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/be11653c

Branch: refs/heads/tv/docs
Commit: be11653c5f804cfcdc31ddbacd5b35b9b469defa
Parents: a028f97
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Thu Apr 18 16:56:03 2013 +0400
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Wed May 1 20:38:38 2013 +0000

----------------------------------------------------------------------
 Allura/allura/model/project.py                    |    2 +-
 Allura/allura/nf/allura/css/site_style.css        |    9 ++++++---
 Allura/allura/templates/jinja_master/top_nav.html |   14 +++++++++-----
 Allura/allura/tests/functional/test_admin.py      |    2 +-
 Allura/allura/tests/functional/test_home.py       |    2 +-
 5 files changed, 18 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/be11653c/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index 73894e3..8a06566 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -511,7 +511,7 @@ class Project(MappedClass, ActivityNode, ActivityObject):
                         grouped_nav[tool_name].children.append(e)
                     elif len(grouped_nav[tool_name].children) == 10:
                         e.url = self.url() + '_list/' + tool_name
-                        e.label = '...more...'
+                        e.label = 'More...'
                         grouped_nav[tool_name].children.append(e)
         return grouped_nav.values()
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/be11653c/Allura/allura/nf/allura/css/site_style.css
----------------------------------------------------------------------
diff --git a/Allura/allura/nf/allura/css/site_style.css b/Allura/allura/nf/allura/css/site_style.css
index 98938e8..06b93ca 100644
--- a/Allura/allura/nf/allura/css/site_style.css
+++ b/Allura/allura/nf/allura/css/site_style.css
@@ -994,7 +994,6 @@ a.btn:active {
   text-align: center;
   position: relative;
   margin: 0 0 20px;
-  height: 50px;
 }
 .btn-bar.pop, .pop#top_nav {
   height: 150px;
@@ -2123,8 +2122,8 @@ nav .ico {
   box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4) inset,0 1px 0 rgba(255, 255, 255, 0.9);
   border: medium none;
   margin: 0 0 20px 0;
-  display: block;
   overflow: visible;
+  width: 940px;
 }
 #top_nav a {
   float: left;
@@ -2923,6 +2922,9 @@ ul.dropdown ul {
     background-color: #ffffff;
     -moz-border-radius: 5px;
     -webkit-border-radius: 5px;
+    -o-border-radius: 5px;
+    -ms-border-radius: 5px;
+    -khtml-border-radius: 5px;
     border-radius: 5px;
     border-width: 1px;
     border-style: solid;
@@ -2942,6 +2944,7 @@ ul.dropdown ul li a {
     height: 20px !important;
     font-weight:normal;
 }
-li.selected {
+li.selected,
+ul.dropdown ul li.selected a{
     font-weight:bold;
 }

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/be11653c/Allura/allura/templates/jinja_master/top_nav.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/top_nav.html b/Allura/allura/templates/jinja_master/top_nav.html
index aeec126..47ef332 100644
--- a/Allura/allura/templates/jinja_master/top_nav.html
+++ b/Allura/allura/templates/jinja_master/top_nav.html
@@ -36,11 +36,15 @@
         </a>
         {% set grouped_tool_count = s.matching_urls|length %}
         {% if grouped_tool_count %}
-          <ul>
-              {%for tool in s.children%}
-                <li><span><a href="{{tool.url}}">{{tool.label}}</a></span></li>
-              {%endfor%}
-          </ul>
+            <ul>
+                {%for tool in s.children%}
+                    {% set selected = False %}
+                    {% if tool.matches_url(request) or c.project.neighborhood.url()+'_admin' in request.upath_info%}
+                        {% set selected = True %}
+                    {% endif %}
+                    <li class="{% if selected %}selected{% endif %}"><a href="{{tool.url}}">{{tool.label}}</a></li>
+                {%endfor%}
+            </ul>
         {% endif %}
     </li>
 	{% endfor %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/be11653c/Allura/allura/tests/functional/test_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_admin.py b/Allura/allura/tests/functional/test_admin.py
index 1752707..3197386 100644
--- a/Allura/allura/tests/functional/test_admin.py
+++ b/Allura/allura/tests/functional/test_admin.py
@@ -119,7 +119,7 @@ class TestProjectAdmin(TestController):
         # check the nav - tools of same type are grouped
         r = self.app.get('/p/test/test-tool/Home/')
         active_link = r.html.findAll('li',{'class':'selected'})
-        assert len(active_link) == 1
+        assert len(active_link) == 2
         assert active_link[0].contents[1]['href'] == '/p/test/_list/wiki'
         assert r.html.findAll('a', {'href':'/p/test/test-tool2/'})
         assert r.html.findAll('a', {'href':'/p/test/test-tool/'})

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/be11653c/Allura/allura/tests/functional/test_home.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_home.py b/Allura/allura/tests/functional/test_home.py
index 4904394..3e11437 100644
--- a/Allura/allura/tests/functional/test_home.py
+++ b/Allura/allura/tests/functional/test_home.py
@@ -65,7 +65,7 @@ class TestProjectHome(TestController):
         response = self.app.get('/p/test/_nav.json')
         menu = response.json['menu']
         assert_equal(len(menu[1]['children']), 11)
-        assert {u'url': u'/p/test/_list/wiki', u'name': u'...more...', u'icon': u'tool-wiki'} in menu[1]['children']
+        assert {u'url': u'/p/test/_list/wiki', u'name': u'More...', u'icon': u'tool-wiki'} in menu[1]['children']
 
     @td.with_wiki
     def test_neighborhood_home(self):


[12/50] git commit: [#5891] ticket:316 add attachments to replies

Posted by tv...@apache.org.
[#5891] ticket:316 add attachments to replies


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/57d4e6fb
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/57d4e6fb
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/57d4e6fb

Branch: refs/heads/tv/docs
Commit: 57d4e6fb9af1eabbf5cb16acbafbe0c00550db39
Parents: 5fb297e
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Mon Apr 22 14:25:23 2013 +0400
Committer: Yuriy Arhipov <yu...@yandex.ru>
Committed: Tue Apr 30 11:16:44 2013 +0400

----------------------------------------------------------------------
 Allura/allura/controllers/discuss.py           |   11 ++++++++++-
 Allura/allura/tests/functional/test_discuss.py |   18 ++++++++++++++++++
 2 files changed, 28 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/57d4e6fb/Allura/allura/controllers/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index 2ef1df4..b0bb426 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -344,11 +344,20 @@ class PostController(BaseController):
     @validate(pass_validator, error_handler=index)
     @utils.AntiSpam.validate('Spambot protection engaged')
     @require_post(redir='.')
-    def reply(self, **kw):
+    def reply(self, file_info=None, **kw):
         require_access(self.thread, 'post')
         kw = self.W.edit_post.to_python(kw, None)
         p = self.thread.add_post(parent_id=self.post._id, **kw)
         is_spam = g.spam_checker.check(kw['text'], artifact=p, user=c.user)
+        if hasattr(file_info, 'file'):
+            mime_type = file_info.type
+            if not mime_type or '/' not in mime_type:
+                mime_type = utils.guess_mime_type(file_info.filename)
+            p.attach(
+                file_info.filename, file_info.file, content_type=mime_type,
+                post_id=p._id,
+                thread_id=p.thread_id,
+                discussion_id=p.discussion_id)
         redirect(request.referer)
 
     @h.vardec

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/57d4e6fb/Allura/allura/tests/functional/test_discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_discuss.py b/Allura/allura/tests/functional/test_discuss.py
index 83910e9..633f078 100644
--- a/Allura/allura/tests/functional/test_discuss.py
+++ b/Allura/allura/tests/functional/test_discuss.py
@@ -220,3 +220,21 @@ class TestAttachment(TestController):
         r = self.app.post(self.post_link + 'attach',
                           upload_files=[('file_info', 'test.o12', 'HiThere!')])
         r = self.app.post(alink, params=dict(delete='on'))
+
+    @patch('allura.model.discuss.Post.notify')
+    def test_reply_attach(self, notify):
+        notify.return_value = True
+        r = self.app.get(self.thread_link)
+        post_form = r.html.find('form', {'action':self.post_link + 'reply'})
+        params = dict()
+        inputs = post_form.findAll('input')
+
+        for field in inputs:
+            if field.has_key('name') and (field['name']!='file_info'):
+                params[field['name']] = field.has_key('value') and field['value'] or ''
+        params[post_form.find('textarea')['name']] = 'Reply'
+        r = self.app.post(self.post_link + 'reply',
+                          params=params,
+                          upload_files=[('file_info', 'test.txt', 'HiThere!')])
+        r = self.app.get(self.thread_link)
+        assert "test.txt" in r


[44/50] git commit: [#6133] remove extremely slow methods using `self.query.find()`

Posted by tv...@apache.org.
[#6133] remove extremely slow methods using `self.query.find()`

And remove table displaying these values.  A few other values of this
table (the 'Value' column) could still be displayed, but showing just
one column in a table would look bad, and these values are basically
available from the main table on the stats page anyway.  The methods
for computing those values were left, just unused now.


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/b21778f7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/b21778f7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/b21778f7

Branch: refs/heads/tv/docs
Commit: b21778f718934462187b1fdc1d76107c37450176
Parents: 47e7e08
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Sat May 4 22:47:52 2013 -0400
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon May 6 21:34:31 2013 +0000

----------------------------------------------------------------------
 Allura/allura/model/stats.py                       |   60 -----------
 .../forgeuserstats/controllers/userstats.py        |   81 ++++-----------
 ForgeUserStats/forgeuserstats/templates/index.html |   44 --------
 3 files changed, 22 insertions(+), 163 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/b21778f7/Allura/allura/model/stats.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/stats.py b/Allura/allura/model/stats.py
index 06ed07d..cff1abc 100644
--- a/Allura/allura/model/stats.py
+++ b/Allura/allura/model/stats.py
@@ -117,66 +117,6 @@ class Stats(MappedClass):
                 return round(float(tickets.solved) / tickets.assigned, 2)
         return 0
 
-    @classmethod
-    def getMaxAndAverageCodeContribution(self):
-        res = self.query.find()
-        n = res.count()
-        if n == 0:
-            return 0, 0
-        values = [x.getCodeContribution() for x in res]
-        maxcontribution=max(values)
-        averagecontribution=sum(values) / n
-        return maxcontribution, round(averagecontribution, 2)
-
-    @classmethod
-    def getMaxAndAverageDiscussionContribution(self):
-        res = self.query.find()
-        n = res.count()
-        if n == 0:
-            return 0, 0
-        values = [x.getDiscussionContribution() for x in res]
-        maxcontribution=max(values)
-        averagecontribution=sum(values)/n
-        return maxcontribution, round(averagecontribution, 2)
-
-    @classmethod
-    def getMaxAndAverageTicketsSolvingPercentage(self):
-        res = self.query.find()
-        n = res.count()
-        if n == 0:
-            return 0, 0
-        values = [x.getTicketsContribution() for x in res]
-        maxcontribution=max(values)
-        averagecontribution=sum(values)/n
-        return maxcontribution, round(averagecontribution, 2)
-
-    def codeRanking(self):
-        res = self.query.find()
-        totn = res.count()
-        if totn == 0:
-            return 0
-        codcontr = self.getCodeContribution()
-        upper = len([x for x in res if x.getCodeContribution() > codcontr])
-        return round((totn - upper) * 100.0 / totn, 2)
-
-    def discussionRanking(self):
-        res = self.query.find()
-        totn = res.count()
-        if totn == 0:
-            return 0
-        disccontr = self.getDiscussionContribution()
-        upper=len([x for x in res if x.getDiscussionContribution()>disccontr])
-        return round((totn - upper) * 100.0 / totn, 2)
-
-    def ticketsRanking(self):
-        res = self.query.find()
-        totn = res.count()
-        if totn == 0:
-            return 0
-        ticketscontr = self.getTicketsContribution()
-        upper=len([x for x in res if x.getTicketsContribution()>ticketscontr])
-        return round((totn - upper) * 100.0 / totn, 2)
-
     def getCommits(self, category = None):
         i = getElementIndex(self.general, category = category)
         if i is None:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/b21778f7/ForgeUserStats/forgeuserstats/controllers/userstats.py
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/controllers/userstats.py b/ForgeUserStats/forgeuserstats/controllers/userstats.py
index 5b95954..1cb5505 100644
--- a/ForgeUserStats/forgeuserstats/controllers/userstats.py
+++ b/ForgeUserStats/forgeuserstats/controllers/userstats.py
@@ -45,14 +45,14 @@ class ForgeUserStatsCatController(BaseController):
     @with_trailing_slash
     def index(self, **kw):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return None
         stats = self.user.stats
         if (not stats.visible) and (c.user != self.user):
             return dict(user=self.user)
-        
+
         cat_id = None
-        if self.category: 
+        if self.category:
             cat_id = self.category._id
         ret_dict = _getDataForCategory(cat_id, stats)
         ret_dict['user'] = self.user
@@ -62,23 +62,23 @@ class ForgeUserStatsCatController(BaseController):
 
 class ForgeUserStatsController(BaseController):
 
-    category = ForgeUserStatsCatController()            
-    
+    category = ForgeUserStatsCatController()
+
     @expose('jinja:forgeuserstats:templates/settings.html')
     @with_trailing_slash
     def settings(self, **kw):
         require_access(c.project, 'admin')
 
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
         return dict(
-            user = self.user, 
+            user = self.user,
             form = StatsPreferencesForm(
                 action = c.project.url() + 'userstats/change_settings'))
-      
+
     @expose()
     @require_post()
     @validate(stats_preferences_form, error_handler=settings)
@@ -86,7 +86,7 @@ class ForgeUserStatsController(BaseController):
         require_access(c.project, 'admin')
 
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
@@ -98,7 +98,7 @@ class ForgeUserStatsController(BaseController):
     @with_trailing_slash
     def index(self, **kw):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
@@ -131,25 +131,12 @@ class ForgeUserStatsController(BaseController):
         ret_dict['lastmonth_logins'] = stats.getLastMonthLogins()
         ret_dict['categories'] = categories
         days = ret_dict['days']
-        if days >= 30: 
+        if days >= 30:
             ret_dict['permonthlogins'] = \
                 round(stats.tot_logins_count*30.0/days,2)
         else:
             ret_dict['permonthlogins'] = 'n/a'
 
-        ret_dict['codepercentage'] = stats.codeRanking()
-        ret_dict['discussionpercentage'] = stats.discussionRanking()
-        ret_dict['ticketspercentage'] = stats.ticketsRanking()
-        ret_dict['codecontribution'] = stats.getCodeContribution()
-        ret_dict['discussioncontribution'] = stats.getDiscussionContribution()
-        ret_dict['ticketcontribution'] = stats.getTicketsContribution()
-        ret_dict['maxcodecontrib'], ret_dict['averagecodecontrib'] =\
-            stats.getMaxAndAverageCodeContribution()
-        ret_dict['maxdisccontrib'], ret_dict['averagedisccontrib'] =\
-            stats.getMaxAndAverageDiscussionContribution()
-        ret_dict['maxticketcontrib'], ret_dict['averageticketcontrib'] =\
-            stats.getMaxAndAverageTicketsSolvingPercentage()
-        
         return ret_dict
 
 
@@ -157,7 +144,7 @@ class ForgeUserStatsController(BaseController):
     @with_trailing_slash
     def commits(self, **kw):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
@@ -165,17 +152,17 @@ class ForgeUserStatsController(BaseController):
 
         if (not stats.visible) and (c.user != self.user):
             return dict(user=self.user)
-        
+
         commits = stats.getCommitsByCategory()
         return dict(
             user = self.user,
-            data = commits) 
+            data = commits)
 
     @expose('jinja:forgeuserstats:templates/artifacts.html')
     @with_trailing_slash
     def artifacts(self, **kw):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
@@ -184,7 +171,7 @@ class ForgeUserStatsController(BaseController):
         if (not stats.visible) and (c.user != self.user):
             return dict(user=self.user)
 
-        stats = self.user.stats       
+        stats = self.user.stats
         artifacts = stats.getArtifactsByCategory(detailed=True)
         return dict(
             user = self.user,
@@ -194,7 +181,7 @@ class ForgeUserStatsController(BaseController):
     @with_trailing_slash
     def tickets(self, **kw):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
@@ -211,7 +198,7 @@ class ForgeUserStatsController(BaseController):
     @expose()
     def categories_graph(self):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return None
 
         categories = {}
@@ -234,39 +221,16 @@ class ForgeUserStatsController(BaseController):
             labels.append(label)
             i += 1
 
-        return create_histogram(data, labels, 
+        return create_histogram(data, labels,
             'Number of projects', 'Projects by category')
 
-    @expose()
-    def code_ranking_bar(self):
-        self.user = c.project.user_project_of
-        if not self.user: 
-            return None
-        stats = self.user.stats
-        return create_progress_bar(stats.codeRanking())
-
-    @expose()
-    def discussion_ranking_bar(self):
-        self.user = c.project.user_project_of
-        if not self.user: 
-            return None
-        stats = self.user.stats
-        return create_progress_bar(stats.discussionRanking())
-
-    @expose()
-    def tickets_ranking_bar(self):
-        self.user = c.project.user_project_of
-        if not self.user: 
-            return None
-        stats = self.user.stats
-        return create_progress_bar(stats.ticketsRanking())
 
 def _getDataForCategory(category, stats):
     totcommits = stats.getCommits(category)
     tottickets = stats.getTickets(category)
     averagetime = tottickets.get('averagesolvingtime')
     artifacts_by_type = stats.getArtifactsByType(category)
-    totartifacts = artifacts_by_type.get(None) 
+    totartifacts = artifacts_by_type.get(None)
     if totartifacts:
         del artifacts_by_type[None]
     else:
@@ -279,7 +243,7 @@ def _getDataForCategory(category, stats):
     averagetime = lm_tickets.get('averagesolvingtime')
 
     days = (datetime.utcnow() - stats.registration_date).days
-    if days >= 30: 
+    if days >= 30:
         pmartifacts = dict(
             created = round(totartifacts['created']*30.0/days,2),
             modified=round(totartifacts['modified']*30.0/days,2))
@@ -297,7 +261,7 @@ def _getDataForCategory(category, stats):
                 round(value['created']*30.0/days,2)
             artifacts_by_type[key]['pmmodified']= \
                 round(value['modified']*30.0/days,2)
-    else: 
+    else:
         pmartifacts = dict(created='n/a', modified='n/a')
         pmcommits = dict(number='n/a', lines='n/a')
         pmtickets = dict(
@@ -322,4 +286,3 @@ def _getDataForCategory(category, stats):
         artifacts_by_type = artifacts_by_type,
         lastmonth_artifacts_by_type = lm_artifacts_by_type,
         permonthtickets = pmtickets)
-

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/b21778f7/ForgeUserStats/forgeuserstats/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/index.html b/ForgeUserStats/forgeuserstats/templates/index.html
index bc23ec0..2bb6314 100644
--- a/ForgeUserStats/forgeuserstats/templates/index.html
+++ b/ForgeUserStats/forgeuserstats/templates/index.html
@@ -391,50 +391,6 @@
           </p>
         {% endif %}
     {% endif %}
-    {% if not category %}
-      <h2>Overview</h2>
-      <table>
-        <thead>
-          <tr>
-            <th>Field</th>
-            <th>Value</th>
-            <th>Average per-user value</th>
-            <th>Maximum per-user value</th>
-            <th>Rank bar</th>
-          </tr>
-        </thead>
-        <tbody>
-          <tr>
-            <td>Code</td>
-            <td>{{codecontribution}} LOC{% if codecontribution != 1 %}s{% endif %}/month</td>
-            <td>{{averagecodecontrib}} LOC{% if averagecodecontrib != 1 %}s{% endif %}/month</td>
-            <td>{{maxcodecontrib}} LOC{% if maxcodecontrib != 1 %}s{% endif %}/month</td>
-            <td><img src="{{c.project.url()}}userstats/code_ranking_bar"/> {{codepercentage}} %</td>
-          </tr>
-          <tr>
-            <td>Discussion</td>
-            <td>{{discussioncontribution}} contr./month</td>
-            <td>{{averagedisccontrib}} contr./month</td>
-            <td>{{maxdisccontrib}} contr./month</td>
-            <td><img src="{{c.project.url()}}userstats/discussion_ranking_bar"/> {{discussionpercentage}} %</td>
-          </tr>
-          <tr>
-            <td>Solved issues</td>
-            <td>{{ticketcontribution*100}} %</td>
-            <td>{{averageticketcontrib*100}} %</td>
-            <td>{{maxticketcontrib*100}} %</td>
-            <td><img src="{{c.project.url()}}userstats/tickets_ranking_bar"/> {{ticketspercentage}} %</td>
-          </tr>
-        </tbody>
-      </table>
-      <h3>Note</h3>
-      <p>
-         The above table compares the average monthly contribution of this user with the average monthly contributions of the
-         other users of the forge. The progressbar and the percentage refer to the user's position in an overall ranking of the
-         users of this forge. For example, a value of 100% in the field "Code" is associated to the user who has the highest
-         average number of committed LOCs per month. Of course, this doesn't consider the quality of the contributions.
-      </p>
-    {% endif %}
   {% else %}
     {% if user %}
       <h2>Statistics not available</h2>


[14/50] git commit: [#6179] ignore the u/ prefix of user-projects so that a 15-char username can have their user project created successfully

Posted by tv...@apache.org.
[#6179] ignore the u/ prefix of user-projects so that a 15-char username can have their user project created successfully


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/f7461097
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/f7461097
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/f7461097

Branch: refs/heads/tv/docs
Commit: f7461097b15347cb3ae196fd0e486844d017e381
Parents: 5c8db54
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Apr 30 18:16:50 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Apr 30 18:16:50 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py        |    4 ++-
 Allura/allura/tests/test_plugin.py |   40 +++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f7461097/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index b7722d2..02aae3a 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -464,7 +464,9 @@ class ProjectRegistrationProvider(object):
 
         self.rate_limit(user, neighborhood)
 
-        if not h.re_project_name.match(shortname.replace('/', '')):
+        if user_project and shortname.startswith('u/'):
+            shortname = shortname.replace('u/', '', 1)
+        if not h.re_project_name.match(shortname):
             raise ValueError('Invalid project shortname: %s' % shortname)
 
         p = M.Project.query.get(shortname=shortname, neighborhood_id=neighborhood._id)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f7461097/Allura/allura/tests/test_plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_plugin.py b/Allura/allura/tests/test_plugin.py
new file mode 100644
index 0000000..6e1a07a
--- /dev/null
+++ b/Allura/allura/tests/test_plugin.py
@@ -0,0 +1,40 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+from nose.tools import assert_equals
+from mock import MagicMock, patch
+
+from allura import model as M
+from allura.lib.utils import TruthyCallable
+from allura.lib.plugin import ProjectRegistrationProvider
+
+
+class TestProjectRegistrationProvider(object):
+
+    @patch('allura.lib.security.has_access')
+    def test_validate_project_15char_user(self, has_access):
+        has_access.return_value = TruthyCallable(lambda: True)
+        provider = ProjectRegistrationProvider()
+        nbhd = M.Neighborhood()
+        provider.validate_project(
+            neighborhood=nbhd,
+            shortname='u/' + ('a' * 15),
+            project_name='15 char username',
+            user=MagicMock(),
+            user_project=True,
+            private_project=False,
+        )
\ No newline at end of file


[11/50] git commit: [#5891] ticket:327 refactoring for comments attachments

Posted by tv...@apache.org.
[#5891]  ticket:327  refactoring for comments attachments


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/c40773b7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/c40773b7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/c40773b7

Branch: refs/heads/tv/docs
Commit: c40773b77f71335adfe7a300955e5fc99d0266c1
Parents: 57d4e6f
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Tue Apr 30 11:15:35 2013 +0400
Committer: Yuriy Arhipov <yu...@yandex.ru>
Committed: Tue Apr 30 11:16:44 2013 +0400

----------------------------------------------------------------------
 Allura/allura/controllers/discuss.py         |   35 ++------------------
 Allura/allura/lib/helpers.py                 |   13 ++++++++
 Allura/allura/tests/model/test_discussion.py |   14 ++++++++
 3 files changed, 31 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c40773b7/Allura/allura/controllers/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index b0bb426..eb34981 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -211,12 +211,7 @@ class ThreadController(BaseController):
         file_info = kw.get('file_info', None)
         p = self.thread.add_post(**kw)
         is_spam = g.spam_checker.check(kw['text'], artifact=p, user=c.user)
-        if hasattr(file_info, 'file'):
-            p.attach(
-                file_info.filename, file_info.file, content_type=file_info.type,
-                post_id=p._id,
-                thread_id=p.thread_id,
-                discussion_id=p.discussion_id)
+        h.attach_to_post(p, file_info)
         if self.thread.artifact:
             self.thread.artifact.mod_date = datetime.utcnow()
         flash('Message posted')
@@ -299,12 +294,7 @@ class PostController(BaseController):
             require_access(self.post, 'moderate')
             post_fields = self.W.edit_post.to_python(kw, None)
             file_info = post_fields.pop('file_info', None)
-            if hasattr(file_info, 'file'):
-                self.post.attach(
-                    file_info.filename, file_info.file, content_type=file_info.type,
-                    post_id=self.post._id,
-                    thread_id=self.post.thread_id,
-                    discussion_id=self.post.discussion_id)
+            h.attach_to_post(self.post, file_info)
             for k,v in post_fields.iteritems():
                 try:
                     setattr(self.post, k, v)
@@ -349,15 +339,7 @@ class PostController(BaseController):
         kw = self.W.edit_post.to_python(kw, None)
         p = self.thread.add_post(parent_id=self.post._id, **kw)
         is_spam = g.spam_checker.check(kw['text'], artifact=p, user=c.user)
-        if hasattr(file_info, 'file'):
-            mime_type = file_info.type
-            if not mime_type or '/' not in mime_type:
-                mime_type = utils.guess_mime_type(file_info.filename)
-            p.attach(
-                file_info.filename, file_info.file, content_type=mime_type,
-                post_id=p._id,
-                thread_id=p.thread_id,
-                discussion_id=p.discussion_id)
+        h.attach_to_post(p, file_info)
         redirect(request.referer)
 
     @h.vardec
@@ -391,16 +373,7 @@ class PostController(BaseController):
     @require_post()
     def attach(self, file_info=None):
         require_access(self.post, 'moderate')
-        if hasattr(file_info, 'file'):
-            mime_type = file_info.type
-            # If mime type was not passed or bogus, guess it
-            if not mime_type or '/' not in mime_type:
-                mime_type = utils.guess_mime_type(file_info.filename)
-            self.post.attach(
-                file_info.filename, file_info.file, content_type=mime_type,
-                post_id=self.post._id,
-                thread_id=self.post.thread_id,
-                discussion_id=self.post.discussion_id)
+        h.attach_to_post(self.post, file_info)
         redirect(request.referer)
 
     @expose()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c40773b7/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 9ddad18..deed268 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -51,6 +51,7 @@ from allura.lib import exceptions as exc
 from allura.lib.decorators import exceptionless
 from allura.lib import AsciiDammit
 from .security import has_access
+from allura.lib import utils
 
 
 # validates project, subproject, and user names
@@ -702,3 +703,15 @@ def get_first(d, key):
     if isinstance(v, list):
         return v[0] if len(v) > 0 else None
     return v
+
+
+def attach_to_post(post, file_info):
+    if hasattr(file_info, 'file'):
+        mime_type = file_info.type
+        if not mime_type or '/' not in mime_type:
+            mime_type = utils.guess_mime_type(file_info.filename)
+        post.attach(
+            file_info.filename, file_info.file, content_type=mime_type,
+            post_id=post._id,
+            thread_id=post.thread_id,
+            discussion_id=post.discussion_id)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c40773b7/Allura/allura/tests/model/test_discussion.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_discussion.py b/Allura/allura/tests/model/test_discussion.py
index 7e9df32..2ab4b2a 100644
--- a/Allura/allura/tests/model/test_discussion.py
+++ b/Allura/allura/tests/model/test_discussion.py
@@ -206,6 +206,20 @@ def test_attachment_methods():
     assert '\nAttachment: fake.txt (37 Bytes; text/plain)' in n.text
 
 @with_setup(setUp, tearDown)
+def test_attach_to_post():
+    test_file = FieldStorage()
+    test_file.name = 'file_info'
+    test_file.filename = 'test.txt'
+    test_file.type = 'text/plain'
+    test_file.file=StringIO('test file\n')
+    d = M.Discussion(shortname='test', name='test')
+    t = M.Thread.new(discussion_id=d._id, subject='Test Thread')
+    test_post = t.post('test post')
+    h.attach_to_post(test_post, test_file)
+    ThreadLocalORMSession.flush_all()
+    assert test_post.attachments.count() == 1, test_post.attachments.count()
+
+@with_setup(setUp, tearDown)
 def test_discussion_delete():
     d = M.Discussion(shortname='test', name='test')
     t = M.Thread.new(discussion_id=d._id, subject='Test Thread')


[25/50] git commit: [#5913] Updated html for new nav

Posted by tv...@apache.org.
[#5913] Updated html for new nav


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/c853c466
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/c853c466
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/c853c466

Branch: refs/heads/tv/docs
Commit: c853c4663b7b25b4a9fca65347af251de769771e
Parents: 833aa4a
Author: Jenny Steele <js...@geek.net>
Authored: Wed Mar 20 12:44:51 2013 -0700
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Wed May 1 20:38:37 2013 +0000

----------------------------------------------------------------------
 Allura/allura/templates/jinja_master/top_nav.html |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c853c466/Allura/allura/templates/jinja_master/top_nav.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/top_nav.html b/Allura/allura/templates/jinja_master/top_nav.html
index 7304f4c..599eb3e 100644
--- a/Allura/allura/templates/jinja_master/top_nav.html
+++ b/Allura/allura/templates/jinja_master/top_nav.html
@@ -32,11 +32,13 @@
     {% endif %}
     <li{% if selected %} class="selected"{% endif %}>
       <a href="{{s.url}}">
+        <span>
         {{s.label}}
         {% set grouped_tool_count = s.matching_urls|length %}
         {% if grouped_tool_count %}
           <span class="tool-count">{{grouped_tool_count}}</span>
         {% endif %}
+        </span>
       </a>
     </li>
 	{% endfor %}


[02/50] git commit: [#2835] avoid double-escaping solr text by escaping it only on the way out. tests

Posted by tv...@apache.org.
[#2835] avoid double-escaping solr text by escaping it only on the way out.  tests


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/69d75753
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/69d75753
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/69d75753

Branch: refs/heads/tv/docs
Commit: 69d757538ad8d5c30cffe491b56c8b701f7c4dd8
Parents: c8311bb
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu Apr 25 20:20:12 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Apr 29 13:38:36 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/search.py           |    4 +-
 Allura/allura/tests/unit/test_solr.py |   86 +++++++++++++++++++++++++++-
 2 files changed, 85 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/69d75753/Allura/allura/lib/search.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/search.py b/Allura/allura/lib/search.py
index 203e37a..d43af9c 100644
--- a/Allura/allura/lib/search.py
+++ b/Allura/allura/lib/search.py
@@ -46,8 +46,6 @@ def solarize(obj):
     text = doc['text']
     text = g.markdown.convert(text)
     doc['text'] = jinja2.Markup.escape(text).striptags()
-    # striptags decodes html entities, so we should escape them again
-    doc['text'] = jinja2.Markup.escape(doc['text'])
     return doc
 
 class SearchError(SolrError):
@@ -201,7 +199,7 @@ def search_app(q='', fq=None, app=True, **kw):
     score_url = url(request.path, params=params)
     params.update({'sort': date_url})
     date_url = url(request.path, params=params)
-    return dict(q=q, history=history, results=results or [],
+    return dict(q=q, history=history, results=list(results) or [],
                 count=count, limit=limit, page=page, search_error=search_error,
                 sort_score_url=score_url, sort_date_url=date_url,
                 sort_field=field)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/69d75753/Allura/allura/tests/unit/test_solr.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_solr.py b/Allura/allura/tests/unit/test_solr.py
index 5226f07..f431ea3 100644
--- a/Allura/allura/tests/unit/test_solr.py
+++ b/Allura/allura/tests/unit/test_solr.py
@@ -16,11 +16,15 @@
 #       under the License.
 
 import unittest
+
 import mock
 from nose.tools import assert_equal
+from markupsafe import Markup
 
+from allura.lib import helpers as h
+from allura.tests import decorators as td
 from allura.lib.solr import Solr
-from allura.lib.search import solarize
+from allura.lib.search import solarize, search_app
 
 class TestSolr(unittest.TestCase):
     @mock.patch('allura.lib.solr.pysolr')
@@ -72,5 +76,83 @@ class TestSolarize(unittest.TestCase):
         obj = mock.MagicMock()
         obj.index.return_value = {'text': '<script>alert(1)</script>'}
         assert_equal(solarize(obj), {'text': ''})
+
         obj.index.return_value = {'text': '&lt;script&gt;alert(1)&lt;/script&gt;'}
-        assert_equal(solarize(obj), {'text': '&lt;script&gt;alert(1)&lt;/script&gt;'})
+        assert_equal(solarize(obj), {'text': '<script>alert(1)</script>'})
+
+
+class TestSearch_app(unittest.TestCase):
+
+    @td.with_wiki
+    @mock.patch('allura.lib.search.url')
+    @mock.patch('allura.lib.search.request')
+    def test_basic(self, req, url_fn):
+        req.GET = dict()
+        req.path = '/test/search'
+        url_fn.side_effect = ['the-score-url', 'the-date-url']
+        with h.push_context('test', 'wiki', neighborhood='Projects'):
+            resp = search_app(q='foo bar')
+        assert_equal(resp, dict(
+            q='foo bar',
+            history=None,
+            results=[],
+            count=0,
+            limit=25,
+            page=0,
+            search_error=None,
+            sort_score_url='the-score-url',
+            sort_date_url='the-date-url',
+            sort_field='score',
+        ))
+
+    @td.with_wiki
+    @mock.patch('allura.lib.search.g.solr.search')
+    @mock.patch('allura.lib.search.url')
+    @mock.patch('allura.lib.search.request')
+    def test_escape_solr_text(self, req, url_fn, solr_search):
+        req.GET = dict()
+        req.path = '/test/wiki/search'
+        url_fn.side_effect = ['the-score-url', 'the-date-url']
+        results = mock.Mock(hits=2, docs=[
+                {'id': 123, 'type_s':'WikiPage Snapshot', 'url_s':'/test/wiki/Foo', 'version_i':2},
+                {'id': 321, 'type_s':'Post'},
+            ], highlighting={
+                123: dict(title='some #ALLURA-HIGHLIGHT-START#Foo#ALLURA-HIGHLIGHT-END# stuff',
+                         text='scary <script>alert(1)</script> bar'),
+                321: dict(title='blah blah',
+                         text='less scary but still dangerous &lt;script&gt;alert(1)&lt;/script&gt; '
+                              'blah #ALLURA-HIGHLIGHT-START#bar#ALLURA-HIGHLIGHT-END# foo foo'),
+            },
+        )
+        results.__iter__ = lambda self: iter(results.docs)
+        solr_search.return_value = results
+        with h.push_context('test', 'wiki', neighborhood='Projects'):
+            resp = search_app(q='foo bar')
+
+        assert_equal(resp, dict(
+            q='foo bar',
+            history=None,
+            count=2,
+            limit=25,
+            page=0,
+            search_error=None,
+            sort_score_url='the-score-url',
+            sort_date_url='the-date-url',
+            sort_field='score',
+            results=[{
+                'id': 123,
+                'type_s': 'WikiPage Snapshot',
+                'version_i': 2,
+                'url_s': '/test/wiki/Foo?version=2',
+                # highlighting works
+                'title_match': Markup('some <strong>Foo</strong> stuff'),
+                # HTML in the solr plaintext results get escaped
+                'text_match': Markup('scary &lt;script&gt;alert(1)&lt;/script&gt; bar'),
+                }, {
+                'id': 321,
+                'type_s': 'Post',
+                'title_match': Markup('blah blah'),
+                # highlighting in text
+                'text_match': Markup('less scary but still dangerous &amp;lt;script&amp;gt;alert(1)&amp;lt;/script&amp;gt; blah <strong>bar</strong> foo foo'),
+                }]
+        ))


[35/50] git commit: [#5773] ticket:328 refactored log widget

Posted by tv...@apache.org.
[#5773]  ticket:328  refactored log widget


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/cf331123
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/cf331123
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/cf331123

Branch: refs/heads/tv/docs
Commit: cf33112318ea778be43d46fa1827a26c016b75a6
Parents: d7bcc22
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Wed May 1 14:50:55 2013 +0400
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu May 2 20:37:05 2013 +0000

----------------------------------------------------------------------
 Allura/allura/config/app_cfg.py               |    1 +
 Allura/allura/lib/helpers.py                  |    6 +++++-
 Allura/allura/nf/allura/css/allura.css        |    3 +++
 Allura/allura/templates/widgets/repo/log.html |   16 ++++++++--------
 Allura/allura/tests/test_helpers.py           |    4 ++++
 5 files changed, 21 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cf331123/Allura/allura/config/app_cfg.py
----------------------------------------------------------------------
diff --git a/Allura/allura/config/app_cfg.py b/Allura/allura/config/app_cfg.py
index f6b11e4..86c65b4 100644
--- a/Allura/allura/config/app_cfg.py
+++ b/Allura/allura/config/app_cfg.py
@@ -101,6 +101,7 @@ class ForgeConfig(AppConfig):
             extensions=['jinja2.ext.do', 'jinja2.ext.i18n'])
         jinja2_env.install_gettext_translations(pylons.i18n)
         jinja2_env.filters['filesizeformat'] = helpers.do_filesizeformat
+        jinja2_env.filters['datetimeformat'] = helpers.datetimeformat
         jinja2_env.globals.update({'hasattr': hasattr})
         config['pylons.app_globals'].jinja2_env = jinja2_env
         # Jinja's unable to request c's attributes without strict_c

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cf331123/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 29cf44e..9d97c02 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -701,4 +701,8 @@ def get_first(d, key):
     v = d.get(key)
     if isinstance(v, list):
         return v[0] if len(v) > 0 else None
-    return v
\ No newline at end of file
+    return v
+
+
+def datetimeformat(value, format='%Y-%m-%d %H:%M:%S'):
+    return value.strftime(format)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cf331123/Allura/allura/nf/allura/css/allura.css
----------------------------------------------------------------------
diff --git a/Allura/allura/nf/allura/css/allura.css b/Allura/allura/nf/allura/css/allura.css
index d468b1a..7b0471c 100644
--- a/Allura/allura/nf/allura/css/allura.css
+++ b/Allura/allura/nf/allura/css/allura.css
@@ -211,3 +211,6 @@ b.ico.ico-vote-down { background-image: url('../images/vote_down.png'); }
 .pagination_size {
     height: 40px;
 }
+tr.rev div.markdown_content p {
+    padding: 0;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cf331123/Allura/allura/templates/widgets/repo/log.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/repo/log.html b/Allura/allura/templates/widgets/repo/log.html
index bdeeda2..50affe6 100644
--- a/Allura/allura/templates/widgets/repo/log.html
+++ b/Allura/allura/templates/widgets/repo/log.html
@@ -33,10 +33,16 @@
       {% for commit in value %}
         <tr class="rev">
           <td>
-            <div class="grid-14">
+            <div>
                 {%if is_file%}
                     <div class="grid-1"><input type="checkbox" class="revision" revision="{{commit._id.split(':')[-1]}}" url_commit="{{commit.url()}}"></div>
                 {%endif%}
+                <a href="{{c.app.repo.url_for_commit(commit)}}">{{commit.shorthand_id()}}</a>
+                {% if c.app.repo.symbolics_for_commit(commit)[1] %}
+                    ({% for tag in c.app.repo.symbolics_for_commit(commit)[1] -%}
+                        <a href="{{c.app.repo.url_for_commit(tag)}}">{{tag}}</a>{% if not loop.last %}&nbsp;{% endif %}
+                    {%- endfor %})
+                {% endif %}
                 {% if commit.committed.email != commit.authored.email %}
                 {% if commit.committer_url %}
                 <a href="{{commit.committer_url}}">{{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}}
@@ -47,12 +53,6 @@
                 pushed
                 {% endif %}
                 {% endif %}
-                <a href="{{commit.url()}}">{{commit.shorthand_id()}}</a>
-                {% if c.app.repo.symbolics_for_commit(commit)[1] %}
-                    ({% for tag in c.app.repo.symbolics_for_commit(commit)[1] -%}
-                        <a href="{{c.app.repo.url()}}ci/{{tag}}/tree{{request.params.get('path')}}">{{tag}}</a>{% if not loop.last %}&nbsp;{% endif %}
-                    {%- endfor %})
-                {% endif %}
                 by
                 {{email_gravatar(commit.authored.email, title=commit.authored.name, size=16)}} {{commit.authored.name}}
                 {%if is_file%}
@@ -62,7 +62,7 @@
             </div>
           </td>
           <td style="vertical-align: text-top">
-            {% if commit.committed.date %}{{commit.committed.date}}{% endif %}
+            {% if commit.committed.date %}{{commit.committed.date|datetimeformat}}{% endif %}
           </td>
           <td style="text-align: left; vertical-align: text-top">
             <a href="{{commit.url()}}tree{{request.params.get('path')}}">

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cf331123/Allura/allura/tests/test_helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index ed40cfc..40c0e96 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -238,3 +238,7 @@ def test_inject_user(context):
     context.user = Mock(username='*anonymous')
     result = inject_user('reported_by_s:$USER OR assigned_to_s:$USER')
     assert_equals(result, 'reported_by_s:"*anonymous" OR assigned_to_s:"*anonymous"')
+
+def test_datetimeformat():
+    from datetime import date
+    assert h.datetimeformat(date(2013, 01, 01)) == '2013-01-01 00:00:00'


[46/50] git commit: [#6133] avoid div by 0 errors when no data

Posted by tv...@apache.org.
[#6133] avoid div by 0 errors when no data


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/59ea05c1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/59ea05c1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/59ea05c1

Branch: refs/heads/tv/docs
Commit: 59ea05c12a813fdddb047953c7c5ed93b37a991d
Parents: fae7479
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Sat May 4 21:41:45 2013 -0400
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon May 6 21:34:31 2013 +0000

----------------------------------------------------------------------
 Allura/allura/model/stats.py |   88 ++++++++++++++++++++-----------------
 1 files changed, 47 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/59ea05c1/Allura/allura/model/stats.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/stats.py b/Allura/allura/model/stats.py
index 5365503..06ed07d 100644
--- a/Allura/allura/model/stats.py
+++ b/Allura/allura/model/stats.py
@@ -86,7 +86,7 @@ class Stats(MappedClass):
         for val in self['general']:
             if val['category'] is None:
                 for commits in val['commits']:
-                    if commits['language'] is None: 
+                    if commits['language'] is None:
                         if days > 30:
                             return round(float(commits.lines)/days*30, 2)
                         else:
@@ -100,7 +100,7 @@ class Stats(MappedClass):
         for val in self['general']:
             if val['category'] is None:
                 for artifact in val['messages']:
-                    if artifact['messagetype'] is None: 
+                    if artifact['messagetype'] is None:
                         tot = artifact.created+artifact.modified
                         if days > 30:
                             return round(float(tot)/days*30,2)
@@ -153,6 +153,8 @@ class Stats(MappedClass):
     def codeRanking(self):
         res = self.query.find()
         totn = res.count()
+        if totn == 0:
+            return 0
         codcontr = self.getCodeContribution()
         upper = len([x for x in res if x.getCodeContribution() > codcontr])
         return round((totn - upper) * 100.0 / totn, 2)
@@ -160,6 +162,8 @@ class Stats(MappedClass):
     def discussionRanking(self):
         res = self.query.find()
         totn = res.count()
+        if totn == 0:
+            return 0
         disccontr = self.getDiscussionContribution()
         upper=len([x for x in res if x.getDiscussionContribution()>disccontr])
         return round((totn - upper) * 100.0 / totn, 2)
@@ -167,20 +171,22 @@ class Stats(MappedClass):
     def ticketsRanking(self):
         res = self.query.find()
         totn = res.count()
+        if totn == 0:
+            return 0
         ticketscontr = self.getTicketsContribution()
         upper=len([x for x in res if x.getTicketsContribution()>ticketscontr])
         return round((totn - upper) * 100.0 / totn, 2)
 
     def getCommits(self, category = None):
         i = getElementIndex(self.general, category = category)
-        if i is None: 
+        if i is None:
             return dict(number=0, lines=0)
         cat = self.general[i]
         j = getElementIndex(cat.commits, language = None)
         if j is None:
             return dict(number=0, lines=0)
         return dict(
-            number=cat.commits[j]['number'], 
+            number=cat.commits[j]['number'],
             lines=cat.commits[j]['lines'])
 
     def getArtifacts(self, category = None, art_type = None):
@@ -202,10 +208,10 @@ class Stats(MappedClass):
                 revoked=0,
                 averagesolvingtime=None)
         if self.general[i].tickets.solved > 0:
-            tot = self.general[i].tickets.totsolvingtime 
+            tot = self.general[i].tickets.totsolvingtime
             number = self.general[i].tickets.solved
             average = tot / number
-        else: 
+        else:
             average = None
         return dict(
             assigned=self.general[i].tickets.assigned,
@@ -220,9 +226,9 @@ class Stats(MappedClass):
         for entry in self.general:
             cat = entry.category
             i = getElementIndex(entry.commits, language = None)
-            if i is None: 
+            if i is None:
                 n, lines = 0, 0
-            else: 
+            else:
                 n, lines = entry.commits[i].number, entry.commits[i].lines
             if cat != None:
                 cat = TroveCategory.query.get(_id = cat)
@@ -237,7 +243,7 @@ class Stats(MappedClass):
         langlist = []
         by_lang = {}
         i = getElementIndex(self.general, category=None)
-        if i is None: 
+        if i is None:
             return dict(number=0, lines=0)
         return dict([(el.language, dict(lines=el.lines, number=el.number))
                      for el in self.general[i].commits])
@@ -248,21 +254,21 @@ class Stats(MappedClass):
         by_cat = {}
         for entry in self.general:
             cat = entry.category
-            if cat != None: 
+            if cat != None:
                 cat = TroveCategory.query.get(_id = cat)
-            if detailed: 
+            if detailed:
                 by_cat[cat] = entry.messages
             else:
                 i = getElementIndex(entry.messages, messagetype=None)
                 if i is not None:
                     by_cat[cat] = entry.messages[i]
-                else: 
+                else:
                     by_cat[cat] = dict(created=0, modified=0)
         return by_cat
 
     def getArtifactsByType(self, category=None):
         i = getElementIndex(self.general, category = category)
-        if i is None: 
+        if i is None:
             return {}
         entry = self.general[i].messages
         by_type = dict([(el.messagetype, dict(created=el.created,
@@ -287,12 +293,12 @@ class Stats(MappedClass):
             by_cat[cat] = dict(
                 assigned=a,
                 solved=s,
-                revoked=r, 
+                revoked=r,
                 averagesolvingtime=_convertTimeDiff(average))
         return by_cat
 
     def getLastMonthCommits(self, category = None):
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
         lineslist = [el.lines for el in self.lastmonth.commits
                      if category in el.categories + [None]]
         return dict(number=len(lineslist), lines=sum(lineslist))
@@ -300,7 +306,7 @@ class Stats(MappedClass):
     def getLastMonthCommitsByCategory(self):
         from allura.model.project import TroveCategory
 
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
         seen = set()
         catlist=[el.category for el in self.general
                  if el.category not in seen and not seen.add(el.category)]
@@ -319,7 +325,7 @@ class Stats(MappedClass):
     def getLastMonthCommitsByLanguage(self):
         from allura.model.project import TroveCategory
 
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
         seen = set()
         langlist=[el.language for el in self.general
                   if el.language not in seen and not seen.add(el.language)]
@@ -336,13 +342,13 @@ class Stats(MappedClass):
         return by_lang
 
     def getLastMonthArtifacts(self, category = None, art_type = None):
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
         cre, mod = reduce(
-            addtuple, 
+            addtuple,
             [(int(el.created),1-int(el.created))
                 for el in self.lastmonth.messages
-                if (category is None or category in el.categories) and 
-                (el.messagetype == art_type or art_type is None)], 
+                if (category is None or category in el.categories) and
+                (el.messagetype == art_type or art_type is None)],
             (0,0))
         return dict(created=cre, modified=mod)
 
@@ -355,7 +361,7 @@ class Stats(MappedClass):
         by_type = {}
         for t in types:
             cre, mod = reduce(
-                addtuple, 
+                addtuple,
                 [(int(el.created),1-int(el.created))
                  for el in self.lastmonth.messages
                  if el.messagetype == t and
@@ -367,7 +373,7 @@ class Stats(MappedClass):
     def getLastMonthArtifactsByCategory(self):
         from allura.model.project import TroveCategory
 
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
         seen = set()
         catlist=[el.category for el in self.general
                  if el.category not in seen and not seen.add(el.category)]
@@ -375,9 +381,9 @@ class Stats(MappedClass):
         by_cat = {}
         for cat in catlist:
             cre, mod = reduce(
-                addtuple, 
+                addtuple,
                 [(int(el.created),1-int(el.created))
-                 for el in self.lastmonth.messages 
+                 for el in self.lastmonth.messages
                  if cat in el.categories + [None]], (0,0))
             if cat != None:
                 cat = TroveCategory.query.get(_id = cat)
@@ -393,7 +399,7 @@ class Stats(MappedClass):
         r = len([el for el in self.lastmonth.revokedtickets
                  if category in el.categories + [None]])
         s, time = reduce(
-            addtuple, 
+            addtuple,
             [(1, el.solvingtime)
              for el in self.lastmonth.solvedtickets
              if category in el.categories + [None]],
@@ -407,9 +413,9 @@ class Stats(MappedClass):
         return dict(
             assigned=a,
             revoked=r,
-            solved=s, 
+            solved=s,
             averagesolvingtime=_convertTimeDiff(time))
-        
+
     def getLastMonthTicketsByCategory(self):
         from allura.model.project import TroveCategory
 
@@ -428,17 +434,17 @@ class Stats(MappedClass):
                                         if cat in el.categories+[None]],(0,0))
             if cat != None:
                 cat = TroveCategory.query.get(_id = cat)
-            if s > 0: 
+            if s > 0:
                 time = time / s
             else:
                 time = None
             by_cat[cat] = dict(
                 assigned=a,
                 revoked=r,
-                solved=s, 
+                solved=s,
                 averagesolvingtime=_convertTimeDiff(time))
         return by_cat
-        
+
     def checkOldArtifacts(self):
         now = datetime.utcnow()
         for m in self.lastmonth.messages:
@@ -509,11 +515,11 @@ class Stats(MappedClass):
                 lines = 0
             return lines
 
-        def _addCommitData(stats, topics, languages, lines):          
+        def _addCommitData(stats, topics, languages, lines):
             lt = topics + [None]
             ll = languages + [None]
             for t in lt:
-                i = getElementIndex(stats.general, category=t) 
+                i = getElementIndex(stats.general, category=t)
                 if i is None:
                     newstats = dict(
                         category=t,
@@ -561,14 +567,14 @@ class Stats(MappedClass):
         _addCommitData(self, topics, languages, totlines)
 
         self.lastmonth.commits.append(dict(
-            datetime=commit_datetime, 
-            categories=topics, 
+            datetime=commit_datetime,
+            categories=topics,
             programming_languages=languages,
             lines=totlines))
         self.checkOldArtifacts()
 
     def _updateArtifactsStats(self, art_type, art_datetime, project, action):
-        if action not in ['created', 'modified']: 
+        if action not in ['created', 'modified']:
             return
         topics = [t for t in project.trove_topic if t]
         lt = [None] + topics
@@ -601,7 +607,7 @@ class Stats(MappedClass):
             created=(action == 'created'),
             categories=topics,
             messagetype=art_type))
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
 
     def _updateTicketsStats(self, topics, action, s_time = None):
         if action not in ['solved', 'assigned', 'revoked']:
@@ -621,8 +627,8 @@ class Stats(MappedClass):
                     messages=[])
                 self.general.append(stats)
                 i = getElementIndex(self.general, category = t)
-            self.general[i]['tickets'][action] += 1 
-            if action == 'solved': 
+            self.general[i]['tickets'][action] += 1
+            if action == 'solved':
                 self.general[i]['tickets']['totsolvingtime']+=s_time
 
 def getElementIndex(el_list, **kw):
@@ -649,8 +655,8 @@ def _convertTimeDiff(int_seconds):
     minutes = seconds / 60
     seconds = seconds % 60
     return dict(
-        days=days, 
-        hours=hours, 
+        days=days,
+        hours=hours,
         minutes=minutes,
         seconds=seconds)
 


[09/50] git commit: [#5607] make max markdown render length more easily configurable; and lower the default cutoff

Posted by tv...@apache.org.
[#5607] make max markdown render length more easily configurable; and lower the default cutoff


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/5fb297e6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/5fb297e6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/5fb297e6

Branch: refs/heads/tv/docs
Commit: 5fb297e6dc05ea9a38b43532febbb79d7b4edf0a
Parents: 4510805
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Apr 29 21:59:29 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Apr 29 21:59:43 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/app_globals.py    |    4 +---
 Allura/allura/tests/test_globals.py |    3 +--
 2 files changed, 2 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5fb297e6/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index a8d2006..0621b8d 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -60,12 +60,10 @@ from allura.lib.zarkov_helpers import ZarkovClient, zmq
 
 log = logging.getLogger(__name__)
 
-BIG_TEXT_THRESHOLD = 90000
-
 
 class ForgeMarkdown(markdown.Markdown):
     def convert(self, source):
-        if len(source) > BIG_TEXT_THRESHOLD:
+        if len(source) > asint(config.get('markdown_render_max_length', 40000)):
             # if text is too big, markdown can take a long time to process it, so we return it as a plain text
             log.info('Text is too big. Skipping markdown processing')
             escaped = cgi.escape(h.really_unicode(source))

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5fb297e6/Allura/allura/tests/test_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_globals.py b/Allura/allura/tests/test_globals.py
index ccf90cc..2adc64c 100644
--- a/Allura/allura/tests/test_globals.py
+++ b/Allura/allura/tests/test_globals.py
@@ -285,8 +285,7 @@ def test_markdown_within_html():
 
 def test_markdown_big_text():
     '''If text is too big g.markdown.convert should return plain text'''
-    from allura.lib.app_globals import BIG_TEXT_THRESHOLD
-    text = 'a' * (BIG_TEXT_THRESHOLD + 1)
+    text = 'a' * 40001
     assert_equal(g.markdown.convert(text), '<pre>%s</pre>' % text)
     assert_equal(g.markdown_wiki.convert(text), '<pre>%s</pre>' % text)
 


[15/50] git commit: [#6179] don't change 'shortname' var

Posted by tv...@apache.org.
[#6179] don't change 'shortname' var


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/3d3f1997
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/3d3f1997
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/3d3f1997

Branch: refs/heads/tv/docs
Commit: 3d3f199782450d1c497a8146528dfe17b2f8c62f
Parents: f746109
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Apr 30 18:30:58 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Apr 30 18:30:58 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3d3f1997/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 02aae3a..3bb1655 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -465,8 +465,10 @@ class ProjectRegistrationProvider(object):
         self.rate_limit(user, neighborhood)
 
         if user_project and shortname.startswith('u/'):
-            shortname = shortname.replace('u/', '', 1)
-        if not h.re_project_name.match(shortname):
+            check_shortname = shortname.replace('u/', '', 1)
+        else:
+            check_shortname = shortname
+        if not h.re_project_name.match(check_shortname):
             raise ValueError('Invalid project shortname: %s' % shortname)
 
         p = M.Project.query.get(shortname=shortname, neighborhood_id=neighborhood._id)


[04/50] git commit: [#5332] Relax mount point name rules for repos

Posted by tv...@apache.org.
[#5332] Relax mount point name rules for repos

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/ba32ac79
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/ba32ac79
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/ba32ac79

Branch: refs/heads/tv/docs
Commit: ba32ac79881cb1ba74cea0ea279a426c5e416801
Parents: f2c3475
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Thu Apr 25 18:34:31 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Apr 29 14:44:04 2013 +0000

----------------------------------------------------------------------
 Allura/allura/app.py                               |   30 +++++++++++++--
 Allura/allura/controllers/project.py               |    4 +-
 Allura/allura/controllers/rest.py                  |    2 -
 .../allura/ext/admin/templates/project_tools.html  |   23 +++++++++--
 Allura/allura/lib/helpers.py                       |    3 +-
 Allura/allura/lib/repository.py                    |    1 +
 Allura/allura/model/project.py                     |    2 +-
 Allura/allura/public/nf/js/project_tools.js        |   12 +++++-
 Allura/allura/tests/unit/test_app.py               |   13 ++++++
 9 files changed, 74 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ba32ac79/Allura/allura/app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index bf874bf..124f084 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -28,7 +28,7 @@ from bson import ObjectId
 from ming.orm import session, state
 from ming.utils import LazyProperty
 
-from allura.lib.helpers import push_config, vardec
+from allura.lib import helpers as h
 from allura.lib.security import require, has_access, require_access
 from allura import model
 from allura.controllers import BaseController
@@ -144,6 +144,10 @@ class Application(object):
     :cvar bool hidden: Default is False, Application is not hidden from the
         list of a project's installed tools.
     :cvar str tool_description: Text description of this Application.
+    :cvar bool relaxed_mount_points: Set to True to relax the default mount point
+        naming restrictions for this Application. Default is False. See
+        :attr:`default mount point naming rules <allura.lib.helpers.re_tool_mount_point>` and
+        :attr:`relaxed mount point naming rules <allura.lib.helpers.re_relaxed_tool_mount_point>`.
     :cvar Controller root: Serves content at
         /<neighborhood>/<project>/<app>/. Default is None - subclasses should
         override.
@@ -154,7 +158,6 @@ class Application(object):
         /<neighborhood>/<project>/<admin>/<app>/. Default is a
         :class:`DefaultAdminController` instance.
     :cvar dict icons: Mapping of icon sizes to application-specific icon paths.
-
     """
 
     __version__ = None
@@ -178,6 +181,7 @@ class Application(object):
     tool_description="This is a tool for Allura forge."
     default_mount_label='Tool Name'
     default_mount_point='tool'
+    relaxed_mount_points=False
     ordinal=0
     hidden = False
     icons={
@@ -203,6 +207,24 @@ class Application(object):
         return self.config.parent_security_context()
 
     @classmethod
+    def validate_mount_point(cls, mount_point):
+        """Check if ``mount_point`` is valid for this Application.
+
+        In general, subclasses should not override this, but rather toggle
+        the strictness of allowed mount point names by toggling
+        :attr:`Application.relaxed_mount_points`.
+
+        :param mount_point: the mount point to validate
+        :type mount_point: str
+        :rtype: A :class:`regex Match object <_sre.SRE_Match>` if the mount
+                point is valid, else None
+
+        """
+        re = (h.re_relaxed_tool_mount_point if cls.relaxed_mount_points
+                else h.re_tool_mount_point)
+        return re.match(mount_point)
+
+    @classmethod
     def status_int(self):
         return self.status_map.index(self.status)
 
@@ -450,7 +472,7 @@ class DefaultAdminController(BaseController):
     @expose()
     @require_post()
     def configure(self, **kw):
-        with push_config(c, app=self.app):
+        with h.push_config(c, app=self.app):
             require_access(self.app, 'configure')
             is_admin = self.app.config.tool_name == 'admin'
             if kw.pop('delete', False):
@@ -481,7 +503,7 @@ class DefaultAdminController(BaseController):
 
     @without_trailing_slash
     @expose()
-    @vardec
+    @h.vardec
     @require_post()
     def update(self, card=None, **kw):
         self.app.config.acl = []

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ba32ac79/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index 2f59a38..75e7792 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -317,8 +317,6 @@ class ProjectController(object):
     @expose()
     def _lookup(self, name, *remainder):
         name = unquote(name)
-        if not h.re_path_portion.match(name):
-            raise exc.HTTPNotFound, name
         subproject = M.Project.query.get(shortname=c.project.shortname + '/' + name,
                                          neighborhood_id=c.project.neighborhood_id)
         if subproject:
@@ -592,7 +590,7 @@ class NeighborhoodAdminController(object):
 
 
         for tool in validate_tools.keys():
-            if not h.re_tool_mount_point.match(tool):
+            if tool not in g.entry_points['tool']:
                 flash('Anchored tools "%s" is invalid' % anchored_tools,'error')
                 result = False
         if result:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ba32ac79/Allura/allura/controllers/rest.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/rest.py b/Allura/allura/controllers/rest.py
index cf03733..8ae0c70 100644
--- a/Allura/allura/controllers/rest.py
+++ b/Allura/allura/controllers/rest.py
@@ -257,8 +257,6 @@ class ProjectRestController(object):
     def _lookup(self, name, *remainder):
         if not name:
             return self, ()
-        if not h.re_path_portion.match(name):
-            raise exc.HTTPNotFound, name
         subproject = M.Project.query.get(shortname=c.project.shortname + '/' + name,
                                          neighborhood_id=c.project.neighborhood_id,
                                          deleted=False)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ba32ac79/Allura/allura/ext/admin/templates/project_tools.html
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/templates/project_tools.html b/Allura/allura/ext/admin/templates/project_tools.html
index 6516039..dc7646c 100644
--- a/Allura/allura/ext/admin/templates/project_tools.html
+++ b/Allura/allura/ext/admin/templates/project_tools.html
@@ -30,7 +30,7 @@
   <div class="nested-grid-container">
     {% for tool in installable_tools %}
       <span class="tcenter grid-4 installable_tool">
-        <a class="install_trig" data-tool="{{ tool['name'] }}">
+        <a class="install_trig" data-tool="{{ tool['name'] }}" data-relaxed-mount-points="{{ tool.app.relaxed_mount_points and 'true' or 'false' }}">
           <span class="tool_title">{{ tool['app'].tool_label }}{{' (%s)' % tool.app.status if tool.app.status != 'production' else ''}}</span><br />
           <img src="{{ g.theme.app_icon_url(tool['app'], 32) or 'unk.png' }}" alt="">
         </a>
@@ -50,9 +50,24 @@
     <div class="grid-13"><input type="text" name="new.mount_label" class="new_mount_label"></div>
     <label class="grid-13">Mount Point</label>
     <div class="grid-13"><input type="text" name="new.mount_point" class="new_mount_point"></div>
-    <div class="grid-13"><small>* The mount point is the name of the tool as it will appear in a URL.
-      A valid mount point must begin with a letter, contain only letters, numbers, and dashes,
-      and be from 1-63 characters in length.</small></div>
+    <div class="grid-13">
+      <small>
+        * The mount point is the name of the tool as it will appear in a URL.
+        <span class="mount-point-name-rules tool">
+          A valid mount point for this tool must begin with a letter, contain only letters,
+          numbers, and dashes, and be from 1-63 characters in length.
+        </span>
+        <span class="mount-point-name-rules tool-relaxed">
+          A valid mount point for this tool must begin with a letter or number, contain only
+          letters, numbers, dashes, underscores, periods, and plus signs, and be
+          from 1-63 characters in length.
+        </span>
+        <span class="mount-point-name-rules subproject">
+          A valid subproject mount point must begin with a letter, contain only letters,
+          numbers, and dashes, and be from 3-63 characters in length.
+        </span>
+      </small>
+    </div>
     <hr>
     <div class="grid-13">&nbsp;</div>
     <div class="grid-13">

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ba32ac79/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index ea2b4d2..b118efe 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -53,8 +53,9 @@ from allura.lib import AsciiDammit
 from .security import has_access
 
 re_path_portion_fragment = re.compile(r'[a-z][-a-z0-9]*')
-re_path_portion = re.compile(r'^[a-z][-a-z0-9]{2,}$')
+re_path_portion = re.compile(r'^[a-z][-a-z0-9]{2,62}$')
 re_tool_mount_point = re.compile(r'^[a-z][-a-z0-9]{0,62}$')
+re_relaxed_tool_mount_point = re.compile(r'^[a-z0-9][-a-z0-9_\.\+]{0,62}$')
 re_clean_vardec_key = re.compile(r'''\A
 ( # first part
 \w+# name...

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ba32ac79/Allura/allura/lib/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/repository.py b/Allura/allura/lib/repository.py
index 69736b6..3a432ec 100644
--- a/Allura/allura/lib/repository.py
+++ b/Allura/allura/lib/repository.py
@@ -53,6 +53,7 @@ class RepositoryApp(Application):
     tool_label='Repository'
     default_mount_label='Code'
     default_mount_point='code'
+    relaxed_mount_points=True
     ordinal=2
     forkable=False
     default_branch_name=None # master or default or some such

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ba32ac79/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index d207aab..b3f1131 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -547,7 +547,7 @@ class Project(MappedClass, ActivityNode, ActivityObject):
             for x in range(10):
                 if self.app_instance(mount_point) is None: break
                 mount_point = base_mount_point + '-%d' % x
-        if not h.re_tool_mount_point.match(mount_point):
+        if not App.validate_mount_point(mount_point):
             raise exceptions.ToolError, 'Mount point "%s" is invalid' % mount_point
         # HACK: reserved url components
         if mount_point in ('feed', 'index', 'icon', '_nav.json'):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ba32ac79/Allura/allura/public/nf/js/project_tools.js
----------------------------------------------------------------------
diff --git a/Allura/allura/public/nf/js/project_tools.js b/Allura/allura/public/nf/js/project_tools.js
index 3a5b5d7..b148ba4 100644
--- a/Allura/allura/public/nf/js/project_tools.js
+++ b/Allura/allura/public/nf/js/project_tools.js
@@ -28,20 +28,30 @@
     var new_mount_point = install_form.find('input.new_mount_point');
     var new_mount_label = install_form.find('input.new_mount_label');
     var install_tool_label = $('#install_tool_label');
+    var mount_point_rule_names = $('#install_form .mount-point-rule-names');
     install_popup.append(install_form.show());
     $('a.install_trig').click(function () {
-        var datatool = $(this).attr('data-tool');
+        var datatool = $(this).data('tool');
+        var relaxed_mount_points = $(this).data('relaxed-mount-points');
+        install_form.find('.mount-point-name-rules').hide();
         if (datatool) {
             var tool = defaults[datatool];
             install_tool_label.html(tool.default_label);
             new_ep_name.val(datatool);
             new_mount_point.val(tool.default_mount);
             new_mount_label.val(tool.default_label);
+            if (relaxed_mount_points) {
+              install_form.find('.mount-point-name-rules.tool-relaxed').show();
+            }
+            else {
+              install_form.find('.mount-point-name-rules.tool').show();
+            }
         } else {
             install_tool_label.html("Subproject");
             new_ep_name.val('');
             new_mount_point.val('');
             new_mount_label.val('');
+            install_form.find('.mount-point-name-rules.subproject').show();
         }
     });
     // Edit popup

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ba32ac79/Allura/allura/tests/unit/test_app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_app.py b/Allura/allura/tests/unit/test_app.py
index 668ac65..8f0c0db 100644
--- a/Allura/allura/tests/unit/test_app.py
+++ b/Allura/allura/tests/unit/test_app.py
@@ -15,6 +15,9 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+import re
+from unittest import TestCase
+
 from allura.app import Application
 from allura import model
 from allura.tests.unit import WithDatabase
@@ -22,6 +25,16 @@ from allura.tests.unit.patches import fake_app_patch
 from allura.tests.unit.factories import create_project, create_app_config
 
 
+class TestApplication(TestCase):
+
+    def test_validate_mount_point(self):
+        app = Application
+        mount_point = '1.2+foo_bar'
+        self.assertIsNone(app.validate_mount_point(mount_point))
+        app.relaxed_mount_points = True
+        self.assertIsNotNone(app.validate_mount_point(mount_point))
+
+
 class TestInstall(WithDatabase):
     patches = [fake_app_patch]
 


[39/50] git commit: [#5998] avoid very deep recursion during tests

Posted by tv...@apache.org.
[#5998] avoid very deep recursion during tests


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/b4fa50de
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/b4fa50de
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/b4fa50de

Branch: refs/heads/tv/docs
Commit: b4fa50de705735bc4bff6e84edd1caacb84db7cb
Parents: 7a332c6
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri May 3 17:52:24 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 3 17:52:24 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/patches.py |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/b4fa50de/Allura/allura/lib/patches.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/patches.py b/Allura/allura/lib/patches.py
index ef6fba5..60c4648 100644
--- a/Allura/allura/lib/patches.py
+++ b/Allura/allura/lib/patches.py
@@ -78,13 +78,16 @@ def apply():
         return func(*args, **kwargs)
 
 
-def newrelic():
-    old_call = tg.controllers.DecoratedController._call
+# must be saved outside the newrelic() method so that multiple newrelic()
+# calls (e.g. during tests) don't cause the patching to get applied to itself
+# over and over
+old_controller_call = tg.controllers.DecoratedController._call
 
+def newrelic():
     @h.monkeypatch(tg.controllers.DecoratedController,
                    tg.controllers.decoratedcontroller.DecoratedController)
     def _call(self, controller, *args, **kwargs):
         '''Set NewRelic transaction name to actual controller name'''
         import newrelic.agent
         newrelic.agent.set_transaction_name(newrelic.agent.callable_name(controller))
-        return old_call(self, controller, *args, **kwargs)
+        return old_controller_call(self, controller, *args, **kwargs)


[49/50] git commit: [#6189] allow uppercase characters in code repos' relaxed mount point names

Posted by tv...@apache.org.
[#6189] allow uppercase characters in code repos' relaxed mount point names


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/8e9c17de
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/8e9c17de
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/8e9c17de

Branch: refs/heads/tv/docs
Commit: 8e9c17dea40135c41cb834e64f82709d201253fc
Parents: 87a89b2
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue May 7 20:56:17 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Wed May 8 13:22:00 2013 +0000

----------------------------------------------------------------------
 Allura/allura/ext/admin/admin_main.py              |    2 +-
 .../allura/ext/admin/templates/project_tools.html  |    4 ++--
 Allura/allura/lib/helpers.py                       |    7 ++++---
 Allura/allura/model/project.py                     |    2 ++
 Allura/allura/tests/test_helpers.py                |    8 ++++++--
 5 files changed, 15 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8e9c17de/Allura/allura/ext/admin/admin_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/admin_main.py b/Allura/allura/ext/admin/admin_main.py
index 34bc64c..433fade 100644
--- a/Allura/allura/ext/admin/admin_main.py
+++ b/Allura/allura/ext/admin/admin_main.py
@@ -559,7 +559,7 @@ class ProjectAdminController(BaseController):
                     sp.ordinal = int(new['ordinal'])
                 else:
                     require_access(c.project, 'admin')
-                    mount_point = new['mount_point'].lower() or ep_name.lower()
+                    mount_point = new['mount_point'] or ep_name
                     M.AuditLog.log('install tool %s', mount_point)
                     h.log_action(log, 'install tool').info(
                         'install tool %s', mount_point,

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8e9c17de/Allura/allura/ext/admin/templates/project_tools.html
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/templates/project_tools.html b/Allura/allura/ext/admin/templates/project_tools.html
index 0c8046d..e103ffe 100644
--- a/Allura/allura/ext/admin/templates/project_tools.html
+++ b/Allura/allura/ext/admin/templates/project_tools.html
@@ -54,7 +54,7 @@
       <small>
         * The mount point is the name of the tool as it will appear in a URL.
         <span class="mount-point-name-rules tool">
-          A valid mount point for this tool must begin with a letter, contain only letters,
+          A valid mount point for this tool must begin with a letter, contain only lowercase letters,
           numbers, and dashes, and be from 1-63 characters in length.
         </span>
         <span class="mount-point-name-rules tool-relaxed">
@@ -63,7 +63,7 @@
           from 1-63 characters in length.
         </span>
         <span class="mount-point-name-rules subproject">
-          A valid subproject mount point must begin with a letter, contain only letters,
+          A valid subproject mount point must begin with a letter, contain only lowercase letters,
           numbers, and dashes, and be from 3-15 characters in length.
         </span>
       </small>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8e9c17de/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index d55b511..c7b8fc6 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -60,8 +60,8 @@ re_project_name = re.compile(r'^[a-z][-a-z0-9]{2,14}$')
 # validates tool mount point names
 re_tool_mount_point = re.compile(r'^[a-z][-a-z0-9]{0,62}$')
 re_tool_mount_point_fragment = re.compile(r'[a-z][-a-z0-9]*')
-re_relaxed_tool_mount_point = re.compile(r'^[a-z0-9][-a-z0-9_\.\+]{0,62}$')
-re_relaxed_tool_mount_point_fragment = re.compile(r'[a-z0-9][-a-z0-9_\.\+]*')
+re_relaxed_tool_mount_point = re.compile(r'^[a-zA-Z0-9][-a-zA-Z0-9_\.\+]{0,62}$')
+re_relaxed_tool_mount_point_fragment = re.compile(r'[a-zA-Z0-9][-a-zA-Z0-9_\.\+]*')
 
 re_clean_vardec_key = re.compile(r'''\A
 ( # first part
@@ -90,7 +90,8 @@ def make_safe_path_portion(ustr, relaxed=True):
     ustr = really_unicode(ustr)
     s = ustr.encode('latin1', 'ignore')
     s = AsciiDammit.asciiDammit(s)
-    s = s.lower()
+    if not relaxed:
+        s = s.lower()
     s = '-'.join(regex.findall(s))
     s = s.replace('--', '-')
     return s

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8e9c17de/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index 39f1adb..da36ada 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -558,6 +558,8 @@ class Project(MappedClass, ActivityNode, ActivityObject):
             for x in range(10):
                 if self.app_instance(mount_point) is None: break
                 mount_point = base_mount_point + '-%d' % x
+        if not App.relaxed_mount_points:
+            mount_point = mount_point.lower()
         if not App.validate_mount_point(mount_point):
             raise exceptions.ToolError, 'Mount point "%s" is invalid' % mount_point
         # HACK: reserved url components

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8e9c17de/Allura/allura/tests/test_helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index 40c0e96..6eb1719 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -41,11 +41,11 @@ class TestMakeSafePathPortion(TestCase):
         self.f = h.make_safe_path_portion
 
     def test_no_latin1_chars(self):
-        s = self.f(u'Задачи')
+        s = self.f(u'Задачи', relaxed=False)
         self.assertEqual(s, '')
 
     def test_some_latin1_chars(self):
-        s = self.f('åß∂ƒ')
+        s = self.f('åß∂ƒ', relaxed=False)
         self.assertEqual(s, 'ab')
 
     def test_strict_mount_point_names(self):
@@ -53,12 +53,16 @@ class TestMakeSafePathPortion(TestCase):
         self.assertEqual(s, 'this-is-illegal')
         s = self.f('this-1-is-legal', relaxed=False)
         self.assertEqual(s, 'this-1-is-legal')
+        s = self.f('THIS-IS-Illegal', relaxed=False)
+        self.assertEqual(s, 'this-is-illegal')
 
     def test_relaxed_mount_point_names(self):
         s = self.f('1_this+is.legal')
         self.assertEqual(s, '1_this+is.legal')
         s = self.f('not*_legal')
         self.assertEqual(s, 'not-legal')
+        s = self.f('THIS-IS-Illegal')
+        self.assertEqual(s, 'THIS-IS-Illegal')
 
 
 def test_really_unicode():


[30/50] git commit: [#6138] more updates to transition stored tool_names to lowercase

Posted by tv...@apache.org.
[#6138] more updates to transition stored tool_names to lowercase


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/17617e6e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/17617e6e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/17617e6e

Branch: refs/heads/tv/docs
Commit: 17617e6ebd6c1aad2b7f198526c6811d17b14d7d
Parents: 7cc8df7
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu May 2 20:08:01 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu May 2 20:08:01 2013 +0000

----------------------------------------------------------------------
 .../templates/admin_widgets/metadata_admin.html    |    2 +-
 .../allura/ext/admin/templates/project_admin.html  |    4 ++--
 Allura/allura/templates/jinja_master/lib.html      |    2 +-
 Allura/allura/tests/model/test_project.py          |    2 +-
 Allura/allura/tests/test_globals.py                |    6 +++---
 5 files changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/17617e6e/Allura/allura/ext/admin/templates/admin_widgets/metadata_admin.html
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/templates/admin_widgets/metadata_admin.html b/Allura/allura/ext/admin/templates/admin_widgets/metadata_admin.html
index 738428f..ff60ab3 100644
--- a/Allura/allura/ext/admin/templates/admin_widgets/metadata_admin.html
+++ b/Allura/allura/ext/admin/templates/admin_widgets/metadata_admin.html
@@ -46,7 +46,7 @@
     <input name="support_page" type="radio" value=""{% if value.support_page == '' %} checked{% endif %} id="support_page_none">
     <label for="support_page_none">None</label><br>
     {% for ac in value.app_configs %}
-      {% if ac.tool_name in ['Wiki', 'Tickets', 'Discussion'] %}
+      {% if ac.tool_name.lower() in ['wiki', 'tickets', 'discussion'] %}
         <input name="support_page" type="radio" value="{{ac.options.mount_point}}" id="support_page_{{ac.options.mount_point}}"
                {% if value.support_page == ac.options.mount_point %} checked{% endif %}>
         <label for="support_page_{{ac.options.mount_point}}">{{ac.options.mount_label}}</label><br>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/17617e6e/Allura/allura/ext/admin/templates/project_admin.html
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/templates/project_admin.html b/Allura/allura/ext/admin/templates/project_admin.html
index 3da1c0c..f8453f2 100644
--- a/Allura/allura/ext/admin/templates/project_admin.html
+++ b/Allura/allura/ext/admin/templates/project_admin.html
@@ -49,7 +49,7 @@
   </div>
   <div class="grid-4">
     {% for tool in c.project.app_configs %}
-      {% if tool.tool_name == 'Wiki' and not wiki_found %}
+      {% if tool.tool_name.lower() == 'wiki' and not wiki_found %}
         <a href="{{c.project.url()}}{{tool.options.mount_point}}/add">Add Page</a><br>
         <a href="{{c.project.url()}}{{tool.options.mount_point}}/">View Wiki</a>
         {% set wiki_found = True %}
@@ -82,7 +82,7 @@
   </div>
   <div class="grid-4">
     {% for tool in c.project.app_configs %}
-      {% if tool.tool_name == 'Tickets' and not tracker_found %}
+      {% if tool.tool_name.lower() == 'tickets' and not tracker_found %}
         <a href="{{c.project.url()}}{{tool.options.mount_point}}/new">Create Ticket</a><br>
         <a href="{{c.project.url()}}{{tool.options.mount_point}}/milestones">Edit Milestones</a><br>
         <a href="{{c.project.url()}}{{tool.options.mount_point}}/">View Tickets</a>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/17617e6e/Allura/allura/templates/jinja_master/lib.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/lib.html b/Allura/allura/templates/jinja_master/lib.html
index 0e4938a..48934d3 100644
--- a/Allura/allura/templates/jinja_master/lib.html
+++ b/Allura/allura/templates/jinja_master/lib.html
@@ -659,7 +659,7 @@ allowed, permitting basic styling and layout: &lt;div markdown style="float:left
 <h2 id="md_ex_neighborhood_notes{{id}}">Neighborhood Notifications</h2>
 <p>You can list updates from all projects in a neighborhood by tool type. Max_number (default is 5) and sort (default is pubdate) are optional:</p>
 <div class="codehilite"><pre>
-[[neighborhood_feeds tool_name=Wiki max_number=10 sort=pubdate]]
+[[neighborhood_feeds tool_name=wiki max_number=10 sort=pubdate]]
 </pre></div>
 </div>
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/17617e6e/Allura/allura/tests/model/test_project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_project.py b/Allura/allura/tests/model/test_project.py
index 232dec5..16f5a97 100644
--- a/Allura/allura/tests/model/test_project.py
+++ b/Allura/allura/tests/model/test_project.py
@@ -107,7 +107,7 @@ def test_anchored_tools():
     c.project.install_app = MagicMock()
     assert c.project.sitemap()[0].label == 'Wiki'
     assert c.project.install_app.call_args[0][0] == 'tickets'
-    assert c.project.ordered_mounts()[0]['ac'].tool_name == 'Wiki'
+    assert c.project.ordered_mounts()[0]['ac'].tool_name == 'wiki'
 
 
 def test_set_ordinal_to_admin_tool():

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/17617e6e/Allura/allura/tests/test_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_globals.py b/Allura/allura/tests/test_globals.py
index 2adc64c..bf17979 100644
--- a/Allura/allura/tests/test_globals.py
+++ b/Allura/allura/tests/test_globals.py
@@ -143,7 +143,7 @@ def test_macros():
     r = g.markdown_wiki.convert('[[download_button]]')
     assert_equal(r, '<div class="markdown_content"><p><span class="download-button-%s" style="margin-bottom: 1em; display: block;"></span></p>\n</div>' % p_test._id)
     h.set_context('--init--', 'wiki', neighborhood='Projects')
-    r = g.markdown_wiki.convert('[[neighborhood_feeds tool_name=Wiki]]')
+    r = g.markdown_wiki.convert('[[neighborhood_feeds tool_name=wiki]]')
     assert 'Home modified by' in r, r
     orig_len = len(r)
     # Make project private & verify we don't see its new feed items
@@ -155,7 +155,7 @@ def test_macros():
     pg = WM.Page.query.get(title='Home', app_config_id=c.app.config._id)
     pg.text = 'Change'
     pg.commit()
-    r = g.markdown_wiki.convert('[[neighborhood_feeds tool_name=Wiki]]')
+    r = g.markdown_wiki.convert('[[neighborhood_feeds tool_name=wiki]]')
     new_len = len(r)
     assert new_len == orig_len
     p = BM.BlogPost(title='test me', neighborhood_id=p_test.neighborhood_id)
@@ -361,7 +361,7 @@ def test_macro_include():
 
 def test_macro_nbhd_feeds():
     with h.push_context('--init--', 'wiki', neighborhood='Projects'):
-        r = g.markdown_wiki.convert('[[neighborhood_feeds tool_name=Wiki]]')
+        r = g.markdown_wiki.convert('[[neighborhood_feeds tool_name=wiki]]')
         assert 'Home modified by ' in r, r
 
 


[28/50] git commit: [#5599] Removed empty children list from _nav.json

Posted by tv...@apache.org.
[#5599] Removed empty children list from _nav.json

Signed-off-by: Cory Johns <cj...@slashdotmedia.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/dbee43f2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/dbee43f2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/dbee43f2

Branch: refs/heads/tv/docs
Commit: dbee43f23c3ae07ced764f33392fe199409f76ce
Parents: 323b7d9
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Thu May 2 15:32:56 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Thu May 2 15:41:56 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/project.py |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/dbee43f2/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index f8789a3..d47caf4 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -311,8 +311,10 @@ class ProjectController(FeedController):
     def _nav(self):
         menu = []
         for s in c.project.grouped_navbar_entries():
-            children = [dict(name=child.label, url=child.url, icon=child.ui_icon) for child in s.children]
-            menu.append(dict(name=s.label, url=s.url, icon=s.ui_icon, children=children))
+            entry = dict(name=s.label, url=s.url, icon=s.ui_icon)
+            if s.children:
+                entry['children'] = [dict(name=child.label, url=child.url, icon=child.ui_icon) for child in s.children]
+            menu.append(entry)
         return dict(menu=menu)
 
     @expose()


[32/50] git commit: [#5773] ticket:314 added full commit message, full date, download link in History view

Posted by tv...@apache.org.
[#5773] ticket:314 added full commit message, full date, download link in History view


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/e14b56ee
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/e14b56ee
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/e14b56ee

Branch: refs/heads/tv/docs
Commit: e14b56ee7bcdc4a1abca954351caa5ef1135cfc2
Parents: a9b5b11
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Fri Apr 19 11:38:44 2013 +0400
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu May 2 20:37:02 2013 +0000

----------------------------------------------------------------------
 Allura/allura/templates/widgets/repo/log.html      |   59 ++++++++++----
 .../forgegit/tests/functional/test_controllers.py  |   12 ++-
 .../forgesvn/tests/functional/test_controllers.py  |    4 +-
 3 files changed, 53 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/e14b56ee/Allura/allura/templates/widgets/repo/log.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/repo/log.html b/Allura/allura/templates/widgets/repo/log.html
index d7307a5..11fa918 100644
--- a/Allura/allura/templates/widgets/repo/log.html
+++ b/Allura/allura/templates/widgets/repo/log.html
@@ -33,30 +33,55 @@
       {% for commit in value %}
         <tr class="rev">
           <td>
-            {%if is_file%}
+            <div class="grid-14">
+                {%if is_file%}
                 <div class="grid-1"><input type="checkbox" class="revision" revision="{{commit._id.split(':')[-1]}}" url_commit="{{commit.url()}}"></div>
-            {%endif%}
-            {{commit.summary}}
-            <br/>
-            {% if commit.committed.email != commit.authored.email %}
-              {% if commit.committer_url %}
+                {%endif%}
+                {%for tag in c.app.repo.symbolics_for_commit(commit)[1]%}
+                        <a href="{{c.app.repo.url()}}ci/{{tag}}/tree{{request.params.get('path')}}">{{tag}}</a>
+                {%endfor%}
+                {% if commit.committed.email != commit.authored.email %}
+                {% if commit.committer_url %}
                 <a href="{{commit.committer_url}}">{{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}}
-                {{commit.committed.name}}</a>
+                    {{commit.committed.name}}</a>
                 pushed
-              {% else %}
+                {% else %}
                 {{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}} {{commit.committed.name}}
                 pushed
-              {% endif %}
-            {% endif %}
-             <a href="{{commit.url()}}">{{commit.shorthand_id()}}</a>
-            by
-              {{email_gravatar(commit.authored.email, title=commit.authored.name, size=16)}} {{commit.authored.name}}
+                {% endif %}
+                {% endif %}
+                <a href="{{commit.url()}}">{{commit.shorthand_id()}}</a>
+                by
+                {{email_gravatar(commit.authored.email, title=commit.authored.name, size=16)}} {{commit.authored.name}}
+                {%if is_file%}
+                    {%if request.params.get('path')[:1]=='/'%}
+                        {%set path = request.params.get('path')[1:]%}
+                    {%else%}
+                        {%set path = request.params.get('path')%}
+                    {%endif%}
+
+                    {{commit.tree.get_blob(path).size}} Bytes
+                {%endif%}
+            </div>
+            <div>
+              {{g.markdown.convert(commit.message)}}
+            </div>
           </td>
-          <td>
-            {% if commit.committed.date %}{{abbr_date(commit.committed.date)}}{% endif %}
+          <td style="vertical-align: text-top">
+            {% if commit.committed.date %}{{commit.committed.date}}{% endif %}
           </td>
-          <td style="text-align: right">
-            <a href="{{commit.url()}}tree/">Tree</a>
+          <td style="text-align: left; vertical-align: text-top">
+            <a href="{{commit.url()}}tree{{request.params.get('path')}}">
+            {%if is_file%}
+                View
+            {% else %}
+                Tree
+            {%endif%}
+            </a>
+              {%if is_file%}
+              <br/>
+              <a href="{{commit.url()}}tree{{request.params.get('path')}}?format=raw ">Download</a>
+              {%endif%}
           </td>
         </tr>
       {% endfor %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/e14b56ee/ForgeGit/forgegit/tests/functional/test_controllers.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/tests/functional/test_controllers.py b/ForgeGit/forgegit/tests/functional/test_controllers.py
index 186b46a..78ff5a9 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -110,10 +110,16 @@ class TestRootController(_TestCase):
     def test_log(self):
         resp = self.app.get('/src-git/ci/1e146e67985dcd71c74de79613719bef7bddca4a/log/')
         assert 'Initial commit' in resp
-        assert 'Change README' in resp
+        assert '<div class="markdown_content"><p>Change README</p></div>' in resp
+        assert 'tree/README?format=raw ">Download</a>' not in resp
+        assert'28 Bytes' not in resp.html.find('td').contents[1].text
+        assert 'Tree' in resp.html.findAll('td')[2].text, resp.html.findAll('td')[2].text
         resp = self.app.get('/src-git/ci/1e146e67985dcd71c74de79613719bef7bddca4a/log/?path=/README')
-        assert 'Change README ' in resp
-        assert 'Add README ' in resp
+        assert'28 Bytes' in resp.html.find('td').contents[1].text
+        assert 'View' in resp.html.findAll('td')[2].text
+        assert 'Change README' in resp
+        assert 'tree/README?format=raw ">Download</a>' in resp
+        assert 'Add README' in resp
         assert "Initial commit " not in resp
         resp = self.app.get('/src-git/ci/1e146e67985dcd71c74de79613719bef7bddca4a/log/?path=/a/b/c/')
         assert 'Remove file' in resp

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/e14b56ee/ForgeSVN/forgesvn/tests/functional/test_controllers.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/tests/functional/test_controllers.py b/ForgeSVN/forgesvn/tests/functional/test_controllers.py
index 90af545..9ab3b57 100644
--- a/ForgeSVN/forgesvn/tests/functional/test_controllers.py
+++ b/ForgeSVN/forgesvn/tests/functional/test_controllers.py
@@ -138,10 +138,10 @@ class TestRootController(SVNTestController):
         assert 'Create readme' in r
         r = self.app.get('/src/2/log/?path=')
         assert "Create readme" in r
-        assert "Add path " in r
+        assert "Add path" in r
         r = self.app.get('/src/2/log/?path=README')
         assert "Modify readme" not in r
-        assert "Create readme " in r
+        assert "Create readme" in r
         r = self.app.get('/src/2/log/?path=/a/b/c/')
         assert 'Add path' in r
         assert 'Remove hello.txt' not in r


[29/50] git commit: [#6138] Force all tool_names to be lower-case

Posted by tv...@apache.org.
[#6138] Force all tool_names to be lower-case

Signed-off-by: Cory Johns <cj...@slashdotmedia.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/7cc8df70
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/7cc8df70
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/7cc8df70

Branch: refs/heads/tv/docs
Commit: 7cc8df70ee7a28b8f111434ddc8aafced682a3c5
Parents: dbee43f
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Wed May 1 21:35:07 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu May 2 19:06:08 2013 +0000

----------------------------------------------------------------------
 Allura/allura/model/project.py            |    2 +-
 Allura/allura/tests/model/test_project.py |    3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7cc8df70/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index f95aae0..982dad8 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -577,7 +577,7 @@ class Project(MappedClass, ActivityNode, ActivityObject):
         options.update(override_options)
         cfg = AppConfig(
             project_id=self._id,
-            tool_name=ep_name,
+            tool_name=ep_name.lower(),
             options=options)
         app = App(self, cfg)
         with h.push_config(c, project=self, app=app):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7cc8df70/Allura/allura/tests/model/test_project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_project.py b/Allura/allura/tests/model/test_project.py
index bbff251..232dec5 100644
--- a/Allura/allura/tests/model/test_project.py
+++ b/Allura/allura/tests/model/test_project.py
@@ -20,7 +20,7 @@
 """
 Model tests for project
 """
-from nose.tools import with_setup
+from nose.tools import with_setup, assert_equal
 from pylons import tmpl_context as c
 from ming.orm.ormsession import ThreadLocalORMSession
 
@@ -62,6 +62,7 @@ def test_project():
 
     c.project.install_app('Wiki', 'hello-test-mount-point')
     c.project.support_page = 'hello-test-mount-point'
+    assert_equal(c.project.app_config('wiki').tool_name, 'wiki')
     ThreadLocalORMSession.flush_all()
     with td.raises(ToolError):
         # already installed


[40/50] git commit: [#6110] Log output on all tasks to prevent Broken pipe errors

Posted by tv...@apache.org.
[#6110] Log output on all tasks to prevent Broken pipe errors

Signed-off-by: Cory Johns <cj...@slashdotmedia.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/94cd1ede
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/94cd1ede
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/94cd1ede

Branch: refs/heads/tv/docs
Commit: 94cd1ede798aa2cb4ec4b3a515cb1a3f627a2eaa
Parents: b4fa50d
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Fri May 3 17:09:19 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 3 18:59:22 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/helpers.py        |   23 ++++++++++++++++++++++-
 Allura/allura/model/monq_model.py   |    4 +++-
 Allura/allura/scripts/scripttask.py |   23 ++++-------------------
 3 files changed, 29 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/94cd1ede/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 9d97c02..d55b511 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -17,6 +17,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+import sys
 import os
 import os.path
 import difflib
@@ -705,4 +706,24 @@ def get_first(d, key):
 
 
 def datetimeformat(value, format='%Y-%m-%d %H:%M:%S'):
-    return value.strftime(format)
\ No newline at end of file
+    return value.strftime(format)
+
+
+@contextmanager
+def log_output(log):
+    class Writer(object):
+        def __init__(self, func):
+            self.func = func
+
+        def write(self, buf):
+            self.func(buf)
+
+    _stdout = sys.stdout
+    _stderr = sys.stderr
+    sys.stdout = Writer(log.info)
+    sys.stderr = Writer(log.error)
+    try:
+        yield log
+    finally:
+        sys.stdout = _stdout
+        sys.stderr = _stderr

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/94cd1ede/Allura/allura/model/monq_model.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/monq_model.py b/Allura/allura/model/monq_model.py
index 49cb6e9..d298c1b 100644
--- a/Allura/allura/model/monq_model.py
+++ b/Allura/allura/model/monq_model.py
@@ -30,6 +30,7 @@ from ming import schema as S
 from ming.orm import session, FieldProperty
 from ming.orm.declarative import MappedClass
 
+from allura.lib.helpers import log_output
 from .session import task_orm_session
 
 log = logging.getLogger(__name__)
@@ -251,7 +252,8 @@ class MonQTask(MappedClass):
                 if app_config:
                     c.app = c.project.app_instance(app_config)
             c.user = M.User.query.get(_id=self.context.user_id)
-            self.result = func(*self.args, **self.kwargs)
+            with log_output(log):
+                self.result = func(*self.args, **self.kwargs)
             self.state = 'complete'
             return self.result
         except Exception, exc:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/94cd1ede/Allura/allura/scripts/scripttask.py
----------------------------------------------------------------------
diff --git a/Allura/allura/scripts/scripttask.py b/Allura/allura/scripts/scripttask.py
index 8fa0984..b686838 100644
--- a/Allura/allura/scripts/scripttask.py
+++ b/Allura/allura/scripts/scripttask.py
@@ -55,13 +55,6 @@ from allura.lib.decorators import task
 log = logging.getLogger(__name__)
 
 
-class Writer(object):
-    def __init__(self, func):
-        self.func = func
-
-    def write(self, buf):
-        self.func(buf)
-
 
 class ScriptTask(object):
     """Base class for a command-line script that is also executable as a task."""
@@ -79,18 +72,10 @@ class ScriptTask(object):
     @classmethod
     def _execute_task(cls, arg_string):
         try:
-            _stdout = sys.stdout
-            _stderr = sys.stderr
-            sys.stdout = Writer(log.info)
-            sys.stderr = Writer(log.error)
-            try:
-                options = cls.parser().parse_args(shlex.split(arg_string or ''))
-            except SystemExit:
-                raise Exception("Error parsing args: '%s'" % arg_string)
-            cls.execute(options)
-        finally:
-            sys.stdout = _stdout
-            sys.stderr = _stderr
+            options = cls.parser().parse_args(shlex.split(arg_string or ''))
+        except SystemExit:
+            raise Exception("Error parsing args: '%s'" % arg_string)
+        cls.execute(options)
 
     @classmethod
     def execute(cls, options):


[07/50] git commit: [#5332] Fix test

Posted by tv...@apache.org.
[#5332] Fix test

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/2c50ad0c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/2c50ad0c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/2c50ad0c

Branch: refs/heads/tv/docs
Commit: 2c50ad0c57a3555d5c81bb3fdfc65633b8789aca
Parents: f8475cd
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Mon Apr 29 15:27:11 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Mon Apr 29 15:27:11 2013 +0000

----------------------------------------------------------------------
 Allura/allura/tests/model/test_project.py |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2c50ad0c/Allura/allura/tests/model/test_project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_project.py b/Allura/allura/tests/model/test_project.py
index 0a218b1..bbff251 100644
--- a/Allura/allura/tests/model/test_project.py
+++ b/Allura/allura/tests/model/test_project.py
@@ -91,7 +91,10 @@ def test_project():
     c.app.config.breadcrumbs()
 
 def test_subproject():
-    sp = c.project.new_subproject('test-project-nose')
+    with td.raises(ToolError):
+        # name exceeds 15 chars
+        sp = c.project.new_subproject('test-project-nose')
+    sp = c.project.new_subproject('test-proj-nose')
     spp = sp.new_subproject('spp')
     ThreadLocalORMSession.flush_all()
     sp.delete()


[47/50] git commit: [#6138] Changed grouped tool label to use defined capitalization instead of calling .capitalize()

Posted by tv...@apache.org.
[#6138] Changed grouped tool label to use defined capitalization instead of calling .capitalize()

Signed-off-by: Cory Johns <cj...@slashdotmedia.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/9bfc415a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/9bfc415a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/9bfc415a

Branch: refs/heads/tv/docs
Commit: 9bfc415a5d2c3f43263cde410245cf4f75e317ed
Parents: 3e12f6d
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon May 6 18:47:44 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue May 7 17:41:58 2013 +0000

----------------------------------------------------------------------
 Allura/allura/model/project.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/9bfc415a/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index 982dad8..39f1adb 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -498,7 +498,7 @@ class Project(MappedClass, ActivityNode, ActivityObject):
                 if tool_name not in grouped_nav:
                     child = deepcopy(e)
                     # change label to be the tool name (type)
-                    e.label = tool_name.capitalize()
+                    e.label = g.entry_points['tool'][tool_name].tool_label
                     # add tool url to list of urls that will match this nav entry
                     # have to do this before changing the url to the list page
                     e.matching_urls.append(e.url)


[20/50] git commit: [#6186] make SMTP timeouts configurable

Posted by tv...@apache.org.
[#6186] make SMTP timeouts configurable


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/404b1528
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/404b1528
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/404b1528

Branch: refs/heads/tv/docs
Commit: 404b152838b0ba65de2adc59f721c0a0c291302a
Parents: d34331e
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Wed May 1 18:33:57 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed May 1 18:33:57 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/mail_util.py |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/404b1528/Allura/allura/lib/mail_util.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py
index 166bc92..db7ddb3 100644
--- a/Allura/allura/lib/mail_util.py
+++ b/Allura/allura/lib/mail_util.py
@@ -218,11 +218,15 @@ class SMTPClient(object):
         if asbool(tg.config.get('smtp_ssl', False)):
             smtp_client = smtplib.SMTP_SSL(
                 tg.config.get('smtp_server', 'localhost'),
-                asint(tg.config.get('smtp_port', 25)))
+                asint(tg.config.get('smtp_port', 25)),
+                timeout=float(tg.config.get('smtp_timeout', 10)),
+            )
         else:
             smtp_client = smtplib.SMTP(
                 tg.config.get('smtp_server', 'localhost'),
-                asint(tg.config.get('smtp_port', 465)))
+                asint(tg.config.get('smtp_port', 465)),
+                timeout=float(tg.config.get('smtp_timeout', 10)),
+            )
         if tg.config.get('smtp_user', None):
             smtp_client.login(tg.config['smtp_user'], tg.config['smtp_password'])
         if asbool(tg.config.get('smtp_tls', False)):


[23/50] git commit: [#5913] restore ui-icon-* classes in top menu

Posted by tv...@apache.org.
[#5913] restore ui-icon-* classes in top menu


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/4469a52b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/4469a52b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/4469a52b

Branch: refs/heads/tv/docs
Commit: 4469a52b876042a2017b229b606e8c5dbf2257d1
Parents: 22df7b4
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Apr 1 19:30:10 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Wed May 1 20:38:37 2013 +0000

----------------------------------------------------------------------
 Allura/allura/templates/jinja_master/top_nav.html |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/4469a52b/Allura/allura/templates/jinja_master/top_nav.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/top_nav.html b/Allura/allura/templates/jinja_master/top_nav.html
index 599eb3e..1b17d11 100644
--- a/Allura/allura/templates/jinja_master/top_nav.html
+++ b/Allura/allura/templates/jinja_master/top_nav.html
@@ -30,7 +30,7 @@
         {% set selected = True %}
       {% endif %}
     {% endif %}
-    <li{% if selected %} class="selected"{% endif %}>
+    <li class="ui-icon-{{s.ui_icon or 'admin'}}{% if selected %} selected{% endif %}">
       <a href="{{s.url}}">
         <span>
         {{s.label}}


[36/50] git commit: [#5773] ticket:328 fixed css for log widget

Posted by tv...@apache.org.
[#5773]  ticket:328  fixed css for log widget


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/5a51840a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/5a51840a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/5a51840a

Branch: refs/heads/tv/docs
Commit: 5a51840a77960d13fe96f897290d0eee09fbe963
Parents: cf33112
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Wed May 1 18:19:25 2013 +0400
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu May 2 20:37:05 2013 +0000

----------------------------------------------------------------------
 Allura/allura/nf/allura/css/allura.css        |    2 ++
 Allura/allura/templates/widgets/repo/log.html |    6 ++++--
 2 files changed, 6 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5a51840a/Allura/allura/nf/allura/css/allura.css
----------------------------------------------------------------------
diff --git a/Allura/allura/nf/allura/css/allura.css b/Allura/allura/nf/allura/css/allura.css
index 7b0471c..1334b0c 100644
--- a/Allura/allura/nf/allura/css/allura.css
+++ b/Allura/allura/nf/allura/css/allura.css
@@ -211,6 +211,8 @@ b.ico.ico-vote-down { background-image: url('../images/vote_down.png'); }
 .pagination_size {
     height: 40px;
 }
+
 tr.rev div.markdown_content p {
     padding: 0;
+    margin-bottom: 0;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5a51840a/Allura/allura/templates/widgets/repo/log.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/repo/log.html b/Allura/allura/templates/widgets/repo/log.html
index 50affe6..c46b425 100644
--- a/Allura/allura/templates/widgets/repo/log.html
+++ b/Allura/allura/templates/widgets/repo/log.html
@@ -45,11 +45,13 @@
                 {% endif %}
                 {% if commit.committed.email != commit.authored.email %}
                 {% if commit.committer_url %}
+                by
                 <a href="{{commit.committer_url}}">{{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}}
-                    {{commit.committed.name}}</a>
+                    {{commit.committed.name}}</a>,
                 pushed
                 {% else %}
-                {{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}} {{commit.committed.name}}
+                by
+                {{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}} {{commit.committed.name}},
                 pushed
                 {% endif %}
                 {% endif %}


[10/50] git commit: [#5607] ticket:319 Render text as plain text if it's too big

Posted by tv...@apache.org.
[#5607] ticket:319 Render text as plain text if it's too big


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/4510805a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/4510805a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/4510805a

Branch: refs/heads/tv/docs
Commit: 4510805ac0c6fe8594cb220850dd0efe2cc50e4c
Parents: ed4a5a0
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Apr 25 10:49:20 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Apr 29 21:59:43 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/app_globals.py    |    7 +++++++
 Allura/allura/tests/test_globals.py |    8 ++++++++
 2 files changed, 15 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/4510805a/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index e5b00c7..a8d2006 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -60,9 +60,16 @@ from allura.lib.zarkov_helpers import ZarkovClient, zmq
 
 log = logging.getLogger(__name__)
 
+BIG_TEXT_THRESHOLD = 90000
+
 
 class ForgeMarkdown(markdown.Markdown):
     def convert(self, source):
+        if len(source) > BIG_TEXT_THRESHOLD:
+            # if text is too big, markdown can take a long time to process it, so we return it as a plain text
+            log.info('Text is too big. Skipping markdown processing')
+            escaped = cgi.escape(h.really_unicode(source))
+            return h.html.literal(u'<pre>%s</pre>' % escaped)
         try:
             return markdown.Markdown.convert(self, source)
         except Exception:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/4510805a/Allura/allura/tests/test_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_globals.py b/Allura/allura/tests/test_globals.py
index ea7fc1d..ccf90cc 100644
--- a/Allura/allura/tests/test_globals.py
+++ b/Allura/allura/tests/test_globals.py
@@ -283,6 +283,14 @@ def test_markdown_within_html():
 </div>''' in r, r
 
 
+def test_markdown_big_text():
+    '''If text is too big g.markdown.convert should return plain text'''
+    from allura.lib.app_globals import BIG_TEXT_THRESHOLD
+    text = 'a' * (BIG_TEXT_THRESHOLD + 1)
+    assert_equal(g.markdown.convert(text), '<pre>%s</pre>' % text)
+    assert_equal(g.markdown_wiki.convert(text), '<pre>%s</pre>' % text)
+
+
 @td.with_wiki
 def test_markdown_basics():
     with h.push_context('test', 'wiki', neighborhood='Projects'):


[41/50] git commit: [#6197] better qualify .selected so it doesn't conflict with nav menu

Posted by tv...@apache.org.
[#6197] better qualify .selected so it doesn't conflict with nav menu


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/eca53d73
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/eca53d73
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/eca53d73

Branch: refs/heads/tv/docs
Commit: eca53d73c4274492d4295731ca0be8fb5d3a7478
Parents: 94cd1ed
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu May 2 20:48:10 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon May 6 14:30:51 2013 +0000

----------------------------------------------------------------------
 Allura/allura/templates/repo/log.html |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/eca53d73/Allura/allura/templates/repo/log.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/repo/log.html b/Allura/allura/templates/repo/log.html
index 7d41198..53b7b39 100644
--- a/Allura/allura/templates/repo/log.html
+++ b/Allura/allura/templates/repo/log.html
@@ -39,7 +39,7 @@
 
 {% block extra_css %}
 <style type="text/css">
-    .selected {
+    .rev.selected {
         background-color: #FFFFBE;
     }
 </style>


[27/50] git commit: [#5599] Fixed and cleaned up nav-bar selection logic

Posted by tv...@apache.org.
[#5599] Fixed and cleaned up nav-bar selection logic

Signed-off-by: Cory Johns <cj...@slashdotmedia.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/323b7d93
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/323b7d93
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/323b7d93

Branch: refs/heads/tv/docs
Commit: 323b7d93786f8d79b2070e5193b4a6f1e58f1845
Parents: be11653
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Wed May 1 20:37:09 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Wed May 1 20:38:38 2013 +0000

----------------------------------------------------------------------
 Allura/allura/model/project.py                    |    2 +
 Allura/allura/templates/jinja_master/top_nav.html |   19 +--------------
 2 files changed, 4 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/323b7d93/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index 8a06566..f95aae0 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -445,6 +445,8 @@ class Project(MappedClass, ActivityNode, ActivityObject):
                         ordinal = anchored_tools.keys().index(entry.tool_name.lower())
                     else:
                         ordinal = int(ac.options.get('ordinal', 0)) + delta_ordinal
+                    if self.is_nbhd_project and entry.label == 'Admin':
+                        entry.matching_urls.append('%s_admin/' % self.url())
                     if ordinal > max_ordinal:
                         max_ordinal = ordinal
                     entries.append({'ordinal':ordinal,'entry':entry})

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/323b7d93/Allura/allura/templates/jinja_master/top_nav.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/top_nav.html b/Allura/allura/templates/jinja_master/top_nav.html
index 47ef332..8ef4621 100644
--- a/Allura/allura/templates/jinja_master/top_nav.html
+++ b/Allura/allura/templates/jinja_master/top_nav.html
@@ -19,18 +19,7 @@
 {% if c.project %}
 <ul class="dropdown">
   {% for s in c.project.grouped_navbar_entries() %}
-    {% set selected = False %}
-    {% if s.label == 'Home' %}
-      {% set url_length = s.url|length %}
-      {% if request.url.rfind(s.url, -url_length) != -1 %}
-        {% set selected = True %}
-      {% endif %}
-    {% else %}
-      {% if s.matches_url(request) or c.project.neighborhood.url()+'_admin' in request.upath_info %}
-        {% set selected = True %}
-      {% endif %}
-    {% endif %}
-    <li class="{% if selected %}selected{% endif %}">
+    <li class="{% if s.matches_url(request) %}selected{% endif %}">
         <a href="{{s.url}}" class="ui-icon-{{s.ui_icon or 'admin'}}">
             {{s.label}}
         </a>
@@ -38,11 +27,7 @@
         {% if grouped_tool_count %}
             <ul>
                 {%for tool in s.children%}
-                    {% set selected = False %}
-                    {% if tool.matches_url(request) or c.project.neighborhood.url()+'_admin' in request.upath_info%}
-                        {% set selected = True %}
-                    {% endif %}
-                    <li class="{% if selected %}selected{% endif %}"><a href="{{tool.url}}">{{tool.label}}</a></li>
+                    <li class="{% if tool.matches_url(request) %}selected{% endif %}"><a href="{{tool.url}}">{{tool.label}}</a></li>
                 {%endfor%}
             </ul>
         {% endif %}


[38/50] git commit: [#6161] ticket:329 Push changes to multiple solr instances

Posted by tv...@apache.org.
[#6161] ticket:329 Push changes to multiple solr instances


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/7a332c6e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/7a332c6e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/7a332c6e

Branch: refs/heads/tv/docs
Commit: 7a332c6ecdc6c2cffd5f262d0293d7afdf195d85
Parents: ba100cc
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon Apr 29 12:46:33 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu May 2 22:18:14 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/app_globals.py      |   19 +++++---
 Allura/allura/lib/solr.py             |   47 +++++++++++++++-----
 Allura/allura/tests/unit/test_solr.py |   67 +++++++++++++++++++++------
 Allura/development.ini                |    3 +
 4 files changed, 104 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7a332c6e/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index 0621b8d..b030d6f 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -38,7 +38,7 @@ import pygments.util
 from tg import config, session
 from pylons import request
 from pylons import tmpl_context as c
-from paste.deploy.converters import asbool, asint
+from paste.deploy.converters import asbool, asint, aslist
 from pypeline.markup import markup as pypeline_markup
 
 import ew as ew_core
@@ -93,14 +93,21 @@ class Globals(object):
         self.allura_templates = pkg_resources.resource_filename('allura', 'templates')
 
         # Setup SOLR
-        self.solr_server = config.get('solr.server')
+        self.solr_server = aslist(config.get('solr.server'), ',')
+        # skip empty strings in case of extra commas
+        self.solr_server = [s for s in self.solr_server if s]
+        self.solr_query_server = config.get('solr.query_server')
         if asbool(config.get('solr.mock')):
             self.solr = self.solr_short_timeout = MockSOLR()
         elif self.solr_server:
-            self.solr = Solr(self.solr_server, commit=asbool(config.get('solr.commit', True)),
-                    commitWithin=config.get('solr.commitWithin'), timeout=int(config.get('solr.long_timeout', 60)))
-            self.solr_short_timeout = Solr(self.solr_server, commit=asbool(config.get('solr.commit', True)),
-                    commitWithin=config.get('solr.commitWithin'), timeout=int(config.get('solr.short_timeout', 10)))
+            self.solr = Solr(self.solr_server, self.solr_query_server,
+                             commit=asbool(config.get('solr.commit', True)),
+                             commitWithin=config.get('solr.commitWithin'),
+                             timeout=int(config.get('solr.long_timeout', 60)))
+            self.solr_short_timeout = Solr(self.solr_server, self.solr_query_server,
+                                           commit=asbool(config.get('solr.commit', True)),
+                                           commitWithin=config.get('solr.commitWithin'),
+                                           timeout=int(config.get('solr.short_timeout', 10)))
         else: # pragma no cover
             self.solr = None
             self.solr_short_timeout = None

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7a332c6e/Allura/allura/lib/solr.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/solr.py b/Allura/allura/lib/solr.py
index e91b183..e1e9567 100644
--- a/Allura/allura/lib/solr.py
+++ b/Allura/allura/lib/solr.py
@@ -20,28 +20,53 @@ import pysolr
 from pysolr import SolrError
 
 
-class Solr(pysolr.Solr):
-    """Solr server that accepts default values for `commit` and
-    `commitWithin` and passes those values through to each `add` and
-    `delete` call, unless explicitly overridden.
+class Solr(object):
+    """Solr interface that pushes updates to multiple solr instances.
+
+    `push_servers`: list of servers to push to.
+    `query_server`: server to read from. Uses `push_servers[0]` if not specified.
+
+    Also, accepts default values for `commit` and `commitWithin`
+    and passes those values through to each `add` and `delete` call,
+    unless explicitly overridden.
     """
 
-    def __init__(self, server, commit=True, commitWithin=None, **kw):
-        pysolr.Solr.__init__(self, server, **kw)
-        self.commit = commit
+    def __init__(self, push_servers, query_server=None,
+                 commit=True, commitWithin=None, **kw):
+        self.push_pool = [pysolr.Solr(s, **kw) for s in push_servers]
+        if query_server:
+            self.query_server = pysolr.Solr(query_server, **kw)
+        else:
+            self.query_server = self.push_pool[0]
+        self._commit = commit
         self.commitWithin = commitWithin
 
     def add(self, *args, **kw):
         if 'commit' not in kw:
-            kw['commit'] = self.commit
+            kw['commit'] = self._commit
         if self.commitWithin and 'commitWithin' not in kw:
             kw['commitWithin'] = self.commitWithin
-        return pysolr.Solr.add(self, *args, **kw)
+        responses = []
+        for solr in self.push_pool:
+            responses.append(solr.add(*args, **kw))
+        return responses
 
     def delete(self, *args, **kw):
         if 'commit' not in kw:
-            kw['commit'] = self.commit
-        return pysolr.Solr.delete(self, *args, **kw)
+            kw['commit'] = self._commit
+        responses = []
+        for solr in self.push_pool:
+            responses.append(solr.delete(*args, **kw))
+        return responses
+
+    def commit(self, *args, **kw):
+        responses = []
+        for solr in self.push_pool:
+            responses.append(solr.commit(*args, **kw))
+        return responses
+
+    def search(self, *args, **kw):
+        return self.query_server.search(*args, **kw)
 
 
 class MockSOLR(object):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7a332c6e/Allura/allura/tests/unit/test_solr.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_solr.py b/Allura/allura/tests/unit/test_solr.py
index b3dee43..2bc5cdb 100644
--- a/Allura/allura/tests/unit/test_solr.py
+++ b/Allura/allura/tests/unit/test_solr.py
@@ -28,30 +28,67 @@ from allura.lib.solr import Solr
 from allura.lib.search import solarize, search_app
 
 class TestSolr(unittest.TestCase):
+
     @mock.patch('allura.lib.solr.pysolr')
-    def setUp(self, pysolr):
-        self.solr = Solr('server', commit=False, commitWithin='10000')
+    def test_init(self, pysolr):
+        servers = ['server1', 'server2']
+        solr = Solr(servers, commit=False, commitWithin='10000')
+        calls = [mock.call('server1'), mock.call('server2')]
+        pysolr.Solr.assert_has_calls(calls)
+        assert_equal(len(solr.push_pool), 2)
+
+        pysolr.reset_mock()
+        solr = Solr(servers, 'server3', commit=False, commitWithin='10000')
+        calls = [mock.call('server1'), mock.call('server2'), mock.call('server3')]
+        pysolr.Solr.assert_has_calls(calls)
+        assert_equal(len(solr.push_pool), 2)
 
     @mock.patch('allura.lib.solr.pysolr')
     def test_add(self, pysolr):
-        s = self.solr
-        s.add('foo', commit=True, commitWithin=None)
-        pysolr.Solr.add.assert_called_once_with(s, 'foo', commit=True,
-                commitWithin=None)
+        servers = ['server1', 'server2']
+        solr = Solr(servers, commit=False, commitWithin='10000')
+        solr.add('foo', commit=True, commitWithin=None)
+        calls = [mock.call('foo', commit=True, commitWithin=None)] * 2
+        pysolr.Solr().add.assert_has_calls(calls)
         pysolr.reset_mock()
-        s.add('bar', somekw='value')
-        pysolr.Solr.add.assert_called_once_with(s, 'bar', commit=False,
-                commitWithin='10000', somekw='value')
+        solr.add('bar', somekw='value')
+        calls = [mock.call('bar', commit=False,
+            commitWithin='10000', somekw='value')] * 2
+        pysolr.Solr().add.assert_has_calls(calls)
 
     @mock.patch('allura.lib.solr.pysolr')
     def test_delete(self, pysolr):
-        s = self.solr
-        s.delete('foo', commit=True)
-        pysolr.Solr.delete.assert_called_once_with(s, 'foo', commit=True)
+        servers = ['server1', 'server2']
+        solr = Solr(servers, commit=False, commitWithin='10000')
+        solr.delete('foo', commit=True)
+        calls = [mock.call('foo', commit=True)] * 2
+        pysolr.Solr().delete.assert_has_calls(calls)
+        pysolr.reset_mock()
+        solr.delete('bar', somekw='value')
+        calls = [mock.call('bar', commit=False, somekw='value')] * 2
+        pysolr.Solr().delete.assert_has_calls(calls)
+
+    @mock.patch('allura.lib.solr.pysolr')
+    def test_commit(self, pysolr):
+        servers = ['server1', 'server2']
+        solr = Solr(servers, commit=False, commitWithin='10000')
+        solr.commit('arg')
+        pysolr.Solr().commit.assert_has_calls([mock.call('arg')] * 2)
         pysolr.reset_mock()
-        s.delete('bar', somekw='value')
-        pysolr.Solr.delete.assert_called_once_with(s, 'bar', commit=False,
-                somekw='value')
+        solr.commit('arg', kw='kw')
+        calls = [mock.call('arg', kw='kw')] * 2
+        pysolr.Solr().commit.assert_has_calls(calls)
+
+    @mock.patch('allura.lib.solr.pysolr')
+    def test_search(self, pysolr):
+        servers = ['server1', 'server2']
+        solr = Solr(servers, commit=False, commitWithin='10000')
+        solr.search('foo')
+        solr.query_server.search.assert_called_once_with('foo')
+        pysolr.reset_mock()
+        solr.search('bar', kw='kw')
+        solr.query_server.search.assert_called_once_with('bar', kw='kw')
+
 
 class TestSolarize(unittest.TestCase):
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7a332c6e/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 761876b..b2ac7bf 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -177,7 +177,10 @@ amqp.enabled = false
 openid.realm = http://localhost:8080/
 
 # SOLR setup
+# comma-separated list of servers to push changes to
 solr.server = http://localhost:8983/solr/core0
+# server to read from. Uses solr.server[0] if not specified.
+# solr.query_server =
 # commit on every add/delete?
 solr.commit = false
 # commit add operations within N ms


[08/50] git commit: [#5998] remove newrelic config flag, since it is not config driven any more

Posted by tv...@apache.org.
[#5998] remove newrelic config flag, since it is not config driven any more


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/ed4a5a0e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/ed4a5a0e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/ed4a5a0e

Branch: refs/heads/tv/docs
Commit: ed4a5a0e804c60eebf9bed8c359b5f6acf91558a
Parents: 2c50ad0
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Apr 29 13:09:59 2013 -0400
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Apr 29 13:09:59 2013 -0400

----------------------------------------------------------------------
 Allura/development.ini |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ed4a5a0e/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 9cb99c3..761876b 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -49,8 +49,6 @@ use_queue = true
 
 base_url = http://localhost:8080
 
-# newrelic = true
-
 #lang = ru
 cache_dir = %(here)s/data
 beaker.session.key = allura


[03/50] git commit: [#2835] fix test setup

Posted by tv...@apache.org.
[#2835] fix test setup


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/f2c34752
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/f2c34752
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/f2c34752

Branch: refs/heads/tv/docs
Commit: f2c34752741fdfe19c53ce774bcd9f89c167415c
Parents: 69d7575
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Apr 29 14:16:31 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Apr 29 14:16:31 2013 +0000

----------------------------------------------------------------------
 Allura/allura/tests/unit/test_solr.py |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f2c34752/Allura/allura/tests/unit/test_solr.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_solr.py b/Allura/allura/tests/unit/test_solr.py
index f431ea3..b3dee43 100644
--- a/Allura/allura/tests/unit/test_solr.py
+++ b/Allura/allura/tests/unit/test_solr.py
@@ -23,6 +23,7 @@ from markupsafe import Markup
 
 from allura.lib import helpers as h
 from allura.tests import decorators as td
+from alluratest.controller import setup_basic_test
 from allura.lib.solr import Solr
 from allura.lib.search import solarize, search_app
 
@@ -83,6 +84,10 @@ class TestSolarize(unittest.TestCase):
 
 class TestSearch_app(unittest.TestCase):
 
+    def setUp(self):
+        # need to create the "test" project so @td.with_wiki works
+        setup_basic_test()
+
     @td.with_wiki
     @mock.patch('allura.lib.search.url')
     @mock.patch('allura.lib.search.request')


[22/50] git commit: [#5599] ticket:296 drop-down for grouped menu items

Posted by tv...@apache.org.
[#5599] ticket:296 drop-down for grouped menu items


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/a028f972
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/a028f972
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/a028f972

Branch: refs/heads/tv/docs
Commit: a028f972b9c73eef5cc73e7be2d199e1188aa0de
Parents: 4469a52
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Mon Apr 15 10:28:57 2013 +0400
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Wed May 1 20:38:37 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/project.py               |    8 +-
 Allura/allura/model/project.py                     |    9 ++
 Allura/allura/nf/allura/css/site_style.css         |   78 +++++++++++----
 Allura/allura/templates/award.html                 |    2 +-
 .../templates/jinja_master/neigh_top_nav.html      |   40 --------
 Allura/allura/templates/jinja_master/top_nav.html  |   20 ++--
 .../templates/neighborhood_admin_accolades.html    |    2 +-
 .../templates/neighborhood_admin_overview.html     |    2 +-
 Allura/allura/templates/neighborhood_help.html     |    2 +-
 Allura/allura/templates/neighborhood_moderate.html |    2 +-
 .../templates/neighborhood_project_list.html       |    2 +-
 Allura/allura/templates/neighborhood_stats.html    |    2 +-
 .../templates/neighborhood_stats_adminlist.html    |    2 +-
 Allura/allura/tests/functional/test_admin.py       |   17 ++--
 Allura/allura/tests/functional/test_home.py        |   30 ++++++
 .../allura/tests/functional/test_neighborhood.py   |   16 ++--
 16 files changed, 138 insertions(+), 96 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index e60b494..f8789a3 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -309,9 +309,11 @@ class ProjectController(FeedController):
 
     @expose('json:')
     def _nav(self):
-        return dict(menu=[
-                dict(name=s.label, url=s.url, icon=s.ui_icon)
-                for s in c.project.grouped_navbar_entries()])
+        menu = []
+        for s in c.project.grouped_navbar_entries():
+            children = [dict(name=child.label, url=child.url, icon=child.ui_icon) for child in s.children]
+            menu.append(dict(name=s.label, url=s.url, icon=s.ui_icon, children=children))
+        return dict(menu=menu)
 
     @expose()
     def _lookup(self, name, *remainder):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index 350f353..73894e3 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -18,6 +18,7 @@
 import logging
 from collections import Counter, OrderedDict
 from datetime import datetime
+from copy import deepcopy
 
 from tg import config
 from pylons import tmpl_context as c, app_globals as g
@@ -493,6 +494,7 @@ class Project(MappedClass, ActivityNode, ActivityObject):
             else:
                 # tool of a type we don't have in the navbar yet
                 if tool_name not in grouped_nav:
+                    child = deepcopy(e)
                     # change label to be the tool name (type)
                     e.label = tool_name.capitalize()
                     # add tool url to list of urls that will match this nav entry
@@ -500,10 +502,17 @@ class Project(MappedClass, ActivityNode, ActivityObject):
                     e.matching_urls.append(e.url)
                     # change url to point to tool list page
                     e.url = self.url() + '_list/' + tool_name
+                    e.children.append(child)
                     grouped_nav[tool_name] = e
                 else:
                     # add tool url to list of urls that will match this nav entry
                     grouped_nav[tool_name].matching_urls.append(e.url)
+                    if len(grouped_nav[tool_name].children) < 10:
+                        grouped_nav[tool_name].children.append(e)
+                    elif len(grouped_nav[tool_name].children) == 10:
+                        e.url = self.url() + '_list/' + tool_name
+                        e.label = '...more...'
+                        grouped_nav[tool_name].children.append(e)
         return grouped_nav.values()
 
     def parent_iter(self):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/nf/allura/css/site_style.css
----------------------------------------------------------------------
diff --git a/Allura/allura/nf/allura/css/site_style.css b/Allura/allura/nf/allura/css/site_style.css
index df703d9..98938e8 100644
--- a/Allura/allura/nf/allura/css/site_style.css
+++ b/Allura/allura/nf/allura/css/site_style.css
@@ -370,25 +370,6 @@ td, td img {
   vertical-align: middle;
 }
 
-.diamond {
-  z-index: 1;
-  height: 20px;
-  width: 20px;
-  display: block;
-  position: absolute;
-  bottom: -20px;
-  left: 50%;
-  margin-left: -10px;
-  overflow: hidden;
-  background: #e5e5e5;
-  border-left: 1px solid #aaaaaa;
-  border-top: 1px solid #aaaaaa;
-  -moz-transform: rotate(45deg);
-  -webkit-transform: rotate(45deg);
-  -o-transform: rotate(45deg);
-  transform: rotate(45deg);
-}
-
 .tool-count {
   display: block;
   position: absolute;
@@ -1013,6 +994,7 @@ a.btn:active {
   text-align: center;
   position: relative;
   margin: 0 0 20px;
+  height: 50px;
 }
 .btn-bar.pop, .pop#top_nav {
   height: 150px;
@@ -2905,3 +2887,61 @@ table thead tr th.narrow, table tr td.narrow {
   bottom: -5px;
   left: 45%;
 }
+ul.dropdown,
+ul.dropdown li,
+ul.dropdown ul {
+    list-style: none;
+    margin: 0;
+    padding: 0;
+}
+
+ul.dropdown {
+    position: relative;
+    z-index: 597;
+    float: left;
+}
+
+ul.dropdown li {
+    float: left;
+    vertical-align: middle;
+    zoom: 1;
+}
+
+ul.dropdown li.hover,
+ul.dropdown li:hover {
+    position: relative;
+    z-index: 599;
+    cursor: default;
+}
+
+ul.dropdown ul {
+    visibility: hidden;
+    position: absolute;
+    top:50px;
+    left: 0;
+    z-index: 598;
+    background-color: #ffffff;
+    -moz-border-radius: 5px;
+    -webkit-border-radius: 5px;
+    border-radius: 5px;
+    border-width: 1px;
+    border-style: solid;
+    border-color: #E6EFC2;
+}
+
+ul.dropdown ul li {
+    float: left;
+    margin: 5px;
+    min-width: 100px;
+}
+
+ul.dropdown li:hover > ul {
+    visibility: visible;
+}
+ul.dropdown ul li a {
+    height: 20px !important;
+    font-weight:normal;
+}
+li.selected {
+    font-weight:bold;
+}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/templates/award.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/award.html b/Allura/allura/templates/award.html
index 3cb2b72..503714f 100644
--- a/Allura/allura/templates/award.html
+++ b/Allura/allura/templates/award.html
@@ -27,7 +27,7 @@
 {% endblock %}
 
 {% block top_nav %}
-{% include 'allura:templates/jinja_master/neigh_top_nav.html' %}
+{% include 'allura:templates/jinja_master/top_nav.html' %}
 {% endblock %}
 
 {% block content %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/templates/jinja_master/neigh_top_nav.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/neigh_top_nav.html b/Allura/allura/templates/jinja_master/neigh_top_nav.html
deleted file mode 100644
index 39b37b9..0000000
--- a/Allura/allura/templates/jinja_master/neigh_top_nav.html
+++ /dev/null
@@ -1,40 +0,0 @@
-{#-
-       Licensed to the Apache Software Foundation (ASF) under one
-       or more contributor license agreements.  See the NOTICE file
-       distributed with this work for additional information
-       regarding copyright ownership.  The ASF licenses this file
-       to you under the Apache License, Version 2.0 (the
-       "License"); you may not use this file except in compliance
-       with the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing,
-       software distributed under the License is distributed on an
-       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-       KIND, either express or implied.  See the License for the
-       specific language governing permissions and limitations
-       under the License.
--#}
-{% if neighborhood and neighborhood.neighborhood_project %}
-  {% for s in neighborhood.neighborhood_project.sitemap() %}
-    <a href="{{s.url}}" class="ui-icon-{{s.ui_icon or 'admin'}}">
-      {{s.label}}
-      {% if s.label == 'Home' %}
-        {% set url_length = s.url|length %}
-        {% if request.url.rfind(s.url, -url_length) != -1 %}
-          <span class="diamond"></span>
-        {% endif %}
-      {% elif s.label == 'Admin' %}
-        {% if s.url in request.url or c.project.neighborhood.url()+'_admin' in request.url %}
-          <span class="diamond"></span>
-        {% endif %}
-      {% else %}
-        {% if s.url in request.url %}
-          <span class="diamond"></span>
-        {% endif %}
-      {% endif %}
-    </a>
-        {% endfor %}
-        <div style="clear:both"></div>
-{% endif %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/templates/jinja_master/top_nav.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/top_nav.html b/Allura/allura/templates/jinja_master/top_nav.html
index 1b17d11..aeec126 100644
--- a/Allura/allura/templates/jinja_master/top_nav.html
+++ b/Allura/allura/templates/jinja_master/top_nav.html
@@ -17,7 +17,7 @@
        under the License.
 -#}
 {% if c.project %}
-  <div><ul>
+<ul class="dropdown">
   {% for s in c.project.grouped_navbar_entries() %}
     {% set selected = False %}
     {% if s.label == 'Home' %}
@@ -30,17 +30,19 @@
         {% set selected = True %}
       {% endif %}
     {% endif %}
-    <li class="ui-icon-{{s.ui_icon or 'admin'}}{% if selected %} selected{% endif %}">
-      <a href="{{s.url}}">
-        <span>
-        {{s.label}}
+    <li class="{% if selected %}selected{% endif %}">
+        <a href="{{s.url}}" class="ui-icon-{{s.ui_icon or 'admin'}}">
+            {{s.label}}
+        </a>
         {% set grouped_tool_count = s.matching_urls|length %}
         {% if grouped_tool_count %}
-          <span class="tool-count">{{grouped_tool_count}}</span>
+          <ul>
+              {%for tool in s.children%}
+                <li><span><a href="{{tool.url}}">{{tool.label}}</a></span></li>
+              {%endfor%}
+          </ul>
         {% endif %}
-        </span>
-      </a>
     </li>
 	{% endfor %}
-	</div></ul>
+</ul>
 {% endif %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/templates/neighborhood_admin_accolades.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/neighborhood_admin_accolades.html b/Allura/allura/templates/neighborhood_admin_accolades.html
index 63264bc..2f6d82f 100644
--- a/Allura/allura/templates/neighborhood_admin_accolades.html
+++ b/Allura/allura/templates/neighborhood_admin_accolades.html
@@ -27,7 +27,7 @@
 {% endblock %}
 
 {% block top_nav %}
-{% include 'allura:templates/jinja_master/neigh_top_nav.html' %}
+{% include 'allura:templates/jinja_master/top_nav.html' %}
 {% endblock %}
 
 {% block content %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/templates/neighborhood_admin_overview.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/neighborhood_admin_overview.html b/Allura/allura/templates/neighborhood_admin_overview.html
index 07489e9..8944b22 100644
--- a/Allura/allura/templates/neighborhood_admin_overview.html
+++ b/Allura/allura/templates/neighborhood_admin_overview.html
@@ -27,7 +27,7 @@
 {% endblock %}
 
 {% block top_nav %}
-{% include 'allura:templates/jinja_master/neigh_top_nav.html' %}
+{% include 'allura:templates/jinja_master/top_nav.html' %}
 {% endblock %}
 
 {% block content %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/templates/neighborhood_help.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/neighborhood_help.html b/Allura/allura/templates/neighborhood_help.html
index 6ad8163..ed57b53 100644
--- a/Allura/allura/templates/neighborhood_help.html
+++ b/Allura/allura/templates/neighborhood_help.html
@@ -27,7 +27,7 @@
 {% endblock %}
 
 {% block top_nav %}
-    {% include 'allura:templates/jinja_master/neigh_top_nav.html' %}
+    {% include 'allura:templates/jinja_master/top_nav.html' %}
 {% endblock %}
 
 {% block content %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/templates/neighborhood_moderate.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/neighborhood_moderate.html b/Allura/allura/templates/neighborhood_moderate.html
index 7beea44..5fe5c3f 100644
--- a/Allura/allura/templates/neighborhood_moderate.html
+++ b/Allura/allura/templates/neighborhood_moderate.html
@@ -28,7 +28,7 @@
 {% endblock %}
 
 {% block top_nav %}
-{% include 'allura:templates/jinja_master/neigh_top_nav.html' %}
+{% include 'allura:templates/jinja_master/top_nav.html' %}
 {% endblock %}
 
 {% block content %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/templates/neighborhood_project_list.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/neighborhood_project_list.html b/Allura/allura/templates/neighborhood_project_list.html
index 1f2939e..b747af0 100644
--- a/Allura/allura/templates/neighborhood_project_list.html
+++ b/Allura/allura/templates/neighborhood_project_list.html
@@ -42,7 +42,7 @@
 {% endblock %}
 
 {% block top_nav %}
-{% include 'allura:templates/jinja_master/neigh_top_nav.html' %}
+{% include 'allura:templates/jinja_master/top_nav.html' %}
 {% endblock %}
 
 {% block inner_grid %}{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/templates/neighborhood_stats.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/neighborhood_stats.html b/Allura/allura/templates/neighborhood_stats.html
index fa0e68f..3b0b0ee 100644
--- a/Allura/allura/templates/neighborhood_stats.html
+++ b/Allura/allura/templates/neighborhood_stats.html
@@ -19,7 +19,7 @@
 {% extends g.theme.master %}
 
 {% block top_nav %}
-    {% include 'allura:templates/jinja_master/neigh_top_nav.html' %}
+    {% include 'allura:templates/jinja_master/top_nav.html' %}
 {% endblock %}
 
 {% block title %}Neighborhood Statistics{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/templates/neighborhood_stats_adminlist.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/neighborhood_stats_adminlist.html b/Allura/allura/templates/neighborhood_stats_adminlist.html
index 4e3afe0..4deafe1 100644
--- a/Allura/allura/templates/neighborhood_stats_adminlist.html
+++ b/Allura/allura/templates/neighborhood_stats_adminlist.html
@@ -23,7 +23,7 @@
 {% block header %}Admins list{% endblock %}
 
 {% block top_nav %}
-    {% include 'allura:templates/jinja_master/neigh_top_nav.html' %}
+    {% include 'allura:templates/jinja_master/top_nav.html' %}
 {% endblock %}
 
 {% block content %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/tests/functional/test_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_admin.py b/Allura/allura/tests/functional/test_admin.py
index ac63ffe..1752707 100644
--- a/Allura/allura/tests/functional/test_admin.py
+++ b/Allura/allura/tests/functional/test_admin.py
@@ -105,9 +105,9 @@ class TestProjectAdmin(TestController):
         assert 'error' not in self.webflash(r)
         # check tool in the nav
         r = self.app.get('/p/test/test-tool/').follow()
-        active_link = r.html.findAll('span',{'class':'diamond'})
-        assert len(active_link) == 1
-        assert active_link[0].parent['href'] == '/p/test/test-tool/'
+        active_link = r.html.findAll('li',{'class':'selected'})
+        assert_equals(len(active_link), 1)
+        assert active_link[0].contents[1]['href'] == '/p/test/test-tool/'
         with audits('install tool test-tool2'):
             r = self.app.post('/admin/update_mounts', params={
                     'new.install':'install',
@@ -118,13 +118,12 @@ class TestProjectAdmin(TestController):
         assert 'error' not in self.webflash(r)
         # check the nav - tools of same type are grouped
         r = self.app.get('/p/test/test-tool/Home/')
-        active_link = r.html.findAll('span', {'class':'diamond'})
+        active_link = r.html.findAll('li',{'class':'selected'})
         assert len(active_link) == 1
-        assert active_link[0].parent['href'] == '/p/test/_list/wiki'
-        # check tool-count of grouped tools
-        tool_count = active_link[0].findNextSibling('span')
-        assert tool_count['class'] == u'tool-count', tool_count['class']
-        assert tool_count.text == u'2', tool_count.text
+        assert active_link[0].contents[1]['href'] == '/p/test/_list/wiki'
+        assert r.html.findAll('a', {'href':'/p/test/test-tool2/'})
+        assert r.html.findAll('a', {'href':'/p/test/test-tool/'})
+
         # check can't create dup tool
         r = self.app.post('/admin/update_mounts', params={
                 'new.install':'install',

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/tests/functional/test_home.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_home.py b/Allura/allura/tests/functional/test_home.py
index 88b2c0d..4904394 100644
--- a/Allura/allura/tests/functional/test_home.py
+++ b/Allura/allura/tests/functional/test_home.py
@@ -18,6 +18,8 @@
 import json
 import re
 
+from pylons import tmpl_context as c
+
 from allura.tests import TestController
 from allura.tests import decorators as td
 from allura import model as M
@@ -38,6 +40,34 @@ class TestProjectHome(TestController):
             assert nl['href'] == entry['url']
 
     @td.with_wiki
+    def test_project_group_nav(self):
+        c.user = M.User.by_username('test-admin')
+        p = M.Project.query.get(shortname='test')
+        c.project = p
+        if 'wiki2' and not p.app_instance('wiki2'):
+            c.app = p.install_app('wiki', 'wiki2', 'wiki2', 9)
+
+        response = self.app.get('/p/test/_nav.json')
+        menu = response.json['menu']
+        assert_equal(len(menu[1]['children']), 2)
+        assert {u'url': u'/p/test/wiki/', u'name': u'Wiki', u'icon': u'tool-wiki'} in menu[1]['children'], menu[1]['children']
+        assert {u'url': u'/p/test/wiki2/', u'name': u'wiki2', u'icon': u'tool-wiki'} in menu[1]['children'], menu[1]['children']
+
+    @td.with_wiki
+    def test_project_group_nav_more_than_ten(self):
+        for i in range(1,15):
+            tool_name = "wiki%s" % str(i)
+            c.user = M.User.by_username('test-admin')
+            p = M.Project.query.get(shortname='test')
+            c.project = p
+            if tool_name and not p.app_instance(tool_name):
+                c.app = p.install_app('wiki', tool_name, tool_name, i)
+        response = self.app.get('/p/test/_nav.json')
+        menu = response.json['menu']
+        assert_equal(len(menu[1]['children']), 11)
+        assert {u'url': u'/p/test/_list/wiki', u'name': u'...more...', u'icon': u'tool-wiki'} in menu[1]['children']
+
+    @td.with_wiki
     def test_neighborhood_home(self):
         self.app.get('/p/test/wiki/', status=302)
         self.app.get('/adobe/test/wiki/', status=404)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a028f972/Allura/allura/tests/functional/test_neighborhood.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_neighborhood.py b/Allura/allura/tests/functional/test_neighborhood.py
index f91b5cb..a641f74 100644
--- a/Allura/allura/tests/functional/test_neighborhood.py
+++ b/Allura/allura/tests/functional/test_neighborhood.py
@@ -638,14 +638,14 @@ class TestNeighborhood(TestController):
         p = M.Project.query.get(shortname='testtemp')
         # make sure the correct tools got installed in the right order
         top_nav = r.html.find('div', {'id':'top_nav'})
-        assert top_nav.contents[1]['href'] == '/adobe/testtemp/wiki/'
-        assert 'Wiki' in top_nav.contents[1].contents[0]
-        assert top_nav.contents[3]['href'] == '/adobe/testtemp/discussion/'
-        assert 'Discussion' in top_nav.contents[3].contents[0]
-        assert top_nav.contents[5]['href'] == '/adobe/testtemp/news/'
-        assert 'News' in top_nav.contents[5].contents[0]
-        assert top_nav.contents[7]['href'] == '/adobe/testtemp/admin/'
-        assert 'Admin' in top_nav.contents[7].contents[0]
+        assert top_nav.contents[1].contents[1].contents[1]['href'] == '/adobe/testtemp/wiki/'
+        assert 'Wiki' in top_nav.contents[1].contents[1].contents[1].contents[0]
+        assert top_nav.contents[1].contents[3].contents[1]['href'] == '/adobe/testtemp/discussion/'
+        assert 'Discussion' in top_nav.contents[1].contents[3].contents[1].contents[0]
+        assert top_nav.contents[1].contents[5].contents[1]['href'] == '/adobe/testtemp/news/'
+        assert 'News' in top_nav.contents[1].contents[5].contents[1].contents[0]
+        assert top_nav.contents[1].contents[7].contents[1]['href'] == '/adobe/testtemp/admin/'
+        assert 'Admin' in top_nav.contents[1].contents[7].contents[1].contents[0]
         # make sure project is private
         r = self.app.get(
             '/adobe/testtemp/wiki/',


[42/50] git commit: [#6159] Changes default ticket permissions to allow Authenticated CREATE

Posted by tv...@apache.org.
[#6159] Changes default ticket permissions to allow Authenticated CREATE


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/fae74792
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/fae74792
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/fae74792

Branch: refs/heads/tv/docs
Commit: fae74792795f9877821c26e33b46e52e195f072f
Parents: eca53d7
Author: Chris Tsai <ct...@users.sf.net>
Authored: Thu Apr 25 20:59:18 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon May 6 15:15:31 2013 +0000

----------------------------------------------------------------------
 .../forgetracker/tests/test_tracker_roles.py       |    2 +-
 .../forgetracker/tests/unit/test_ticket_model.py   |    5 +++--
 ForgeTracker/forgetracker/tracker_main.py          |    2 +-
 3 files changed, 5 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/fae74792/ForgeTracker/forgetracker/tests/test_tracker_roles.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/test_tracker_roles.py b/ForgeTracker/forgetracker/tests/test_tracker_roles.py
index c5f0d14..791268d 100644
--- a/ForgeTracker/forgetracker/tests/test_tracker_roles.py
+++ b/ForgeTracker/forgetracker/tests/test_tracker_roles.py
@@ -41,7 +41,7 @@ def test_role_assignments():
     assert check_access('configure') == (True, False, False)
     assert check_access('read') == (True, True, True)
     assert check_access('update') == (True, False, False)
-    assert check_access('create') == (True, False, False)
+    assert check_access('create') == (True, True, False)
     assert check_access('unmoderated_post') == (True, True, False)
     assert check_access('post') == (True, True, False)
     assert check_access('moderate') == (True, False, False)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/fae74792/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py b/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
index 84d5a6e..9cca6df 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
@@ -109,6 +109,7 @@ class TestTicketModel(TrackerTestWithModel):
                         ACE.allow(role_developer, 'delete'),
                         ACE.allow(role_creator, 'read'),
                         ACE.allow(role_creator, 'post'),
+                        ACE.allow(role_creator, 'create'),
                         ACE.allow(role_creator, 'unmoderated_post'),
                         DENY_ALL])
         assert has_access(t, 'read', user=admin)()
@@ -117,7 +118,7 @@ class TestTicketModel(TrackerTestWithModel):
         assert has_access(t, 'read', user=creator)()
         assert has_access(t, 'post', user=creator)()
         assert has_access(t, 'unmoderated_post', user=creator)()
-        assert not has_access(t, 'create', user=creator)()
+        assert has_access(t, 'create', user=creator)()
         assert not has_access(t, 'update', user=creator)()
         assert has_access(t, 'read', user=developer)()
         assert has_access(t, 'create', user=developer)()
@@ -139,7 +140,7 @@ class TestTicketModel(TrackerTestWithModel):
         assert has_access(t, 'update', user=developer)()
         assert has_access(t, 'read', user=creator)()
         assert has_access(t, 'unmoderated_post', user=creator)()
-        assert not has_access(t, 'create', user=creator)()
+        assert has_access(t, 'create', user=creator)()
         assert not has_access(t, 'update', user=creator)()
         assert has_access(t, 'read', user=observer)()
         assert has_access(t, 'read', user=anon)()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/fae74792/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 0f266aa..3f64528 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -333,8 +333,8 @@ class ForgeTrackerApp(Application):
             M.ACE.allow(role_anon, 'read'),
             M.ACE.allow(role_auth, 'post'),
             M.ACE.allow(role_auth, 'unmoderated_post'),
+            M.ACE.allow(role_auth, 'create'),
             M.ACE.allow(role_developer, 'update'),
-            M.ACE.allow(role_developer, 'create'),
             M.ACE.allow(role_developer, 'moderate'),
             M.ACE.allow(role_developer, 'save_searches'),
             M.ACE.allow(role_developer, 'delete'),


[34/50] git commit: [#5773] ticket:314 fixed filesize errors

Posted by tv...@apache.org.
[#5773] ticket:314 fixed filesize errors


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/94b70cea
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/94b70cea
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/94b70cea

Branch: refs/heads/tv/docs
Commit: 94b70cea70a115851b40446780efc17fc96222be
Parents: e14b56e
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Fri Apr 19 17:11:58 2013 +0400
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu May 2 20:37:04 2013 +0000

----------------------------------------------------------------------
 Allura/allura/templates/widgets/repo/log.html      |   24 +++++---------
 .../forgegit/tests/functional/test_controllers.py  |    8 ++--
 2 files changed, 13 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/94b70cea/Allura/allura/templates/widgets/repo/log.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/repo/log.html b/Allura/allura/templates/widgets/repo/log.html
index 11fa918..086b0b3 100644
--- a/Allura/allura/templates/widgets/repo/log.html
+++ b/Allura/allura/templates/widgets/repo/log.html
@@ -34,12 +34,10 @@
         <tr class="rev">
           <td>
             <div class="grid-14">
+                {{g.markdown.convert(commit.message)}}
                 {%if is_file%}
-                <div class="grid-1"><input type="checkbox" class="revision" revision="{{commit._id.split(':')[-1]}}" url_commit="{{commit.url()}}"></div>
+                    <div class="grid-1"><input type="checkbox" class="revision" revision="{{commit._id.split(':')[-1]}}" url_commit="{{commit.url()}}"></div>
                 {%endif%}
-                {%for tag in c.app.repo.symbolics_for_commit(commit)[1]%}
-                        <a href="{{c.app.repo.url()}}ci/{{tag}}/tree{{request.params.get('path')}}">{{tag}}</a>
-                {%endfor%}
                 {% if commit.committed.email != commit.authored.email %}
                 {% if commit.committer_url %}
                 <a href="{{commit.committer_url}}">{{email_gravatar(commit.committed.email, title=commit.committed.name, size=16)}}
@@ -51,21 +49,17 @@
                 {% endif %}
                 {% endif %}
                 <a href="{{commit.url()}}">{{commit.shorthand_id()}}</a>
+                {% if c.app.repo.symbolics_for_commit(commit)[1] %}
+                    ({% for tag in c.app.repo.symbolics_for_commit(commit)[1] -%}
+                        <a href="{{c.app.repo.url()}}ci/{{tag}}/tree{{request.params.get('path')}}">{{tag}}</a>{% if not loop.last %}&nbsp;{% endif %}
+                    {%- endfor %})
+                {% endif %}
                 by
                 {{email_gravatar(commit.authored.email, title=commit.authored.name, size=16)}} {{commit.authored.name}}
                 {%if is_file%}
-                    {%if request.params.get('path')[:1]=='/'%}
-                        {%set path = request.params.get('path')[1:]%}
-                    {%else%}
-                        {%set path = request.params.get('path')%}
-                    {%endif%}
-
-                    {{commit.tree.get_blob(path).size}} Bytes
+                    ({{commit.tree.get_obj_by_path(request.params.get('path')).size|filesizeformat}})
                 {%endif%}
             </div>
-            <div>
-              {{g.markdown.convert(commit.message)}}
-            </div>
           </td>
           <td style="vertical-align: text-top">
             {% if commit.committed.date %}{{commit.committed.date}}{% endif %}
@@ -80,7 +74,7 @@
             </a>
               {%if is_file%}
               <br/>
-              <a href="{{commit.url()}}tree{{request.params.get('path')}}?format=raw ">Download</a>
+              <a href="{{commit.url()}}tree{{request.params.get('path')}}?format=raw">Download</a>
               {%endif%}
           </td>
         </tr>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/94b70cea/ForgeGit/forgegit/tests/functional/test_controllers.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/tests/functional/test_controllers.py b/ForgeGit/forgegit/tests/functional/test_controllers.py
index 78ff5a9..d5c8365 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -111,14 +111,14 @@ class TestRootController(_TestCase):
         resp = self.app.get('/src-git/ci/1e146e67985dcd71c74de79613719bef7bddca4a/log/')
         assert 'Initial commit' in resp
         assert '<div class="markdown_content"><p>Change README</p></div>' in resp
-        assert 'tree/README?format=raw ">Download</a>' not in resp
-        assert'28 Bytes' not in resp.html.find('td').contents[1].text
+        assert 'tree/README?format=raw">Download</a>' not in resp
+        assert '28 Bytes' not in resp.html.find('td').contents[1].text
         assert 'Tree' in resp.html.findAll('td')[2].text, resp.html.findAll('td')[2].text
         resp = self.app.get('/src-git/ci/1e146e67985dcd71c74de79613719bef7bddca4a/log/?path=/README')
-        assert'28 Bytes' in resp.html.find('td').contents[1].text
+        assert '28 Bytes' in resp.html.find('td').contents[1].text
         assert 'View' in resp.html.findAll('td')[2].text
         assert 'Change README' in resp
-        assert 'tree/README?format=raw ">Download</a>' in resp
+        assert 'tree/README?format=raw">Download</a>' in resp
         assert 'Add README' in resp
         assert "Initial commit " not in resp
         resp = self.app.get('/src-git/ci/1e146e67985dcd71c74de79613719bef7bddca4a/log/?path=/a/b/c/')


[21/50] git commit: [#5913] Updated to use new nav style

Posted by tv...@apache.org.
[#5913] Updated to use new nav style


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/833aa4a9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/833aa4a9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/833aa4a9

Branch: refs/heads/tv/docs
Commit: 833aa4a9823103697228eca014c5d7213ef0571a
Parents: 404b152
Author: Jenny Steele <js...@geek.net>
Authored: Tue Mar 19 19:01:48 2013 -0700
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Wed May 1 20:38:36 2013 +0000

----------------------------------------------------------------------
 Allura/allura/templates/jinja_master/master.html  |    2 +-
 Allura/allura/templates/jinja_master/top_nav.html |   36 +++++++++-------
 2 files changed, 21 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/833aa4a9/Allura/allura/templates/jinja_master/master.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/master.html b/Allura/allura/templates/jinja_master/master.html
index 11482a7..00052c1 100644
--- a/Allura/allura/templates/jinja_master/master.html
+++ b/Allura/allura/templates/jinja_master/master.html
@@ -82,7 +82,7 @@
             {% include g.theme.nav_menu %}
             {% endblock %}
       </div>
-      <div id="top_nav" class="">
+      <div id="main_nav" class="">
         {% block top_nav %}
         {% include g.theme.top_nav %}
         {% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/833aa4a9/Allura/allura/templates/jinja_master/top_nav.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/top_nav.html b/Allura/allura/templates/jinja_master/top_nav.html
index 1e4f54a..7304f4c 100644
--- a/Allura/allura/templates/jinja_master/top_nav.html
+++ b/Allura/allura/templates/jinja_master/top_nav.html
@@ -17,24 +17,28 @@
        under the License.
 -#}
 {% if c.project %}
+  <div><ul>
   {% for s in c.project.grouped_navbar_entries() %}
-    <a href="{{s.url}}" class="ui-icon-{{s.ui_icon or 'admin'}}">
-      {{s.label}}
-      {% if s.label == 'Home' %}
-        {% set url_length = s.url|length %}
-        {% if request.url.rfind(s.url, -url_length) != -1 %}
-          <span class="diamond"></span>
-        {% endif %}
-      {% else %}
-        {% if s.matches_url(request) or c.project.neighborhood.url()+'_admin' in request.upath_info %}
-          <span class="diamond"></span>
-        {% endif %}
+    {% set selected = False %}
+    {% if s.label == 'Home' %}
+      {% set url_length = s.url|length %}
+      {% if request.url.rfind(s.url, -url_length) != -1 %}
+        {% set selected = True %}
       {% endif %}
-      {% set grouped_tool_count = s.matching_urls|length %}
-      {% if grouped_tool_count %}
-        <span class="tool-count">{{grouped_tool_count}}</span>
+    {% else %}
+      {% if s.matches_url(request) or c.project.neighborhood.url()+'_admin' in request.upath_info %}
+        {% set selected = True %}
       {% endif %}
-    </a>
+    {% endif %}
+    <li{% if selected %} class="selected"{% endif %}>
+      <a href="{{s.url}}">
+        {{s.label}}
+        {% set grouped_tool_count = s.matching_urls|length %}
+        {% if grouped_tool_count %}
+          <span class="tool-count">{{grouped_tool_count}}</span>
+        {% endif %}
+      </a>
+    </li>
 	{% endfor %}
-	<div style="clear:both"></div>
+	</div></ul>
 {% endif %}


[16/50] git commit: [#6179] Fix openid user creation

Posted by tv...@apache.org.
[#6179] Fix openid user creation

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/50f9a49f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/50f9a49f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/50f9a49f

Branch: refs/heads/tv/docs
Commit: 50f9a49f435f26a0eb32a9ec997683a7eb24a9e0
Parents: 3d3f199
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Tue Apr 30 19:25:37 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Tue Apr 30 19:25:37 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/50f9a49f/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index a792bb9..4dc83e7 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -188,7 +188,7 @@ class AuthController(BaseController):
         c.user.set_pref('display_name', display_name)
         if u is None:
             n = M.Neighborhood.query.get(name='Users')
-            n.register_project('u/' + username)
+            n.register_project('u/' + username, user_project=True)
         flash('Your username has been set to %s.' % username)
         redirect('/')
 


[18/50] git commit: [#6172] Refactor feed functionality into mixin controller

Posted by tv...@apache.org.
[#6172] Refactor feed functionality into mixin controller

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/391aa922
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/391aa922
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/391aa922

Branch: refs/heads/tv/docs
Commit: 391aa92294b69a228cee4b857c65e0d780ee0a36
Parents: 7244932
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Tue Apr 30 17:44:37 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Apr 30 19:45:59 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/basetest_project_root.py |    2 -
 Allura/allura/controllers/discuss.py               |   75 ++++-------
 Allura/allura/controllers/feed.py                  |  108 +++++++++++++++
 Allura/allura/controllers/project.py               |   39 ++----
 Allura/allura/controllers/repository.py            |   31 +----
 Allura/allura/ext/user_profile/user_main.py        |   55 ++------
 ForgeBlog/forgeblog/main.py                        |   62 ++-------
 .../forgediscussion/controllers/root.py            |   44 ++----
 ForgeSVN/forgesvn/controllers.py                   |    3 +-
 ForgeSVN/forgesvn/svn_main.py                      |    3 -
 ForgeTracker/forgetracker/tracker_main.py          |   64 ++-------
 ForgeWiki/forgewiki/wiki_main.py                   |   67 ++-------
 12 files changed, 219 insertions(+), 334 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/Allura/allura/controllers/basetest_project_root.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/basetest_project_root.py b/Allura/allura/controllers/basetest_project_root.py
index f9ec3d5..8c48ed6 100644
--- a/Allura/allura/controllers/basetest_project_root.py
+++ b/Allura/allura/controllers/basetest_project_root.py
@@ -66,8 +66,6 @@ class BasetestProjectRootController(WsgiDispatchController, ProjectController):
     '''
 
     def __init__(self):
-        setattr(self, 'feed.rss', self.feed)
-        setattr(self, 'feed.atom', self.feed)
         for n in M.Neighborhood.query.find():
             if n.url_prefix.startswith('//'): continue
             n.bind_controller(self)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/Allura/allura/controllers/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index 5abb3a2..b37d880 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -38,6 +38,7 @@ from allura.lib.helpers import DateTimeConverter
 
 from allura.lib.widgets import discuss as DW
 from .attachments import AttachmentsController, AttachmentController
+from .feed import Feed, FeedController
 
 log = logging.getLogger(__name__)
 
@@ -68,13 +69,11 @@ class WidgetConfig(object):
     thread_header = DW.ThreadHeader()
 
 # Controllers
-class DiscussionController(BaseController):
+class DiscussionController(BaseController, FeedController):
     M=ModelConfig
     W=WidgetConfig
 
     def __init__(self):
-        setattr(self, 'feed.rss', self.feed)
-        setattr(self, 'feed.atom', self.feed)
         if not hasattr(self, 'ThreadController'):
             self.ThreadController = ThreadController
         if not hasattr(self, 'PostController'):
@@ -106,29 +105,18 @@ class DiscussionController(BaseController):
             M.session.artifact_orm_session._get().skip_mod_date = True
         redirect(request.referer)
 
-    @without_trailing_slash
-    @expose()
-    @validate(dict(
-            since=DateTimeConverter(if_empty=None),
-            until=DateTimeConverter(if_empty=None),
-            page=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, page=None, limit=None, **kw):
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
-        title = 'Recent posts to %s' % self.discussion.name
-        feed = M.Feed.feed(
+    def get_feed(self, project, app, user):
+        """Return a :class:`allura.controllers.feed.Feed` object describing
+        the xml feed for this controller.
+
+        Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
+
+        """
+        return Feed(
             dict(ref_id={'$in': [t.index_id() for t in self.discussion.threads]}),
-            feed_type,
-            title,
-            self.discussion.url(),
-            title,
-            since, until, page, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
+            'Recent posts to %s' % self.discussion.name,
+            self.discussion.url())
+
 
 class AppDiscussionController(DiscussionController):
 
@@ -156,7 +144,7 @@ class ThreadsController(BaseController):
         else:
             raise exc.HTTPNotFound()
 
-class ThreadController(BaseController):
+class ThreadController(BaseController, FeedController):
     __metaclass__=h.ProxiedAttrMeta
     M=h.attrproxy('_discussion_controller', 'M')
     W=h.attrproxy('_discussion_controller', 'W')
@@ -170,8 +158,6 @@ class ThreadController(BaseController):
             require_access(self.thread.ref.artifact, 'read')
 
     def __init__(self, discussion_controller, thread_id):
-        setattr(self, 'feed.rss', self.feed)
-        setattr(self, 'feed.atom', self.feed)
         self._discussion_controller = discussion_controller
         self.discussion = discussion_controller.discussion
         self.thread = self.M.Thread.query.get(_id=thread_id)
@@ -237,29 +223,18 @@ class ThreadController(BaseController):
         flash('Thread flagged as spam.')
         redirect(self.discussion.url())
 
-    @without_trailing_slash
-    @expose()
-    @validate(dict(
-            since=DateTimeConverter(if_empty=None),
-            until=DateTimeConverter(if_empty=None),
-            page=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, page=None, limit=None, **kw):
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
-        title = 'Recent posts to %s' % (self.thread.subject or '(no subject)')
-        feed = M.Feed.feed(
+    def get_feed(self, project, app, user):
+        """Return a :class:`allura.controllers.feed.Feed` object describing
+        the xml feed for this controller.
+
+        Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
+
+        """
+        return Feed(
             dict(ref_id=self.thread.index_id()),
-            feed_type,
-            title,
-            self.thread.url(),
-            title,
-            since, until, page, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
+            'Recent posts to %s' % (self.thread.subject or '(no subject)'),
+            self.thread.url())
+
 
 class PostController(BaseController):
     __metaclass__=h.ProxiedAttrMeta

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/Allura/allura/controllers/feed.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/feed.py b/Allura/allura/controllers/feed.py
new file mode 100644
index 0000000..f014b21
--- /dev/null
+++ b/Allura/allura/controllers/feed.py
@@ -0,0 +1,108 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+from tg import expose, validate, request, response
+from tg.decorators import without_trailing_slash
+from formencode import validators as V
+from pylons import tmpl_context as c
+from webob import exc
+
+from allura import model as M
+from allura.lib import helpers as h
+
+
+class Feed(object):
+    """A facade for the arguments required by
+    :meth:`allura.model.artifact.Feed.feed`.
+
+    Used by :meth:`FeedController.feed` to create a real feed.
+
+    """
+    def __init__(self, query, title, url, description=None):
+        self.query = query
+        self.title = title
+        self.url = url
+        self.description = description or title
+
+
+class FeedController(object):
+    """Mixin class which adds RSS and Atom feed endpoints to an existing
+    controller.
+
+    Feeds will be accessible at the following URLs:
+
+        http://host/path/to/controller/feed -> RSS
+        http://host/path/to/controller/feed.rss -> RSS
+        http://host/path/to/controller/feed.atom -> Atom
+
+    A default feed is provided by :meth:`get_feed`. Subclasses that need
+    a customized feed should override :meth:`get_feed`.
+
+    """
+    FEED_TYPES = ['.atom', '.rss']
+    FEED_NAMES = ['feed{0}'.format(typ) for typ in FEED_TYPES]
+
+    def __getattr__(self, name):
+        if name in self.FEED_NAMES:
+            return self.feed
+        raise AttributeError(name)
+
+    def _get_feed_type(self, request):
+        for typ in self.FEED_TYPES:
+            if request.environ['PATH_INFO'].endswith(typ):
+                return typ.lstrip('.')
+        return 'rss'
+
+    @without_trailing_slash
+    @expose()
+    @validate(dict(
+            since=h.DateTimeConverter(if_empty=None, if_invalid=None),
+            until=h.DateTimeConverter(if_empty=None, if_invalid=None),
+            page=V.Int(if_empty=None),
+            limit=V.Int(if_empty=None)))
+    def feed(self, since=None, until=None, page=None, limit=None, **kw):
+        """Return a utf8-encoded XML feed (RSS or Atom) to the browser.
+        """
+        feed_def = self.get_feed(c.project, c.app, c.user)
+        if not feed_def:
+            raise exc.HTTPNotFound
+        feed = M.Feed.feed(
+            feed_def.query,
+            self._get_feed_type(request),
+            feed_def.title,
+            feed_def.url,
+            feed_def.description,
+            since, until, page, limit)
+        response.headers['Content-Type'] = ''
+        response.content_type = 'application/xml'
+        return feed.writeString('utf-8')
+
+    def get_feed(self, project, app, user):
+        """Return a default :class:`Feed` for this controller.
+
+        Subclasses should override to customize the feed.
+
+        :param project: :class:`allura.model.project.Project`
+        :param app: :class:`allura.app.Application`
+        :param user: :class:`allura.model.auth.User`
+        :rtype: :class:`Feed`
+
+        """
+        return Feed(
+            dict(project_id=project._id, app_config_id=app.config._id),
+            'Recent changes to %s' % app.config.options.mount_point,
+            app.url)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index 4f02632..3bfe0ca 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -40,6 +40,7 @@ from allura.lib import helpers as h
 from allura.lib import utils
 from allura.lib.decorators import require_post
 from allura.controllers.error import ErrorController
+from allura.controllers.feed import Feed, FeedController
 from allura.lib.security import require_access, has_access
 from allura.lib.security import RoleCache
 from allura.lib.widgets import forms as ff
@@ -299,11 +300,9 @@ class ToolListController(object):
                 if e.tool_name and e.tool_name.lower() == tool_name]
         return dict(entries=entries, type=entries[0].tool_name.capitalize() if entries else None)
 
-class ProjectController(object):
+class ProjectController(FeedController):
 
     def __init__(self):
-        setattr(self, 'feed.rss', self.feed)
-        setattr(self, 'feed.atom', self.feed)
         setattr(self, '_nav.json', self._nav)
         self.screenshot = ScreenshotsController()
         self._list = ToolListController()
@@ -367,29 +366,17 @@ class ProjectController(object):
         else:
             redirect(c.project.app_configs[0].options.mount_point + '/')
 
-    @without_trailing_slash
-    @expose()
-    @validate(dict(
-            since=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            until=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            page=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, page=None, limit=None, **kw):
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
-        title = 'Recent changes to Project %s' % c.project.name
-        feed = M.Feed.feed(
-            dict(project_id=c.project._id),
-            feed_type,
-            title,
-            c.project.url(),
-            title,
-            since, until, page, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
+    def get_feed(self, project, app, user):
+        """Return a :class:`allura.controllers.feed.Feed` object describing
+        the xml feed for this controller.
+
+        Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
+
+        """
+        return Feed(
+            dict(project_id=project._id),
+            'Recent changes to Project %s' % project.name,
+            project.url())
 
     @expose()
     def icon(self, **kw):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/Allura/allura/controllers/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index 5e006ba..59b154e 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -49,6 +49,7 @@ from allura.lib.widgets.subscriptions import SubscribeForm
 from allura import model as M
 from allura.lib.widgets import form_fields as ffw
 from allura.controllers.base import DispatchIndex
+from allura.controllers.feed import FeedController
 from allura.lib.diff import HtmlSideBySideDiff
 from paste.deploy.converters import asbool
 from allura.app import SitemapEntry
@@ -61,14 +62,10 @@ def on_import():
     CommitBrowser.TreeBrowserClass = TreeBrowser
     TreeBrowser.FileBrowserClass = FileBrowser
 
-class RepoRootController(BaseController):
+class RepoRootController(BaseController, FeedController):
     _discuss = AppDiscussionController()
     commit_browser_widget=SCMCommitBrowserWidget()
 
-    def __init__(self):
-        setattr(self, 'feed.atom', self.feed)
-        setattr(self, 'feed.rss', self.feed)
-
     def _check_security(self):
         security.require(security.has_access(c.app, 'read'))
 
@@ -187,30 +184,6 @@ class RepoRootController(BaseController):
             redirect(mr.url())
 
     @without_trailing_slash
-    @expose()
-    @validate(dict(
-            since=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            until=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            offset=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, offset=None, limit=None, **kw):
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
-        title = 'Recent changes to %s' % c.app.config.options.mount_point
-        feed = M.Feed.feed(
-            dict(project_id=c.project._id,app_config_id=c.app.config._id),
-            feed_type,
-            title,
-            c.app.url,
-            title,
-            since, until, offset, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
-
-    @without_trailing_slash
     @expose('jinja:allura:templates/repo/commit_browser.html')
     def commit_browser(self):
         if not c.app.repo or c.app.repo.status != 'ready':

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/Allura/allura/ext/user_profile/user_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/user_profile/user_main.py b/Allura/allura/ext/user_profile/user_main.py
index 0491199..c6e2402 100644
--- a/Allura/allura/ext/user_profile/user_main.py
+++ b/Allura/allura/ext/user_profile/user_main.py
@@ -32,6 +32,7 @@ from allura.lib.helpers import DateTimeConverter
 from allura.lib.security import require_access
 from allura.model import User, Feed, ACE
 from allura.controllers import BaseController
+from allura.controllers.feed import Feed, FeedController
 from allura.lib.decorators import require_post
 
 log = logging.getLogger(__name__)
@@ -79,11 +80,7 @@ class UserProfileApp(Application):
         pass
 
 
-class UserProfileController(BaseController):
-
-    def __init__(self):
-        setattr(self, 'feed.rss', self.feed)
-        setattr(self, 'feed.atom', self.feed)
+class UserProfileController(BaseController, FeedController):
 
     def _check_security(self):
         require_access(c.project, 'read')
@@ -94,38 +91,16 @@ class UserProfileController(BaseController):
         if not user:
             raise exc.HTTPNotFound()
         return dict(user=user)
-    # This will be fully implemented in a future iteration
-    # @expose('jinja:allura.ext.user_profile:templates/user_subscriptions.html')
-    # def subscriptions(self):
-    #     username = c.project.shortname.split('/')[1]
-    #     user = User.by_username(username)
-    #     subs = Subscriptions.query.find({'user_id':user._id}).all()
-    #     for sub in subs:
-    #         for s in sub.subscriptions:
-    #             r = g.solr_short_timeout.search(s.artifact_index_id)
-    #             print r.docs
-    #     return dict(user=user)
-
-    @expose()
-    @validate(dict(
-            since=DateTimeConverter(if_empty=None),
-            until=DateTimeConverter(if_empty=None),
-            page=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, page=None, limit=None, **kw):
-        user = c.project.user_project_of
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
-        title = 'Recent posts by %s' % user.display_name
-        feed = Feed.feed(
-            {'author_link':user.url()},
-            feed_type,
-            title,
-            c.project.url(),
-            title,
-            since, until, page, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
+
+    def get_feed(self, project, app, user):
+        """Return a :class:`allura.controllers.feed.Feed` object describing
+        the xml feed for this controller.
+
+        Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
+
+        """
+        user = project.user_project_of
+        return Feed(
+            {'author_link': user.url()},
+            'Recent posts by %s' % user.display_name,
+            project.url())

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/ForgeBlog/forgeblog/main.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index f745af9..0c7af13 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -46,6 +46,7 @@ from allura.lib.widgets import form_fields as ffw
 from allura.lib.widgets.search import SearchResults, SearchHelp
 from allura import model as M
 from allura.controllers import BaseController, AppDiscussionController
+from allura.controllers.feed import Feed, FeedController
 
 # Local imports
 from forgeblog import model as BM
@@ -180,11 +181,9 @@ class ForgeBlogApp(Application):
         BM.BlogPostSnapshot.query.remove(dict(app_config_id=c.app.config._id))
         super(ForgeBlogApp, self).uninstall(project)
 
-class RootController(BaseController):
+class RootController(BaseController, FeedController):
 
     def __init__(self):
-        setattr(self, 'feed.atom', self.feed)
-        setattr(self, 'feed.rss', self.feed)
         self._discuss = AppDiscussionController()
 
     def _check_security(self):
@@ -255,30 +254,6 @@ class RootController(BaseController):
         redirect(h.really_unicode(post.url()).encode('utf-8'))
 
 
-    @without_trailing_slash
-    @expose()
-    @validate(dict(
-            since=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            until=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            offset=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, offset=None, limit=None, **kw):
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
-        title = '%s - %s' % (c.project.name, c.app.config.options.mount_label)
-        feed = M.Feed.feed(
-            dict(project_id=c.project._id, app_config_id=c.app.config._id),
-            feed_type,
-            title,
-            c.app.url,
-            title,
-            since, until, offset, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
-
     @with_trailing_slash
     @expose('jinja:allura:templates/markdown_syntax_dialog.html')
     def markdown_syntax_dialog(self, **kw):
@@ -293,12 +268,10 @@ class RootController(BaseController):
             raise exc.HTTPNotFound()
         return PostController(post), rest
 
-class PostController(BaseController):
+class PostController(BaseController, FeedController):
 
     def __init__(self, post):
         self.post = post
-        setattr(self, 'feed.atom', self.feed)
-        setattr(self, 'feed.rss', self.feed)
 
     def _check_security(self):
         require_access(self.post, 'read')
@@ -380,28 +353,17 @@ class PostController(BaseController):
             self.post.unsubscribe()
         redirect(h.really_unicode(request.referer).encode('utf-8'))
 
-    @without_trailing_slash
-    @expose()
-    @validate(dict(
-            since=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            until=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            offset=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, offset=None, limit=None, **kw):
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
-        feed = M.Feed.feed(
+    def get_feed(self, project, app, user):
+        """Return a :class:`allura.controllers.feed.Feed` object describing
+        the xml feed for this controller.
+
+        Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
+
+        """
+        return Feed(
             dict(ref_id=self.post.index_id()),
-            feed_type,
-            'Recent changes to %s' % self.post.title,
-            self.post.url(),
             'Recent changes to %s' % self.post.title,
-            since, until, offset, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
+            self.post.url())
 
     def _get_version(self, version):
         if not version: return self.post

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/ForgeDiscussion/forgediscussion/controllers/root.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/controllers/root.py b/ForgeDiscussion/forgediscussion/controllers/root.py
index 02c3cde..f731da3 100644
--- a/ForgeDiscussion/forgediscussion/controllers/root.py
+++ b/ForgeDiscussion/forgediscussion/controllers/root.py
@@ -27,14 +27,13 @@ from pylons import request
 from formencode import validators
 from webob import exc
 
-
 from allura.lib.security import require_access, has_access, require_authenticated
-from allura.model import Feed
 from allura.lib.search import search_app
 from allura.lib import helpers as h
 from allura.lib.utils import AntiSpam
 from allura.lib.decorators import require_post
 from allura.controllers import BaseController, DispatchIndex
+from allura.controllers.feed import Feed, FeedController
 
 from .forum import ForumController
 from forgediscussion import import_support
@@ -48,7 +47,7 @@ from forgediscussion.widgets.admin import AddForumShort
 
 log = logging.getLogger(__name__)
 
-class RootController(BaseController, DispatchIndex):
+class RootController(BaseController, DispatchIndex, FeedController):
 
     class W(object):
         forum_subscription_form=FW.ForumSubscriptionForm()
@@ -58,10 +57,6 @@ class RootController(BaseController, DispatchIndex):
         search_results = SearchResults()
         search_help = SearchHelp(comments=False, history=False)
 
-    def __init__(self):
-        setattr(self, 'feed.rss', self.feed)
-        setattr(self, 'feed.atom', self.feed)
-
     def _check_security(self):
         require_access(c.app, 'read')
 
@@ -191,29 +186,18 @@ class RootController(BaseController, DispatchIndex):
                 obj['obj'].subscriptions.pop(str(c.user._id), None)
         redirect(request.referer)
 
-    @expose()
-    @validate(dict(
-            since=h.DateTimeConverter(if_empty=None),
-            until=h.DateTimeConverter(if_empty=None),
-            page=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, page=None, limit=None, **kw):
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
-        title = 'Recent posts to %s' % c.app.config.options.mount_label
-
-        feed = Feed.feed(
-            dict(project_id=c.project._id, app_config_id=c.app.config._id),
-            feed_type,
-            title,
-            c.app.url,
-            title,
-            since, until, page, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
+    def get_feed(self, project, app, user):
+        """Return a :class:`allura.controllers.feed.Feed` object describing
+        the xml feed for this controller.
+
+        Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
+
+        """
+        return Feed(
+            dict(project_id=project._id, app_config_id=app.config._id),
+             'Recent posts to %s' % app.config.options.mount_label,
+            app.url)
+
 
 class RootRestController(BaseController):
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/ForgeSVN/forgesvn/controllers.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/controllers.py b/ForgeSVN/forgesvn/controllers.py
index 2e39fc7..66709f0 100644
--- a/ForgeSVN/forgesvn/controllers.py
+++ b/ForgeSVN/forgesvn/controllers.py
@@ -20,9 +20,10 @@ from tg.decorators import with_trailing_slash
 from pylons import tmpl_context as c
 
 from allura.controllers import repository
+from allura.controllers.feed import FeedController
 
 
-class BranchBrowser(repository.BranchBrowser):
+class BranchBrowser(repository.BranchBrowser, FeedController):
 
     def __init__(self):
         super(BranchBrowser, self).__init__(None)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/ForgeSVN/forgesvn/svn_main.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/svn_main.py b/ForgeSVN/forgesvn/svn_main.py
index ef7d008..dcb4fd6 100644
--- a/ForgeSVN/forgesvn/svn_main.py
+++ b/ForgeSVN/forgesvn/svn_main.py
@@ -64,9 +64,6 @@ class ForgeSVNApp(RepositoryApp):
         self.root = BranchBrowser()
         default_root = RepoRootController()
         self.root.refresh = default_root.refresh
-        self.root.feed = default_root.feed
-        setattr(self.root, 'feed.rss', self.root.feed)
-        setattr(self.root, 'feed.atom', self.root.feed)
         self.root.commit_browser = default_root.commit_browser
         self.root.commit_browser_data = default_root.commit_browser_data
         self.root.status = default_root.status

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 349ef1e..6270e96 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -61,6 +61,7 @@ from allura.lib.zarkov_helpers import zero_fill_zarkov_result
 from allura.controllers import AppDiscussionController, AppDiscussionRestController
 from allura.controllers import attachments as ac
 from allura.controllers import BaseController
+from allura.controllers.feed import Feed, FeedController
 from allura.tasks import mail_tasks
 
 # Local imports
@@ -467,11 +468,9 @@ def solr_columns():
         columns.append(dict(name='votes', sort_name='votes_total_i', label='Votes', active=True))
     return columns
 
-class RootController(BaseController):
+class RootController(BaseController, FeedController):
 
     def __init__(self):
-        setattr(self, 'feed.atom', self.feed)
-        setattr(self, 'feed.rss', self.feed)
         setattr(self, 'search_feed.atom', self.search_feed)
         setattr(self, 'search_feed.rss', self.search_feed)
         self._discuss = AppDiscussionController()
@@ -711,30 +710,6 @@ class RootController(BaseController):
         'Static page explaining markdown.'
         return dict()
 
-    @without_trailing_slash
-    @expose()
-    @validate(dict(
-            since=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            until=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            offset=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, offset=None, limit=None, **kw):
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
-        title = 'Recent changes to %s' % c.app.config.options.mount_point
-        feed = M.Feed.feed(
-            dict(project_id=c.project._id,app_config_id=c.app.config._id),
-            feed_type,
-            title,
-            c.app.url,
-            title,
-            since, until, offset, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
-
     @expose()
     @h.vardec
     @require_post()
@@ -1233,7 +1208,7 @@ def filtered_by_subscription(tickets, project_id=None, app_config_id=None):
     return filtered
 
 
-class TicketController(BaseController):
+class TicketController(BaseController, FeedController):
 
     def __init__(self, ticket_num=None):
         if ticket_num is not None:
@@ -1248,8 +1223,6 @@ class TicketController(BaseController):
                     utils.permanent_redirect(self.ticket.url())
             self.attachment = AttachmentsController(self.ticket)
             # self.comments = CommentController(self.ticket)
-        setattr(self, 'feed.atom', self.feed)
-        setattr(self, 'feed.rss', self.feed)
 
     def _check_security(self):
         if self.ticket is not None:
@@ -1285,30 +1258,19 @@ class TicketController(BaseController):
         else:
             raise exc.HTTPNotFound, 'Ticket #%s does not exist.' % self.ticket_num
 
-    @without_trailing_slash
-    @expose()
-    @validate(dict(
-            since=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            until=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            offset=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, offset=None, limit=None, **kw):
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
+    def get_feed(self, project, app, user):
+        """Return a :class:`allura.controllers.feed.Feed` object describing
+        the xml feed for this controller.
+
+        Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
+
+        """
         title = 'Recent changes to %d: %s' % (
             self.ticket.ticket_num, self.ticket.summary)
-        feed = M.Feed.feed(
-            {'ref_id':self.ticket.index_id()},
-            feed_type,
-            title,
-            self.ticket.url(),
+        return Feed(
+            {'ref_id': self.ticket.index_id()},
             title,
-            since, until, offset, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
+            self.ticket.url())
 
     @expose()
     @require_post()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/391aa922/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index b923350..dfb982b 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -41,6 +41,7 @@ from allura.lib.security import require_access, has_access
 from allura.controllers import AppDiscussionController, BaseController
 from allura.controllers import DispatchIndex
 from allura.controllers import attachments as ac
+from allura.controllers.feed import Feed, FeedController
 from allura.lib import widgets as w
 from allura.lib.widgets import form_fields as ffw
 from allura.lib.widgets.subscriptions import SubscribeForm
@@ -277,11 +278,9 @@ The wiki uses [Markdown](%s) syntax.
         WM.Globals.query.remove(dict(app_config_id=self.config._id))
         super(ForgeWikiApp, self).uninstall(project)
 
-class RootController(BaseController, DispatchIndex):
+class RootController(BaseController, DispatchIndex, FeedController):
 
     def __init__(self):
-        setattr(self, 'feed.atom', self.feed)
-        setattr(self, 'feed.rss', self.feed)
         c.create_page_lightbox = W.create_page_lightbox
         self._discuss = AppDiscussionController()
 
@@ -409,31 +408,8 @@ class RootController(BaseController, DispatchIndex):
         'Display a page about how to use markdown.'
         return dict(example=MARKDOWN_EXAMPLE)
 
-    @without_trailing_slash
-    @expose()
-    @validate(dict(
-            since=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            until=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            offset=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, offset=None, limit=None, **kw):
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
-        title = 'Recent changes to %s' % c.app.config.options.mount_point
-        feed = M.Feed.feed(
-            dict(project_id=c.project._id,app_config_id=c.app.config._id),
-            feed_type,
-            title,
-            c.app.url,
-            title,
-            since, until, offset, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
-
-class PageController(BaseController):
+
+class PageController(BaseController, FeedController):
 
     def __init__(self, title):
         self.title = h.really_unicode(unquote(title))
@@ -442,8 +418,6 @@ class PageController(BaseController):
         if self.page is not None:
             self.attachment = WikiAttachmentsController(self.page)
         c.create_page_lightbox = W.create_page_lightbox
-        setattr(self, 'feed.atom', self.feed)
-        setattr(self, 'feed.rss', self.feed)
 
     def _check_security(self):
         if self.page:
@@ -583,30 +557,19 @@ class PageController(BaseController):
             raise exc.HTTPNotFound
         return pformat(self.page)
 
-    @without_trailing_slash
-    @expose()
-    @validate(dict(
-            since=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            until=h.DateTimeConverter(if_empty=None, if_invalid=None),
-            offset=validators.Int(if_empty=None),
-            limit=validators.Int(if_empty=None)))
-    def feed(self, since=None, until=None, offset=None, limit=None, **kw):
+    def get_feed(self, project, app, user):
+        """Return a :class:`allura.controllers.feed.Feed` object describing
+        the xml feed for this controller.
+
+        Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
+
+        """
         if not self.page:
-            raise exc.HTTPNotFound
-        if request.environ['PATH_INFO'].endswith('.atom'):
-            feed_type = 'atom'
-        else:
-            feed_type = 'rss'
-        feed = M.Feed.feed(
-            {'ref_id':self.page.index_id()},
-            feed_type,
-            'Recent changes to %s' % self.page.title,
-            self.page.url(),
+            return None
+        return Feed(
+            {'ref_id': self.page.index_id()},
             'Recent changes to %s' % self.page.title,
-            since, until, offset, limit)
-        response.headers['Content-Type'] = ''
-        response.content_type = 'application/xml'
-        return feed.writeString('utf-8')
+            self.page.url())
 
     @without_trailing_slash
     @expose('json')