You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by he...@apache.org on 2015/07/27 22:20:09 UTC

[01/22] allura git commit: [#7927] ticket:821 Implement CORS middleware

Repository: allura
Updated Branches:
  refs/heads/hs/7925 623a5f12a -> 7d57e2db8 (forced update)


[#7927] ticket:821 Implement CORS middleware


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

Branch: refs/heads/hs/7925
Commit: 0c71798b2dbe73f68f5912a81606b9ca73f45704
Parents: de47627
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Jul 16 15:54:22 2015 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Jul 16 17:50:54 2015 +0300

----------------------------------------------------------------------
 Allura/allura/config/middleware.py     |  9 ++++-
 Allura/allura/lib/custom_middleware.py | 57 +++++++++++++++++++++++++++++
 Allura/development.ini                 |  9 +++++
 3 files changed, 74 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/0c71798b/Allura/allura/config/middleware.py
----------------------------------------------------------------------
diff --git a/Allura/allura/config/middleware.py b/Allura/allura/config/middleware.py
index ba07cc4..922034d 100644
--- a/Allura/allura/config/middleware.py
+++ b/Allura/allura/config/middleware.py
@@ -25,7 +25,7 @@ import tg
 import tg.error
 import pkg_resources
 from tg import config
-from paste.deploy.converters import asbool
+from paste.deploy.converters import asbool, aslist, asint
 from paste.registry import RegistryManager
 from routes.middleware import RoutesMiddleware
 from pylons.middleware import StatusCodeRedirect
@@ -44,6 +44,7 @@ from allura.lib.custom_middleware import AlluraTimerMiddleware
 from allura.lib.custom_middleware import SSLMiddleware
 from allura.lib.custom_middleware import StaticFilesMiddleware
 from allura.lib.custom_middleware import CSRFMiddleware
+from allura.lib.custom_middleware import CORSMiddleware
 from allura.lib.custom_middleware import LoginRedirectMiddleware
 from allura.lib.custom_middleware import RememberLoginMiddleware
 from allura.lib import patches
@@ -137,6 +138,12 @@ def _make_core_app(root, global_conf, full_stack=True, **app_conf):
     # Clear cookies when the CSRF field isn't posted
     if not app_conf.get('disable_csrf_protection'):
         app = CSRFMiddleware(app, '_session_id')
+    if asbool(config.get('cors.enabled', False)):
+        # Handle CORS requests
+        allowed_methods = aslist(config.get('cors.methods'))
+        allowed_headers = aslist(config.get('cors.headers'))
+        cache_duration = asint(config.get('cors.cache_duration', 0))
+        app = CORSMiddleware(app, allowed_methods, allowed_headers)
     # Setup the allura SOPs
     app = allura_globals_middleware(app)
     # Ensure http and https used per config

http://git-wip-us.apache.org/repos/asf/allura/blob/0c71798b/Allura/allura/lib/custom_middleware.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/custom_middleware.py b/Allura/allura/lib/custom_middleware.py
index 13c3db5..4eef689 100644
--- a/Allura/allura/lib/custom_middleware.py
+++ b/Allura/allura/lib/custom_middleware.py
@@ -84,6 +84,63 @@ class StaticFilesMiddleware(object):
         return fileapp.FileApp(file_path, [
             ('Access-Control-Allow-Origin', '*')])
 
+class CORSMiddleware(object):
+    '''Enables Cross-Origin Resource Sharing for REST API'''
+
+    def __init__(self, app, allowed_methods, allowed_headers, cache=None):
+        self.app = app
+        self.allowed_methods = [m.upper() for m in allowed_methods]
+        self.allowed_headers = set(h.lower() for h in allowed_headers)
+        self.cache_preflight = cache or None
+
+    def __call__(self, environ, start_response):
+        is_api_request = environ.get('PATH_INFO', '').startswith('/rest/')
+        valid_cors = 'HTTP_ORIGIN' in environ
+        if not is_api_request or not valid_cors:
+            return self.app(environ, start_response)
+
+        method = environ.get('REQUEST_METHOD')
+        acrm = environ.get('HTTP_ACCESS_CONTROL_REQUEST_METHOD')
+        if method == 'OPTIONS' and acrm:
+            return self.handle_preflight_request(environ, start_response)
+        else:
+            return self.handle_simple_request(environ, start_response)
+
+    def handle_simple_request(self, environ, start_response):
+        def cors_start_response(status, headers, exc_info=None):
+            headers.extend(self.get_response_headers(preflight=False))
+            return start_response(status, headers, exc_info)
+        return self.app(environ, cors_start_response)
+
+    def handle_preflight_request(self, environ, start_response):
+        method = environ.get('HTTP_ACCESS_CONTROL_REQUEST_METHOD')
+        if method not in self.allowed_methods:
+            return self.app(environ, start_response)
+        headers = self.get_access_control_request_headers(environ)
+        if not headers.issubset(self.allowed_headers):
+            return self.app(environ, start_response)
+        r = exc.HTTPOk(headers=self.get_response_headers(preflight=True))
+        return r(environ, start_response)
+
+    def get_response_headers(self, preflight=False):
+        headers = [('Access-Control-Allow-Origin', '*')]
+        if preflight:
+            ac_methods = ', '.join(self.allowed_methods)
+            ac_headers = ', '.join(self.allowed_headers)
+            headers.extend([
+                ('Access-Control-Allow-Methods', ac_methods),
+                ('Access-Control-Allow-Headers', ac_headers),
+            ])
+            if self.cache_preflight:
+                headers.append(
+                    ('Access-Control-Max-Age', self.cache_preflight)
+                )
+        return headers
+
+    def get_access_control_request_headers(self, environ):
+        headers = environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS', '')
+        return set(h.strip().lower() for h in headers.split(',') if h.strip())
+
 
 class LoginRedirectMiddleware(object):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/0c71798b/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 02d3e9f..934ea67 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -216,6 +216,15 @@ webhook.repo_push.limit = 30
 ; `WebhookSender.triggered_by`) and values are actual limits (default=3), e.g.:
 webhook.repo_push.max_hooks = {"git": 3, "hg": 3, "svn": 3}
 
+;; Allow Cross-Origin Resource Sharing (CORS) requests to the REST API
+; disabled by default, uncomment the following options to enable:
+;cors.enabled = true
+;cors.methods = GET HEAD POST PUT DELETE
+;cors.headers = Authorization Accept Content-Type
+; Allow clients to cache preflight responses for N seconds
+; Set to 0 or remove completely to disable
+;cors.cache_duration = 86400
+
 ; Additional fields for admin project/user search
 ; Note: whitespace after comma is important!
 ;search.project.additional_search_fields = private, url, title


[08/22] allura git commit: [#7685] ticket:802 Submit subscription request via POST

Posted by he...@apache.org.
[#7685] ticket:802 Submit subscription request via POST


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

Branch: refs/heads/hs/7925
Commit: cc33817a3e151554c2b6446f3afb7c052760129d
Parents: e1ad480
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Wed Jun 24 23:39:53 2015 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Wed Jul 22 15:35:25 2015 +0300

----------------------------------------------------------------------
 Allura/allura/templates/widgets/subscribe.html       | 13 +++++++++++--
 ForgeBlog/forgeblog/main.py                          |  1 +
 ForgeDiscussion/forgediscussion/controllers/forum.py |  1 +
 ForgeTracker/forgetracker/tracker_main.py            |  2 ++
 ForgeWiki/forgewiki/wiki_main.py                     |  2 ++
 5 files changed, 17 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/cc33817a/Allura/allura/templates/widgets/subscribe.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/subscribe.html b/Allura/allura/templates/widgets/subscribe.html
index a88c7e4..5154eb7 100644
--- a/Allura/allura/templates/widgets/subscribe.html
+++ b/Allura/allura/templates/widgets/subscribe.html
@@ -16,9 +16,14 @@
        specific language governing permissions and limitations
        under the License.
 -#}
+{% import 'allura:templates/jinja_master/lib.html' as lib with context %}
 {% if value %}
   {% if style == 'icon' %}
-    <a href="{{action}}?unsubscribe=True" class="artifact_unsubscribe active" title="Unsubscribe from this {{thing}}"><b data-icon="{{g.icons['mail'].char}}" class="ico {{g.icons['mail'].css}}" title="Unsubscribe from this {{thing}}"></b></a>
+    <form action="{{action}}" id="subscribe_form" style="display:inline;" method="POST">
+      {{lib.csrf_token()}}
+      <input type="hidden" name="unsubscribe" value="1">
+      <a href="#" class="artifact_unsubscribe active" title="Unsubscribe from this {{thing}}" onclick="$('#subscribe_form').submit(); return false;"><b data-icon="{{g.icons['mail'].char}}" class="ico {{g.icons['mail'].css}}" title="Unsubscribe from this {{thing}}"></b></a>
+    </form>
   {% else %}
     You are currently subscribed to this {{thing}}.
     <br/>
@@ -26,7 +31,11 @@
   {% endif %}
 {% else %}
   {% if style == 'icon' %}
-    <a href="{{action}}?subscribe=True" class="artifact_subscribe" title="Subscribe to this {{thing}}"><b data-icon="{{g.icons['mail'].char}}" class="ico {{g.icons['mail'].css}}" title="Subscribe to this {{thing}}"></b></a>
+    <form action="{{action}}" id="subscribe_form" style="display:inline;" method="POST">
+      {{lib.csrf_token()}}
+      <input type="hidden" name="subscribe" value="1">
+      <a href="#" class="artifact_subscribe" title="Subscribe to this {{thing}}" onclick="$('#subscribe_form').submit(); return false;"><b data-icon="{{g.icons['mail'].char}}" class="ico {{g.icons['mail'].css}}" title="Subscribe to this {{thing}}"></b></a>
+    </form>
   {% else %}
     You are currently not subscribed to this {{thing}}.
     <br/>

http://git-wip-us.apache.org/repos/asf/allura/blob/cc33817a/ForgeBlog/forgeblog/main.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index edfe1f0..9007f87 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -376,6 +376,7 @@ class PostController(BaseController, FeedController):
         redirect('.')
 
     @expose()
+    @require_post()
     @validate(W.subscribe_form)
     def subscribe(self, subscribe=None, unsubscribe=None, **kw):
         if subscribe:

http://git-wip-us.apache.org/repos/asf/allura/blob/cc33817a/ForgeDiscussion/forgediscussion/controllers/forum.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/controllers/forum.py b/ForgeDiscussion/forgediscussion/controllers/forum.py
index 67dbea3..94fe6d9 100644
--- a/ForgeDiscussion/forgediscussion/controllers/forum.py
+++ b/ForgeDiscussion/forgediscussion/controllers/forum.py
@@ -123,6 +123,7 @@ class ForumController(DiscussionController):
         return dict()
 
     @expose()
+    @require_post()
     @validate(W.subscribe_form)
     def subscribe_to_forum(self, subscribe=None, unsubscribe=None, shortname=None, **kw):
         if subscribe:

http://git-wip-us.apache.org/repos/asf/allura/blob/cc33817a/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 68b1a0c..c3a83e6 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -1091,6 +1091,7 @@ class RootController(BaseController, FeedController):
         )
 
     @expose()
+    @require_post()
     @validate(W.subscribe_form)
     def subscribe(self, subscribe=None, unsubscribe=None):
         if subscribe:
@@ -1520,6 +1521,7 @@ class TicketController(BaseController, FeedController):
         redirect('.')
 
     @expose()
+    @require_post()
     @validate(W.subscribe_form)
     def subscribe(self, subscribe=None, unsubscribe=None):
         if subscribe:

http://git-wip-us.apache.org/repos/asf/allura/blob/cc33817a/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index cfaec31..7899ffa 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -464,6 +464,7 @@ class RootController(BaseController, DispatchIndex, FeedController):
         return dict(example=MARKDOWN_EXAMPLE)
 
     @expose()
+    @require_post()
     @validate(W.subscribe_form)
     def subscribe(self, subscribe=None, unsubscribe=None):
         if subscribe:
@@ -735,6 +736,7 @@ class PageController(BaseController, FeedController):
         redirect(request.referer)
 
     @expose()
+    @require_post()
     @validate(W.subscribe_form)
     def subscribe(self, subscribe=None, unsubscribe=None, **kw):
         if not self.page:


[22/22] allura git commit: [#7925] Update commit web view to show copied and renamed changes

Posted by he...@apache.org.
[#7925] Update commit web view to show copied and renamed changes


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

Branch: refs/heads/hs/7925
Commit: 7d57e2db8ab895e32802d6b258f64770bea713d2
Parents: 0e4847a
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Mon Jul 27 16:11:50 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Jul 27 16:11:50 2015 -0400

----------------------------------------------------------------------
 Allura/allura/controllers/repository.py  | 4 ++--
 Allura/allura/templates/repo/commit.html | 5 +++++
 2 files changed, 7 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/7d57e2db/Allura/allura/controllers/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index 5d03f64..0524589 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -565,8 +565,8 @@ class CommitBrowser(BaseController):
         diffs = self._commit.paged_diffs(start=start, end=start + limit)
         result['artifacts'] = [
             (t, f, 'blob' if tree.get_blob_by_path(f) else 'tree',
-            tree.get_blob_by_path(f) and tree.get_blob_by_path(f).is_text)
-            for t in ('added', 'removed', 'changed', 'copied')
+            tree.get_blob_by_path(f) and tree.get_blob_by_path(f).has_html_view)
+            for t in ('added', 'removed', 'changed', 'copied', 'renamed')
             for f in diffs[t]]
         count = diffs['total']
         result.update(dict(page=page, limit=limit, count=count))

http://git-wip-us.apache.org/repos/asf/allura/blob/7d57e2db/Allura/allura/templates/repo/commit.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/repo/commit.html b/Allura/allura/templates/repo/commit.html
index f029f52..f7206d4 100644
--- a/Allura/allura/templates/repo/commit.html
+++ b/Allura/allura/templates/repo/commit.html
@@ -1,3 +1,4 @@
+
 {#-
        Licensed to the Apache Software Foundation (ASF) under one
        or more contributor license agreements.  See the NOTICE file
@@ -119,6 +120,8 @@ Commit <a href="{{commit.url()}}">{{commit.shorthand_id()}}</a> {{commit_labels(
         <td><a href="#diff-{{loop.index}}">
             {% if type == 'copied' %}
               {{ '%s -> %s' % (h.really_unicode(file.old), h.really_unicode(file.new)) }}
+            {% elif type == 'renamed' %}
+              {{ '%s -> %s' % (h.really_unicode(file.old), h.really_unicode(file.new)) }}
             {% else %}
               {{h.really_unicode(file)}}
             {% endif %}
@@ -142,6 +145,8 @@ Commit <a href="{{commit.url()}}">{{commit.shorthand_id()}}</a> {{commit_labels(
                 {% endif %}
             {% elif type == 'removed' %}
                 <a href="{{prev[0].url()}}tree/{{h.urlquote(h.really_unicode(file))}}">{{h.really_unicode(file)}}</a>
+            {% elif type == 'renamed' %}
+                <a href="{{prev[0].url()}}tree/{{h.urlquote(h.really_unicode(file))}}">{{h.really_unicode(file)}}</a>
             {% elif type == 'copied' %}
                 <a href="{{prev[0].url()}}tree/{{h.urlquote(h.really_unicode(file.old))}}">{{h.really_unicode(file.old)}}</a>
                 to


[20/22] allura git commit: [#7925] Refactor and improve the diff processing

Posted by he...@apache.org.
[#7925] Refactor and improve the diff processing


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

Branch: refs/heads/hs/7925
Commit: ef9cc5fd72e33f636148db4b9e362acf6b1ede48
Parents: 7947ef5
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Mon Jul 27 16:06:28 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Jul 27 16:06:28 2015 -0400

----------------------------------------------------------------------
 Allura/allura/lib/custom_middleware.py |  4 --
 Allura/allura/model/repository.py      | 67 +----------------------------
 ForgeGit/forgegit/model/git_repo.py    | 51 +++++++++++++++-------
 ForgeSVN/forgesvn/model/svn.py         | 17 +++++---
 4 files changed, 47 insertions(+), 92 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/ef9cc5fd/Allura/allura/lib/custom_middleware.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/custom_middleware.py b/Allura/allura/lib/custom_middleware.py
index e56a530..1938e51 100644
--- a/Allura/allura/lib/custom_middleware.py
+++ b/Allura/allura/lib/custom_middleware.py
@@ -322,10 +322,6 @@ class AlluraTimerMiddleware(TimerMiddleware):
             Timer('urlopen', urllib2, 'urlopen'),
             Timer('base_repo_tool.{method_name}',
                   allura.model.repository.RepositoryImplementation, 'last_commit_ids'),
-            Timer('_diffs_copied', allura.model.repository.Commit, '_diffs_copied'),
-            Timer(
-                'sequencematcher.{method_name}', allura.model.repository.SequenceMatcher,
-                'ratio', 'quick_ratio', 'real_quick_ratio'),
             Timer('unified_diff', allura.model.repository, 'unified_diff'),
         ] + [Timer('sidebar', ep.load(), 'sidebar_menu') for ep in tool_entry_points]
 

http://git-wip-us.apache.org/repos/asf/allura/blob/ef9cc5fd/Allura/allura/model/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repository.py b/Allura/allura/model/repository.py
index 5fe2ba9..636d10c 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -1168,78 +1168,15 @@ class Commit(RepoObject, ActivityObject):
 
     def paged_diffs(self, start=0, end=None):
         diffs = self.repo.paged_diffs(self._id, start, end)
-        if not diffs.get('copied'):
-            diffs['copied'] = []
-        copied = self._diffs_copied(diffs['added'], diffs['removed'])
-        diffs['copied'].extend(copied)
+
         return Object(
             added=sorted(diffs['added']),
             removed=sorted(diffs['removed']),
             changed=sorted(diffs['changed']),
             copied=sorted(diffs['copied']),
+            renamed=sorted(diffs['renamed']),
             total=diffs['total'])
 
-    def _diffs_copied(self, added, removed):
-        '''Return list with file renames diffs.
-
-        Will change `added` and `removed` lists also.
-        '''
-        def _blobs_similarity(removed_blob, added):
-            best = dict(ratio=0, name='', blob=None)
-            for added_name in added:
-                added_blob = self.tree.get_obj_by_path(added_name)
-                if not isinstance(added_blob, Blob):
-                    continue
-                diff = SequenceMatcher(None, removed_blob.text,
-                                       added_blob.text)
-                ratio = diff.quick_ratio()
-                if ratio > best['ratio']:
-                    best['ratio'] = ratio
-                    best['name'] = added_name
-                    best['blob'] = added_blob
-
-                if ratio == 1:
-                    break  # we'll won't find better similarity than 100% :)
-
-            if best['ratio'] > DIFF_SIMILARITY_THRESHOLD:
-                diff = ''
-                if best['ratio'] < 1:
-                    added_blob = best['blob']
-                    rpath = ('a' + removed_blob.path()).encode('utf-8')
-                    apath = ('b' + added_blob.path()).encode('utf-8')
-                    diff = ''.join(unified_diff(list(removed_blob),
-                                                list(added_blob),
-                                                rpath, apath))
-                return dict(new=best['name'],
-                            ratio=best['ratio'], diff=diff)
-
-        def _trees_similarity(removed_tree, added):
-            for added_name in added:
-                added_tree = self.tree.get_obj_by_path(added_name)
-                if not isinstance(added_tree, Tree):
-                    continue
-                if removed_tree._id == added_tree._id:
-                    return dict(new=added_name,
-                                ratio=1, diff='')
-
-        if not removed:
-            return []
-        copied = []
-        prev_commit = self.get_parent()
-        for removed_name in removed[:]:
-            removed_blob = prev_commit.tree.get_obj_by_path(removed_name)
-            rename_info = None
-            if isinstance(removed_blob, Blob):
-                rename_info = _blobs_similarity(removed_blob, added)
-            elif isinstance(removed_blob, Tree):
-                rename_info = _trees_similarity(removed_blob, added)
-            if rename_info is not None:
-                rename_info['old'] = removed_name
-                copied.append(rename_info)
-                removed.remove(rename_info['old'])
-                added.remove(rename_info['new'])
-        return copied
-
     def get_path(self, path, create=True):
         path = path.lstrip('/')
         parts = path.split('/')

http://git-wip-us.apache.org/repos/asf/allura/blob/ef9cc5fd/ForgeGit/forgegit/model/git_repo.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/model/git_repo.py b/ForgeGit/forgegit/model/git_repo.py
index 9549fa6..9a8549a 100644
--- a/ForgeGit/forgegit/model/git_repo.py
+++ b/ForgeGit/forgegit/model/git_repo.py
@@ -642,36 +642,55 @@ class GitImplementation(M.RepositoryImplementation):
             max_count=1).splitlines()[1:]
 
     def paged_diffs(self, commit_id, start=0, end=None):
-        added, removed, changed = [], [], []
+        result = {'added': [], 'removed': [], 'changed': [], 'copied': [], 'renamed': [], 'total': 0}
+
         files = self._git.git.diff_tree(
             '--no-commit-id',
+            '--find-renames',
+            '--find-copies',
             '--name-status',
-            '--no-renames',
+            '--no-abbrev',
             '--root',
-            # show tree entry itself as well as subtrees (Commit.added_paths
-            # relies on this)
+            '--find-copies-harder',
+            # show tree entry itself as well as subtrees (Commit.added_paths relies on this)
             '-t',
             '-z',  # don't escape filenames and use \x00 as fields delimiter
             commit_id).split('\x00')[:-1]
 
-        total = len(files) / 2
-        files = [(files[i], h.really_unicode(files[i+1]))
-                 for i in xrange(0, len(files), 2)]
+        result['total'] = len(files) / 2
+        x = 0
+        while x < len(files):
+            try:
+                if files[x].startswith("R") or files[x].startswith("C"):
+                    change_list = result['renamed'] if files[x].startswith("R") else result['copied']
+                    ratio = float(files[x][1:4]) / 100.0
+                    change_list.append({
+                        'new': h.really_unicode(files[x + 2]),
+                        'old': h.really_unicode(files[x + 1]),
+                        'ratio': ratio,
+                        'diff': '',
+                    })
+                    del files[x:x+3]
+                    x += 3
+                    result['total'] -= 1
+                else:
+                    x += 2
+            except IndexError:
+                break
+
+        files = [(files[i], h.really_unicode(files[i + 1]))
+                 for i in xrange(0, result['total'] + 1, 2)]
 
         # files = [('A', u'filename'), ('D', u'another filename'), ...]
         for status, name in files[start:end]:
             if status == 'A':
-                added.append(name)
+                result['added'].append(name)
             elif status == 'D':
-                removed.append(name)
+                result['removed'].append(name)
             elif status == 'M':
-                changed.append(name)
-        return {
-            'added': added,
-            'removed': removed,
-            'changed': changed,
-            'total': total,
-        }
+                result['changed'].append(name)
+
+        return result
 
     @contextmanager
     def _shared_clone(self, from_path):

http://git-wip-us.apache.org/repos/asf/allura/blob/ef9cc5fd/ForgeSVN/forgesvn/model/svn.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/model/svn.py b/ForgeSVN/forgesvn/model/svn.py
index cd410e3..f43f536 100644
--- a/ForgeSVN/forgesvn/model/svn.py
+++ b/ForgeSVN/forgesvn/model/svn.py
@@ -781,13 +781,7 @@ class SVNImplementation(M.RepositoryImplementation):
         return []
 
     def paged_diffs(self, commit_id, start=0, end=None):
-        result = {
-            'added': [],
-            'removed': [],
-            'changed': [],
-            'copied': [],
-            'total': 0,
-        }
+        result = {'added': [], 'removed': [], 'changed': [], 'copied': [], 'renamed': [], 'total': 0}
         rev = self._revision(commit_id)
         try:
             log_info = self._svn.log(
@@ -822,6 +816,15 @@ class SVNImplementation(M.RepositoryImplementation):
                 # svn add aaa.txt
                 # svn commit -m "Replace aaa.txt"
                 result['changed'].append(h.really_unicode(p.path))
+
+        for r in result['copied']:
+            if r['old'] in result['removed'][:]:
+                result['removed'].remove(r['old'])
+                result['copied'].remove(r)
+                result['renamed'].append(r)
+            if r['new'] in result['added']:
+                result['added'].remove(r['new'])
+
         return result
 
 Mapper.compile_all()


[17/22] allura git commit: [#7685] ticket:825 Add UI feedback for subscribe/unsubscribe actions

Posted by he...@apache.org.
[#7685] ticket:825 Add UI feedback for subscribe/unsubscribe actions


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

Branch: refs/heads/hs/7925
Commit: 6d0eb69a33b4118f27617101bf22691f68d60d20
Parents: c89213c
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Jul 22 17:10:45 2015 +0300
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Wed Jul 22 11:47:58 2015 -0400

----------------------------------------------------------------------
 .../lib/widgets/resources/js/subscriptions.js   | 56 ++++++++++++++++----
 Allura/allura/templates/widgets/subscribe.html  |  1 +
 ForgeBlog/forgeblog/main.py                     |  2 +
 .../forgediscussion/controllers/forum.py        |  1 +
 ForgeTracker/forgetracker/tracker_main.py       |  2 +
 ForgeWiki/forgewiki/wiki_main.py                |  2 +
 6 files changed, 53 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/6d0eb69a/Allura/allura/lib/widgets/resources/js/subscriptions.js
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/resources/js/subscriptions.js b/Allura/allura/lib/widgets/resources/js/subscriptions.js
index c03bbeb..d5a7648 100644
--- a/Allura/allura/lib/widgets/resources/js/subscriptions.js
+++ b/Allura/allura/lib/widgets/resources/js/subscriptions.js
@@ -23,21 +23,30 @@ var dom = React.createElement;
 var state = {
   'thing': 'tool',
   'subscribed': false,
+  'subscribed_to_tool': false,
   'url': '',
   'icon': {}
 };
 
 SubscriptionForm = React.createClass({
 
+  getInitialState: function() {
+    return {tooltip_timeout: null};
+  },
+
   render: function() {
     var action = this.props.subscribed ? "Unsubscribe from" : "Subscribe to";
     var title = action + ' this ' + this.props.thing;
     var link_opts = {
+      ref: 'link',
       className: this.props.subscribed ? 'active' : '',
       href: '#',
       title: title,
       onClick: this.handleClick
     };
+    if (this.props.in_progress) {
+      link_opts.style = {cursor: 'wait'};
+    }
     var icon_opts = {
       'data-icon': this.props.icon.char,
       className: 'ico ' + this.props.icon.css,
@@ -56,23 +65,48 @@ SubscriptionForm = React.createClass({
       data.subscribe = true;
     }
     set_state({in_progress: true});
-    /*
-     * TODO:
-     * - show 'in-progress' status to user somehow
-     * - handle errors (show to the user in some kind of popup/flash?)
-     * - If user is subscribed to the whole tool and she tries to subsribe to
-     *   the artifact she will not be subscribed, so nothing will change in the
-     *   UI and it's confusing. We need to show some information message in
-     *   such case
-     */
     $.post(url, data, function(resp) {
       if (resp.status == 'ok') {
-        set_state({subscribed: resp.subscribed});
+        set_state({
+          subscribed: resp.subscribed,
+          subscribed_to_tool: resp.subscribed_to_tool
+        });
+        var link = this.getLinkNode();
+        var text = null;
+        if (resp.subscribed_to_tool) {
+          text = "You can't subscribe to this ";
+          text += this.props.thing;
+          text += " because you are already subscribed to the entire tool";
+        } else {
+          var action = resp.subscribed ? 'subscribed to' : 'unsubscribed from';
+          text = 'Successfully ' + action + ' this ' + this.props.thing;
+        }
+        $(link).tooltipster('content', text).tooltipster('show');
+        if (this.state.tooltip_timeout) {
+          clearTimeout(this.state.tooltip_timeout);
+        }
+        var t = setTimeout(function() { $(link).tooltipster('hide'); }, 4000);
+        this.setState({tooltip_timeout: t});
       }
-    }).always(function() {
+    }.bind(this)).always(function() {
       set_state({in_progress: false});
     });
     return false;
+  },
+
+  getLinkNode: function() { return React.findDOMNode(this.refs.link); },
+
+  componentDidMount: function() {
+    var link = this.getLinkNode();
+    $(link).tooltipster({
+      content: '',
+      animation: 'fade',
+      delay: 200,
+      trigger: 'custom',
+      position: 'top',
+      iconCloning: false,
+      maxWidth: 300
+    });
   }
 
 });

http://git-wip-us.apache.org/repos/asf/allura/blob/6d0eb69a/Allura/allura/templates/widgets/subscribe.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/subscribe.html b/Allura/allura/templates/widgets/subscribe.html
index 1361a9c..2b61f71 100644
--- a/Allura/allura/templates/widgets/subscribe.html
+++ b/Allura/allura/templates/widgets/subscribe.html
@@ -31,6 +31,7 @@
   document.SUBSCRIPTION_OPTIONS = {
     "thing": "{{thing}}",
     "subscribed": {{"true" if value else "false"}},
+    "subscribed_to_tool": {{"true" if tool_subscribed else "false"}},
     "url": "{{action}}",
     "icon": {
       "char": "{{g.icons['mail'].char}}",

http://git-wip-us.apache.org/repos/asf/allura/blob/6d0eb69a/ForgeBlog/forgeblog/main.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index adfc172..b4f4641 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -323,6 +323,7 @@ class PostController(BaseController, FeedController):
         post = self._get_version(version)
         base_post = self.post
         subscribed = M.Mailbox.subscribed(artifact=self.post)
+        c.subscribe_form.tool_subscribed = M.Mailbox.subscribed()
         return dict(post=post, base_post=base_post,
                     page=page, limit=limit, count=post_count,
                     subscribed=subscribed)
@@ -388,6 +389,7 @@ class PostController(BaseController, FeedController):
         return {
             'status': 'ok',
             'subscribed': M.Mailbox.subscribed(artifact=self.post),
+            'subscribed_to_tool': M.Mailbox.subscribed(),
         }
 
     def get_feed(self, project, app, user):

http://git-wip-us.apache.org/repos/asf/allura/blob/6d0eb69a/ForgeDiscussion/forgediscussion/controllers/forum.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/controllers/forum.py b/ForgeDiscussion/forgediscussion/controllers/forum.py
index b915823..8d0117d 100644
--- a/ForgeDiscussion/forgediscussion/controllers/forum.py
+++ b/ForgeDiscussion/forgediscussion/controllers/forum.py
@@ -133,6 +133,7 @@ class ForumController(DiscussionController):
         return {
             'status': 'ok',
             'subscribed': M.Mailbox.subscribed(artifact=self.discussion),
+            'subscribed_to_tool': M.Mailbox.subscribed(),
         }
 
 

http://git-wip-us.apache.org/repos/asf/allura/blob/6d0eb69a/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 0049957..ddf570d 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -1359,6 +1359,7 @@ class TicketController(BaseController, FeedController):
             c.ticket_custom_field = W.ticket_custom_field
             c.vote_form = W.vote_form
             tool_subscribed = M.Mailbox.subscribed()
+            c.subscribe_form.tool_subscribed = tool_subscribed
             if tool_subscribed:
                 subscribed = False
             else:
@@ -1534,6 +1535,7 @@ class TicketController(BaseController, FeedController):
         return {
             'status': 'ok',
             'subscribed': M.Mailbox.subscribed(artifact=self.ticket),
+            'subscribed_to_tool': M.Mailbox.subscribed(),
         }
 
     @expose('json:')

http://git-wip-us.apache.org/repos/asf/allura/blob/6d0eb69a/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index 9fca1c2..513b1e2 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -558,6 +558,7 @@ class PageController(BaseController, FeedController):
         next = cur + 1
         hide_left_bar = not (c.app.show_left_bar)
         subscribed_to_page = M.Mailbox.subscribed(artifact=self.page)
+        c.subscribe_form.tool_subscribed = M.Mailbox.subscribed()
         return dict(
             page=page,
             cur=cur, prev=prev, next=next,
@@ -750,6 +751,7 @@ class PageController(BaseController, FeedController):
         return {
             'status': 'ok',
             'subscribed': M.Mailbox.subscribed(artifact=self.page),
+            'subscribed_to_tool': M.Mailbox.subscribed(),
         }
 
 


[03/22] allura git commit: [#7927] strengthen / document tests a bit

Posted by he...@apache.org.
[#7927] strengthen / document tests a bit


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

Branch: refs/heads/hs/7925
Commit: bbeebdbb9a3059f1c4595203967e2dbb6bd3a7a6
Parents: 82a3642
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Jul 21 17:43:23 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 21 17:44:31 2015 +0000

----------------------------------------------------------------------
 Allura/allura/tests/functional/test_rest.py | 18 ++++++++++++++++++
 Allura/allura/tests/test_middlewares.py     |  1 +
 2 files changed, 19 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/bbeebdbb/Allura/allura/tests/functional/test_rest.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_rest.py b/Allura/allura/tests/functional/test_rest.py
index 3fed49c..903cda7 100644
--- a/Allura/allura/tests/functional/test_rest.py
+++ b/Allura/allura/tests/functional/test_rest.py
@@ -353,6 +353,24 @@ class TestRestHome(TestRestApiBase):
             r = self.api_get('/rest/p/test/')
             assert r.status_int == 404
 
+    @td.with_wiki
+    def test_cors_POST_req_blocked_by_csrf(self):
+        # so test-admin isn't automatically logged in for all requests
+        self.app.extra_environ = {'disable_auth_magic': 'True'}
+
+        # regular login to get a session cookie set up
+        r = self.app.get('/auth/')
+        r.form['username'] = 'test-admin'
+        r.form['password'] = 'foo'
+        r.form.submit()
+
+        # simulate CORS ajax request withCredentials (cookie headers)
+        # make sure we don't allow the cookies to authorize the request (else could be a CSRF attack vector)
+        assert self.app.cookies['allura']
+        self.app.post('/rest/p/test/wiki/NewPage', headers={'Origin': 'http://bad.com/'},
+                      status=401)
+
+
 class TestDoap(TestRestApiBase):
     validate_skip = True
     ns = '{http://usefulinc.com/ns/doap#}'

http://git-wip-us.apache.org/repos/asf/allura/blob/bbeebdbb/Allura/allura/tests/test_middlewares.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_middlewares.py b/Allura/allura/tests/test_middlewares.py
index 4b45097..58dc515 100644
--- a/Allura/allura/tests/test_middlewares.py
+++ b/Allura/allura/tests/test_middlewares.py
@@ -77,6 +77,7 @@ class TestCORSMiddleware(object):
         exc.HTTPOk.return_value.assert_called_once_with(env, callback)
 
     def test_get_response_headers_simple(self):
+        # Allow-Origin: * is crucial for security, since that prevents browsers from exposing results fetched withCredentials: true (aka cookies)
         assert_equal(self.cors.get_response_headers(),
                      [('Access-Control-Allow-Origin', '*')])
         assert_equal(self.cors.get_response_headers(preflight=False),


[13/22] allura git commit: [#7685] ticket:802 Added @with_trailing_slash to discussion thread controller

Posted by he...@apache.org.
[#7685] ticket:802 Added @with_trailing_slash to discussion thread controller


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

Branch: refs/heads/hs/7925
Commit: dada202ff032b97f3d43ffc17eaa3d5f90ff1080
Parents: e2cd5f6
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Thu Jul 2 16:32:16 2015 +0300
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Wed Jul 22 11:47:57 2015 -0400

----------------------------------------------------------------------
 Allura/allura/controllers/discuss.py | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/dada202f/Allura/allura/controllers/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index 28cfcb6..13fe436 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -20,6 +20,7 @@ from datetime import datetime
 import logging
 
 from tg import expose, redirect, validate, request, flash
+from tg.decorators import with_trailing_slash
 from pylons import tmpl_context as c, app_globals as g
 from webob import exc
 
@@ -182,6 +183,7 @@ class ThreadController(BaseController, FeedController):
         id = unquote(id)
         return self.PostController(self._discussion_controller, self.thread, id), remainder
 
+    @with_trailing_slash
     @expose('jinja:allura:templates/discussion/thread.html')
     def index(self, limit=None, page=0, count=0, **kw):
         c.thread = self.W.thread


[14/22] allura git commit: [#7685] ticket:802 Use post in SCM subscription test and fix format call

Posted by he...@apache.org.
[#7685] ticket:802 Use post in SCM subscription test and fix format call


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

Branch: refs/heads/hs/7925
Commit: eb5f3d6ce3297d6ad58d1133670b67df50f76a9d
Parents: dada202
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jul 3 12:45:13 2015 +0300
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Wed Jul 22 11:47:57 2015 -0400

----------------------------------------------------------------------
 .../forgegit/tests/functional/test_controllers.py   | 16 +++++++++-------
 ForgeWiki/forgewiki/wiki_main.py                    |  2 +-
 2 files changed, 10 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/eb5f3d6c/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 b84cd5a..20bfc1b 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -353,24 +353,26 @@ class TestRootController(_TestCase):
         assert link is not None, r.html
 
         # subscribe
-        self.app.get(ci + 'tree/subscribe?subscribe=True',
-                     extra_environ={'username': str(user.username)}).follow()
+        self.app.post(str(ci + 'tree/subscribe'),
+                      {'subscribe': True},
+                      extra_environ={'username': str(user.username)}).follow()
         # user is subscribed
         assert M.Mailbox.subscribed(user_id=user._id)
         r = self.app.get(ci + 'tree/',
                          extra_environ={'username': str(user.username)})
-        link = r.html.find('a', 'artifact_unsubscribe active')
-        assert link is not None, r.html
+        inp = r.html.find('input', {'type': 'hidden', 'name': 'unsubscribe'})
+        assert inp is not None
 
         # unsubscribe
-        self.app.get(ci + 'tree/subscribe?unsubscribe=True',
+        self.app.post(str(ci + 'tree/subscribe'),
+                     {'unsubscribe': True},
                      extra_environ={'username': str(user.username)}).follow()
         # user is not subscribed
         assert not M.Mailbox.subscribed(user_id=user._id)
         r = self.app.get(ci + 'tree/',
                          extra_environ={'username': str(user.username)})
-        link = r.html.find('a', 'artifact_subscribe')
-        assert link is not None, r.html
+        inp = r.html.find('input', {'type': 'hidden', 'name': 'subscribe'})
+        assert inp is not None
 
     def test_timezone(self):
         ci = self._get_ci()

http://git-wip-us.apache.org/repos/asf/allura/blob/eb5f3d6c/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index c2bcb16..229a348 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -249,7 +249,7 @@ The wiki uses [Markdown](%s) syntax.
             subscribe_title = '{}{}'.format(
                 subscribe_action.capitalize(),
                 '' if subscribed else ' to wiki')
-            subscribe_url = '#toggle-subscribe'.format(self.url)
+            subscribe_url = '{}#toggle-subscribe'.format(self.url)
             links += [SitemapEntry(''),
                       SitemapEntry(subscribe_title, subscribe_url, ui_icon=g.icons['mail'])]
         if not admin_menu:


[16/22] allura git commit: [#7685] ticket:819 Fix tests failing due to new markup

Posted by he...@apache.org.
[#7685] ticket:819 Fix tests failing due to new markup


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

Branch: refs/heads/hs/7925
Commit: c89213cb741a860f6e3ed95fc5bb01781228917f
Parents: a5227e2
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon Jul 13 12:32:15 2015 +0300
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Wed Jul 22 11:47:58 2015 -0400

----------------------------------------------------------------------
 AlluraTest/alluratest/controller.py             | 16 ++++++++++++
 .../tests/functional/test_controllers.py        | 26 +++++++++++---------
 .../forgetracker/tests/functional/test_root.py  | 25 ++++++++++---------
 .../forgewiki/tests/functional/test_rest.py     |  2 +-
 .../forgewiki/tests/functional/test_root.py     |  2 --
 5 files changed, 44 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/c89213cb/AlluraTest/alluratest/controller.py
----------------------------------------------------------------------
diff --git a/AlluraTest/alluratest/controller.py b/AlluraTest/alluratest/controller.py
index 4a8f983..5a61ab7 100644
--- a/AlluraTest/alluratest/controller.py
+++ b/AlluraTest/alluratest/controller.py
@@ -18,6 +18,7 @@
 """Unit and functional test suite for allura."""
 import os
 import urllib
+import json
 
 import mock
 import beaker.session
@@ -169,6 +170,21 @@ class TestController(object):
         "Extract webflash content from response."
         return urllib.unquote(response.cookies_set.get('webflash', ''))
 
+    def subscription_options(self, response):
+        """
+        Extract subscription options to be passed to React SubscriptionForm
+        component from the <script> tag
+        """
+        script = None
+        for s in response.html.findAll('script'):
+            if s.getText().strip().startswith('document.SUBSCRIPTION_OPTIONS'):
+                script = s
+                break
+        assert script is not None, 'subscription options not found'
+        _, json_dict = script.getText().split('=')
+        json_dict = json_dict.strip(' ;')
+        return json.loads(json_dict)
+
 
 class TestRestApiBase(TestController):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/c89213cb/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 20bfc1b..7f6bf88 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -349,30 +349,32 @@ class TestRootController(_TestCase):
         assert not M.Mailbox.subscribed(user_id=user._id)
         r = self.app.get(ci + 'tree/',
                          extra_environ={'username': str(user.username)})
-        link = r.html.find('a', 'artifact_subscribe')
-        assert link is not None, r.html
+        opts = self.subscription_options(r)
+        assert_equal(opts['subscribed'], False)
 
         # subscribe
-        self.app.post(str(ci + 'tree/subscribe'),
-                      {'subscribe': True},
-                      extra_environ={'username': str(user.username)}).follow()
+        r = self.app.post(str(ci + 'tree/subscribe'),
+                          {'subscribe': True},
+                          extra_environ={'username': str(user.username)})
+        assert_equal(r.json, {'status': 'ok', 'subscribed': True})
         # user is subscribed
         assert M.Mailbox.subscribed(user_id=user._id)
         r = self.app.get(ci + 'tree/',
                          extra_environ={'username': str(user.username)})
-        inp = r.html.find('input', {'type': 'hidden', 'name': 'unsubscribe'})
-        assert inp is not None
+        opts = self.subscription_options(r)
+        assert_equal(opts['subscribed'], True)
 
         # unsubscribe
-        self.app.post(str(ci + 'tree/subscribe'),
-                     {'unsubscribe': True},
-                     extra_environ={'username': str(user.username)}).follow()
+        r = self.app.post(str(ci + 'tree/subscribe'),
+                          {'unsubscribe': True},
+                          extra_environ={'username': str(user.username)})
+        assert_equal(r.json, {'status': 'ok', 'subscribed': False})
         # user is not subscribed
         assert not M.Mailbox.subscribed(user_id=user._id)
         r = self.app.get(ci + 'tree/',
                          extra_environ={'username': str(user.username)})
-        inp = r.html.find('input', {'type': 'hidden', 'name': 'subscribe'})
-        assert inp is not None
+        opts = self.subscription_options(r)
+        assert_equal(opts['subscribed'], False)
 
     def test_timezone(self):
         ci = self._get_ci()

http://git-wip-us.apache.org/repos/asf/allura/blob/c89213cb/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 23c77f4..de061ca 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -294,7 +294,8 @@ class TestFunctionalController(TrackerTestController):
         summary = 'test new ticket'
         ticket_view = self.new_ticket(summary=summary).follow()
         assert_true(summary in ticket_view)
-        assert 'class="artifact_subscribe' in ticket_view
+        opts = self.subscription_options(ticket_view)
+        assert_equal(opts['subscribed'], False)
 
     def test_labels(self):
         ticket_view = self.new_ticket(summary='summary', labels="test label").follow()
@@ -840,7 +841,7 @@ class TestFunctionalController(TrackerTestController):
         }, upload_files=[upload]).follow()
         assert file_name in ticket_editor, ticket_editor.showbrowser()
         req = self.app.get('/bugs/1/')
-        file_link = req.html.findAll('form')[2].findAll('a')[6]
+        file_link = req.html.findAll('form')[1].findAll('a')[6]
         assert_equal(file_link.string, file_name)
         self.app.post(str(file_link['href']), {
             'delete': 'True'
@@ -882,7 +883,7 @@ class TestFunctionalController(TrackerTestController):
         ticket_editor = self.app.post('/bugs/1/update_ticket', {
             'summary': 'zzz'
         }, upload_files=[upload]).follow()
-        download = self.app.get(str(ticket_editor.html.findAll('form')[2].findAll('a')[7]['href']))
+        download = self.app.get(str(ticket_editor.html.findAll('form')[1].findAll('a')[7]['href']))
         assert_equal(download.body, file_data)
 
     def test_two_attachments(self):
@@ -1239,7 +1240,7 @@ class TestFunctionalController(TrackerTestController):
         # Test edit ticket form
         self.new_ticket(summary='Test ticket')
         response = self.app.get('/bugs/1/')
-        form = response.forms[2]
+        form = response.forms[1]
         assert_equal(
             form['ticket_form.custom_fields._priority'].value, 'normal')
         assert_equal(form['ticket_form.custom_fields._category'].value, '')
@@ -1247,9 +1248,9 @@ class TestFunctionalController(TrackerTestController):
         form['ticket_form.custom_fields._priority'] = 'urgent'
         form['ticket_form.custom_fields._category'] = 'bugs'
         error_form = form.submit()
-        assert_equal(error_form.forms[2]['ticket_form.custom_fields._priority'].value,
+        assert_equal(error_form.forms[1]['ticket_form.custom_fields._priority'].value,
                      'urgent')
-        assert_equal(error_form.forms[2]['ticket_form.custom_fields._category'].value,
+        assert_equal(error_form.forms[1]['ticket_form.custom_fields._category'].value,
                      'bugs')
 
     def test_new_ticket_validation(self):
@@ -1269,7 +1270,7 @@ class TestFunctionalController(TrackerTestController):
         # set a summary, submit, and check for success
         error_form.forms[1]['ticket_form.summary'] = summary
         success = error_form.forms[1].submit().follow().html
-        assert success.findAll('form')[2].get('action') == '/p/test/bugs/1/update_ticket_from_widget'
+        assert success.findAll('form')[1].get('action') == '/p/test/bugs/1/update_ticket_from_widget'
         assert success.find('input', {'name': 'ticket_form.summary'})['value'] == summary
 
     def test_edit_ticket_validation(self):
@@ -1280,7 +1281,7 @@ class TestFunctionalController(TrackerTestController):
         # check that existing form is valid
         assert response.html.find('input', {'name': 'ticket_form.summary'})['value'] == old_summary
         assert not response.html.find('div', {'class': 'error'})
-        form = response.forms[2]
+        form = response.forms[1]
         # try submitting with no summary set and check for error message
         form['ticket_form.summary'] = ""
         error_form = form.submit()
@@ -1289,11 +1290,11 @@ class TestFunctionalController(TrackerTestController):
         assert error_message.string == 'You must provide a Title'
         assert error_message.findPreviousSibling('input').get('name') == 'ticket_form.summary'
         # set a summary, submit, and check for success
-        error_form.forms[2]['ticket_form.summary'] = new_summary
-        r = error_form.forms[2].submit()
+        error_form.forms[1]['ticket_form.summary'] = new_summary
+        r = error_form.forms[1].submit()
         assert r.status_int == 302, r.showbrowser()
         success = r.follow().html
-        assert success.findAll('form')[2].get('action') == '/p/test/bugs/1/update_ticket_from_widget'
+        assert success.findAll('form')[1].get('action') == '/p/test/bugs/1/update_ticket_from_widget'
         assert success.find('input', {'name': 'ticket_form.summary'})['value'] == new_summary
 
     def test_home(self):
@@ -2720,7 +2721,7 @@ class TestCustomUserField(TrackerTestController):
     def test_change_user_field(self):
         kw = {'custom_fields._code_review': ''}
         r = self.new_ticket(summary='test custom fields', **kw).follow()
-        f = r.forms[2]
+        f = r.forms[1]
         # Populate ProjectUserCombo's select with option we want.
         # This is a workaround for tests,
         # in real enviroment this is populated via ajax.

http://git-wip-us.apache.org/repos/asf/allura/blob/c89213cb/ForgeWiki/forgewiki/tests/functional/test_rest.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/tests/functional/test_rest.py b/ForgeWiki/forgewiki/tests/functional/test_rest.py
index a2b58ae..6a5de3b 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_rest.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_rest.py
@@ -42,7 +42,7 @@ class TestWikiApi(TestRestApiBase):
 
     def test_get_page(self):
         r = self.app.get('/p/test/wiki/Home/')
-        discussion_url = r.html.findAll('form')[3]['action'][:-4]
+        discussion_url = r.html.findAll('form')[2]['action'][:-4]
         content = file(__file__).read()
         self.app.post('/wiki/Home/attach',
                       upload_files=[('file_info', 'test_root.py', content)])

http://git-wip-us.apache.org/repos/asf/allura/blob/c89213cb/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 dafb74f..3f69d89 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_root.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_root.py
@@ -258,8 +258,6 @@ class TestRootController(TestController):
                 'labels': '',
                 'viewable_by-0.id': 'all'})
         self.app.post('/wiki/tést/revert', params=dict(version='1'))
-        response = self.app.get('/wiki/tést/')
-        assert 'Subscribe' in response
         response = self.app.get('/wiki/tést/diff?v1=0&v2=0')
         assert 'tést' in response
         d = dict(title='testdiff', text="""**Optionally**, you may also want to remove all the unused accounts that have accumulated (one was created for *every* logged in SF-user who has visited your MediaWiki hosted app):


[06/22] allura git commit: [#7932] Fix pagination issue in the commit browser

Posted by he...@apache.org.
[#7932] Fix pagination issue in the commit browser


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

Branch: refs/heads/hs/7925
Commit: 30173000e217fe5756aa9aff34c372ac1db0b4b7
Parents: bbeebdb
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Thu Jul 16 15:13:33 2015 -0400
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 21 20:25:39 2015 +0000

----------------------------------------------------------------------
 ForgeGit/forgegit/model/git_repo.py | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/30173000/ForgeGit/forgegit/model/git_repo.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/model/git_repo.py b/ForgeGit/forgegit/model/git_repo.py
index 7d87a09..9549fa6 100644
--- a/ForgeGit/forgegit/model/git_repo.py
+++ b/ForgeGit/forgegit/model/git_repo.py
@@ -652,13 +652,14 @@ class GitImplementation(M.RepositoryImplementation):
             # relies on this)
             '-t',
             '-z',  # don't escape filenames and use \x00 as fields delimiter
-            commit_id)
-        files = files.split('\x00')[:-1]
-        # files = ['A', 'filename', 'D', 'another filename', ...]
+            commit_id).split('\x00')[:-1]
+
         total = len(files) / 2
-        for i in range(1, len(files), 2):
-            status = files[i-1]
-            name = h.really_unicode(files[i])
+        files = [(files[i], h.really_unicode(files[i+1]))
+                 for i in xrange(0, len(files), 2)]
+
+        # files = [('A', u'filename'), ('D', u'another filename'), ...]
+        for status, name in files[start:end]:
             if status == 'A':
                 added.append(name)
             elif status == 'D':


[02/22] allura git commit: [#7927] ticket:821 Add tests for CORSMiddleware

Posted by he...@apache.org.
[#7927] ticket:821 Add tests for CORSMiddleware


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

Branch: refs/heads/hs/7925
Commit: 6625703b123d070d813f6ddf0dce05de729e15b2
Parents: 0c71798
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Jul 16 18:01:13 2015 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Jul 16 18:01:13 2015 +0300

----------------------------------------------------------------------
 Allura/allura/tests/test_middlewares.py | 106 +++++++++++++++++++++++++++
 1 file changed, 106 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/6625703b/Allura/allura/tests/test_middlewares.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_middlewares.py b/Allura/allura/tests/test_middlewares.py
new file mode 100644
index 0000000..1ca6d8a
--- /dev/null
+++ b/Allura/allura/tests/test_middlewares.py
@@ -0,0 +1,106 @@
+#       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 mock import MagicMock, patch
+from datadiff.tools import assert_equal
+from nose.tools import assert_not_equal
+from allura.lib.custom_middleware import CORSMiddleware
+
+
+class TestCORSMiddleware(object):
+
+    def setUp(self):
+        self.app = MagicMock()
+        self.allowed_methods = ['GET', 'POST', 'DELETE']
+        self.allowed_headers = ['Authorization', 'Accept']
+        self.cors = CORSMiddleware(
+            self.app,
+            self.allowed_methods,
+            self.allowed_headers)
+
+    def test_init(self):
+        cors = CORSMiddleware(self.app, ['get', 'post'], ['Some-Header'])
+        assert_equal(cors.app, self.app)
+        assert_equal(cors.allowed_methods, ['GET', 'POST'])
+        assert_equal(cors.allowed_headers, set(['some-header']))
+
+    def test_call_not_api_request(self):
+        callback = MagicMock()
+        env = {'PATH_INFO': '/p/test/'}
+        self.cors(env, callback)
+        self.app.assert_called_once_with(env, callback)
+
+    def test_call_invalid_cors(self):
+        callback = MagicMock()
+        env = {'PATH_INFO': '/rest/p/test/'}
+        self.cors(env, callback)
+        self.app.assert_called_once_with(env, callback)
+
+    def test_handle_call_simple_request(self):
+        callback = MagicMock()
+        env = {'PATH_INFO': '/rest/p/test/',
+               'HTTP_ORIGIN': 'my.site.com',
+               'REQUEST_METHOD': 'GET'}
+        self.cors(env, callback)
+        assert_equal(self.app.call_count, 1)
+        assert_equal(self.app.call_args_list[0][0][0], env)
+        assert_not_equal(self.app.call_args_list[0][0][1], callback)
+
+    @patch('allura.lib.custom_middleware.exc', autospec=True)
+    def test_handle_call_preflight_request(self, exc):
+        callback = MagicMock()
+        env = {'PATH_INFO': '/rest/p/test/',
+               'HTTP_ORIGIN': 'my.site.com',
+               'REQUEST_METHOD': 'OPTIONS',
+               'HTTP_ACCESS_CONTROL_REQUEST_METHOD': 'POST'}
+        self.cors(env, callback)
+        assert_equal(self.app.call_count, 0)
+        exc.HTTPOk.assert_called_once_with(headers=[
+            ('Access-Control-Allow-Origin', '*'),
+            ('Access-Control-Allow-Methods', 'GET, POST, DELETE'),
+            ('Access-Control-Allow-Headers', 'accept, authorization')
+        ])
+        exc.HTTPOk.return_value.assert_called_once_with(env, callback)
+
+    def test_get_response_headers_simple(self):
+        assert_equal(self.cors.get_response_headers(),
+                     [('Access-Control-Allow-Origin', '*')])
+        assert_equal(self.cors.get_response_headers(preflight=False),
+                     [('Access-Control-Allow-Origin', '*')])
+
+    def test_get_response_headers_preflight(self):
+        assert_equal(
+            self.cors.get_response_headers(preflight=True),
+            [('Access-Control-Allow-Origin', '*'),
+             ('Access-Control-Allow-Methods', 'GET, POST, DELETE'),
+             ('Access-Control-Allow-Headers', 'accept, authorization')])
+
+    def test_get_response_headers_preflight_with_cache(self):
+        cors = CORSMiddleware(self.app, ['GET', 'PUT'], ['Accept'], 86400)
+        assert_equal(cors.get_response_headers(preflight=True),
+                     [('Access-Control-Allow-Origin', '*'),
+                      ('Access-Control-Allow-Methods', 'GET, PUT'),
+                      ('Access-Control-Allow-Headers', 'accept'),
+                      ('Access-Control-Max-Age', 86400)])
+
+    def test_get_access_control_request_headers(self):
+        key = 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS'
+        f = self.cors.get_access_control_request_headers
+        assert_equal(f({}), set())
+        assert_equal(f({key: ''}), set())
+        assert_equal(f({key: 'Authorization, Accept'}),
+                     set(['authorization', 'accept']))


[12/22] allura git commit: [#7685] ticket:802 Require POST for repository subscription

Posted by he...@apache.org.
[#7685] ticket:802 Require POST for repository subscription


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

Branch: refs/heads/hs/7925
Commit: 4b76e4cdfc60518d75e5945bb2bd16ef829c6cc2
Parents: 55c7b48
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Thu Jul 2 14:29:12 2015 +0300
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Wed Jul 22 11:47:57 2015 -0400

----------------------------------------------------------------------
 Allura/allura/controllers/repository.py | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/4b76e4cd/Allura/allura/controllers/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index f8b0834..0178723 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -689,6 +689,7 @@ class TreeBrowser(BaseController, DispatchIndex):
             self), rest
 
     @expose()
+    @require_post()
     @validate(subscribe_form)
     def subscribe(self, subscribe=None, unsubscribe=None, **kw):
         if subscribe:


[04/22] allura git commit: [#7927] pass cache setting through; use str in headers

Posted by he...@apache.org.
[#7927] pass cache setting through; use str in headers


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

Branch: refs/heads/hs/7925
Commit: 82a3642b3c36839e7fcbbc9ebce43fad4eb6a531
Parents: 6625703
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Jul 21 17:42:55 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 21 17:44:31 2015 +0000

----------------------------------------------------------------------
 Allura/allura/config/middleware.py      | 2 +-
 Allura/allura/lib/custom_middleware.py  | 2 +-
 Allura/allura/tests/test_middlewares.py | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/82a3642b/Allura/allura/config/middleware.py
----------------------------------------------------------------------
diff --git a/Allura/allura/config/middleware.py b/Allura/allura/config/middleware.py
index 922034d..6c39d4b 100644
--- a/Allura/allura/config/middleware.py
+++ b/Allura/allura/config/middleware.py
@@ -143,7 +143,7 @@ def _make_core_app(root, global_conf, full_stack=True, **app_conf):
         allowed_methods = aslist(config.get('cors.methods'))
         allowed_headers = aslist(config.get('cors.headers'))
         cache_duration = asint(config.get('cors.cache_duration', 0))
-        app = CORSMiddleware(app, allowed_methods, allowed_headers)
+        app = CORSMiddleware(app, allowed_methods, allowed_headers, cache_duration)
     # Setup the allura SOPs
     app = allura_globals_middleware(app)
     # Ensure http and https used per config

http://git-wip-us.apache.org/repos/asf/allura/blob/82a3642b/Allura/allura/lib/custom_middleware.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/custom_middleware.py b/Allura/allura/lib/custom_middleware.py
index 4eef689..e56a530 100644
--- a/Allura/allura/lib/custom_middleware.py
+++ b/Allura/allura/lib/custom_middleware.py
@@ -133,7 +133,7 @@ class CORSMiddleware(object):
             ])
             if self.cache_preflight:
                 headers.append(
-                    ('Access-Control-Max-Age', self.cache_preflight)
+                    ('Access-Control-Max-Age', str(self.cache_preflight))
                 )
         return headers
 

http://git-wip-us.apache.org/repos/asf/allura/blob/82a3642b/Allura/allura/tests/test_middlewares.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_middlewares.py b/Allura/allura/tests/test_middlewares.py
index 1ca6d8a..4b45097 100644
--- a/Allura/allura/tests/test_middlewares.py
+++ b/Allura/allura/tests/test_middlewares.py
@@ -95,7 +95,7 @@ class TestCORSMiddleware(object):
                      [('Access-Control-Allow-Origin', '*'),
                       ('Access-Control-Allow-Methods', 'GET, PUT'),
                       ('Access-Control-Allow-Headers', 'accept'),
-                      ('Access-Control-Max-Age', 86400)])
+                      ('Access-Control-Max-Age', '86400')])
 
     def test_get_access_control_request_headers(self):
         key = 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS'


[11/22] allura git commit: [#7685] ticket:802 Fixed subscription to whole wiki

Posted by he...@apache.org.
[#7685] ticket:802 Fixed subscription to whole wiki


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

Branch: refs/heads/hs/7925
Commit: e2cd5f60a02c3780cdf66228a22380d01724b7e5
Parents: 4b76e4c
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Thu Jul 2 16:26:09 2015 +0300
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Wed Jul 22 11:47:57 2015 -0400

----------------------------------------------------------------------
 ForgeWiki/forgewiki/templates/wiki/page_view.html | 12 +++++++++++-
 ForgeWiki/forgewiki/wiki_main.py                  |  4 +++-
 2 files changed, 14 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e2cd5f60/ForgeWiki/forgewiki/templates/wiki/page_view.html
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/templates/wiki/page_view.html b/ForgeWiki/forgewiki/templates/wiki/page_view.html
index 7289f23..7a6135e 100644
--- a/ForgeWiki/forgewiki/templates/wiki/page_view.html
+++ b/ForgeWiki/forgewiki/templates/wiki/page_view.html
@@ -116,12 +116,22 @@
       {% endif %}
   {% endif %}
   {{c.confirmation.display(content='')}}
+  {% if not c.user.is_anonymous() %}
+    <form action="{{c.app.url}}subscribe" id="wiki_subscribe_form" style="display:none;" method="POST">
+      {{lib.csrf_token()}}
+      {% if c.subscribed %}
+        <input type="hidden" name="unsubscribe" value="1">
+      {% else %}
+        <input type="hidden" name="subscribe" value="1">
+      {% endif %}
+    </form>
+  {% endif %}
 {% endblock %}
 
 {% block wiki_extra_js %}
   <script type="text/javascript">
     $('a[href$="#toggle-subscribe"]').click(function() {
-      $('#subscribe_form').submit();
+      $('#wiki_subscribe_form').submit();
       return false;
     })
   </script>

http://git-wip-us.apache.org/repos/asf/allura/blob/e2cd5f60/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index 229b217..c2bcb16 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -249,7 +249,7 @@ The wiki uses [Markdown](%s) syntax.
             subscribe_title = '{}{}'.format(
                 subscribe_action.capitalize(),
                 '' if subscribed else ' to wiki')
-            subscribe_url = '{}#toggle-subscribe'.format(self.url, subscribe_action)
+            subscribe_url = '#toggle-subscribe'.format(self.url)
             links += [SitemapEntry(''),
                       SitemapEntry(subscribe_title, subscribe_url, ui_icon=g.icons['mail'])]
         if not admin_menu:
@@ -483,6 +483,8 @@ class PageController(BaseController, FeedController):
         if self.page is not None:
             self.attachment = WikiAttachmentsController(self.page)
         c.create_page_lightbox = W.create_page_lightbox
+        if not c.user.is_anonymous():
+            c.subscribed = M.Mailbox.subscribed()
 
     def _check_security(self):
         if self.page:


[19/22] allura git commit: [#7925] Improve binary file detection

Posted by he...@apache.org.
[#7925] Improve binary file detection


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

Branch: refs/heads/hs/7925
Commit: 7947ef537e763d7d0d98a13d32566fb106814c70
Parents: cfe570b
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Mon Jul 27 15:58:59 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Jul 27 15:58:59 2015 -0400

----------------------------------------------------------------------
 Allura/allura/model/repository.py | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/7947ef53/Allura/allura/model/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repository.py b/Allura/allura/model/repository.py
index 7bc36c1..5fe2ba9 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -77,11 +77,21 @@ SObjType = S.OneOf('blob', 'tree', 'submodule')
 
 # Used for when we're going to batch queries using $in
 QSIZE = 100
-README_RE = re.compile('^README(\.[^.]*)?$', re.IGNORECASE)
-VIEWABLE_EXTENSIONS = [
-    '.php', '.py', '.js', '.java', '.html', '.htm', '.yaml', '.sh',
-    '.rb', '.phtml', '.txt', '.bat', '.ps1', '.xhtml', '.css', '.cfm', '.jsp', '.jspx',
-    '.pl', '.php4', '.php3', '.rhtml', '.svg', '.markdown', '.json', '.ini', '.tcl', '.vbs', '.xsl']
+BINARY_EXTENSIONS = [
+    "3ds", "3g2", "3gp", "7z", "a", "aac", "adp", "ai", "aif", "apk", "ar", "asf", "au", "avi",
+    "bak", "bin", "bk", "bmp", "btif", "bz2", "cab", "caf", "cgm", "cmx", "cpio", "cr2", "dat", "deb", "djvu", "dll",
+    "dmg", "dng", "doc", "docx", "dra", "DS_Store", "dsk", "dts", "dtshd", "dvb", "dwg", "dxf", "ecelp4800",
+    "ecelp7470", "ecelp9600", "egg", "eol", "eot", "epub", "exe", "f4v", "fbs", "fh", "fla", "flac", "fli", "flv",
+    "fpx", "fst", "fvt", "g3", "gif", "gz", "h261", "h263", "h264", "ico", "ief", "img", "ipa", "iso", "jar", "jpeg",
+    "jpg", "jpgv", "jpm", "jxr", "ktx", "lvp", "lz", "lzma", "lzo", "m3u", "m4a", "m4v", "mar", "mdi", "mid", "mj2",
+    "mka", "mkv", "mmr", "mng", "mov", "movie", "mp3", "mp4", "mp4a", "mpeg", "mpg", "mpga", "mxu", "nef", "npx", "o",
+    "oga", "ogg", "ogv", "otf", "pbm", "pcx", "pdf", "pea", "pgm", "pic", "png", "pnm", "ppm", "psd", "pya", "pyc",
+    "pyo", "pyv", "qt", "rar", "ras", "raw", "rgb", "rip", "rlc", "rz", "s3m", "s7z", "scpt", "sgi", "shar", "sil",
+    "smv", "so", "sub", "swf", "tar", "tbz2", "tga", "tgz", "tif", "tiff", "tlz", "ts", "ttf", "uvh", "uvi", "uvm",
+    "uvp", "uvs", "uvu", "viv", "vob", "war", "wav", "wax", "wbmp", "wdp", "weba", "webm", "webp", "whl", "wm", "wma",
+    "wmv", "wmx", "woff", "woff2", "wvx", "xbm", "xif", "xm", "xpi", "xpm", "xwd", "xz", "z", "zip", "zipx"
+]
+
 PYPELINE_EXTENSIONS = utils.MARKDOWN_EXTENSIONS + ['.rst']
 
 DIFF_SIMILARITY_THRESHOLD = .5  # used for determining file renames
@@ -1520,12 +1530,6 @@ class Blob(object):
         return self._content_type_encoding[0]
 
     @LazyProperty
-    def is_text(self):
-        """Return true if this blob is text."""
-
-        return self.content_type.startswith("text")
-
-    @LazyProperty
     def content_encoding(self):
         return self._content_type_encoding[1]
 
@@ -1535,8 +1539,10 @@ class Blob(object):
             return True
         return False
 
-    @property
+    @LazyProperty
     def has_html_view(self):
+        if self.extension in BINARY_EXTENSIONS:
+            return False
         if (self.content_type.startswith('text/') or
                 self.extension in VIEWABLE_EXTENSIONS or
                 self.extension in PYPELINE_EXTENSIONS or


[15/22] allura git commit: [#7685] ticket:802 Add trailing slash to discussion controller

Posted by he...@apache.org.
[#7685] ticket:802 Add trailing slash to discussion controller


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

Branch: refs/heads/hs/7925
Commit: 63dbb3dfadabf1b5dff1d5feecf426c56e963576
Parents: eb5f3d6
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jul 3 12:53:50 2015 +0300
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Wed Jul 22 11:47:57 2015 -0400

----------------------------------------------------------------------
 Allura/allura/controllers/discuss.py | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/63dbb3df/Allura/allura/controllers/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index 13fe436..b329b01 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -89,6 +89,7 @@ class DiscussionController(BaseController, FeedController):
         if not hasattr(self, 'moderate'):
             self.moderate = ModerationController(self)
 
+    @with_trailing_slash
     @expose('jinja:allura:templates/discussion/index.html')
     def index(self, threads=None, limit=None, page=0, count=0, **kw):
         c.discussion = self.W.discussion


[18/22] allura git commit: [#7925] Speed up diff processing on commit browser page

Posted by he...@apache.org.
[#7925] Speed up diff processing on commit browser page


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

Branch: refs/heads/hs/7925
Commit: cfe570b366f2f2f3fbbcc8fccc834fa147db76a7
Parents: 6d0eb69
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Thu Jul 16 15:02:55 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Wed Jul 22 16:22:19 2015 -0400

----------------------------------------------------------------------
 Allura/allura/controllers/repository.py  |  3 ++-
 Allura/allura/model/repository.py        |  6 ++++++
 Allura/allura/templates/repo/commit.html | 14 ++++++++------
 3 files changed, 16 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/cfe570b3/Allura/allura/controllers/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index 2b9ae89..5d03f64 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -564,7 +564,8 @@ class CommitBrowser(BaseController):
                                              default=self.DEFAULT_PAGE_LIMIT)
         diffs = self._commit.paged_diffs(start=start, end=start + limit)
         result['artifacts'] = [
-            (t, f, 'blob' if tree.get_blob_by_path(f) else 'tree')
+            (t, f, 'blob' if tree.get_blob_by_path(f) else 'tree',
+            tree.get_blob_by_path(f) and tree.get_blob_by_path(f).is_text)
             for t in ('added', 'removed', 'changed', 'copied')
             for f in diffs[t]]
         count = diffs['total']

http://git-wip-us.apache.org/repos/asf/allura/blob/cfe570b3/Allura/allura/model/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repository.py b/Allura/allura/model/repository.py
index b3c60b7..7bc36c1 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -1520,6 +1520,12 @@ class Blob(object):
         return self._content_type_encoding[0]
 
     @LazyProperty
+    def is_text(self):
+        """Return true if this blob is text."""
+
+        return self.content_type.startswith("text")
+
+    @LazyProperty
     def content_encoding(self):
         return self._content_type_encoding[1]
 

http://git-wip-us.apache.org/repos/asf/allura/blob/cfe570b3/Allura/allura/templates/repo/commit.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/repo/commit.html b/Allura/allura/templates/repo/commit.html
index 4870332..f029f52 100644
--- a/Allura/allura/templates/repo/commit.html
+++ b/Allura/allura/templates/repo/commit.html
@@ -113,7 +113,7 @@ Commit <a href="{{commit.url()}}">{{commit.shorthand_id()}}</a> {{commit_labels(
 {{c.page_list.display(page=page, limit=limit, count=count)}}
 <table>
   <tbody>
-    {% for type, file, _ in artifacts %}
+    {% for type, file, _, _ in artifacts %}
     <tr>
         <td>{{ type }}</td>
         <td><a href="#diff-{{loop.index}}">
@@ -128,9 +128,10 @@ Commit <a href="{{commit.url()}}">{{commit.shorthand_id()}}</a> {{commit_labels(
   </tbody>
 </table>
 
-{% for type, file, obj_type in artifacts %}
-        <div class="inline-diff">
-            <h6>
+    {% for type, file, obj_type, is_text in artifacts %}
+        {% if is_text %}
+            <div class="inline-diff">
+                <h6>
             {% if type in ('added', 'changed') %}
                 {% if obj_type == 'tree' %}
                     <a href="{{commit.url()}}tree/{{h.urlquote(h.really_unicode(file))}}">{{h.really_unicode(file)}}</a>
@@ -169,6 +170,7 @@ Commit <a href="{{commit.url()}}">{{commit.shorthand_id()}}</a> {{commit_labels(
                 {% endif %}
             </div>
         </div>
-{% endfor %}
-{{c.page_list.display(page=page, limit=limit, count=count)}}
+        {% endif %}
+    {% endfor %}
+    {{ c.page_list.display(page=page, limit=limit, count=count) }}
 {% endblock %}


[07/22] allura git commit: [#7685] ticket:802 Subsribe via POST in wiki sidebar

Posted by he...@apache.org.
[#7685] ticket:802 Subsribe via POST in wiki sidebar


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

Branch: refs/heads/hs/7925
Commit: c5f8bdad548216d2579bc05261e70b3fd63abfd4
Parents: cc33817
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Thu Jun 25 14:24:05 2015 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Wed Jul 22 15:35:25 2015 +0300

----------------------------------------------------------------------
 ForgeWiki/forgewiki/templates/wiki/page_view.html | 10 +++++++++-
 ForgeWiki/forgewiki/wiki_main.py                  |  2 +-
 2 files changed, 10 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/c5f8bdad/ForgeWiki/forgewiki/templates/wiki/page_view.html
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/templates/wiki/page_view.html b/ForgeWiki/forgewiki/templates/wiki/page_view.html
index 0420ecf..7289f23 100644
--- a/ForgeWiki/forgewiki/templates/wiki/page_view.html
+++ b/ForgeWiki/forgewiki/templates/wiki/page_view.html
@@ -116,5 +116,13 @@
       {% endif %}
   {% endif %}
   {{c.confirmation.display(content='')}}
-
 {% endblock %}
+
+{% block wiki_extra_js %}
+  <script type="text/javascript">
+    $('a[href$="#toggle-subscribe"]').click(function() {
+      $('#subscribe_form').submit();
+      return false;
+    })
+  </script>
+{% endblock wiki_extra_js %}

http://git-wip-us.apache.org/repos/asf/allura/blob/c5f8bdad/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index 7899ffa..229b217 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -249,7 +249,7 @@ The wiki uses [Markdown](%s) syntax.
             subscribe_title = '{}{}'.format(
                 subscribe_action.capitalize(),
                 '' if subscribed else ' to wiki')
-            subscribe_url = '{}subscribe?{}=True'.format(self.url, subscribe_action)
+            subscribe_url = '{}#toggle-subscribe'.format(self.url, subscribe_action)
             links += [SitemapEntry(''),
                       SitemapEntry(subscribe_title, subscribe_url, ui_icon=g.icons['mail'])]
         if not admin_menu:


[09/22] allura git commit: [#7685] ticket:802 Fixed tests

Posted by he...@apache.org.
[#7685] ticket:802 Fixed tests


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

Branch: refs/heads/hs/7925
Commit: 55c7b485a169e72cf402504122ac68c85b16c028
Parents: c5f8bda
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Sat Jun 27 22:53:54 2015 +0300
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Wed Jul 22 11:47:56 2015 -0400

----------------------------------------------------------------------
 .../tests/functional/test_forum.py              |  2 +-
 .../forgetracker/tests/functional/test_root.py  | 22 ++++++++++----------
 .../forgewiki/tests/functional/test_rest.py     |  2 +-
 .../forgewiki/tests/functional/test_root.py     | 16 +++++++-------
 4 files changed, 21 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/55c7b485/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 9c5397f..ae91bf0 100644
--- a/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
+++ b/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
@@ -576,7 +576,7 @@ class TestForum(TestController):
             if field.has_key('name') and 'subscription' not in field['name']:
                 params[field['name']] = field.has_key('value') and field['value'] or ''
         self.app.post(str(subscribe_url), params=params)
-        self.app.get('/discussion/general/subscribe_to_forum?subscribe=True')
+        self.app.post('/discussion/general/subscribe_to_forum', {'subscribe': True})
         f = thread.html.find('div', {'class': 'row reply_post_form'}).find('form')
         rep_url = f.get('action')
         params = dict()

http://git-wip-us.apache.org/repos/asf/allura/blob/55c7b485/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 871f0fd..23c77f4 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -840,7 +840,7 @@ class TestFunctionalController(TrackerTestController):
         }, upload_files=[upload]).follow()
         assert file_name in ticket_editor, ticket_editor.showbrowser()
         req = self.app.get('/bugs/1/')
-        file_link = req.html.findAll('form')[1].findAll('a')[6]
+        file_link = req.html.findAll('form')[2].findAll('a')[6]
         assert_equal(file_link.string, file_name)
         self.app.post(str(file_link['href']), {
             'delete': 'True'
@@ -882,7 +882,7 @@ class TestFunctionalController(TrackerTestController):
         ticket_editor = self.app.post('/bugs/1/update_ticket', {
             'summary': 'zzz'
         }, upload_files=[upload]).follow()
-        download = self.app.get(str(ticket_editor.html.findAll('form')[1].findAll('a')[7]['href']))
+        download = self.app.get(str(ticket_editor.html.findAll('form')[2].findAll('a')[7]['href']))
         assert_equal(download.body, file_data)
 
     def test_two_attachments(self):
@@ -1239,7 +1239,7 @@ class TestFunctionalController(TrackerTestController):
         # Test edit ticket form
         self.new_ticket(summary='Test ticket')
         response = self.app.get('/bugs/1/')
-        form = response.forms[1]
+        form = response.forms[2]
         assert_equal(
             form['ticket_form.custom_fields._priority'].value, 'normal')
         assert_equal(form['ticket_form.custom_fields._category'].value, '')
@@ -1247,9 +1247,9 @@ class TestFunctionalController(TrackerTestController):
         form['ticket_form.custom_fields._priority'] = 'urgent'
         form['ticket_form.custom_fields._category'] = 'bugs'
         error_form = form.submit()
-        assert_equal(error_form.forms[1]['ticket_form.custom_fields._priority'].value,
+        assert_equal(error_form.forms[2]['ticket_form.custom_fields._priority'].value,
                      'urgent')
-        assert_equal(error_form.forms[1]['ticket_form.custom_fields._category'].value,
+        assert_equal(error_form.forms[2]['ticket_form.custom_fields._category'].value,
                      'bugs')
 
     def test_new_ticket_validation(self):
@@ -1269,7 +1269,7 @@ class TestFunctionalController(TrackerTestController):
         # set a summary, submit, and check for success
         error_form.forms[1]['ticket_form.summary'] = summary
         success = error_form.forms[1].submit().follow().html
-        assert success.findAll('form')[1].get('action') == '/p/test/bugs/1/update_ticket_from_widget'
+        assert success.findAll('form')[2].get('action') == '/p/test/bugs/1/update_ticket_from_widget'
         assert success.find('input', {'name': 'ticket_form.summary'})['value'] == summary
 
     def test_edit_ticket_validation(self):
@@ -1280,7 +1280,7 @@ class TestFunctionalController(TrackerTestController):
         # check that existing form is valid
         assert response.html.find('input', {'name': 'ticket_form.summary'})['value'] == old_summary
         assert not response.html.find('div', {'class': 'error'})
-        form = response.forms[1]
+        form = response.forms[2]
         # try submitting with no summary set and check for error message
         form['ticket_form.summary'] = ""
         error_form = form.submit()
@@ -1289,11 +1289,11 @@ class TestFunctionalController(TrackerTestController):
         assert error_message.string == 'You must provide a Title'
         assert error_message.findPreviousSibling('input').get('name') == 'ticket_form.summary'
         # set a summary, submit, and check for success
-        error_form.forms[1]['ticket_form.summary'] = new_summary
-        r = error_form.forms[1].submit()
+        error_form.forms[2]['ticket_form.summary'] = new_summary
+        r = error_form.forms[2].submit()
         assert r.status_int == 302, r.showbrowser()
         success = r.follow().html
-        assert success.findAll('form')[1].get('action') == '/p/test/bugs/1/update_ticket_from_widget'
+        assert success.findAll('form')[2].get('action') == '/p/test/bugs/1/update_ticket_from_widget'
         assert success.find('input', {'name': 'ticket_form.summary'})['value'] == new_summary
 
     def test_home(self):
@@ -2720,7 +2720,7 @@ class TestCustomUserField(TrackerTestController):
     def test_change_user_field(self):
         kw = {'custom_fields._code_review': ''}
         r = self.new_ticket(summary='test custom fields', **kw).follow()
-        f = r.forms[1]
+        f = r.forms[2]
         # Populate ProjectUserCombo's select with option we want.
         # This is a workaround for tests,
         # in real enviroment this is populated via ajax.

http://git-wip-us.apache.org/repos/asf/allura/blob/55c7b485/ForgeWiki/forgewiki/tests/functional/test_rest.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/tests/functional/test_rest.py b/ForgeWiki/forgewiki/tests/functional/test_rest.py
index 6a5de3b..a2b58ae 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_rest.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_rest.py
@@ -42,7 +42,7 @@ class TestWikiApi(TestRestApiBase):
 
     def test_get_page(self):
         r = self.app.get('/p/test/wiki/Home/')
-        discussion_url = r.html.findAll('form')[2]['action'][:-4]
+        discussion_url = r.html.findAll('form')[3]['action'][:-4]
         content = file(__file__).read()
         self.app.post('/wiki/Home/attach',
                       upload_files=[('file_info', 'test_root.py', content)])

http://git-wip-us.apache.org/repos/asf/allura/blob/55c7b485/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 aea9028..dafb74f 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_root.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_root.py
@@ -754,24 +754,24 @@ class TestRootController(TestController):
         # user is not subscribed
         assert not M.Mailbox.subscribed(user_id=user._id)
         r = self.app.get('/p/test/wiki/Home/', extra_environ={'username': str(user.username)})
-        link = r.html.find('a', {'href': '/p/test/wiki/subscribe?subscribe=True'})
-        assert link is not None
+        inp = r.html.find('input', {'type': 'hidden', 'name': 'subscribe'})
+        assert inp is not None
         # subscribe
-        self.app.get('/p/test/wiki/subscribe?subscribe=True',
+        self.app.post('/p/test/wiki/subscribe', {'subscribe': True},
                      extra_environ={'username': str(user.username)}).follow()
         # user is subscribed
         assert M.Mailbox.subscribed(user_id=user._id)
         r = self.app.get('/p/test/wiki/Home/', extra_environ={'username': str(user.username)})
-        link = r.html.find('a', {'href': '/p/test/wiki/subscribe?unsubscribe=True'})
-        assert link is not None
+        inp = r.html.find('input', {'type': 'hidden', 'name': 'unsubscribe'})
+        assert inp is not None
         # unsubscribe
-        self.app.get('/p/test/wiki/subscribe?unsubscribe=True',
+        self.app.post('/p/test/wiki/subscribe', {'unsubscribe': True},
                      extra_environ={'username': str(user.username)}).follow()
         # user is not subscribed
         assert not M.Mailbox.subscribed(user_id=user._id)
         r = self.app.get('/p/test/wiki/Home/', extra_environ={'username': str(user.username)})
-        link = r.html.find('a', {'href': '/p/test/wiki/subscribe?subscribe=True'})
-        assert link is not None
+        inp = r.html.find('input', {'type': 'hidden', 'name': 'subscribe'})
+        assert inp is not None
 
     def test_rate_limit_new_page(self):
         # Set rate limit to unlimit


[21/22] allura git commit: [#7925] Update tests to work with new diff processing

Posted by he...@apache.org.
[#7925] Update tests to work with new diff processing


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

Branch: refs/heads/hs/7925
Commit: 0e4847a60b9b1c862b0758a161065f7c816d7565
Parents: ef9cc5f
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Mon Jul 27 16:08:05 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Jul 27 16:09:43 2015 -0400

----------------------------------------------------------------------
 Allura/allura/tests/model/test_repo.py          |  2 +
 .../forgegit/tests/model/test_repository.py     | 10 ++++
 .../forgesvn/tests/model/test_repository.py     | 59 +++++++++++++-------
 3 files changed, 52 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/0e4847a6/Allura/allura/tests/model/test_repo.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_repo.py b/Allura/allura/tests/model/test_repo.py
index 1f6ec3c..c0a6bc8 100644
--- a/Allura/allura/tests/model/test_repo.py
+++ b/Allura/allura/tests/model/test_repo.py
@@ -143,6 +143,8 @@ class TestLastCommit(unittest.TestCase):
         self.repo.paged_diffs.return_value = {
             'added': [],
             'removed': [],
+            'copied': [],
+            'renamed': [],
             'changed': [],
             'total': 0,
         }

http://git-wip-us.apache.org/repos/asf/allura/blob/0e4847a6/ForgeGit/forgegit/tests/model/test_repository.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/tests/model/test_repository.py b/ForgeGit/forgegit/tests/model/test_repository.py
index 9f007e6..948f228 100644
--- a/ForgeGit/forgegit/tests/model/test_repository.py
+++ b/ForgeGit/forgegit/tests/model/test_repository.py
@@ -670,6 +670,8 @@ class TestGitRepo(unittest.TestCase, RepoImplTestBase):
             'added': [u'with space.txt', u'привіт.txt'],
             'removed': [],
             'changed': [],
+            'copied': [],
+            'renamed': [],
             'total': 2,
         }
         assert_equals(diffs, expected)
@@ -678,6 +680,8 @@ class TestGitRepo(unittest.TestCase, RepoImplTestBase):
         expected = {
             'added': [],
             'removed': [],
+            'copied': [],
+            'renamed': [],
             'changed': [u'привіт.txt'],
             'total': 1,
         }
@@ -689,6 +693,8 @@ class TestGitRepo(unittest.TestCase, RepoImplTestBase):
             'added': [u'README.md'],
             'removed': [],
             'changed': [],
+            'copied': [],
+            'renamed': [],
             'total': 1,
         }
         assert_equals(diffs, expected)
@@ -698,6 +704,8 @@ class TestGitRepo(unittest.TestCase, RepoImplTestBase):
         expected = {
             'added': [u'with space.txt'],
             'removed': [],
+            'copied': [],
+            'renamed': [],
             'changed': [],
             'total': 2,
         }
@@ -706,6 +714,8 @@ class TestGitRepo(unittest.TestCase, RepoImplTestBase):
         expected = {
             'added': [u'привіт.txt'],
             'removed': [],
+            'copied': [],
+            'renamed': [],
             'changed': [],
             'total': 2,
         }

http://git-wip-us.apache.org/repos/asf/allura/blob/0e4847a6/ForgeSVN/forgesvn/tests/model/test_repository.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/tests/model/test_repository.py b/ForgeSVN/forgesvn/tests/model/test_repository.py
index 79beb52..9889a60 100644
--- a/ForgeSVN/forgesvn/tests/model/test_repository.py
+++ b/ForgeSVN/forgesvn/tests/model/test_repository.py
@@ -363,7 +363,7 @@ class TestSVNRepo(unittest.TestCase, RepoImplTestBase):
         self.assertEqual(entry.diffs, entry.paged_diffs(start=0))
         added_expected = entry.diffs.added[1:3]
         expected = dict(
-            copied=[], changed=[], removed=[],
+            copied=[], changed=[], removed=[], renamed=[],
             added=added_expected, total=4)
         actual = entry.paged_diffs(start=1, end=3)
         self.assertEqual(expected, actual)
@@ -376,7 +376,7 @@ class TestSVNRepo(unittest.TestCase, RepoImplTestBase):
         entry = self.repo.commit(self.repo.log(1, id_only=True).next())
         self.assertEqual(
             entry.diffs, dict(
-                copied=[], changed=[],
+                copied=[], changed=[], renamed=[],
                 removed=[], added=['/README'], total=1))
 
     def test_diff_create_path(self):
@@ -385,7 +385,7 @@ class TestSVNRepo(unittest.TestCase, RepoImplTestBase):
         actual.added = sorted(actual.added)
         self.assertEqual(
             entry.diffs, dict(
-                copied=[], changed=[], removed=[],
+                copied=[], changed=[], removed=[], renamed=[],
                 added=sorted([
                     '/a', '/a/b', '/a/b/c',
                     '/a/b/c/hello.txt']), total=4))
@@ -394,20 +394,20 @@ class TestSVNRepo(unittest.TestCase, RepoImplTestBase):
         entry = self.repo.commit(self.repo.log(3, id_only=True).next())
         self.assertEqual(
             entry.diffs, dict(
-                copied=[], changed=['/README'],
+                copied=[], changed=['/README'], renamed=[],
                 removed=[], added=[], total=1))
 
     def test_diff_delete(self):
         entry = self.repo.commit(self.repo.log(4, id_only=True).next())
         self.assertEqual(
             entry.diffs, dict(
-                copied=[], changed=[],
+                copied=[], changed=[], renamed=[],
                 removed=['/a/b/c/hello.txt'], added=[], total=1))
 
     def test_diff_copy(self):
         entry = self.repo.commit(self.repo.log(5, id_only=True).next())
         assert_equals(dict(entry.diffs), dict(
-                copied=[{'new': u'/b', 'old': u'/a', 'diff': '', 'ratio': 1}],
+                copied=[{'new': u'/b', 'old': u'/a', 'diff': '', 'ratio': 1}],  renamed=[],
                 changed=[], removed=[], added=[], total=1))
 
     def test_commit(self):
@@ -1002,6 +1002,8 @@ class TestCommit(_TestWithRepo):
         self.repo._impl.paged_diffs.return_value = {
             'added': ['a', 'a/a', 'a/a/a', 'a/a/b', 'a/b'],
             'changed': [],
+            'copied': [],
+            'renamed': [],
             'removed': [],
             'total': 5,
         }
@@ -1024,6 +1026,8 @@ class TestCommit(_TestWithRepo):
         self._make_log(ci)
         self.repo._impl.paged_diffs.return_value = {
             'added': ['b', 'b/a', 'b/a/a', 'b/a/b', 'b/b'],
+            'renamed': [],
+            'copied': [],
             'changed': [],
             'removed': ['a', 'a/a', 'a/a/a', 'a/a/b', 'a/b'],
             'total': 10,
@@ -1044,25 +1048,38 @@ class TestCommit(_TestWithRepo):
         ci.parent_ids = ['bar']
         self._make_log(ci)
         self.repo._impl.paged_diffs.return_value = {
-            'added': ['b/c', 'b/a/z'],
+            'added': [u'b/c', u'b/a/z'],
+            'removed': [u'/b/a/b', u'b/b'],
             'changed': [],
-            'removed': ['b/a/b', 'b/b', 'b/a/a'],
-            'total': 10,
+            'copied': [
+                {
+                    'new': u'b/c',
+                    'old': u'b/a/b',
+                    'ratio': 1,
+                    'diff': '',
+                },
+                {
+                    'new': u'b/a/z',
+                    'old': u'b/b',
+                    'ratio': 1,
+                    'diff': '',
+                },
+            ],
+            'renamed': [],
+            'total': 2
         }
         M.repo_refresh.refresh_commit_trees(ci, {})
-        assert_equal(ci.diffs.added, [])
+        assert_equal(ci.diffs.added, [u'b/a/z', u'b/c'])
         assert_equal(ci.diffs.changed, [])
-        assert_equal(ci.diffs.removed, ['b/a/a'])
+        assert_equal(ci.diffs.removed, [u'/b/a/b', u'b/b'])
         # see mock for open_blob
         assert_equal(len(ci.diffs.copied), 2)
-        assert_equal(ci.diffs.copied[0]['old'], 'b/a/b')
-        assert_equal(ci.diffs.copied[0]['new'], 'b/c')
-        assert_equal(ci.diffs.copied[0]['ratio'], 1)
-        assert_equal(ci.diffs.copied[0]['diff'], '')
-        assert_equal(ci.diffs.copied[1]['old'], 'b/b')
-        assert_equal(ci.diffs.copied[1]['new'], 'b/a/z')
-        assert ci.diffs.copied[1]['ratio'] < 1, ci.diffs.copied[1]['ratio']
-        assert '+++' in ci.diffs.copied[1]['diff'], ci.diffs.copied[1]['diff']
+        assert_equal(ci.diffs.copied[1]['old'], 'b/a/b')
+        assert_equal(ci.diffs.copied[1]['new'], 'b/c')
+        assert_equal(ci.diffs.copied[1]['ratio'], 1)
+        assert_equal(ci.diffs.copied[1]['diff'], '')
+        assert_equal(ci.diffs.copied[0]['old'], 'b/b')
+        assert_equal(ci.diffs.copied[0]['new'], 'b/a/z')
 
     def test_context(self):
         self.ci.context()
@@ -1132,6 +1149,7 @@ class TestDirectRepoAccess(object):
             'removed': [],
             'changed': [],
             'copied': [],
+            'renamed': [],
             'total': 1,
         }
         assert_equals(diffs, expected)
@@ -1142,6 +1160,7 @@ class TestDirectRepoAccess(object):
             'added': [u'/a', u'/a/b', u'/a/b/c', u'/a/b/c/hello.txt'],
             'removed': [],
             'changed': [],
+            'renamed': [],
             'copied': [],
             'total': 4,
         }
@@ -1152,6 +1171,7 @@ class TestDirectRepoAccess(object):
         expected = {
             'added': [],
             'removed': [],
+            'renamed': [],
             'changed': [u'/README'],
             'copied': [],
             'total': 1,
@@ -1164,6 +1184,7 @@ class TestDirectRepoAccess(object):
             'added': [],
             'removed': ['/a/b/c/hello.txt'],
             'changed': [],
+            'renamed': [],
             'copied': [],
             'total': 1,
         }


[10/22] allura git commit: [#7685] ticket:819 Use ajax requests in subscription icons

Posted by he...@apache.org.
[#7685] ticket:819 Use ajax requests in subscription icons


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

Branch: refs/heads/hs/7925
Commit: a5227e2e1f75ca831a39aa468582e41943004002
Parents: 63dbb3d
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jul 10 18:03:02 2015 +0300
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Wed Jul 22 11:47:57 2015 -0400

----------------------------------------------------------------------
 Allura/allura/controllers/repository.py         |  7 +-
 .../lib/widgets/resources/js/subscriptions.js   | 99 ++++++++++++++++++++
 Allura/allura/lib/widgets/subscriptions.py      |  7 +-
 Allura/allura/templates/widgets/subscribe.html  | 44 ++++-----
 ForgeBlog/forgeblog/main.py                     | 11 ++-
 .../forgediscussion/controllers/forum.py        |  7 +-
 ForgeTracker/forgetracker/tracker_main.py       | 14 ++-
 ForgeWiki/forgewiki/wiki_main.py                |  7 +-
 8 files changed, 158 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/a5227e2e/Allura/allura/controllers/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index 0178723..2b9ae89 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -688,7 +688,7 @@ class TreeBrowser(BaseController, DispatchIndex):
             self._path + '/' + next,
             self), rest
 
-    @expose()
+    @expose('json:')
     @require_post()
     @validate(subscribe_form)
     def subscribe(self, subscribe=None, unsubscribe=None, **kw):
@@ -696,7 +696,10 @@ class TreeBrowser(BaseController, DispatchIndex):
             M.Mailbox.subscribe()
         elif unsubscribe:
             M.Mailbox.unsubscribe()
-        redirect(request.referer)
+        return {
+            'status': 'ok',
+            'subscribed': M.Mailbox.subscribed(),
+        }
 
 
 class FileBrowser(BaseController):

http://git-wip-us.apache.org/repos/asf/allura/blob/a5227e2e/Allura/allura/lib/widgets/resources/js/subscriptions.js
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/resources/js/subscriptions.js b/Allura/allura/lib/widgets/resources/js/subscriptions.js
new file mode 100644
index 0000000..c03bbeb
--- /dev/null
+++ b/Allura/allura/lib/widgets/resources/js/subscriptions.js
@@ -0,0 +1,99 @@
+/*
+       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.
+*/
+
+var dom = React.createElement;
+
+/* top-level form state */
+var state = {
+  'thing': 'tool',
+  'subscribed': false,
+  'url': '',
+  'icon': {}
+};
+
+SubscriptionForm = React.createClass({
+
+  render: function() {
+    var action = this.props.subscribed ? "Unsubscribe from" : "Subscribe to";
+    var title = action + ' this ' + this.props.thing;
+    var link_opts = {
+      className: this.props.subscribed ? 'active' : '',
+      href: '#',
+      title: title,
+      onClick: this.handleClick
+    };
+    var icon_opts = {
+      'data-icon': this.props.icon.char,
+      className: 'ico ' + this.props.icon.css,
+      title: title
+    };
+    return dom('a', link_opts, dom('b', icon_opts));
+  },
+
+  handleClick: function() {
+    var url = this.props.url;
+    var csrf = $.cookie('_session_id');
+    var data = {_session_id: csrf};
+    if (this.props.subscribed) {
+      data.unsubscribe = true;
+    } else {
+      data.subscribe = true;
+    }
+    set_state({in_progress: true});
+    /*
+     * TODO:
+     * - show 'in-progress' status to user somehow
+     * - handle errors (show to the user in some kind of popup/flash?)
+     * - If user is subscribed to the whole tool and she tries to subsribe to
+     *   the artifact she will not be subscribed, so nothing will change in the
+     *   UI and it's confusing. We need to show some information message in
+     *   such case
+     */
+    $.post(url, data, function(resp) {
+      if (resp.status == 'ok') {
+        set_state({subscribed: resp.subscribed});
+      }
+    }).always(function() {
+      set_state({in_progress: false});
+    });
+    return false;
+  }
+
+});
+
+function set_state(new_state) {
+  /* Set state and re-render entire UI */
+  for (var key in new_state) {
+    state[key] = new_state[key];
+  }
+  render(state);
+}
+
+function render(state) {
+  var props = {};
+  for (var key in state) { props[key] = state[key]; }
+  React.render(
+    dom(SubscriptionForm, props),
+    document.getElementById('subscription-form')
+  );
+}
+
+$(function() {
+  set_state(document.SUBSCRIPTION_OPTIONS);
+});

http://git-wip-us.apache.org/repos/asf/allura/blob/a5227e2e/Allura/allura/lib/widgets/subscriptions.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/subscriptions.py b/Allura/allura/lib/widgets/subscriptions.py
index dec1274..c8d3dcd 100644
--- a/Allura/allura/lib/widgets/subscriptions.py
+++ b/Allura/allura/lib/widgets/subscriptions.py
@@ -75,7 +75,7 @@ class SubscribeForm(ew.SimpleForm):
     defaults = dict(
         ew.SimpleForm.defaults,
         thing='tool',
-        style='text',
+        style='icon',
         tool_subscribed=False,
         value=None)
 
@@ -86,3 +86,8 @@ class SubscribeForm(ew.SimpleForm):
 
     def from_python(self, value, state):
         return value
+
+    def resources(self):
+        for r in super(SubscribeForm, self).resources():
+            yield r
+        yield ew.JSLink('js/subscriptions.js')

http://git-wip-us.apache.org/repos/asf/allura/blob/a5227e2e/Allura/allura/templates/widgets/subscribe.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/subscribe.html b/Allura/allura/templates/widgets/subscribe.html
index 5154eb7..1361a9c 100644
--- a/Allura/allura/templates/widgets/subscribe.html
+++ b/Allura/allura/templates/widgets/subscribe.html
@@ -17,28 +17,24 @@
        under the License.
 -#}
 {% import 'allura:templates/jinja_master/lib.html' as lib with context %}
-{% if value %}
-  {% if style == 'icon' %}
-    <form action="{{action}}" id="subscribe_form" style="display:inline;" method="POST">
-      {{lib.csrf_token()}}
-      <input type="hidden" name="unsubscribe" value="1">
-      <a href="#" class="artifact_unsubscribe active" title="Unsubscribe from this {{thing}}" onclick="$('#subscribe_form').submit(); return false;"><b data-icon="{{g.icons['mail'].char}}" class="ico {{g.icons['mail'].css}}" title="Unsubscribe from this {{thing}}"></b></a>
-    </form>
-  {% else %}
-    You are currently subscribed to this {{thing}}.
-    <br/>
-    {{fields['unsubscribe'].display()}}
-  {% endif %}
-{% else %}
-  {% if style == 'icon' %}
-    <form action="{{action}}" id="subscribe_form" style="display:inline;" method="POST">
-      {{lib.csrf_token()}}
-      <input type="hidden" name="subscribe" value="1">
-      <a href="#" class="artifact_subscribe" title="Subscribe to this {{thing}}" onclick="$('#subscribe_form').submit(); return false;"><b data-icon="{{g.icons['mail'].char}}" class="ico {{g.icons['mail'].css}}" title="Subscribe to this {{thing}}"></b></a>
-    </form>
-  {% else %}
-    You are currently not subscribed to this {{thing}}.
-    <br/>
-    {{fields['subscribe'].display()}}
-  {% endif %}
+
+{% do g.register_forge_js('js/react.min.js', location='head_js') %}
+{% for blob in g.resource_manager.emit('head_js') %}
+{% if 'react.min.js' in blob %}
+  {{ blob }}
 {% endif %}
+{% endfor %}
+
+<div id="subscription-form" style="display: inline;">{# see subscription.js #}</div>
+
+<script>
+  document.SUBSCRIPTION_OPTIONS = {
+    "thing": "{{thing}}",
+    "subscribed": {{"true" if value else "false"}},
+    "url": "{{action}}",
+    "icon": {
+      "char": "{{g.icons['mail'].char}}",
+      "css": "{{g.icons['mail'].css}}"
+    }
+  };
+</script>

http://git-wip-us.apache.org/repos/asf/allura/blob/a5227e2e/ForgeBlog/forgeblog/main.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index 9007f87..adfc172 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -322,8 +322,10 @@ class PostController(BaseController, FeedController):
         version = kw.pop('version', None)
         post = self._get_version(version)
         base_post = self.post
+        subscribed = M.Mailbox.subscribed(artifact=self.post)
         return dict(post=post, base_post=base_post,
-                    page=page, limit=limit, count=post_count)
+                    page=page, limit=limit, count=post_count,
+                    subscribed=subscribed)
 
     @expose('jinja:forgeblog:templates/blog/edit_post.html')
     @without_trailing_slash
@@ -375,7 +377,7 @@ class PostController(BaseController, FeedController):
         self.post.commit()
         redirect('.')
 
-    @expose()
+    @expose('json:')
     @require_post()
     @validate(W.subscribe_form)
     def subscribe(self, subscribe=None, unsubscribe=None, **kw):
@@ -383,7 +385,10 @@ class PostController(BaseController, FeedController):
             self.post.subscribe(type='direct')
         elif unsubscribe:
             self.post.unsubscribe()
-        redirect(h.really_unicode(request.referer).encode('utf-8'))
+        return {
+            'status': 'ok',
+            'subscribed': M.Mailbox.subscribed(artifact=self.post),
+        }
 
     def get_feed(self, project, app, user):
         """Return a :class:`allura.controllers.feed.FeedArgs` object describing

http://git-wip-us.apache.org/repos/asf/allura/blob/a5227e2e/ForgeDiscussion/forgediscussion/controllers/forum.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/controllers/forum.py b/ForgeDiscussion/forgediscussion/controllers/forum.py
index 94fe6d9..b915823 100644
--- a/ForgeDiscussion/forgediscussion/controllers/forum.py
+++ b/ForgeDiscussion/forgediscussion/controllers/forum.py
@@ -122,7 +122,7 @@ class ForumController(DiscussionController):
     def deleted(self):
         return dict()
 
-    @expose()
+    @expose('json:')
     @require_post()
     @validate(W.subscribe_form)
     def subscribe_to_forum(self, subscribe=None, unsubscribe=None, shortname=None, **kw):
@@ -130,7 +130,10 @@ class ForumController(DiscussionController):
             self.discussion.subscribe(type='direct')
         elif unsubscribe:
             self.discussion.unsubscribe()
-        redirect(h.really_unicode(request.referer).encode('utf-8'))
+        return {
+            'status': 'ok',
+            'subscribed': M.Mailbox.subscribed(artifact=self.discussion),
+        }
 
 
 class ForumThreadController(ThreadController):

http://git-wip-us.apache.org/repos/asf/allura/blob/a5227e2e/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index c3a83e6..0049957 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -1090,7 +1090,7 @@ class RootController(BaseController, FeedController):
             dates=dates,
         )
 
-    @expose()
+    @expose('json:')
     @require_post()
     @validate(W.subscribe_form)
     def subscribe(self, subscribe=None, unsubscribe=None):
@@ -1098,7 +1098,10 @@ class RootController(BaseController, FeedController):
             M.Mailbox.subscribe(type='direct')
         elif unsubscribe:
             M.Mailbox.unsubscribe()
-        redirect(request.referer)
+        return {
+            'status': 'ok',
+            'subscribed': M.Mailbox.subscribed(),
+        }
 
 
 class BinController(BaseController):
@@ -1520,7 +1523,7 @@ class TicketController(BaseController, FeedController):
         c.app.globals.invalidate_bin_counts()
         redirect('.')
 
-    @expose()
+    @expose('json:')
     @require_post()
     @validate(W.subscribe_form)
     def subscribe(self, subscribe=None, unsubscribe=None):
@@ -1528,7 +1531,10 @@ class TicketController(BaseController, FeedController):
             self.ticket.subscribe(type='direct')
         elif unsubscribe:
             self.ticket.unsubscribe()
-        redirect(request.referer)
+        return {
+            'status': 'ok',
+            'subscribed': M.Mailbox.subscribed(artifact=self.ticket),
+        }
 
     @expose('json:')
     @require_post()

http://git-wip-us.apache.org/repos/asf/allura/blob/a5227e2e/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index 229a348..9fca1c2 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -737,7 +737,7 @@ class PageController(BaseController, FeedController):
         self.page.add_multiple_attachments(file_info)
         redirect(request.referer)
 
-    @expose()
+    @expose('json:')
     @require_post()
     @validate(W.subscribe_form)
     def subscribe(self, subscribe=None, unsubscribe=None, **kw):
@@ -747,7 +747,10 @@ class PageController(BaseController, FeedController):
             self.page.subscribe(type='direct')
         elif unsubscribe:
             self.page.unsubscribe()
-        redirect(request.referer)
+        return {
+            'status': 'ok',
+            'subscribed': M.Mailbox.subscribed(artifact=self.page),
+        }
 
 
 class WikiAttachmentController(ac.AttachmentController):


[05/22] allura git commit: [#7932] add test for git paged_diffs pagination

Posted by he...@apache.org.
[#7932] add test for git paged_diffs pagination


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

Branch: refs/heads/hs/7925
Commit: e1ad48033b356ebed24512d154e03514168dc890
Parents: 3017300
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Jul 21 20:02:10 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 21 20:25:39 2015 +0000

----------------------------------------------------------------------
 ForgeGit/forgegit/tests/model/test_repository.py | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e1ad4803/ForgeGit/forgegit/tests/model/test_repository.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/tests/model/test_repository.py b/ForgeGit/forgegit/tests/model/test_repository.py
index 4cfd2ef..9f007e6 100644
--- a/ForgeGit/forgegit/tests/model/test_repository.py
+++ b/ForgeGit/forgegit/tests/model/test_repository.py
@@ -693,6 +693,24 @@ class TestGitRepo(unittest.TestCase, RepoImplTestBase):
         }
         assert_equals(diffs, expected)
 
+        # pagination
+        diffs = repo.paged_diffs('407950e8fba4dbc108ffbce0128ed1085c52cfd7', start=0, end=1)
+        expected = {
+            'added': [u'with space.txt'],
+            'removed': [],
+            'changed': [],
+            'total': 2,
+        }
+        assert_equals(diffs, expected)
+        diffs = repo.paged_diffs('407950e8fba4dbc108ffbce0128ed1085c52cfd7', start=1, end=2)
+        expected = {
+            'added': [u'привіт.txt'],
+            'removed': [],
+            'changed': [],
+            'total': 2,
+        }
+        assert_equals(diffs, expected)
+
     def test_merge_base(self):
         res = self.repo._impl.merge_base(self.merge_request)
         assert_equal(res, '1e146e67985dcd71c74de79613719bef7bddca4a')