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/06/15 14:27:20 UTC

[01/46] allura git commit: [#7888] has_activity_access handles objects without deleted attribute

Repository: allura
Updated Branches:
  refs/heads/hs/7873 2702dfc23 -> f24debe77 (forced update)


[#7888] has_activity_access handles objects without deleted attribute


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

Branch: refs/heads/hs/7873
Commit: 3ed25d582f19649a6a69535e31f97ca72543c110
Parents: 8afd9b0
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri Jun 5 15:56:44 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jun 5 15:56:44 2015 +0000

----------------------------------------------------------------------
 Allura/allura/model/timeline.py            |  2 +-
 Allura/allura/tests/model/test_timeline.py | 42 +++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/3ed25d58/Allura/allura/model/timeline.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/timeline.py b/Allura/allura/model/timeline.py
index d5b9af8..66ecdaf 100644
--- a/Allura/allura/model/timeline.py
+++ b/Allura/allura/model/timeline.py
@@ -100,7 +100,7 @@ class ActivityObject(ActivityObjectBase):
         """Return True if user has perm access to this object, otherwise
         return False.
         """
-        if self.project is None or self.deleted:
+        if self.project is None or getattr(self, 'deleted', False):
             return False
         return security.has_access(self, perm, user, self.project)
 

http://git-wip-us.apache.org/repos/asf/allura/blob/3ed25d58/Allura/allura/tests/model/test_timeline.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_timeline.py b/Allura/allura/tests/model/test_timeline.py
new file mode 100644
index 0000000..6f7ae94
--- /dev/null
+++ b/Allura/allura/tests/model/test_timeline.py
@@ -0,0 +1,42 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+from nose.tools import assert_equal
+
+from allura import model as M
+from allura.tests import decorators as td
+from alluratest.controller import setup_basic_test, setup_global_objects
+
+
+class TestActivityObject_Functional(object):
+    # NOTE not for unit tests, this class sets up all the junk
+
+    def setUp(self):
+        setup_basic_test()
+        setup_global_objects()
+
+    @td.with_wiki
+    def test_has_activity_access_app_config(self):
+        # AppConfig inherits ActivityObject but may have different attributes
+        # than other ActivityObjects that are mostly artifacts
+
+        p = M.Project.query.get(shortname='test')
+        wiki_app = p.app_instance('wiki')
+        app_config = wiki_app.config
+
+        assert_equal(bool(app_config.has_activity_access('read', user=M.User.anonymous(), activity=None)),
+                     True)
\ No newline at end of file


[34/46] allura git commit: [#7825] Added "new commits" email template.

Posted by he...@apache.org.
[#7825] Added "new commits" email template.


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

Branch: refs/heads/hs/7873
Commit: 51fc93b4758757eb69ec9e10be415c4c27b19701
Parents: b2a1b10
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Tue May 26 20:36:50 2015 -0400
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jun 12 18:18:41 2015 +0000

----------------------------------------------------------------------
 Allura/allura/model/repo_refresh.py             | 48 ++++++++++++--------
 Allura/allura/model/repository.py               |  2 +-
 Allura/allura/templates/mail/commits.md         | 24 ++++++++++
 .../tests/functional/test_controllers.py        |  4 +-
 .../forgegit/tests/model/test_repository.py     | 10 ++--
 .../forgesvn/tests/model/test_repository.py     | 12 +++--
 6 files changed, 68 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/51fc93b4/Allura/allura/model/repo_refresh.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repo_refresh.py b/Allura/allura/model/repo_refresh.py
index 1711bc3..fca220f 100644
--- a/Allura/allura/model/repo_refresh.py
+++ b/Allura/allura/model/repo_refresh.py
@@ -360,10 +360,18 @@ def unknown_commit_ids(all_commit_ids):
 
 
 def send_notifications(repo, commit_ids):
-    '''Create appropriate notification and feed objects for a refresh'''
+    """Create appropriate notification and feed objects for a refresh
+
+    :param repo: A repository artifact instance.
+    :type repo: Repository
+
+    :param commit_ids: A list of commit hash strings.
+    :type commit_ids: list
+    """
     from allura.model import Feed, Notification
     commit_msgs = []
     base_url = tg.config['base_url']
+    last_branch = []
     for oids in utils.chunked_iter(commit_ids, QSIZE):
         chunk = list(oids)
         index = dict(
@@ -382,26 +390,30 @@ def send_notifications(repo, commit_ids):
                 author_name=ci.authored.name,
                 link=href,
                 unique_id=href)
-            branches = repo.symbolics_for_commit(ci)[0]
-            commit_msgs.append('%s: %s by %s %s%s' % (
-                ",".join(b for b in branches),
-                summary, ci.authored.name, base_url, ci.url()))
+
+            summary = g.markdown_commit.convert(ci.message) if ci.message else ""
+
+            current_branch = repo.symbolics_for_commit(ci)[0]
+            if last_branch == current_branch:
+                branches = []
+            else:
+                branches = current_branch
+                last_branch = branches
+
+            commit_msgs.append(dict(
+                author=ci.authored.name,
+                date=ci.authored.date.strftime("%m/%d/%Y %H:%M"),
+                summary=summary,
+                branches=branches,
+                commit_url=base_url + href))
+
     if commit_msgs:
         if len(commit_msgs) > 1:
-            subject = '%d new commits to %s %s' % (
-                len(commit_msgs), repo.app.project.name, repo.app.config.options.mount_label)
-            text = '\n\n'.join(commit_msgs)
+            subject = u"{} new commits to {}".format(len(commit_msgs), repo.app.config.options.mount_label)
         else:
-            subject = '{0} - {1}: {2}'.format(
-                repo.shorthand_for_commit(ci._id),
-                ci.authored.name,
-                summary)
-            branches = repo.symbolics_for_commit(ci)[0]
-            text_branches = ('%s: ' % ",".join(b for b in branches)
-                             if branches else '')
-            text = "%s%s %s%s" % (text_branches,
-                                  ci.message,
-                                  base_url, ci.url())
+            subject = u'New commit by {}'.format(commit_msgs[0]['author'])
+        template = g.jinja2_env.get_template("allura:templates/mail/commits.md")
+        text = u"\n\n-----".join([template.render(d) for d in commit_msgs])
 
         Notification.post(
             artifact=repo,

http://git-wip-us.apache.org/repos/asf/allura/blob/51fc93b4/Allura/allura/model/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repository.py b/Allura/allura/model/repository.py
index ec623a3..022343f 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -578,7 +578,7 @@ class Repository(Artifact, ActivityObject):
         result.update(
             name_s=self.name,
             type_s=self.type_s,
-            title='Repository %s %s' % (self.project.name, self.name))
+            title=u'{} {} repository'.format(self.project.name, self.app.tool_label))
         return result
 
     @property

http://git-wip-us.apache.org/repos/asf/allura/blob/51fc93b4/Allura/allura/templates/mail/commits.md
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/mail/commits.md b/Allura/allura/templates/mail/commits.md
new file mode 100644
index 0000000..7d4e4b1
--- /dev/null
+++ b/Allura/allura/templates/mail/commits.md
@@ -0,0 +1,24 @@
+{# <!---
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+--> #}
+{% if branches %}## Branch: {% for b in branches %} {{ b }}  {% endfor%}{% endif %}
+
+{{summary}}
+
+By {{ author }} on {{ date }}
+[**View Changes**]({{ commit_url }})

http://git-wip-us.apache.org/repos/asf/allura/blob/51fc93b4/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 1312188..917f765 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -264,9 +264,7 @@ class TestRootController(_TestCase):
         assert '<table class="side-by-side-diff">' in r
 
     def test_refresh(self):
-        notification = M.Notification.query.find(
-            dict(subject='[test:src-git] 5 new commits to Test Project Git')
-        ).first()
+        notification = M.Notification.query.find({'subject': '[test:src-git] 5 new commits to Git'}).first()
         assert notification
         domain = '.'.join(
             reversed(c.app.url[1:-1].split('/'))).replace('_', '-')

http://git-wip-us.apache.org/repos/asf/allura/blob/51fc93b4/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 936fbee..349efe6 100644
--- a/ForgeGit/forgegit/tests/model/test_repository.py
+++ b/ForgeGit/forgegit/tests/model/test_repository.py
@@ -29,7 +29,7 @@ from pylons import tmpl_context as c, app_globals as g
 import tg
 from ming.base import Object
 from ming.orm import ThreadLocalORMSession, session
-from nose.tools import assert_equal
+from nose.tools import assert_equal, assert_in
 from testfixtures import TempDirectory
 from datadiff.tools import assert_equals
 
@@ -376,15 +376,15 @@ class TestGitRepo(unittest.TestCase, RepoImplTestBase):
         send_notifications(
             self.repo, ['1e146e67985dcd71c74de79613719bef7bddca4a', ])
         ThreadLocalORMSession.flush_all()
-        n = M.Notification.query.find(
-            dict(subject='[test:src-git] [1e146e] - Rick Copeland: Change README')).first()
+
+        n = M.Notification.query.find({'subject': u'[test:src-git] New commit by Rick Copeland'}).first()
         assert n
-        assert 'master: ' in n.text, n.text
+        assert_in('Change README', n.text)
         send_notifications(
             self.repo, ['1e146e67985dcd71c74de79613719bef7bddca4a', 'df30427c488aeab84b2352bdf88a3b19223f9d7a'])
         ThreadLocalORMSession.flush_all()
         assert M.Notification.query.find(
-            dict(subject='[test:src-git] 2 new commits to Test Project Git')).first()
+            dict(subject=u'[test:src-git] 2 new commits to Git')).first()
 
     def test_tarball(self):
         tmpdir = tg.config['scm.repos.tarball.root']

http://git-wip-us.apache.org/repos/asf/allura/blob/51fc93b4/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 744d30a..79beb52 100644
--- a/ForgeSVN/forgesvn/tests/model/test_repository.py
+++ b/ForgeSVN/forgesvn/tests/model/test_repository.py
@@ -27,7 +27,7 @@ from zipfile import ZipFile
 from collections import defaultdict
 from pylons import tmpl_context as c, app_globals as g
 import mock
-from nose.tools import assert_equal
+from nose.tools import assert_equal, assert_in
 from datadiff.tools import assert_equals
 import tg
 import ming
@@ -693,10 +693,10 @@ class TestSVNRev(unittest.TestCase):
         ThreadLocalORMSession.flush_all()
         send_notifications(self.repo, [self.repo.rev_to_commit_id(1)])
         ThreadLocalORMSession.flush_all()
-        n = M.Notification.query.find(
-            dict(subject='[test:src] [r1] - rick446: Create readme')).first()
+        n = M.Notification.query.find({u'subject': u'[test:src] New commit by rick446'}).first()
         assert n
-        assert_equal(n.text, 'Create readme http://localhost:8080/p/test/src/1/')
+        assert_in(u'By rick446', n.text)
+        assert_in(u'Create readme', n.text)
 
 
 class _Test(unittest.TestCase):
@@ -869,6 +869,7 @@ class TestRepo(_TestWithRepo):
             M.repository.CommitDoc(dict(
                 authored=dict(
                     name=committer_name,
+                    date=datetime(2010, 10, 8, 15, 32, 48, 0),
                     email=committer_email),
                 _id=oid)).m.insert()
         self.repo._impl.refresh_commit_info = refresh_commit_info
@@ -880,7 +881,8 @@ class TestRepo(_TestWithRepo):
         notifications = M.Notification.query.find().all()
         for n in notifications:
             if '100 new commits' in n.subject:
-                assert "master,branch:  by %s http://localhost:8080/ci/foo99" % committer_name in n.text
+                assert_in(u'By Test Committer on 10/08/2010 15:32', n.text)
+                assert_in(u'http://localhost:8080/ci/foo99/', n.text)
                 break
         else:
             assert False, 'Did not find notification'


[40/46] allura git commit: CHANGES updated for ASF release 1.3.0

Posted by he...@apache.org.
CHANGES updated for ASF release 1.3.0


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

Branch: refs/heads/hs/7873
Commit: 195c0b10086d84c4306063405626197ce54dbe28
Parents: be5c811
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon Jun 15 13:34:43 2015 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Mon Jun 15 13:34:43 2015 +0300

----------------------------------------------------------------------
 CHANGES | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/195c0b10/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 76a4292..5f4f0a9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,82 @@
+Version 1.3.0  (June 2015)
+
+Upgrade Instructions
+
+ * Run: cd Allura; paster script development.ini allura/scripts/trim_emails.py
+
+New Features
+
+ Webhooks:
+ * [#4542] Implement webhooks
+ * [#7832] APIs to manage webhooks
+ * [#7829] Webhooks documentation
+ Merge requests:
+ * [#7830] One-click merge
+ * [#7865] Config options to disable one-click merge requests
+ * [#7866] Run can_merge in background, and cache results
+ * [#7882] Option to use a tmp dir for git ops on merge request view
+ * [#7872] Show markdown preview/help buttons for merge requests
+ Phone verification:
+ * [#7868] Phone verification system
+ * [#7881] Clean up phone numbers before using them
+ * [#7887] Better messaging for phone validation
+ Other:
+ * [#7806] Create a docker image for Allura
+ * [#7886] Config options to limit ticket & wiki page creation
+ * [#7840] Support Authorization header for OAuth
+ * [#7633] API for has_access
+ * [#6057] Adding an external link should be one step, not two
+ * [#7850] Ability to close discussion on a ticket
+ * [#6107] Disable email posting for the forum? [ss3579]
+
+Security
+
+ * [#7786] Invalidate pwd reset tokens after email change
+ * [#7893] CSRF checks don't work on login
+
+Bug Fixes & Minor Improvements
+
+ Tickets:
+ * [#6017] Should show attachment changelog when ticket gains an attachment
+ * [#5467] Create Issue Button Should Always Appear (Only possibly refer to an explanation for why it was disabled).
+ * [#7834] Bug: viewing a ticket updates its 'updated' date
+ * [#7874] UnicodeEncodeError on ticket attachment diff
+ Code Repositories:
+ * [#7837] Use repo directly instead of DiffInfoDoc
+ * [#7843] Handle quotes in filenames on commit view
+ * [#7857] Retry svnsync repo clone failures
+ * [#7825] Update "new commits" email template
+ * [#7836] Merge request shows 0 commits, if upstream has new commits
+ Wiki:
+ * [#7841] wiki code to not show delete authors.
+ User Profile:
+ * [#7072] User can't access personal subscriptions page [ss6565]
+ * [#7833] Trim emails before saving them to mongo NEEDS SCRIPT
+ Tools Configuration:
+ * [#7817] Replace "mount point" field with URL field, on tool creation forms
+ * [#7820] Validate URLs when configuring external link tool
+ Importers:
+ * [#7864] Error on google code import with paginated comments
+ * [#7854] Decode html entities in importers; and make taskd easier to debug
+ Activity Stream:
+ * [#7823] Commit activity is assigned to wrong person
+ * [#7082] Filter deleted, unmoderated, or spam artifacts from Activity Stream
+ * [#7888] has_activity_access/deleted error
+ Administration:
+ * [#7892] script/task to disable list users
+ For Developers:
+ * [#7827] Upgrade jQuery to latest version
+ * [#7835] Update theme for the documentation.
+ * [#7855] Upgrade docutils, Pygments and Babel, so docs can be built easily
+ * [#7869] During tests, apply patches only once
+ * [#7870] Clean up .ini files
+ Other:
+ * [#1731] Cannot delete a post, after deleting its parent
+ * [#7852] Don't update mod time when viewing artifact creates a cache
+ * [#7856] Error looking up user by email address when email is invalid
+ * [#7876] projects macro display_mode=list is missing CSS
+
+
 Version 1.2.1  (February 2015)
 
 Bug Fixes & Minor Improvements


[14/46] allura git commit: [#6057] ticket:788 Remove unnecessary ForgeLink app admin controller

Posted by he...@apache.org.
[#6057] ticket:788 Remove unnecessary ForgeLink app admin controller


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

Branch: refs/heads/hs/7873
Commit: 1ac85b82a7d4b77cbff630f0a7de9188bc947044
Parents: 3852cd2
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jun 5 09:09:58 2015 +0000
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Tue Jun 9 21:06:06 2015 +0000

----------------------------------------------------------------------
 ForgeLink/forgelink/link_main.py                | 33 +--------
 .../forgelink/templates/app_admin_options.html  | 77 --------------------
 .../forgelink/tests/functional/test_root.py     | 44 -----------
 3 files changed, 4 insertions(+), 150 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/1ac85b82/ForgeLink/forgelink/link_main.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/link_main.py b/ForgeLink/forgelink/link_main.py
index cd43d3f..b50c22e 100644
--- a/ForgeLink/forgelink/link_main.py
+++ b/ForgeLink/forgelink/link_main.py
@@ -15,20 +15,20 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-#-*- python -*-
+# -*- python -*-
 import logging
 import json
 
 # Non-stdlib imports
-from tg import expose, redirect, flash, jsonify
+from tg import expose, jsonify
 from pylons import tmpl_context as c
 from pylons import request
 from formencode import validators as fev
 
 # Pyforge-specific imports
-from allura.app import Application, ConfigOption, SitemapEntry, DefaultAdminController
+from allura.app import Application, ConfigOption, SitemapEntry
 from allura.lib import helpers as h
-from allura.lib.security import require_access, has_access
+from allura.lib.security import require_access
 from allura.lib.utils import permanent_redirect
 from allura import model as M
 from allura.controllers import BaseController
@@ -69,7 +69,6 @@ class ForgeLinkApp(Application):
     def __init__(self, project, config):
         Application.__init__(self, project, config)
         self.root = RootController()
-        self.admin = LinkAdminController(self)
         self.api_root = RootRestController(self)
 
     @property
@@ -126,30 +125,6 @@ class RootController(BaseController):
         return dict()
 
 
-class LinkAdminController(DefaultAdminController):
-
-    @expose()
-    def index(self, **kw):
-        flash('External link URL updated.')
-        redirect(c.project.url() + 'admin/tools')
-
-    @expose('jinja:forgelink:templates/app_admin_options.html')
-    def options(self):
-        return dict(
-            app=self.app,
-            allow_config=has_access(self.app, 'configure')())
-
-    @expose('json:')
-    def set_url(self, **kw):
-        validator = fev.URL(not_empty=True, add_http=True)
-        try:
-            url = validator.to_python(kw.get('url'))
-        except fev.Invalid as e:
-            return {'status': 'error', 'errors': {'url': e.msg}}
-        self.app.config.options['url'] = url
-        return {'status': 'ok'}
-
-
 class RootRestController(BaseController, AppRestControllerMixin):
 
     def __init__(self, app):

http://git-wip-us.apache.org/repos/asf/allura/blob/1ac85b82/ForgeLink/forgelink/templates/app_admin_options.html
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/templates/app_admin_options.html b/ForgeLink/forgelink/templates/app_admin_options.html
deleted file mode 100644
index a62dfa7..0000000
--- a/ForgeLink/forgelink/templates/app_admin_options.html
+++ /dev/null
@@ -1,77 +0,0 @@
-{#-
-       Licensed to the Apache Software Foundation (ASF) under one
-       or more contributor license agreements.  See the NOTICE file
-       distributed with this work for additional information
-       regarding copyright ownership.  The ASF licenses this file
-       to you under the Apache License, Version 2.0 (the
-       "License"); you may not use this file except in compliance
-       with the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing,
-       software distributed under the License is distributed on an
-       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-       KIND, either express or implied.  See the License for the
-       specific language governing permissions and limitations
-       under the License.
--#}
-<!DOCTYPE html>
-{% import 'allura:templates/jinja_master/lib.html' as lib with context %}
-<form id="set-url-form" method="post" action="{{c.project.url()}}admin/{{app.config.options.mount_point}}/set_url">
-  <label for="url" class="grid-4">url</label>
-  <div class="grid-9">
-    {% if not allow_config %}
-      {{app.config.options.get('url', '')}}
-    {% else %}
-      <input id="url" name="url" value="{{app.config.options.get('url', '')}}">
-    {% endif %}
-  </div>
-  <div class="grid-4">&nbsp;</div><div id='url-error' class='grid-9'></div>
-  {% if allow_config %}
-    <div class="grid-13">&nbsp;</div>
-    <hr>
-    <div class="grid-13">&nbsp;</div>
-    <div class="grid-13">
-      <input type="submit" value="Save" id="save" />
-      <a href="#" class="close">Cancel</a>
-    </div>
-  {% endif %}
-  {{lib.csrf_token()}}
-</form>
-
-<script type="text/javascript">
-$(function() {
-  $('#save').on('click', function(e) {
-    e.preventDefault();
-    var form = $('#set-url-form');
-    var button = $(this);
-    var input = form.find('input[name="url"]')
-    var url_error = $('#url-error');
-    var url = input.val();
-    var csrf = $.cookie('_session_id');
-    button.prop('disabled', true);
-    input.prop('disabled', true);
-    url_error.text('');
-    $.post(
-      form.attr('action'),
-      {'_session_id': csrf, 'url': url},
-      function(data) {
-        if (data['status'] == 'ok') {
-          location.reload();
-        } else {
-          url_error.text(data['errors']['url']);
-        }
-        button.prop('disabled', false);
-        input.prop('disabled', false);
-      });
-  });
-});
-</script>
-
-<style type="text/css">
-#url-error {
-  margin-left: 15px;
-  color: #f33;
-}
-</style>

http://git-wip-us.apache.org/repos/asf/allura/blob/1ac85b82/ForgeLink/forgelink/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/tests/functional/test_root.py b/ForgeLink/forgelink/tests/functional/test_root.py
index e4fc656..021b91f 100644
--- a/ForgeLink/forgelink/tests/functional/test_root.py
+++ b/ForgeLink/forgelink/tests/functional/test_root.py
@@ -61,47 +61,3 @@ class TestRootController(TestController):
         response = self.app.get('/link/help')
         # HACK: support for remote redirects is limited in follow()
         assert 'http://www.google.de/search?q=help' in response
-
-    @td.with_link
-    def test_set_url_validation(self):
-        r = self.app.post('/p/test/admin/link/set_url', {})
-        expected = {'status': 'error',
-                    'errors': {'url': u'Please enter a value'}}
-        assert_equal(r.json, expected)
-
-        r = self.app.post('/p/test/admin/link/set_url', {'url': ''})
-        expected = {'status': 'error',
-                    'errors': {'url': u'Please enter a value'}}
-        assert_equal(r.json, expected)
-
-        r = self.app.post('/p/test/admin/link/set_url', {'url': 'bad url'})
-        expected = {'status': 'error',
-                    'errors': {'url': u'That is not a valid URL'}}
-        assert_equal(r.json, expected)
-
-        p = M.Project.query.get(shortname='test')
-        link = p.app_instance('link')
-        assert_equal(link.config.options.get('url'), None)
-
-    @td.with_link
-    def test_set_url(self):
-        data = {'url': 'http://example.com'}  # http
-        r = self.app.post('/p/test/admin/link/set_url', data)
-        assert_equal(r.json, {'status': 'ok'})
-        p = M.Project.query.get(shortname='test')
-        link = p.app_instance('link')
-        assert_equal(link.config.options.get('url'), 'http://example.com')
-
-        data = {'url': 'https://google.com'}  # https
-        r = self.app.post('/p/test/admin/link/set_url', data)
-        assert_equal(r.json, {'status': 'ok'})
-        p = M.Project.query.get(shortname='test')
-        link = p.app_instance('link')
-        assert_equal(link.config.options.get('url'), 'https://google.com')
-
-        data = {'url': 'lmgtfy.com'}  # http is added if not provided
-        r = self.app.post('/p/test/admin/link/set_url', data)
-        assert_equal(r.json, {'status': 'ok'})
-        p = M.Project.query.get(shortname='test')
-        link = p.app_instance('link')
-        assert_equal(link.config.options.get('url'), 'http://lmgtfy.com')


[08/46] allura git commit: [#6057] ticket:788 Validate options in default app admin controller

Posted by he...@apache.org.
[#6057] ticket:788 Validate options in default app admin controller


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

Branch: refs/heads/hs/7873
Commit: 3852cd26008351e4e00ab0099c2172470870bc91
Parents: 72decc8
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jun 5 09:09:17 2015 +0000
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Tue Jun 9 21:06:05 2015 +0000

----------------------------------------------------------------------
 Allura/allura/app.py | 6 ++++++
 1 file changed, 6 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/3852cd26/Allura/allura/app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index c52f1c7..a9d3ff0 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -32,6 +32,7 @@ from bson import ObjectId
 from bson.errors import InvalidId
 from formencode import validators as V
 from webob import exc
+from formencode import validators as fev
 
 from ming.orm import session
 from ming.utils import LazyProperty
@@ -854,6 +855,11 @@ class DefaultAdminController(BaseController):
                     val = asbool(val or False)
                 elif opt.ming_type == int:
                     val = asint(val or 0)
+                try:
+                    val = opt.validate(val)
+                except fev.Invalid as e:
+                    flash(u'{}: {}'.format(opt.name, str(e)), 'error')
+                    continue
                 self.app.config.options[opt.name] = val
             if is_admin:
                 # possibly moving admin mount point


[39/46] allura git commit: [#7886] ticket:789 Add options and help text to development.ini

Posted by he...@apache.org.
[#7886] ticket:789 Add options and help text to development.ini


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

Branch: refs/heads/hs/7873
Commit: be5c8111fa8a2c581c305045e26ee363a25aa44b
Parents: 6936ce2
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Jun 10 09:40:36 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jun 12 18:44:26 2015 +0000

----------------------------------------------------------------------
 Allura/development.ini | 7 +++++++
 1 file changed, 7 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/be5c8111/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index d5a12f4..20ef1ca 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -417,6 +417,13 @@ forgemail.domain = .in.localhost
 ; and 5 projects if the account is less than a day old.  No limits after that
 ;project.rate_limits = {"3600": 2, "86400": 6}
 
+; Specify the number of artifacts allowed to be created by a user
+; depending on the age of the project.
+; Currently supports only tickets and wiki page creation rate limiting.
+; See project.rate_limits help text above for keys & values meaning.
+;forgewiki.rate_limits = {"3600": 100, "172800": 10000}
+;forgetracker.rate_limits = {"3600": 100, "172800": 10000}
+
 ; set this to "false" if you are deploying to production and want performance improvements
 auto_reload_templates = true
 


[06/46] allura git commit: [#7892] delay c.project evaluation more (a scripttask was erroring since `c` wasn't set up

Posted by he...@apache.org.
[#7892] delay c.project evaluation more (a scripttask was erroring since `c` wasn't set up


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

Branch: refs/heads/hs/7873
Commit: 3f2f1ab9344b5e75c27916607c5ff7d4e2f05016
Parents: 66c8d48
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Jun 8 16:44:29 2015 +0000
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Tue Jun 9 15:34:51 2015 +0000

----------------------------------------------------------------------
 Allura/allura/model/auth.py            | 2 +-
 Allura/allura/scripts/disable_users.py | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/3f2f1ab9/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index bc16649..163d5de 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -990,7 +990,7 @@ class AuditLog(object):
 
     @classmethod
     def log(cls, message, *args, **kwargs):
-        project = kwargs.pop('project', c.project)
+        project = kwargs.pop('project') if 'project' in kwargs else c.project
         user = kwargs.pop('user', c.user)
         url = kwargs.pop('url', request.url)
         if args:

http://git-wip-us.apache.org/repos/asf/allura/blob/3f2f1ab9/Allura/allura/scripts/disable_users.py
----------------------------------------------------------------------
diff --git a/Allura/allura/scripts/disable_users.py b/Allura/allura/scripts/disable_users.py
index 9ce1a1b..7eeef33 100644
--- a/Allura/allura/scripts/disable_users.py
+++ b/Allura/allura/scripts/disable_users.py
@@ -49,6 +49,9 @@ class DisableUsers(ScriptTask):
             user = M.User.query.get(username=username)
             if not user:
                 log.info('Could not find user: %s', username)
+            elif user.disabled:
+                log.info('User is already disabled: %s', username)
+                session(user).expunge(user)
             else:
                 log.info('Disabling user: %s', username)
                 auth_provider.disable_user(user)


[29/46] allura git commit: [#7806] ticket:778 Add stuff for SCM snapshots

Posted by he...@apache.org.
[#7806] ticket:778 Add stuff for SCM snapshots


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

Branch: refs/heads/hs/7873
Commit: 05ca971d9fb4ca337328f40b47c9c49314ae3649
Parents: 260e5f5
Author: Igor Bondarenko <je...@gmail.com>
Authored: Sat May 30 13:31:44 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:34 2015 -0400

----------------------------------------------------------------------
 Allura/docker-dev.ini | 4 ++++
 Dockerfile            | 5 +++++
 docker-compose.yml    | 1 +
 3 files changed, 10 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/05ca971d/Allura/docker-dev.ini
----------------------------------------------------------------------
diff --git a/Allura/docker-dev.ini b/Allura/docker-dev.ini
index 2e22df7..0ce00eb 100644
--- a/Allura/docker-dev.ini
+++ b/Allura/docker-dev.ini
@@ -37,6 +37,10 @@ scm.host.rw.hg = /allura-data/scm/hg$path
 scm.host.ro.svn = file:///allura-data/scm/svn$path/
 scm.host.rw.svn = file:///allura-data/scm/svn$path/
 
+scm.repos.tarball.enable = true
+scm.repos.tarball.root = /allura-data/scm/snapshots/
+scm.repos.tarball.url_prefix = http://localhost:8080/
+
 solr.server = http://solr:8983/solr
 
 ;forgemail.host = smtp

http://git-wip-us.apache.org/repos/asf/allura/blob/05ca971d/Dockerfile
----------------------------------------------------------------------
diff --git a/Dockerfile b/Dockerfile
index 26ee833..e054b6f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -27,7 +27,12 @@ RUN apt-get update && apt-get install -y \
     libjpeg8-dev \
     zlib1g-dev \
     python-pip \
+    zip \
     subversion \
     python-svn
 
+# Snapshot generation for SVN (and maybe other SCMs) might fail without this
+RUN locale-gen en_US.UTF-8
+ENV LANG en_US.UTF-8
+
 WORKDIR /allura

http://git-wip-us.apache.org/repos/asf/allura/blob/05ca971d/docker-compose.yml
----------------------------------------------------------------------
diff --git a/docker-compose.yml b/docker-compose.yml
index 835f91a..586afed 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -30,6 +30,7 @@ web:
     - /allura-data/scm/git:/allura-data/scm/git
     - /allura-data/scm/hg:/allura-data/scm/hg
     - /allura-data/scm/svn:/allura-data/scm/svn
+    - /allura-data/scm/snapshots:/allura-data/scm/snapshots
   links:
     - mongo
     - solr


[23/46] allura git commit: [#7806] ticket:773 Add java (jslint in AllutaTest needs it) & svn deps to web image

Posted by he...@apache.org.
[#7806] ticket:773 Add java (jslint in AllutaTest needs it) & svn deps to web image


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

Branch: refs/heads/hs/7873
Commit: 2f4c16b91a02f3c2515a114338121255deca32a2
Parents: 03296bf
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon May 25 13:35:38 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:31 2015 -0400

----------------------------------------------------------------------
 Dockerfile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/2f4c16b9/Dockerfile
----------------------------------------------------------------------
diff --git a/Dockerfile b/Dockerfile
index ed8efe0..1fc3181 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,13 +2,16 @@ FROM ubuntu:12.04
 
 RUN apt-get update && apt-get install -y \
     git-core \
+    default-jre-headless \
     python-dev \
     libssl-dev \
     libldap2-dev \
     libsasl2-dev \
     libjpeg8-dev \
     zlib1g-dev \
-    python-pip
+    python-pip \
+    subversion \
+    python-svn
 
 ENV basedir /allura
 


[22/46] allura git commit: [#7806] ticket:773 Mount SCM dirs to the host and add some options for the future

Posted by he...@apache.org.
[#7806] ticket:773 Mount SCM dirs to the host and add some options for the future


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

Branch: refs/heads/hs/7873
Commit: e43ece79da64580e131a730968c473fb4e2210ba
Parents: 15adba6
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu May 21 17:57:03 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:30 2015 -0400

----------------------------------------------------------------------
 Allura/docker-dev.ini | 12 ++++++++++++
 Dockerfile            |  1 +
 docker-compose.yml    |  5 +++++
 3 files changed, 18 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e43ece79/Allura/docker-dev.ini
----------------------------------------------------------------------
diff --git a/Allura/docker-dev.ini b/Allura/docker-dev.ini
index 37378a1..f33f264 100644
--- a/Allura/docker-dev.ini
+++ b/Allura/docker-dev.ini
@@ -29,6 +29,18 @@ ming.main.uri = mongodb://mongo:27017/allura
 ming.project.uri = mongodb://mongo:27017/project-data
 ming.task.uri = mongodb://mongo:27017/task
 
+scm.repos.root = /allura-data/scm
+scm.host.ro.git = /allura-data/scm/git$path
+scm.host.rw.git = /allura-data/scm/git$path
+scm.host.ro.hg = /allura-data/scm/hg$path
+scm.host.rw.hg = /allura-data/scm/srv/hg$path
+scm.host.ro.svn = file:///allura-data/scm/svn$path/
+scm.host.rw.svn = file:///allura-data/scm/svn$path/
+
+;solr.server = http://solr:8983/solr
+
+;forgemail.host = smtp
+;forgemail.port = 8825
 
 [filter-app:profile]
 use=egg:keas.profile#profiler

http://git-wip-us.apache.org/repos/asf/allura/blob/e43ece79/Dockerfile
----------------------------------------------------------------------
diff --git a/Dockerfile b/Dockerfile
index 1c8e06f..ed8efe0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,7 @@
 FROM ubuntu:12.04
 
 RUN apt-get update && apt-get install -y \
+    git-core \
     python-dev \
     libssl-dev \
     libldap2-dev \

http://git-wip-us.apache.org/repos/asf/allura/blob/e43ece79/docker-compose.yml
----------------------------------------------------------------------
diff --git a/docker-compose.yml b/docker-compose.yml
index b64d4d4..0444ba8 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,6 +6,11 @@ web:
     - "8080:8080"
   volumes:
     - .:/allura
+
+    # mounting it separatelly to create git, svn, hg directories automatically
+    - /allura-data/scm/git:/allura-data/scm/git
+    - /allura-data/scm/hg:/allura-data/scm/hg
+    - /allura-data/scm/svn:/allura-data/scm/svn
   links:
     - mongo
 mongo:


[37/46] allura git commit: [#7886] ticket:789 Helper to check if limit is exceeded for artifact

Posted by he...@apache.org.
[#7886] ticket:789 Helper to check if limit is exceeded for artifact


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

Branch: refs/heads/hs/7873
Commit: d22046ce603f7ec97a1c2ba3b38011f8c22446b7
Parents: be93d3d
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Jun 10 07:48:45 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jun 12 18:44:25 2015 +0000

----------------------------------------------------------------------
 Allura/allura/model/artifact.py | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/d22046ce/Allura/allura/model/artifact.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/artifact.py b/Allura/allura/model/artifact.py
index 32ebc10..1d4e230 100644
--- a/Allura/allura/model/artifact.py
+++ b/Allura/allura/model/artifact.py
@@ -32,6 +32,8 @@ from webhelpers import feedgenerator as FG
 from allura.lib import helpers as h
 from allura.lib import security
 from allura.lib import utils
+from allura.lib import plugin
+from allura.lib import exceptions as forge_exc
 
 from allura.lib.search import SearchIndexable
 from .session import main_orm_session
@@ -408,6 +410,26 @@ class Artifact(MappedClass, SearchIndexable):
         '''Persistent, email-friendly (Message-ID header) id of this artifact'''
         return h.gen_message_id(self._id)
 
+    @classmethod
+    def is_limit_exceeded(cls, app_config):
+        """
+        Returns True if any of artifact creation rate limits are exceeded,
+        False otherwise
+        """
+        pkg = cls.__module__.split('.', 1)[0]
+        opt = u'{}.rate_limits'.format(pkg)
+        count = cls.query.find(dict(app_config_id=app_config._id)).count()
+        provider = plugin.ProjectRegistrationProvider.get()
+        start = provider.registration_date(app_config.project)
+        # have to have the replace because, the generation_time is offset-aware
+        # UTC and h.rate_limit uses offset-naive UTC dates
+        start = start.replace(tzinfo=None)
+        try:
+            h.rate_limit(opt, count, start)
+        except forge_exc.RatelimitError:
+            return True
+        return False
+
 
 class Snapshot(Artifact):
 


[19/46] allura git commit: [#7806] ticket:773 Don't use env vars (not expanded, wrong mount path in result)

Posted by he...@apache.org.
[#7806] ticket:773 Don't use env vars (not expanded, wrong mount path in result)


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

Branch: refs/heads/hs/7873
Commit: 5ceb84dea49c6a15cb47fa9494ccf6adb9f4b7bd
Parents: 6e36416
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu May 21 17:22:58 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:29 2015 -0400

----------------------------------------------------------------------
 docker-compose.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/5ceb84de/docker-compose.yml
----------------------------------------------------------------------
diff --git a/docker-compose.yml b/docker-compose.yml
index 8b7ac88..b64d4d4 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,11 +1,11 @@
 web:
   build: .
-  working_dir: ${basedir}
+  working_dir: /allura
   command: paster serve Allura/docker-dev.ini --reload
   ports:
     - "8080:8080"
   volumes:
-    - .:/${basedir}
+    - .:/allura
   links:
     - mongo
 mongo:


[15/46] allura git commit: [#6057] ticket:792 Get rid of help text for mount points

Posted by he...@apache.org.
[#6057] ticket:792 Get rid of help text for mount points


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

Branch: refs/heads/hs/7873
Commit: 672649fb81687247ffb43a6d7b578f69a5e53790
Parents: 3090de7
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Jun 9 14:10:51 2015 +0000
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Tue Jun 9 21:06:07 2015 +0000

----------------------------------------------------------------------
 .../ext/admin/templates/project_tools.html      | 21 +-------------------
 Allura/allura/public/nf/js/project_tools.js     |  9 ---------
 2 files changed, 1 insertion(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/672649fb/Allura/allura/ext/admin/templates/project_tools.html
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/templates/project_tools.html b/Allura/allura/ext/admin/templates/project_tools.html
index 057af51..38705ed 100644
--- a/Allura/allura/ext/admin/templates/project_tools.html
+++ b/Allura/allura/ext/admin/templates/project_tools.html
@@ -31,7 +31,7 @@
   <div class="nested-grid-container">
     {% for tool in installable_tools %}
       <span class="tcenter grid-4 installable_tool">
-        <a class="install_trig" data-tool="{{ tool['name'] }}" data-relaxed-mount-points="{{ 'true' if tool.app.relaxed_mount_points else 'false' }}">
+        <a class="install_trig" data-tool="{{ tool['name'] }}">
           <span class="tool_title">{{ tool['app'].tool_label }}{{' (%s)' % tool.app.status if tool.app.status != 'production' else ''}}</span><br />
           <img src="{{ g.theme.app_icon_url(tool['name'], 32) or 'unk.png' }}" alt="">
         </a>
@@ -55,25 +55,6 @@
         <input id="id_url_input" type="text" name="new.mount_point" title="The url for this tool relative to {{ full_url }} " class="new_mount_point">
        <p><span id="full-url-preview" data-url="{{full_url}}"></span></p>
     </div>
-    <div class="grid-13">
-      <small>
-        * The mount point is the name of the tool as it will appear in a URL.
-        <span class="mount-point-name-rules tool">
-          A valid mount point for this tool must begin with a letter, contain only lowercase letters,
-          numbers, and dashes, and be from 1-63 characters in length.
-        </span>
-        <span class="mount-point-name-rules tool-relaxed">
-          A valid mount point for this tool must begin with a letter or number, contain only
-          letters, numbers, dashes, underscores, periods, and plus signs, and be
-          from 1-63 characters in length.
-        </span>
-        <span class="mount-point-name-rules subproject">
-          A valid subproject mount point must begin with a letter, contain only lowercase letters,
-          numbers, and dashes, and be from 3-15 characters in length.
-        </span>
-      </small>
-    </div>
-    <div class="grid-13">&nbsp;</div>
     <div id="install_options">{# js inserts form fields here #}</div>
     <div class="grid-13">&nbsp;</div>
     <hr>

http://git-wip-us.apache.org/repos/asf/allura/blob/672649fb/Allura/allura/public/nf/js/project_tools.js
----------------------------------------------------------------------
diff --git a/Allura/allura/public/nf/js/project_tools.js b/Allura/allura/public/nf/js/project_tools.js
index b7c4e0c..a690937 100644
--- a/Allura/allura/public/nf/js/project_tools.js
+++ b/Allura/allura/public/nf/js/project_tools.js
@@ -33,8 +33,6 @@
     install_popup.append(install_form.show());
     $('a.install_trig').click(function () {
         var datatool = $(this).data('tool');
-        var relaxed_mount_points = $(this).data('relaxed-mount-points');
-        install_form.find('.mount-point-name-rules').hide();
         if (datatool) {
             var tool = defaults[datatool];
             install_options.html('Loading options...');
@@ -45,18 +43,11 @@
             new_ep_name.val(datatool);
             new_mount_point.val(tool.default_mount);
             new_mount_label.val(tool.default_label);
-            if (relaxed_mount_points) {
-              install_form.find('.mount-point-name-rules.tool-relaxed').show();
-            }
-            else {
-              install_form.find('.mount-point-name-rules.tool').show();
-            }
         } else {
             install_tool_label.html("Subproject");
             new_ep_name.val('');
             new_mount_point.val('');
             new_mount_label.val('');
-            install_form.find('.mount-point-name-rules.subproject').show();
         }
     });
     // Edit popup


[46/46] allura git commit: [#7873] Clear cache for branches/tags on repo_refresh

Posted by he...@apache.org.
[#7873] Clear cache for branches/tags on repo_refresh


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

Branch: refs/heads/hs/7873
Commit: 52b6b04eeb552a38ab0588ff94f5d3e7b9f50ea4
Parents: 6352e50
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Mon Jun 15 08:12:17 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Jun 15 08:26:32 2015 -0400

----------------------------------------------------------------------
 Allura/allura/model/repo_refresh.py | 9 +++++++++
 1 file changed, 9 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/52b6b04e/Allura/allura/model/repo_refresh.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repo_refresh.py b/Allura/allura/model/repo_refresh.py
index fca220f..74e79ba 100644
--- a/Allura/allura/model/repo_refresh.py
+++ b/Allura/allura/model/repo_refresh.py
@@ -124,6 +124,15 @@ def refresh_repo(repo, all_commits=False, notify=True, new_clone=False):
             if (i + 1) % 100 == 0:
                 log.info('Compute last commit info %d: %s', (i + 1), ci._id)
 
+    # Clear any existing caches for branches/tags
+    if repo.cached_branches:
+        repo.cached_branches = []
+        session(repo).flush()
+
+    if repo.cached_tags:
+        repo.cached_tags = []
+        session(repo).flush()
+
     if not all_commits and not new_clone:
         for commit in commit_ids:
             new = repo.commit(commit)


[31/46] allura git commit: [#7806] ticket:778 Add docker docs

Posted by he...@apache.org.
[#7806] ticket:778 Add docker docs


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

Branch: refs/heads/hs/7873
Commit: 7164f5083e97ae9462a6841a9f5ce97e079ad2ea
Parents: 25a242f
Author: Igor Bondarenko <je...@gmail.com>
Authored: Sat May 30 15:37:05 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:36 2015 -0400

----------------------------------------------------------------------
 INSTALL-docker.markdown | 112 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 112 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/7164f508/INSTALL-docker.markdown
----------------------------------------------------------------------
diff --git a/INSTALL-docker.markdown b/INSTALL-docker.markdown
new file mode 100644
index 0000000..5330084
--- /dev/null
+++ b/INSTALL-docker.markdown
@@ -0,0 +1,112 @@
+<!--
+    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.
+-->
+
+# General info
+
+## Allura runs on following docker containers:
+
+- web
+- mongo
+- taskd
+- solr
+- inmail
+- outmail
+
+## Host-mounted volumes (created on first run)
+
+Current directory mounted as `/allura` inside containers.
+
+Python environment:
+
+- `env-docker/python`
+- `env-docker/bin`
+
+Services data:
+
+- `/allura-data/mongo` - mongo data
+- `/allura-data/solr` - SOLR index
+- `/allura-data/scm/{git,hg,svn}` - code repositories
+- `/allura-data/scm/snapshots` - generated code snapshots
+
+## Ports, exposed to host system:
+
+- 8080 - webapp
+- 8983 - SOLR admin panel (http://localhost:8983/solr/)
+- 8825 - incoming mail listener
+
+
+# First run
+
+Install [Docker](http://docs.docker.com/installation/) 
+and [Docker Compose](https://docs.docker.com/compose/install/).
+
+Build/fetch all required images:
+
+    ~$ docker-compose build
+
+Install requirements:
+
+    ~$ docker-compose run web pip install -r requirements.txt
+
+Install Allura packages:
+
+    ~$ docker-compose run web ./rebuild-all.bash
+
+Initialize database with test data:
+
+    ~$ docker-compose run web bash -c 'cd Allura && paster setup-app docker-dev.ini'
+
+Start containers in background:
+
+    ~$ docker-compose up -d
+
+# Useful commands
+
+Restarting all containers:
+
+    ~$ docker-compose up -d
+
+View logs from all services:
+
+    ~$ docker-compose logs
+
+You can specify one or more services to view logs only from them, e.g. to see
+outgoing mail:
+
+    ~$ docker-compose logs outmail
+
+Update requirements and reinstall apps:
+
+    ~$ docker-compose run web pip install -r requirements.txt
+    ~$ docker-compose run web ./rebuild-all.bash
+
+You may want to restart at least taskd container after that in order for it to
+pick up changes.
+
+Running all tests:
+
+    ~$ docker-compose run web ./run_tests
+
+Running subset of tests:
+
+    ~$ docker-compose run web bash -c 'cd ForgeGit && nosetests forgegit.tests.functional.test_controllers:TestFork'
+
+Connecting to mongo directly:
+
+    ~$ docker-compose run mongo mongo --host mongo


[44/46] allura git commit: [#7873] Add tests for git branch/tag cache system

Posted by he...@apache.org.
[#7873] Add tests for git branch/tag cache system


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

Branch: refs/heads/hs/7873
Commit: f24debe77605f328768c0c30ae76664cfcd6307d
Parents: 0bdceea
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Mon Jun 15 08:25:17 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Jun 15 08:26:32 2015 -0400

----------------------------------------------------------------------
 ForgeGit/forgegit/tests/functional/test_controllers.py |  5 ++++-
 ForgeGit/forgegit/tests/model/test_repository.py       | 11 +++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/f24debe7/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 917f765..29c6453 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -390,7 +390,10 @@ class TestRootController(_TestCase):
 
     def test_default_branch(self):
         assert_equal(c.app.default_branch_name, 'master')
-        c.app.repo.set_default_branch('zz')
+        vv = c.app.repo.set_default_branch('zz')
+        print('-' * 10)
+        print(vv)
+        print('-' * 10)
         assert_equal(c.app.default_branch_name, 'zz')
         c.app.repo.set_default_branch('master')
         assert_equal(c.app.default_branch_name, 'master')

http://git-wip-us.apache.org/repos/asf/allura/blob/f24debe7/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 349efe6..47dc34d 100644
--- a/ForgeGit/forgegit/tests/model/test_repository.py
+++ b/ForgeGit/forgegit/tests/model/test_repository.py
@@ -728,6 +728,17 @@ class TestGitRepo(unittest.TestCase, RepoImplTestBase):
             res_with_tmp = self.repo.merge_request_commits(mr)
         assert_equals(res_without_tmp, res_with_tmp)
 
+    def test_cached_branches(self):
+        with mock.patch.dict('allura.lib.app_globals.config', {'repo_refs_cache_threshold': '0'}):
+            rev = GM.Repository.query.get(_id=self.repo['_id'])
+            branches = rev._impl._get_refs('branches')
+            assert_equal(rev.cached_branches, branches)
+
+    def test_cached_tags(self):
+        with mock.patch.dict('allura.lib.app_globals.config', {'repo_refs_cache_threshold': '0'}):
+            rev = GM.Repository.query.get(_id=self.repo['_id'])
+            tags = rev._impl._get_refs('tags')
+            assert_equal(rev.cached_tags, tags)
 
 class TestGitImplementation(unittest.TestCase):
 


[41/46] allura git commit: [#7873] Performance improvements when accessing tags and branches in git

Posted by he...@apache.org.
[#7873] Performance improvements when accessing tags and branches in git


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

Branch: refs/heads/hs/7873
Commit: 6e5d65936f44f57d615336708817862353a7b21f
Parents: 195c0b1
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Tue May 5 13:47:19 2015 +0000
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Jun 15 08:26:31 2015 -0400

----------------------------------------------------------------------
 ForgeGit/forgegit/git_main.py       |  2 +-
 ForgeGit/forgegit/model/git_repo.py | 32 +++++++++++++++++++++++++++++---
 2 files changed, 30 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/6e5d6593/ForgeGit/forgegit/git_main.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/git_main.py b/ForgeGit/forgegit/git_main.py
index 62fc0f7..bb19ec3 100644
--- a/ForgeGit/forgegit/git_main.py
+++ b/ForgeGit/forgegit/git_main.py
@@ -66,7 +66,7 @@ class ForgeGitApp(RepositoryApp):
     def repo(self):
         return GM.Repository.query.get(app_config_id=self.config._id)
 
-    @property
+    @LazyProperty
     def default_branch_name(self):
         return self.repo.get_default_branch('master')
 

http://git-wip-us.apache.org/repos/asf/allura/blob/6e5d6593/ForgeGit/forgegit/model/git_repo.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/model/git_repo.py b/ForgeGit/forgegit/model/git_repo.py
index 416db33..d6e791c 100644
--- a/ForgeGit/forgegit/model/git_repo.py
+++ b/ForgeGit/forgegit/model/git_repo.py
@@ -533,6 +533,32 @@ class GitImplementation(M.RepositoryImplementation):
             return False
 
     @LazyProperty
+    def _is_valid(self):
+        """ Verifies the validity of the reference objects in the git database
+
+        Returns True if no issues are found. This allows us to bypass the individual testing of each ref
+        unless absolutely necessary.
+
+        :rtype: bool
+        """
+        try:
+            self._git.git.fsck(full=True)
+            return True
+        except git.GitCommandError as gce:
+            log.debug(u"Found inconsistency in {}: {}".format(self._repo.name, gce.stderr))
+            return False
+
+    def _get_refs(self, ref_list):
+        """ Returns a list of valid reference objects from the git database
+
+        :return: List of git ref objects.
+        :rtype: list
+        """
+        if self._is_valid:
+            return [Object(name=ref.name, object_id=ref.commit.hexsha) for ref in ref_list]
+        return [Object(name=ref.name, object_id=ref.commit.hexsha) for ref in ref_list if ref.is_valid()]
+
+    @LazyProperty
     def head(self):
         if not self._git or not self._git.heads:
             return None
@@ -549,15 +575,15 @@ class GitImplementation(M.RepositoryImplementation):
 
     @LazyProperty
     def heads(self):
-        return [Object(name=b.name, object_id=b.commit.hexsha) for b in self._git.heads if b.is_valid()]
+        return self._get_refs(self._git.heads)
 
     @LazyProperty
     def branches(self):
-        return [Object(name=b.name, object_id=b.commit.hexsha) for b in self._git.branches if b.is_valid()]
+        return self._get_refs(self._git.branches)
 
     @LazyProperty
     def tags(self):
-        return [Object(name=t.name, object_id=t.commit.hexsha) for t in self._git.tags if t.is_valid()]
+        return self._get_refs(self._git.tags)
 
     def set_default_branch(self, name):
         if not name:


[32/46] allura git commit: [#7806] use mongod --smallfiles to avoid mongo startup errors if disk space is limited (e.g. boot2docker defaults)

Posted by he...@apache.org.
[#7806] use mongod --smallfiles to avoid mongo startup errors if disk space is limited (e.g. boot2docker defaults)


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

Branch: refs/heads/hs/7873
Commit: e7f1995b509c3fe412f110a0caab70194827ad91
Parents: 7164f50
Author: Dave Brondsema <da...@brondsema.net>
Authored: Fri Jun 12 11:37:51 2015 -0400
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:36 2015 -0400

----------------------------------------------------------------------
 docker-compose.yml | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e7f1995b/docker-compose.yml
----------------------------------------------------------------------
diff --git a/docker-compose.yml b/docker-compose.yml
index 230b3d5..8c75cb4 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -62,6 +62,7 @@ mongo:
     - "27017"
   volumes:
     - /allura-data/mongo:/data/db
+  command: mongod --smallfiles
 
 outmail:
   image: allura_web


[04/46] allura git commit: [#7893] clean up prints

Posted by he...@apache.org.
[#7893] clean up prints


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

Branch: refs/heads/hs/7873
Commit: 0d593dcb200bee27263e5a6f9bf6be3d685e2dea
Parents: b6623f9
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Jun 9 13:47:51 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jun 9 13:47:51 2015 +0000

----------------------------------------------------------------------
 Allura/allura/tests/functional/test_auth.py | 3 ---
 1 file changed, 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/0d593dcb/Allura/allura/tests/functional/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_auth.py b/Allura/allura/tests/functional/test_auth.py
index ea13ee1..3727c6c 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -333,13 +333,10 @@ class TestAuth(TestController):
         email.confirmed = False
         ThreadLocalORMSession.flush_all()
 
-        print 'email working with is', email
         self.app.post('/auth/send_verification_link',
                       params=dict(a=email_address,
                                   _session_id=self.app.cookies['_session_id']),
                       extra_environ=dict(username='test-user'))
-        print 'later', M.EmailAddress.find(dict(email=email_address, claimed_by_user_id=user._id)).first()
-        assert email.nonce
 
         user1 = M.User.query.get(username='test-user-1')
         user1.claim_address(email_address)


[45/46] allura git commit: [#7873] Add a mongo cache backend to speed up branches/tags

Posted by he...@apache.org.
[#7873] Add a mongo cache backend to speed up branches/tags


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

Branch: refs/heads/hs/7873
Commit: 0bdceea52a7d0b6d6f96d9614255af8a32d8849c
Parents: 64fd1d8
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Mon Jun 15 08:24:29 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Jun 15 08:26:32 2015 -0400

----------------------------------------------------------------------
 ForgeGit/forgegit/git_main.py       |  2 +-
 ForgeGit/forgegit/model/git_repo.py | 63 ++++++++++++++++++++------------
 2 files changed, 40 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/0bdceea5/ForgeGit/forgegit/git_main.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/git_main.py b/ForgeGit/forgegit/git_main.py
index bb19ec3..62fc0f7 100644
--- a/ForgeGit/forgegit/git_main.py
+++ b/ForgeGit/forgegit/git_main.py
@@ -66,7 +66,7 @@ class ForgeGitApp(RepositoryApp):
     def repo(self):
         return GM.Repository.query.get(app_config_id=self.config._id)
 
-    @LazyProperty
+    @property
     def default_branch_name(self):
         return self.repo.get_default_branch('master')
 

http://git-wip-us.apache.org/repos/asf/allura/blob/0bdceea5/ForgeGit/forgegit/model/git_repo.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/model/git_repo.py b/ForgeGit/forgegit/model/git_repo.py
index d6e791c..d9ede88 100644
--- a/ForgeGit/forgegit/model/git_repo.py
+++ b/ForgeGit/forgegit/model/git_repo.py
@@ -532,31 +532,45 @@ class GitImplementation(M.RepositoryImplementation):
         except KeyError:
             return False
 
-    @LazyProperty
-    def _is_valid(self):
-        """ Verifies the validity of the reference objects in the git database
-
-        Returns True if no issues are found. This allows us to bypass the individual testing of each ref
-        unless absolutely necessary.
+    def _get_refs(self, field_name):
+        """ Returns a list of valid reference objects (branches or tags) from the git database
 
-        :rtype: bool
+        :return: List of git ref objects.
+        :rtype: list
         """
+
+        cache_name = 'cached_' + field_name
+        cache = getattr(self._repo, cache_name, None)
+
+        if cache:
+            return cache
+
+        ref_list = getattr(self._git, field_name)
+
+        refs = []
+        start_time = time()
+        for ref in ref_list:
+            try:
+                hex_sha = ref.commit.hexsha
+            except ValueError:
+                log.debug(u"Found invalid sha: {}".format(ref))
+                continue
+            refs.append(Object(name=ref.name, object_id=hex_sha))
+        time_taken = time() - start_time
+
+        threshold = tg.config.get('repo_refs_cache_threshold')
         try:
-            self._git.git.fsck(full=True)
-            return True
-        except git.GitCommandError as gce:
-            log.debug(u"Found inconsistency in {}: {}".format(self._repo.name, gce.stderr))
-            return False
+            threshold = float(threshold) if threshold else None
+        except ValueError:
+            threshold = None
+            log.warn('Skipping reference caching - The value for config param '
+                     '"repo_refs_cache_threshold" must be a float.')
 
-    def _get_refs(self, ref_list):
-        """ Returns a list of valid reference objects from the git database
+        if threshold is not None and time_taken > threshold:
+            setattr(self._repo, cache_name, refs)
+            session(self._repo).flush(self._repo)
 
-        :return: List of git ref objects.
-        :rtype: list
-        """
-        if self._is_valid:
-            return [Object(name=ref.name, object_id=ref.commit.hexsha) for ref in ref_list]
-        return [Object(name=ref.name, object_id=ref.commit.hexsha) for ref in ref_list if ref.is_valid()]
+        return refs
 
     @LazyProperty
     def head(self):
@@ -573,17 +587,18 @@ class GitImplementation(M.RepositoryImplementation):
                 return None  # no valid heads
         return self._git.head.commit.hexsha
 
-    @LazyProperty
+    @property
     def heads(self):
-        return self._get_refs(self._git.heads)
+        """ In git, heads are just branches """
+        return self.branches
 
     @LazyProperty
     def branches(self):
-        return self._get_refs(self._git.branches)
+        return self._get_refs('branches')
 
     @LazyProperty
     def tags(self):
-        return self._get_refs(self._git.tags)
+        return self._get_refs('tags')
 
     def set_default_branch(self, name):
         if not name:


[12/46] allura git commit: [#6057] ticket:792 Allow ConfigOption to specify extra attrs for html input tag

Posted by he...@apache.org.
[#6057] ticket:792 Allow ConfigOption to specify extra attrs for html input tag

and use it to pass type='url' to ForgeLink's url options


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

Branch: refs/heads/hs/7873
Commit: bc3c028c7cc04430aaf0a1d81c8c194ed65301cb
Parents: a0b3aed
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Jun 9 13:41:25 2015 +0000
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Tue Jun 9 21:06:06 2015 +0000

----------------------------------------------------------------------
 Allura/allura/app.py                                      | 8 +++++++-
 Allura/allura/templates/app_admin_options.html            | 4 ++--
 Allura/allura/templates/app_admin_options_on_install.html | 4 ++--
 Allura/allura/tests/test_app.py                           | 5 +++++
 ForgeLink/forgelink/link_main.py                          | 3 ++-
 5 files changed, 18 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/bc3c028c/Allura/allura/app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index 58aa49d..2683e36 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -36,6 +36,7 @@ from formencode import validators as fev
 
 from ming.orm import session
 from ming.utils import LazyProperty
+import ew.jinja2_ew as ew
 
 from allura.lib import helpers as h
 from allura.lib.security import has_access, require_access
@@ -56,13 +57,14 @@ class ConfigOption(object):
 
     """
 
-    def __init__(self, name, ming_type, default, label=None, validator=None):
+    def __init__(self, name, ming_type, default, label=None, validator=None, extra_attrs=None):
         """Create a new ConfigOption.
 
         """
         self.name, self.ming_type, self._default, self.label = (
             name, ming_type, default, label or name)
         self.validator = validator
+        self.extra_attrs = extra_attrs
 
     @property
     def default(self):
@@ -78,6 +80,10 @@ class ConfigOption(object):
             return self.validator.to_python(value)
         return value
 
+    def render_attrs(self):
+        """Return extra_attrs formatted in a way that allows inserting into html tag"""
+        return ew._Jinja2Widget().j2_attrs(self.extra_attrs or {})
+
 
 class SitemapEntry(object):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/bc3c028c/Allura/allura/templates/app_admin_options.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/app_admin_options.html b/Allura/allura/templates/app_admin_options.html
index 8924823..bf013c4 100644
--- a/Allura/allura/templates/app_admin_options.html
+++ b/Allura/allura/templates/app_admin_options.html
@@ -26,9 +26,9 @@
            {{app.config.options.get(o.name, o.default)}}
       {% else%}
         {% if o.ming_type.__name__ == 'bool' %}
-            <input id="{{o.name}}" name="{{o.name}}" type="checkbox"{{ ' checked="checked"' if app.config.options.get(o.name, o.default)}}>
+            <input {{o.render_attrs()}} id="{{o.name}}" name="{{o.name}}" type="checkbox"{{ ' checked="checked"' if app.config.options.get(o.name, o.default)}}>
         {% else %}
-            <input id="{{o.name}}" name="{{o.name}}" value="{{app.config.options.get(o.name, o.default)}}">
+            <input {{o.render_attrs()}} id="{{o.name}}" name="{{o.name}}" value="{{app.config.options.get(o.name, o.default)}}">
         {% endif %}
       {% endif %}
     </div>

http://git-wip-us.apache.org/repos/asf/allura/blob/bc3c028c/Allura/allura/templates/app_admin_options_on_install.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/app_admin_options_on_install.html b/Allura/allura/templates/app_admin_options_on_install.html
index bc0d8ea..218dd61 100644
--- a/Allura/allura/templates/app_admin_options_on_install.html
+++ b/Allura/allura/templates/app_admin_options_on_install.html
@@ -20,9 +20,9 @@
   <label class="grid-13" for="{{o.name}}">{{o.label|capitalize}}</label>
   <div class="grid-13">
     {% if o.ming_type.__name__ == 'bool' %}
-      <input id="{{o.name}}" name="{{o.name}}" type="checkbox"{{ ' checked="checked"' if o.default}}>
+      <input {{o.render_attrs()}}id="{{o.name}}" name="{{o.name}}" type="checkbox"{{ ' checked="checked"' if o.default}}>
     {% else %}
-      <input id="{{o.name}}" name="{{o.name}}" value="{{o.default or ''}}">
+      <input {{o.render_attrs()}} id="{{o.name}}" name="{{o.name}}" value="{{o.default or ''}}">
     {% endif %}
   </div>
 {% endfor %}

http://git-wip-us.apache.org/repos/asf/allura/blob/bc3c028c/Allura/allura/tests/test_app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_app.py b/Allura/allura/tests/test_app.py
index 2642a95..230b5f9 100644
--- a/Allura/allura/tests/test_app.py
+++ b/Allura/allura/tests/test_app.py
@@ -54,6 +54,11 @@ def test_config_options():
     assert options[1].default == 'MyTestValue'
 
 
+def test_config_options_render_attrs():
+    opt = app.ConfigOption('test1', str, None, extra_attrs={'type': 'url'})
+    assert_equal(opt.render_attrs(), 'type="url"')
+
+
 def test_config_option_without_validator():
     opt = app.ConfigOption('test1', str, None)
     assert_equal(opt.validate(None), None)

http://git-wip-us.apache.org/repos/asf/allura/blob/bc3c028c/ForgeLink/forgelink/link_main.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/link_main.py b/ForgeLink/forgelink/link_main.py
index b50c22e..ec32974 100644
--- a/ForgeLink/forgelink/link_main.py
+++ b/ForgeLink/forgelink/link_main.py
@@ -51,7 +51,8 @@ class ForgeLinkApp(Application):
     config_options = Application.config_options + [
         ConfigOption(
             'url', str, None,
-            validator=fev.URL(not_empty=True, add_http=True)),
+            validator=fev.URL(not_empty=True, add_http=True),
+            extra_attrs={'type': 'url'}),
     ]
     config_on_install = ['url']
     searchable = True


[18/46] allura git commit: [#7806] ticket:773 Inherit docker-dev.ini from development.ini

Posted by he...@apache.org.
[#7806] ticket:773 Inherit docker-dev.ini from development.ini


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

Branch: refs/heads/hs/7873
Commit: 15adba65b3ac78ff89a8240d666bf1e1594fc27f
Parents: 5ceb84d
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu May 21 17:37:22 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:29 2015 -0400

----------------------------------------------------------------------
 Allura/docker-dev.ini | 457 +--------------------------------------------
 1 file changed, 1 insertion(+), 456 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/15adba65/Allura/docker-dev.ini
----------------------------------------------------------------------
diff --git a/Allura/docker-dev.ini b/Allura/docker-dev.ini
index 0343dd3..37378a1 100644
--- a/Allura/docker-dev.ini
+++ b/Allura/docker-dev.ini
@@ -15,484 +15,29 @@
 ;       specific language governing permissions and limitations
 ;       under the License.
 
-
-;
-; Allura configuration
-;
-; Default config values are shown in this file.
-; Commented-out configurations are examples that you can use if you want.
-;
-; Logging configuration is at the end of the file (starting at [loggers])
-;
-; There are many settings you should change for your site (name, domain, secret keys, etc)
-; More settings should be changed for good performance in a production site (no autoreload, no debugging, etc)
-;
-; You may copy this file to make a new configuration file (e.g. production.ini)
-; Or inherit from this file by starting your .ini file like this:
-;    [app:main]
-;    use = config:development.ini#main
-; Then just use the new file name instead of development.ini for any paster commands you run.
-
-
-[DEFAULT]
-; this section is for a few settings that are shared with error handling middleware
-
-; WARNING: *THE LINE BELOW MUST BE CHANGED ON A PRODUCTION ENVIRONMENT*
-; Debug mode will enable the interactive debugging tool, allowing ANYONE to
-; execute malicious code after an exception is raised.
-debug = true
-; If you want to receive an email for every unhandled HTTP 500 error, set your email address here:
-;email_to = you@yourdomain.com
-error_email_from = paste@localhost
-
-; SMTP settings for outgoing mail
-smtp_tls = false
-smtp_ssl = false
-;smtp_user = some_user
-;smtp_password = some_password
-smtp_timeout = 10
-smtp_server = localhost
-smtp_port = 8826
-; Reply-To and From address often used in email notifications:
-forgemail.return_path = noreply@localhost
-
-
-;
-; Settings for `paster serve` command
-;
 [server:main]
 use = egg:Paste#http
 host = 0.0.0.0
 port = 8080
 
-
-;
-; The main allura settings
-;
 [app:main]
-use = egg:Allura
-full_stack = true
-
-; Change this to your website's name
-site_name = Allura
-; Change these to your website's domain
-domain = localhost
-; Change this to your website's full URL
-base_url = http://localhost:8080
-; This should be the same as base_url
-forgemail.url = http://localhost:8080
-
-; Used to uniquify references to static resources, can be a timestamp or any unique value
-; This should be updated each time you deploy (or make significant changes, like new tools, new css)
-build_key=1276635823
-
-; Used by Turbogears / Pylons in some cases.  Not particularly relevant for Allura.
-cache_dir = %(here)s/data
-
-; Cache Neighborhood objects for N seconds (speeds up requests).
-; Set to 0 to disable (the default).
-;neighborhood.cache.duration = 0
-
-; Template cache settings
-; See http://jinja.pocoo.org/docs/api/#jinja2.Environment
-jinja_cache_size = -1
-;jinja_bytecode_cache_type = filesystem
-;jinja_bytecode_cache_type = memcached
-;memcached_host =
-
-; Docs at http://beaker.readthedocs.org/en/latest/configuration.html#session-options
-; and http://beaker.readthedocs.org/en/latest/modules/session.html#beaker.session.CookieSession
-beaker.session.key = allura
-beaker.session.type = cookie
-beaker.session.httponly = true
-; set this to true if you use HTTPS.  If you use force_ssl.logged_in, this will be set automatically when logged in and not when not.
-beaker.session.secure = false
-; CHANGE THIS VALUE FOR YOUR SITE
-beaker.session.validate_key = 714bfe3612c42390726f
-
-; Google Analytics account for tracking
-;ga.account = UA-XXXXX-X
-
-; Project registration system.  Only local is available, unless you write a custom one for custom integration.
-registration.method = local
-theme = allura
-
-; For LDAP see https://forge-allura.apache.org/docs/getting_started/installation.html#using-ldap
-;auth.method = ldap
-auth.method = local
-auth.remember_for = 365  ; in days, for the "remember me" checkbox on login
-
-; Customize login/logout URLs only if you have some custom authentication set up.
-auth.login_url = /auth/
-auth.logout_url = /auth/logout
-; the login fragement URL shows just the form, not a whole page.  It is used within a login overlay on some pages
-auth.login_fragment_url = /auth/login_fragment/
-auth.post_logout_url = /
-
-auth.min_password_len = 6
-auth.max_password_len = 30
-
-; password expiration options (disabled if neither is set)
-;auth.pwdexpire.days = 1
-;auth.pwdexpire.before = 1401949912  ; unix timestamp
-
-; if using LDAP, also run `pip install python-ldap` in your Allura environment
-
-auth.ldap.server = ldaps://localhost/
-auth.ldap.suffix = ou=people,dc=localdomain
-auth.ldap.admin_dn = cn=admin,dc=localdomain
-auth.ldap.admin_password = secret
-auth.ldap.schroot_name = scm
-auth.ldap.use_schroot = false
-auth.ldap.password.algorithm = 6
-auth.ldap.password.rounds = 6000
-auth.ldap.password.salt_len = 16
-; "autoregister" allows users to log in to Allura with an existing LDAP account
-; If using ldap, with autoregister, you should also set "allow_user_registration"
-; to false below.
-; Set "autoregister" to false to require user to register in Allura to create
-; the LDAP record and Allura record for the user.
-auth.ldap.autoregister = true
-
-auth.allow_user_registration = true
-auth.allow_user_to_disable_account = true
-auth.allow_edit_prefs = true
-auth.allow_password_change = true
-auth.allow_upload_ssh_key = false
-auth.allow_user_messages_config = true
-auth.allow_birth_date = true
-auth.allow_non_primary_email_password_reset = true
-auth.require_email_addr = true
-; List of social network options to use on user account settings
-socialnetworks = Facebook, Linkedin, Twitter, Google+
-
-; In seconds
-auth.recovery_hash_expiry_period = 600
-
-user_prefs_storage.method = local
-; user_prefs_storage.method = ldap
-; If using ldap, you can specify which fields to use for a preference.
-; Any fields not specified here will be stored locally in mongo
-user_prefs_storage.ldap.fields.display_name = cn
-
-; Limit the number of emails a user can claim.
-user_prefs.maximum_claimed_emails = 20
-
-; Control the order of sections on the user profile page
-;user_profile_sections.order = activity, personal-data, skills
-
-; Site admins will be the same as the admins of this project:
-site_admin_project = allura
-site_admin_project_nbhd = Projects
-
-; Spam filtering service: mollom or akismet
-;spam.method = akismet
-; for akismet:
-;spam.key =
-; for mollom:
-;spam.public_key =
-;spam.private_key =
-
-; Webhook timeout in seconds
-webhook.timeout = 30
-; List of pauses between retries, if hook fails (in seconds)
-webhook.retry = 60 120 240
-; Limit rate of webhook firing (in seconds, default = 30)
-; Option format: webhook.<hook type>.limit,
-; all '-' in hook type must be changed to '_'
-; e.g. for repo-push webhook:
-webhook.repo_push.limit = 30
-; Limit max number of hooks that can be created for given project/app
-; Option name format: same as above.
-; Value format: json dict, where keys are app names (as appears in
-; `WebhookSender.triggered_by`) and values are actual limits (default=3), e.g.:
-webhook.repo_push.max_hooks = {"git": 3, "hg": 3, "svn": 3}
-
-; Additional fields for admin project/user search
-; Note: whitespace after comma is important!
-;search.project.additional_search_fields = private, url, title
-;search.user.additional_search_fields = email_addresses
-
-; Additional fields to show in the result of admin project/user search
-; Note: whitespace after comma is important!
-;search.project.additional_display_fields = private, url, title
-;search.user.additional_display_fields = email_addresses
-
-; To make all pages use ssl:   (also set beaker.session.secure above)
-;force_ssl.pattern = .
-; To use ssl if and only if a user is logged in:
-;force_ssl.logged_in = true
-; If you set force_ssl.logged_in, you probably want some URLs to be ssl when logged out:
-;force_ssl.pattern = ^/auth|^/[a-z0-9-]+/import_project/  ; import_project uses a login overlay
-; And to permit some URLs to be accessed over http anyway:
-;no_redirect.pattern = ^/nf/\d+/_(ew|static)_/|^/rest/|^/nf/tool_icon_css|^/auth/refresh_repo
-
-
-; Set the locations of some static resources.  ("ew" stands for EasyWidgets library)
-;  script_name is the path that is handled by the application
-;  url_base is the prefix that references to the static resources should have
-; If you use a CDN, put your CDN prefix in the url_base values
-ew.script_name = /nf/%(build_key)s/_ew_/
-ew.url_base = /nf/%(build_key)s/_ew_/
-static.script_name = /nf/%(build_key)s/_static_/
-static.url_base = /nf/%(build_key)s/_static_/
-
-; Expires header for "static" resources served through allura (e.g. icons, attachments, /nf/tool_icon_css)
-files_expires_header_secs = 1209600 ; 2 weeks
-
-ew.extra_headers = [ ('Access-Control-Allow-Origin', '*') ]
-
-; If your environment (e.g. behind a server-side proxy) needs to look at an http header to get the actual remote addr
-;ip_address_header = X-Forwarded-For
-
-; SCM settings for local development
-scm.host.ro.git = /srv/git$path
-scm.host.rw.git = /srv/git$path
-; remote access varies by configuration.  If you are using a vagrant VM, this should work:
-;scm.host.rw.git = ssh://vagrant@localhost:2222/srv/git$path
-scm.host.ro.hg = /srv/hg$path
-scm.host.rw.hg = /srv/hg$path
-scm.host.ro.svn = file:///srv/svn$path/
-scm.host.rw.svn = file:///srv/svn$path/
-
-; SCM settings for chroot + ldap configuration.  See Allura/docs/getting_started/scm_host.rst
-;scm.host.ro.git = git://git.localhost$path
-;scm.host.rw.git = ssh://$username@localhost:8022/scm-repo$path
-;scm.host.ro.hg = http://hg.localhost$path
-;scm.host.rw.hg = ssh://$username@localhost:8022/scm-repo$path
-;scm.host.ro.svn = http://svn.localhost$path/
-;scm.host.rw.svn = svn+ssh://localhost:8022/scm-repo$path/
-
-; SCM settings for https (sorry no docs for setting these up)
-; these settings are currently required by the template, no matter what
-scm.host.https.git = https://$username@localhost:8022/scm-repo$path
-scm.host.https_anon.git = https://localhost:8022/scm-repo$path
-scm.host.https.hg = https://$username@localhost:8022/scm-repo$path
-scm.host.https_anon.hg = https://localhost:8022/scm-repo$path
-scm.host.https.svn = https://localhost:8022/scm-repo$path/
-scm.host.https_anon.svn = https://localhost:8022/scm-repo$path/
-
-scm.clone.git = git clone $source_url $dest_path
-scm.clone.hg = hg clone $source_url $dest_path
-scm.clone.ro.svn = svn checkout $source_url $dest_path
-scm.clone.https_anon.svn = svn checkout $source_url $dest_path
-scm.clone.svn = svn checkout --username=$username $source_url $dest_path
+use = config:development.ini#main
 
-scm.repos.root = /srv
-scm.repos.tarball.enable = false
-scm.repos.tarball.root = /usr/share/nginx/www/
-scm.repos.tarball.url_prefix = http://localhost/
-scm.repos.tarball.zip_binary = /usr/bin/zip
-
-; SCM imports (currently just SVN) will retry if it fails
-; You can control the number of tries and delay between tries here:
-scm.import.retry_count = 50
-scm.import.retry_sleep_secs = 5
-
-; One-click merge is enabled by default, but can be turned off on for each type of repo
-scm.merge.git.disabled = false
-scm.merge.hg.disabled = false
-
-
-; bulk_export_enabled = true
-; If you keep bulk_export_enabled, you should set up your server to securely share bulk_export_path with users somehow
-bulk_export_path = /tmp/bulk_export/{nbhd}/{project}
-bulk_export_filename = {project}-backup-{date:%Y-%m-%d-%H%M%S}.zip
-; You will need to specify site-specific instructions here for accessing the exported files.
-bulk_export_download_instructions = Sample instructions for {project}
-
-importer_upload_path = /tmp/importer_upload/{nbhd}/{project}
-
-; To disable any plugin, tool, importer, etc from being available, you can use the disable_entry_points config option.
-; Specify the keys and values as they are declared in the tool's "setup.py" file.
-; Examples:
-;disable_entry_points.importers = google-code-tracker, google-code-repo
-;disable_entry_points.allura.project_importers = google-code
-
-; Importers specifically, can be left enabled but not linked to.  You have to know the URL to use it.  Example:
-;hidden_importers = trac-tickets
-
-; GitHub importer keys.  For github ticket import, it is best to set
-; up an app at https://github.com/settings/applications  Use the root URL
-; of your Allura instance for both URLs, and enter client values here:
-;github_importer.client_id =
-;github_importer.client_secret =
-
-; If your site has docs about specific importers, you can add them here and
-; they'll appear on the import forms
-;doc.url.importers.Google Code = http://...
-
-; List of oauth API keys permitted to use special forum import API
-; (should be converted to newer importer system)
-;oauth.can_import_forum = api-key-1234, fa832r0fdsafd, f23f80sdf32fd
-
-
-; space-separated list of tool names that are valid options
-; for project admins to set for their 'support_page' field
-; this field is not used by default in Allura, so this option
-; is disabled by default
-;support_tool_choices = wiki tickets discussion
-
-; Control how /categories URL can be accessed to edit trove categories (used in project categories and user skills)
-; Default: everyone
-trovecategories.enableediting = true
-; Nobody:
-;trovecategories.enableediting = false
-; Site admins only:
-;trovecategories.enableediting = admin
-
-; ActivityStream
 activitystream.master = mongodb://mongo:27017
-activitystream.database = activitystream
-activitystream.activity_collection = activities
-activitystream.node_collection = nodes
-activitystream.timeline_collection = timelines
-activitystream.enabled = true
-activitystream.recording.enabled = true
 
-; Ming setup
-; These don't necessarily have to be separate databases, they could
-; be all in the same database if desired
 ming.main.uri = mongodb://mongo:27017/allura
-ming.main.auto_ensure_indexes = False
 ming.project.uri = mongodb://mongo:27017/project-data
-ming.project.auto_ensure_indexes = False
 ming.task.uri = mongodb://mongo:27017/task
-ming.task.auto_ensure_indexes = False
-;ming.zarkov.uri = mongodb://127.0.0.1:27017/zarkov
-;ming.zarkov.auto_ensure_indexes = False
-
-; Zarkov host setting, requires the zarkov and gevent libraries.
-;zarkov.host = tcp://127.0.0.1:9000
-
-; A float from 0-1 representing a % of requests to measure timing on.
-; Sampled requests will have timing logged to stats.log (can change file in [handler_timermiddleware] logging section)
-stats.sample_rate = 1
-
-; Taskd setup
-; number of seconds to sleep between checking for new tasks
-monq.poll_interval=2
-
-; SOLR setup
-solr.server = http://localhost:8983/solr
-; Alternate server to use just for querying
-;solr.query_server =
-; Shorter timeout for search queries (longer timeout for saving to solr)
-solr.short_timeout = 10
-; commit on every add/delete?
-solr.commit = false
-; commit add operations within N ms
-solr.commitWithin = 10000
-; Use improved data types for labels and custom fields?
-; New Allura deployments should leave this set to true. Existing deployments
-; should set to false until existing data has been reindexed. Reindexing will
-; convert existing label and custom field data to more appropriate solr types.
-solr.use_new_types = true
-
-; Incoming email settings.  Used when you run: paster smtp_server development.ini
-; address to listen to
-forgemail.host = 0.0.0.0
-forgemail.port = 8825
-; domain suffix for your mail, change this.  You also need to route *.*.*.forgemail.domain to the above host/port via
-; your mail and DNS configuration
-forgemail.domain = .in.localhost
-
-; Specify the number of projects allowed to be created by a user
-; depending on the age of their user account.
-; Keys are number of seconds, values are max number of projects allowed
-; (including the default user-project, so you probably want to add 1)
-; This example allows for 1 project if the account is less than an hour old
-; and 5 projects if the account is less than a day old.  No limits after that
-;project.rate_limits = {"3600": 2, "86400": 6}
-
-; set this to "false" if you are deploying to production and want performance improvements
-auto_reload_templates = true
-
-; How frequently users can send messages, in seconds
-user_message.time_interval = 3600
-; Max number of messages that can be sent within that time interval.
-user_message.max_messages = 20
-
-; Default number of times to show a sitewide notification
-; See https://forge-allura.apache.org/docs/getting_started/administration.html#site-notifications
-site_notification.impressions = 0
-
-; When rendering discussion post Markdown to html, if the render takes longer
-; than `markdown_cache_threshold` (in seconds), the resulting html will be
-; cached and served from cache on subsequent requests. Set to 0 to cache all
-; posts. Remove entirely to cache nothing.
-markdown_cache_threshold = .1
-; markdown text longer than max length will not be converted to html
-markdown_render_max_length = 999999999
-; Don't add rel=nofollow to these domains when generating links from Markdown content
-;nofollow_exempt_domains =
-
-; Export control choices on the project admin overview page.
-show_export_control = false
-
-; By default project admins can soft-delete their projects.
-; A soft-deleted project will still be in the database and visible to admins, but not to others.
-allow_project_delete = true
-allow_project_undelete = true
 
-; Advanced settings for controlling "Last Commit Doc" algorithm used when visiting any repo browse page
-lcd_thread_chunk_size = 10
-lcd_timeout = 60
 
-
-;
-; Settings for the Blog tool
-;
-; Enable or disable external RSS feed importing in ForgeBlog tool.
-; Default is "false". This feature requires GPL library "html2text". Install it with following command:
-;   pip install -e git://github.com/brondsem/html2text.git#egg=html2text
-; You will also need to run `paster pull-rss-feeds development.ini` in a cron job to fetch them.
-forgeblog.exfeed = false
-
-;
-; Settings for the Chat tool
-;
-forgechat.host = irc.freenode.net
-forgechat.port = 6667
-ircbot.nick = allurabot
-
-;
-; Settings for ShortUrl tool
-;
-; Override this if you set up an additional shortening mechanism (e.g. custom short domain)
-short_url.url_pattern = {base_url}/{nbhd}/{project}/{mount_point}/{short_name}
-
-
-;
-; Settings for UserStats tool
-;
-userstats.count_lines_of_code = true
-
-
-;
-; Optional settings for profiling with https://pypi.python.org/pypi/keas.profile
-;
 [filter-app:profile]
 use=egg:keas.profile#profiler
 next=main
 
-
-;
-; setup for the taskd background daemon request controller
-;
 [app:task]
 use = main
 override_root = task ; TurboGears will use controllers/task.py as root controller
 
-
-
-;
-; Logging configuration
-;
-; Add additional loggers, handlers, formatters here
-; Uses python's logging config file format
-; https://docs.python.org/2/library/logging.config.html#configuration-file-format
-;
 [loggers]
 keys = root, allura, sqlalchemy, paste, pylons, taskdstatus, timermiddleware, tmw_details
 


[03/46] allura git commit: [#7893] update /auth/ tests that now need _session_id passed through

Posted by he...@apache.org.
[#7893] update /auth/ tests that now need _session_id passed through


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

Branch: refs/heads/hs/7873
Commit: b6623f9f06ebe1fcfb0db4d07443722718d1e827
Parents: 10e1f51
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Jun 8 22:05:40 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Jun 8 23:33:05 2015 +0000

----------------------------------------------------------------------
 Allura/allura/tests/functional/test_auth.py     | 354 ++++++++++++++-----
 .../forgeuserstats/tests/test_stats.py          |   5 +-
 2 files changed, 274 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/b6623f9f/Allura/allura/tests/functional/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_auth.py b/Allura/allura/tests/functional/test_auth.py
index 20ceda3..ea13ee1 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -55,9 +55,11 @@ def unentity(s):
 class TestAuth(TestController):
     def test_login(self):
         self.app.get('/auth/')
-        r = self.app.post('/auth/send_verification_link', params=dict(a='test@example.com'))
+        r = self.app.post('/auth/send_verification_link', params=dict(a='test@example.com',
+                                                                      _session_id=self.app.cookies['_session_id']))
         email = M.User.query.get(username='test-admin').email_addresses[0]
-        r = self.app.post('/auth/send_verification_link', params=dict(a=email))
+        r = self.app.post('/auth/send_verification_link', params=dict(a=email,
+                                                                      _session_id=self.app.cookies['_session_id']))
         ThreadLocalORMSession.flush_all()
         r = self.app.get('/auth/verify_addr', params=dict(a='foo'))
         assert json.loads(self.webflash(r))['status'] == 'error', self.webflash(r)
@@ -66,12 +68,15 @@ class TestAuth(TestController):
         assert json.loads(self.webflash(r))['status'] == 'ok', self.webflash(r)
         r = self.app.get('/auth/logout')
         r = self.app.post('/auth/do_login', params=dict(
-            username='test-user', password='foo'))
+            username='test-user', password='foo',
+            _session_id=self.app.cookies['_session_id']))
         r = self.app.post('/auth/do_login', params=dict(
-            username='test-user', password='food'))
+            username='test-user', password='food',
+            _session_id=self.app.cookies['_session_id']))
         assert 'Invalid login' in str(r), r.showbrowser()
         r = self.app.post('/auth/do_login', params=dict(
-            username='test-usera', password='foo'))
+            username='test-usera', password='foo',
+            _session_id=self.app.cookies['_session_id']))
         assert 'Invalid login' in str(r), r.showbrowser()
 
     def test_logout(self):
@@ -95,12 +100,14 @@ class TestAuth(TestController):
         assert_equal(user.last_access['login_ip'], None)
         assert_equal(user.last_access['login_ua'], None)
 
+        self.app.get('/')  # establish session
         self.app.post('/auth/do_login',
                       headers={'User-Agent': 'browser'},
                       extra_environ={'REMOTE_ADDR': 'addr'},
                       params=dict(
                           username='test-user',
-                          password='foo'
+                          password='foo',
+                          _session_id=self.app.cookies['_session_id'],
                       ))
         user = M.User.by_username('test-user')
         assert_not_equal(user.last_access['login_date'], None)
@@ -110,9 +117,13 @@ class TestAuth(TestController):
     def test_rememberme(self):
         username = M.User.query.get(username='test-user').username
 
+        r = self.app.get('/')  # establish session
+
         # Login as test-user with remember me checkbox off
         r = self.app.post('/auth/do_login', params=dict(
-            username='test-user', password='foo'))
+            username='test-user', password='foo',
+            _session_id=self.app.cookies['_session_id'],
+        ))
         assert_equal(r.session['username'], username)
         assert_equal(r.session['login_expires'], True)
 
@@ -122,7 +133,9 @@ class TestAuth(TestController):
 
         # Login as test-user with remember me checkbox on
         r = self.app.post('/auth/do_login', params=dict(
-            username='test-user', password='foo', rememberme='on'))
+            username='test-user', password='foo', rememberme='on',
+            _session_id=self.app.cookies['_session_id'],
+        ))
         assert_equal(r.session['username'], username)
         assert_not_equal(r.session['login_expires'], True)
 
@@ -135,6 +148,7 @@ class TestAuth(TestController):
         email_address = 'test_abcd_123@domain.net'
         user = M.User.query.get(username='test-admin')
         addresses_number = len(user.email_addresses)
+        self.app.get('/')  # establish session
         self.app.post('/auth/preferences/update_emails',
                       params={
                           'new_addr.addr': email_address,
@@ -142,6 +156,7 @@ class TestAuth(TestController):
                           'primary_addr': 'test-admin@users.localhost',
                           'preferences.email_format': 'plain',
                           'password': 'foo',
+                          '_session_id': self.app.cookies['_session_id'],
                       },
                       extra_environ=dict(username='test-admin'))
 
@@ -153,6 +168,7 @@ class TestAuth(TestController):
                               'primary_addr': 'test-admin@users.localhost',
                               'preferences.email_format': 'plain',
                               'password': 'foo',
+                              '_session_id': self.app.cookies['_session_id'],
                           },
                           extra_environ=dict(username='test-admin'))
 
@@ -164,6 +180,7 @@ class TestAuth(TestController):
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     @patch('allura.lib.helpers.gen_message_id')
     def test_user_added_claimed_address_by_other_user_confirmed(self, gen_message_id, sendsimplemail):
+        self.app.get('/')  # establish session
         email_address = 'test_abcd_123@domain.net'
 
         # test-user claimed & confirmed email address
@@ -185,6 +202,7 @@ class TestAuth(TestController):
                               'primary_addr': 'test-admin@users.localhost',
                               'preferences.email_format': 'plain',
                               'password': 'foo',
+                              '_session_id': self.app.cookies['_session_id'],
                           },
                           extra_environ=dict(username='test-admin'))
 
@@ -220,6 +238,7 @@ class TestAuth(TestController):
 
         user1 = M.User.query.get(username='test-user-1')
         addresses_number = len(user1.email_addresses)
+        self.app.get('/')  # establish session
         r = self.app.post('/auth/preferences/update_emails',
                           params={
                               'new_addr.addr': email_address,
@@ -227,6 +246,7 @@ class TestAuth(TestController):
                               'primary_addr': 'test-user-1@users.localhost',
                               'preferences.email_format': 'plain',
                               'password': 'foo',
+                              '_session_id': self.app.cookies['_session_id'],
                           },
                           extra_environ=dict(username='test-user-1'))
 
@@ -242,6 +262,7 @@ class TestAuth(TestController):
     @patch('allura.lib.helpers.gen_message_id')
     def test_user_cannot_claim_more_than_max_limit(self, gen_message_id, sendsimplemail):
         with h.push_config(config, **{'user_prefs.maximum_claimed_emails': '1'}):
+            self.app.get('/')  # establish session
             r = self.app.post('/auth/preferences/update_emails',
                               params={
                                   'new_addr.addr': 'test_abcd_1@domain.net',
@@ -249,6 +270,7 @@ class TestAuth(TestController):
                                   'primary_addr': 'test-user-1@users.localhost',
                                   'preferences.email_format': 'plain',
                                   'password': 'foo',
+                                  '_session_id': self.app.cookies['_session_id'],
                               },
                               extra_environ=dict(username='test-user-1'))
             assert json.loads(self.webflash(r))['status'] == 'ok'
@@ -260,6 +282,7 @@ class TestAuth(TestController):
                                   'primary_addr': 'test-user-1@users.localhost',
                                   'preferences.email_format': 'plain',
                                   'password': 'foo',
+                                  '_session_id': self.app.cookies['_session_id'],
                               },
                               extra_environ=dict(username='test-user-1'))
 
@@ -269,6 +292,7 @@ class TestAuth(TestController):
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     @patch('allura.lib.helpers.gen_message_id')
     def test_verification_link_for_confirmed_email(self, gen_message_id, sendsimplemail):
+        self.app.get('/')  # establish session
         email_address = 'test_abcd@domain.net'
 
         # test-user claimed email address
@@ -285,8 +309,8 @@ class TestAuth(TestController):
         ThreadLocalORMSession.flush_all()
 
         r = self.app.post('/auth/send_verification_link',
-                          params=dict(a=email_address),
-                          extra_environ=dict(username='test-user-1'))
+                          params=dict(a=email_address, _session_id=self.app.cookies['_session_id']),
+                          extra_environ=dict(username='test-user-1', _session_id=self.app.cookies['_session_id']))
 
         assert json.loads(self.webflash(r))['status'] == 'ok'
         assert json.loads(self.webflash(r))['message'] == 'Verification link sent'
@@ -299,6 +323,7 @@ class TestAuth(TestController):
                "but it is already claimed by your %s account." % (email_address, user.username) in kwargs['text']
 
     def test_invalidate_verification_link_if_email_was_confirmed(self):
+        self.app.get('/')  # establish session
         email_address = 'test_abcd@domain.net'
 
         # test-user claimed email address
@@ -308,9 +333,13 @@ class TestAuth(TestController):
         email.confirmed = False
         ThreadLocalORMSession.flush_all()
 
+        print 'email working with is', email
         self.app.post('/auth/send_verification_link',
-                      params=dict(a=email_address),
+                      params=dict(a=email_address,
+                                  _session_id=self.app.cookies['_session_id']),
                       extra_environ=dict(username='test-user'))
+        print 'later', M.EmailAddress.find(dict(email=email_address, claimed_by_user_id=user._id)).first()
+        assert email.nonce
 
         user1 = M.User.query.get(username='test-user-1')
         user1.claim_address(email_address)
@@ -377,6 +406,8 @@ class TestAuth(TestController):
         user = self._create_password_reset_hash()
         session(user).flush(user)
 
+        self.app.get('/')  # establish session
+        change_params['_session_id'] = self.app.cookies['_session_id']
         self.app.post('/auth/preferences/update_emails',
                       extra_environ=dict(username='test-admin'),
                       params=change_params)
@@ -388,6 +419,7 @@ class TestAuth(TestController):
 
     @td.with_user_project('test-admin')
     def test_change_password(self):
+        self.app.get('/')  # establish session
         # Get and assert user with password reset token.
         user = self._create_password_reset_hash()
         old_pass = user.get_pref('password')
@@ -399,6 +431,7 @@ class TestAuth(TestController):
                           'oldpw': 'foo',
                           'pw': 'asdfasdf',
                           'pw2': 'asdfasdf',
+                          '_session_id': self.app.cookies['_session_id'],
                       })
 
         # Confirm password was changed.
@@ -427,7 +460,8 @@ class TestAuth(TestController):
                                   'new_addr.claim': 'Claim Address',
                                   'primary_addr': 'test-admin@users.localhost',
                                   'password': 'foo',
-                                  'preferences.email_format': 'plain'
+                                  'preferences.email_format': 'plain',
+                                  '_session_id': self.app.cookies['_session_id'],
                               })
         r = self.app.get('/auth/preferences/')
         assert 'test@example.com' in r
@@ -445,7 +479,8 @@ class TestAuth(TestController):
                                   'new_addr.addr': '',
                                   'primary_addr': 'test-admin@users.localhost',
                                   'password': 'foo',
-                                  'preferences.email_format': 'plain'
+                                  'preferences.email_format': 'plain',
+                                  '_session_id': self.app.cookies['_session_id'],
                               })
         r = self.app.get('/auth/preferences/')
         assert 'test-admin@users.localhost' not in r
@@ -455,16 +490,20 @@ class TestAuth(TestController):
 
         with td.audits('Display Name changed Test Admin => Admin', user=True):
             r = self.app.post('/auth/preferences/update',
-                              params={'preferences.display_name': 'Admin'},
+                              params={'preferences.display_name': 'Admin',
+                                      '_session_id': self.app.cookies['_session_id'],
+                                      },
                               extra_environ=dict(username='test-admin'))
 
     @td.with_user_project('test-admin')
     def test_email_prefs_change_requires_password(self):
+        self.app.get('/')  # establish session
         # Claim new email
         new_email_params = {
             'new_addr.addr': 'test@example.com',
             'new_addr.claim': 'Claim Address',
             'primary_addr': 'test-admin@users.localhost',
+            '_session_id': self.app.cookies['_session_id'],
         }
         r = self.app.post('/auth/preferences/update_emails',
                           params=new_email_params,
@@ -490,6 +529,7 @@ class TestAuth(TestController):
         change_primary_params = {
             'new_addr.addr': '',
             'primary_addr': 'test@example.com',
+            '_session_id': self.app.cookies['_session_id'],
         }
         r = self.app.post('/auth/preferences/update_emails',
                           params=change_primary_params,
@@ -518,6 +558,7 @@ class TestAuth(TestController):
             'addr-2.delete': 'on',
             'new_addr.addr': '',
             'primary_addr': 'test-admin@users.localhost',
+            '_session_id': self.app.cookies['_session_id'],
         }
         r = self.app.post('/auth/preferences/update_emails',
                           params=remove_email_params,
@@ -611,16 +652,20 @@ class TestAuth(TestController):
         assert not s, "User still has subscription with Mailbox._id %s" % s_id
 
     def test_format_email(self):
+        self.app.get('/')  # establish session
         self.app.post('/auth/subscriptions/update_subscriptions',
-                      params={'email_format': 'html', 'subscriptions': ''})
+                      params={'email_format': 'html', 'subscriptions': '',
+                              '_session_id': self.app.cookies['_session_id']})
         r = self.app.get('/auth/subscriptions/')
         assert '<option selected value="html">HTML</option>' in r
         self.app.post('/auth/subscriptions/update_subscriptions',
-                      params={'email_format': 'plain', 'subscriptions': ''})
+                      params={'email_format': 'plain', 'subscriptions': '',
+                              '_session_id': self.app.cookies['_session_id']})
         r = self.app.get('/auth/subscriptions/')
         assert '<option selected value="plain">Plain Text</option>' in r
         self.app.post('/auth/subscriptions/update_subscriptions',
-                      params={'email_format': 'both', 'subscriptions': ''})
+                      params={'email_format': 'both', 'subscriptions': '',
+                              '_session_id': self.app.cookies['_session_id']})
         r = self.app.get('/auth/subscriptions/')
         assert '<option selected value="both">Combined</option>' in r
 
@@ -628,7 +673,8 @@ class TestAuth(TestController):
         r = self.app.get('/auth/create_account')
         assert 'Create an Account' in r
         r = self.app.post('/auth/save_new',
-                          params=dict(username='aaa', pw='123'))
+                          params=dict(username='aaa', pw='123',
+                                      _session_id=self.app.cookies['_session_id']))
         assert 'Enter a value 6 characters long or more' in r
         r = self.app.post(
             '/auth/save_new',
@@ -636,7 +682,9 @@ class TestAuth(TestController):
                 username='aaa',
                 pw='12345678',
                 pw2='12345678',
-                display_name='Test Me'))
+                display_name='Test Me',
+                _session_id=self.app.cookies['_session_id'],
+            ))
         r = r.follow()
         assert 'User "aaa" registered' in unentity(r.body)
         r = self.app.post(
@@ -645,15 +693,19 @@ class TestAuth(TestController):
                 username='aaa',
                 pw='12345678',
                 pw2='12345678',
-                display_name='Test Me'))
+                display_name='Test Me',
+                _session_id=self.app.cookies['_session_id'],
+            ))
         assert 'That username is already taken. Please choose another.' in r
         r = self.app.get('/auth/logout')
         r = self.app.post(
             '/auth/do_login',
-            params=dict(username='aaa', password='12345678'),
+            params=dict(username='aaa', password='12345678',
+                        _session_id=self.app.cookies['_session_id']),
             status=302)
 
     def test_create_account_require_email(self):
+        self.app.get('/')  # establish session
         with h.push_config(config, **{'auth.require_email_addr': 'false'}):
             self.app.post(
                 '/auth/save_new',
@@ -662,7 +714,9 @@ class TestAuth(TestController):
                     pw='12345678',
                     pw2='12345678',
                     display_name='Test Me',
-                    email='test@example.com'))
+                    email='test@example.com',
+                    _session_id=self.app.cookies['_session_id'],
+                ))
             user = M.User.query.get(username='aaa')
             assert not user.pending
         with h.push_config(config, **{'auth.require_email_addr': 'true'}):
@@ -673,12 +727,15 @@ class TestAuth(TestController):
                     pw='12345678',
                     pw2='12345678',
                     display_name='Test Me',
-                    email='test@example.com'))
+                    email='test@example.com',
+                    _session_id=self.app.cookies['_session_id']
+                ))
             user = M.User.query.get(username='bbb')
             assert user.pending
 
     def test_verify_email(self):
         with h.push_config(config, **{'auth.require_email_addr': 'true'}):
+            self.app.get('/')  # establish session
             r = self.app.post(
                 '/auth/save_new',
                 params=dict(
@@ -686,7 +743,9 @@ class TestAuth(TestController):
                     pw='12345678',
                     pw2='12345678',
                     display_name='Test Me',
-                    email='test@example.com'))
+                    email='test@example.com',
+                    _session_id=self.app.cookies['_session_id']
+                ))
             r = r.follow()
             user = M.User.query.get(username='aaa')
             em = M.EmailAddress.get(email='test@example.com')
@@ -709,12 +768,15 @@ class TestAuth(TestController):
 
     def test_create_account_disabled_submit_fails(self):
         with h.push_config(config, **{'auth.allow_user_registration': 'false'}):
+            self.app.get('/')  # establish session
             self.app.post('/auth/save_new',
                           params=dict(
                               username='aaa',
                               pw='12345678',
                               pw2='12345678',
-                              display_name='Test Me'),
+                              display_name='Test Me',
+                              _session_id=self.app.cookies['_session_id']
+                          ),
                           status=404)
 
     def test_one_project_role(self):
@@ -723,12 +785,15 @@ class TestAuth(TestController):
            an admin page."""
         p_nbhd = M.Neighborhood.query.get(name='Projects')
         p = M.Project.query.get(shortname='test', neighborhood_id=p_nbhd._id)
+        self.app.get('/')  # establish session
         self.app.post('/auth/save_new', params=dict(
             username='aaa',
             pw='12345678',
             pw2='12345678',
             display_name='Test Me',
-            email='test@example.com')).follow()
+            email='test@example.com',
+            _session_id=self.app.cookies['_session_id'],
+        )).follow()
         user = M.User.query.get(username='aaa')
         user.pending = False
         session(user).flush(user)
@@ -762,28 +827,32 @@ class TestAuth(TestController):
         assert_equal(r.location, 'http://localhost/auth/?return_to=%2Fp%2Ftest%2Fadmin%2F')
 
     def test_no_open_return_to(self):
-        r = self.app.get('/auth/logout')
+        r = self.app.get('/auth/logout').follow()
         r = self.app.post('/auth/do_login', params=dict(
             username='test-user', password='foo',
-            return_to='/foo'))
+            return_to='/foo',
+            _session_id=self.app.cookies['_session_id']))
         assert_equal(r.location, 'http://localhost/foo')
 
         r = self.app.get('/auth/logout')
         r = self.app.post('/auth/do_login', params=dict(
             username='test-user', password='foo',
-            return_to='http://localhost:8080/foo'))
+            return_to='http://localhost:8080/foo',
+            _session_id=self.app.cookies['_session_id']))
         assert_equal(r.location, 'http://localhost:8080/foo')
 
         r = self.app.get('/auth/logout')
         r = self.app.post('/auth/do_login', params=dict(
             username='test-user', password='foo',
-            return_to='http://example.com/foo'))
+            return_to='http://example.com/foo',
+            _session_id=self.app.cookies['_session_id']))
         assert_equal(r.location, 'http://localhost/')
 
         r = self.app.get('/auth/logout')
         r = self.app.post('/auth/do_login', params=dict(
             username='test-user', password='foo',
-            return_to='//example.com/foo'))
+            return_to='//example.com/foo',
+            _session_id=self.app.cookies['_session_id']))
         assert_equal(r.location, 'http://localhost/')
 
 
@@ -803,7 +872,9 @@ class TestPreferences(TestController):
                               birthdate=setbirthdate,
                               country=setcountry,
                               city=setcity,
-                              timezone=settimezone))
+                              timezone=settimezone,
+                              _session_id=self.app.cookies['_session_id'],
+                          ))
         user = M.User.query.get(username='test-admin')
         sex = user.sex
         assert sex == setsex
@@ -818,7 +889,7 @@ class TestPreferences(TestController):
 
         # Check if setting a wrong date everything works correctly
         r = self.app.post('/auth/user_info/change_personal_data',
-                          params=dict(birthdate='30/02/1998'))
+                          params=dict(birthdate='30/02/1998', _session_id=self.app.cookies['_session_id']))
         assert 'Please enter a valid date' in str(r)
         user = M.User.query.get(username='test-admin')
         sex = user.sex
@@ -839,7 +910,9 @@ class TestPreferences(TestController):
                               birthdate='',
                               country=setcountry,
                               city=setcity,
-                              timezone=settimezone))
+                              timezone=settimezone,
+                              _session_id=self.app.cookies['_session_id'],
+                          ))
         user = M.User.query.get(username='test-admin')
         assert user.birthdate is None
 
@@ -849,7 +922,7 @@ class TestPreferences(TestController):
         testvalue = 'testaccount'
         self.app.get('/auth/user_info/contacts/')
         self.app.post('/auth/user_info/contacts/skype_account',
-                      params=dict(skypeaccount=testvalue))
+                      params=dict(skypeaccount=testvalue, _session_id=self.app.cookies['_session_id']))
         user = M.User.query.get(username='test-admin')
         assert user.skypeaccount == testvalue
 
@@ -858,7 +931,9 @@ class TestPreferences(TestController):
         accounturl = 'http://www.facebook.com/test'
         self.app.post('/auth/user_info/contacts/add_social_network',
                       params=dict(socialnetwork=socialnetwork,
-                                  accounturl=accounturl))
+                                  accounturl=accounturl,
+                                  _session_id=self.app.cookies['_session_id'],
+                                  ))
         user = M.User.query.get(username='test-admin')
         assert len(user.socialnetworks) == 1
         assert_equal(user.socialnetworks[0].socialnetwork, socialnetwork)
@@ -869,7 +944,9 @@ class TestPreferences(TestController):
         accounturl2 = 'http://twitter.com/test'
         self.app.post('/auth/user_info/contacts/add_social_network',
                       params=dict(socialnetwork=socialnetwork2,
-                                  accounturl='@test'))
+                                  accounturl='@test',
+                                  _session_id=self.app.cookies['_session_id'],
+                                  ))
         user = M.User.query.get(username='test-admin')
         assert len(user.socialnetworks) == 2
         assert_in({'socialnetwork': socialnetwork, 'accounturl': accounturl}, user.socialnetworks)
@@ -878,21 +955,27 @@ class TestPreferences(TestController):
         # Remove first social network account
         self.app.post('/auth/user_info/contacts/remove_social_network',
                       params=dict(socialnetwork=socialnetwork,
-                                  account=accounturl))
+                                  account=accounturl,
+                                  _session_id=self.app.cookies['_session_id'],
+                                  ))
         user = M.User.query.get(username='test-admin')
         assert len(user.socialnetworks) == 1
         assert_in({'socialnetwork': socialnetwork2, 'accounturl': accounturl2}, user.socialnetworks)
 
         # Add empty social network account
         self.app.post('/auth/user_info/contacts/add_social_network',
-                      params=dict(accounturl=accounturl, socialnetwork=''))
+                      params=dict(accounturl=accounturl, socialnetwork='',
+                                  _session_id=self.app.cookies['_session_id'],
+                                  ))
         user = M.User.query.get(username='test-admin')
         assert len(user.socialnetworks) == 1
         assert_in({'socialnetwork': socialnetwork2, 'accounturl': accounturl2}, user.socialnetworks)
 
         # Add invalid social network account
         self.app.post('/auth/user_info/contacts/add_social_network',
-                      params=dict(accounturl=accounturl, socialnetwork='invalid'))
+                      params=dict(accounturl=accounturl, socialnetwork='invalid',
+                                  _session_id=self.app.cookies['_session_id'],
+                                  ))
         user = M.User.query.get(username='test-admin')
         assert len(user.socialnetworks) == 1
         assert_in({'socialnetwork': socialnetwork2, 'accounturl': accounturl2}, user.socialnetworks)
@@ -900,40 +983,52 @@ class TestPreferences(TestController):
         # Add telephone number
         telnumber = '+3902123456'
         self.app.post('/auth/user_info/contacts/add_telnumber',
-                      params=dict(newnumber=telnumber))
+                      params=dict(newnumber=telnumber,
+                                  _session_id=self.app.cookies['_session_id'],
+                                  ))
         user = M.User.query.get(username='test-admin')
         assert (len(user.telnumbers) == 1 and (user.telnumbers[0] == telnumber))
 
         # Add second telephone number
         telnumber2 = '+3902654321'
         self.app.post('/auth/user_info/contacts/add_telnumber',
-                      params=dict(newnumber=telnumber2))
+                      params=dict(newnumber=telnumber2,
+                                  _session_id=self.app.cookies['_session_id'],
+                                  ))
         user = M.User.query.get(username='test-admin')
         assert (len(user.telnumbers) == 2 and telnumber in user.telnumbers and telnumber2 in user.telnumbers)
 
         # Remove first telephone number
         self.app.post('/auth/user_info/contacts/remove_telnumber',
-                      params=dict(oldvalue=telnumber))
+                      params=dict(oldvalue=telnumber,
+                                  _session_id=self.app.cookies['_session_id'],
+                                  ))
         user = M.User.query.get(username='test-admin')
         assert (len(user.telnumbers) == 1 and telnumber2 in user.telnumbers)
 
         # Add website
         website = 'http://www.testurl.com'
         self.app.post('/auth/user_info/contacts/add_webpage',
-                      params=dict(newwebsite=website))
+                      params=dict(newwebsite=website,
+                                  _session_id=self.app.cookies['_session_id'],
+                                  ))
         user = M.User.query.get(username='test-admin')
         assert (len(user.webpages) == 1 and (website in user.webpages))
 
         # Add second website
         website2 = 'http://www.testurl2.com'
         self.app.post('/auth/user_info/contacts/add_webpage',
-                      params=dict(newwebsite=website2))
+                      params=dict(newwebsite=website2,
+                                  _session_id=self.app.cookies['_session_id'],
+                                  ))
         user = M.User.query.get(username='test-admin')
         assert (len(user.webpages) == 2 and website in user.webpages and website2 in user.webpages)
 
         # Remove first website
         self.app.post('/auth/user_info/contacts/remove_webpage',
-                      params=dict(oldvalue=website))
+                      params=dict(oldvalue=website,
+                                  _session_id=self.app.cookies['_session_id'],
+                                  ))
         user = M.User.query.get(username='test-admin')
         assert (len(user.webpages) == 1 and website2 in user.webpages)
 
@@ -949,7 +1044,9 @@ class TestPreferences(TestController):
                           params=dict(
                               weekday=weekday,
                               starttime=starttime.strftime('%H:%M'),
-                              endtime=endtime.strftime('%H:%M')))
+                              endtime=endtime.strftime('%H:%M'),
+                              _session_id=self.app.cookies['_session_id'],
+                          ))
         user = M.User.query.get(username='test-admin')
         timeslot1dict = dict(
             week_day=weekday, start_time=starttime, end_time=endtime)
@@ -965,7 +1062,9 @@ class TestPreferences(TestController):
                           params=dict(
                               weekday=weekday2,
                               starttime=starttime2.strftime('%H:%M'),
-                              endtime=endtime2.strftime('%H:%M')))
+                              endtime=endtime2.strftime('%H:%M'),
+                            _session_id=self.app.cookies['_session_id'],
+                          ))
         user = M.User.query.get(username='test-admin')
         timeslot2dict = dict(week_day=weekday2,
                              start_time=starttime2, end_time=endtime2)
@@ -978,7 +1077,9 @@ class TestPreferences(TestController):
                           params=dict(
                               weekday=weekday,
                               starttime=starttime.strftime('%H:%M'),
-                              endtime=endtime.strftime('%H:%M')))
+                              endtime=endtime.strftime('%H:%M'),
+                              _session_id=self.app.cookies['_session_id'],
+                          ))
         user = M.User.query.get(username='test-admin')
         assert len(user.availability) == 1 and timeslot2dict in user.get_availability_timeslots()
 
@@ -987,7 +1088,9 @@ class TestPreferences(TestController):
                           params=dict(
                               weekday=weekday2,
                               starttime=endtime2.strftime('%H:%M'),
-                              endtime=starttime2.strftime('%H:%M')))
+                              endtime=starttime2.strftime('%H:%M'),
+                              _session_id=self.app.cookies['_session_id'],
+                          ))
         assert 'Invalid period:' in str(r)
         user = M.User.query.get(username='test-admin')
         timeslot2dict = dict(week_day=weekday2,
@@ -1005,7 +1108,9 @@ class TestPreferences(TestController):
         r = self.app.post('/auth/user_info/availability/add_inactive_period',
                           params=dict(
                               startdate=startdate.strftime('%d/%m/%Y'),
-                              enddate=enddate.strftime('%d/%m/%Y')))
+                              enddate=enddate.strftime('%d/%m/%Y'),
+                              _session_id=self.app.cookies['_session_id'],
+                          ))
         user = M.User.query.get(username='test-admin')
         period1dict = dict(start_date=startdate, end_date=enddate)
         assert len(user.inactiveperiod) == 1 and period1dict in user.get_inactive_periods()
@@ -1016,7 +1121,9 @@ class TestPreferences(TestController):
         r = self.app.post('/auth/user_info/availability/add_inactive_period',
                           params=dict(
                               startdate=startdate2.strftime('%d/%m/%Y'),
-                              enddate=enddate2.strftime('%d/%m/%Y')))
+                              enddate=enddate2.strftime('%d/%m/%Y'),
+                              _session_id=self.app.cookies['_session_id'],
+                          ))
         user = M.User.query.get(username='test-admin')
         period2dict = dict(start_date=startdate2, end_date=enddate2)
         assert len(user.inactiveperiod) == 2
@@ -1028,7 +1135,9 @@ class TestPreferences(TestController):
             '/auth/user_info/availability/remove_inactive_period',
             params=dict(
                 startdate=startdate.strftime('%d/%m/%Y'),
-                enddate=enddate.strftime('%d/%m/%Y')))
+                enddate=enddate.strftime('%d/%m/%Y'),
+                _session_id=self.app.cookies['_session_id'],
+            ))
         user = M.User.query.get(username='test-admin')
         assert len(user.inactiveperiod) == 1 and period2dict in user.get_inactive_periods()
 
@@ -1036,7 +1145,9 @@ class TestPreferences(TestController):
         r = self.app.post('/auth/user_info/availability/add_inactive_period',
                           params=dict(
                               startdate='NOT/A/DATE',
-                              enddate=enddate2.strftime('%d/%m/%Y')))
+                              enddate=enddate2.strftime('%d/%m/%Y'),
+                              _session_id=self.app.cookies['_session_id'],
+                          ))
         user = M.User.query.get(username='test-admin')
         assert 'Please enter a valid date' in str(r)
         assert len(user.inactiveperiod) == 1 and period2dict in user.get_inactive_periods()
@@ -1053,7 +1164,9 @@ class TestPreferences(TestController):
                           params=dict(
                               level=level,
                               comment=comment,
-                              selected_skill=str(skill_cat.trove_cat_id)))
+                              selected_skill=str(skill_cat.trove_cat_id),
+                              _session_id=self.app.cookies['_session_id'],
+                          ))
         user = M.User.query.get(username='test-admin')
         skilldict = dict(category_id=skill_cat._id,
                          comment=comment, level=level)
@@ -1067,7 +1180,9 @@ class TestPreferences(TestController):
                           params=dict(
                               level=level,
                               comment=comment,
-                              selected_skill=str(skill_cat.trove_cat_id)))
+                              selected_skill=str(skill_cat.trove_cat_id),
+                              _session_id=self.app.cookies['_session_id'],
+                          ))
         user = M.User.query.get(username='test-admin')
         skilldict = dict(category_id=skill_cat._id,
                          comment=comment, level=level)
@@ -1080,7 +1195,9 @@ class TestPreferences(TestController):
                           params=dict(
                               level=level2,
                               comment=comment2,
-                              selected_skill=str(skill_cat.trove_cat_id)))
+                              selected_skill=str(skill_cat.trove_cat_id),
+                              _session_id=self.app.cookies['_session_id'],
+                          ))
         user = M.User.query.get(username='test-admin')
         # Check that everything is as it was before
         assert len(user.skills) == 1 and skilldict in user.skills
@@ -1089,17 +1206,24 @@ class TestPreferences(TestController):
         self.app.get('/auth/user_info/skills/')
         self.app.post('/auth/user_info/skills/remove_skill',
                       params=dict(
-                          categoryid=str(skill_cat.trove_cat_id)))
+                          categoryid=str(skill_cat.trove_cat_id),
+                          _session_id=self.app.cookies['_session_id'],
+                      ))
         user = M.User.query.get(username='test-admin')
         assert len(user.skills) == 0
 
     @td.with_user_project('test-admin')
     def test_user_message(self):
+        self.app.get('/')  # establish session
         assert not M.User.query.get(username='test-admin').get_pref('disable_user_messages')
-        self.app.post('/auth/preferences/user_message')
+        self.app.post('/auth/preferences/user_message',
+                      params={'_session_id': self.app.cookies['_session_id'],
+                              })
         assert M.User.query.get(username='test-admin').get_pref('disable_user_messages')
         self.app.post('/auth/preferences/user_message',
-                      params={'allow_user_messages': 'on'})
+                      params={'allow_user_messages': 'on',
+                              '_session_id': self.app.cookies['_session_id'],
+                              })
         assert not M.User.query.get(username='test-admin').get_pref('disable_user_messages')
 
     @td.with_user_project('test-admin')
@@ -1130,7 +1254,10 @@ class TestPasswordReset(TestController):
             {'claimed_by_user_id': user._id}).first()
         email.confirmed = False
         ThreadLocalORMSession.flush_all()
-        self.app.post('/auth/password_recovery_hash', {'email': email.email})
+        self.app.get('/')  # establish session
+        self.app.post('/auth/password_recovery_hash', {'email': email.email,
+                                                       '_session_id': self.app.cookies['_session_id'],
+                                                       })
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
         assert hash is None
 
@@ -1142,13 +1269,17 @@ class TestPasswordReset(TestController):
             {'claimed_by_user_id': user._id}).first()
         user.disabled = True
         ThreadLocalORMSession.flush_all()
-        self.app.post('/auth/password_recovery_hash', {'email': email.email})
+        self.app.get('/')  # establish session
+        self.app.post('/auth/password_recovery_hash', {'email': email.email,
+                                                       '_session_id': self.app.cookies['_session_id'],
+                                                       })
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
         assert hash is None
 
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     @patch('allura.lib.helpers.gen_message_id')
     def test_only_primary_email_reset_allowed(self, gen_message_id, sendmail):
+        self.app.get('/')  # establish session
         user = M.User.query.get(username='test-admin')
         user.claim_address(self.test_primary_email)
         user.set_pref('email_address', self.test_primary_email)
@@ -1158,7 +1289,9 @@ class TestPasswordReset(TestController):
         ThreadLocalORMSession.flush_all()
 
         with h.push_config(config, **{'auth.allow_non_primary_email_password_reset': 'false'}):
-            self.app.post('/auth/password_recovery_hash', {'email': self.test_primary_email})
+            self.app.post('/auth/password_recovery_hash', {'email': self.test_primary_email,
+                                                           '_session_id': self.app.cookies['_session_id'],
+                                                           })
             hash = user.get_tool_data('AuthPasswordReset', 'hash')
             assert hash is not None
             args, kwargs = sendmail.post.call_args
@@ -1167,6 +1300,7 @@ class TestPasswordReset(TestController):
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     @patch('allura.lib.helpers.gen_message_id')
     def test_non_primary_email_reset_allowed(self, gen_message_id, sendmail):
+        self.app.get('/')  # establish session
         user = M.User.query.get(username='test-admin')
         email1 = M.EmailAddress.find({'claimed_by_user_id': user._id}).first()
         user.claim_address(self.test_primary_email)
@@ -1175,7 +1309,9 @@ class TestPasswordReset(TestController):
         email.confirmed = True
         ThreadLocalORMSession.flush_all()
         with h.push_config(config, **{'auth.allow_non_primary_email_password_reset': 'true'}):
-            self.app.post('/auth/password_recovery_hash', {'email': email1.email})
+            self.app.post('/auth/password_recovery_hash', {'email': email1.email,
+                                                           '_session_id': self.app.cookies['_session_id'],
+                                                           })
             hash = user.get_tool_data('AuthPasswordReset', 'hash')
             assert hash is not None
             args, kwargs = sendmail.post.call_args
@@ -1184,6 +1320,7 @@ class TestPasswordReset(TestController):
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     @patch('allura.lib.helpers.gen_message_id')
     def test_password_reset(self, gen_message_id, sendmail):
+        self.app.get('/')  # establish session
         user = M.User.query.get(username='test-admin')
         email = M.EmailAddress.find(
             {'claimed_by_user_id': user._id}).first()
@@ -1191,7 +1328,9 @@ class TestPasswordReset(TestController):
         ThreadLocalORMSession.flush_all()
         old_pw_hash = user.password
         with td.audits('Password recovery link sent to: test-admin@users.localhost', user=True):
-            r = self.app.post('/auth/password_recovery_hash', {'email': email.email})
+            r = self.app.post('/auth/password_recovery_hash', {'email': email.email,
+                                                               '_session_id': self.app.cookies['_session_id'],
+                                                               })
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
         hash_expiry = user.get_tool_data('AuthPasswordReset', 'hash_expiry')
         assert hash is not None
@@ -1238,7 +1377,10 @@ To reset your password on %s, please visit the following URL:
             {'claimed_by_user_id': user._id}).first()
         email.confirmed = True
         ThreadLocalORMSession.flush_all()
-        r = self.app.post('/auth/password_recovery_hash', {'email': email.email})
+        self.app.get('/')  # establish session
+        r = self.app.post('/auth/password_recovery_hash', {'email': email.email,
+                                                           '_session_id': self.app.cookies['_session_id'],
+                                                           })
         user = M.User.by_username('test-admin')
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
         user.set_tool_data('AuthPasswordReset',
@@ -1246,7 +1388,9 @@ To reset your password on %s, please visit the following URL:
         r = self.app.get('/auth/forgotten_password/%s' % hash.encode('utf-8'))
         assert_in('Unable to process reset, please try again', r.follow().body)
         r = self.app.post('/auth/set_new_password/%s' %
-                          hash.encode('utf-8'), {'pw': '154321', 'pw2': '154321'})
+                          hash.encode('utf-8'), {'pw': '154321', 'pw2': '154321',
+                                                 '_session_id': self.app.cookies['_session_id'],
+                                                 })
         assert_in('Unable to process reset, please try again', r.follow().body)
 
     @patch('allura.lib.plugin.AuthenticationProvider')
@@ -1258,9 +1402,11 @@ To reset your password on %s, please visit the following URL:
         ap.by_username().username = user.username
         self.app.get('/auth/forgotten_password', status=404)
         self.app.post('/auth/set_new_password',
-                      {'pw': 'foo', 'pw2': 'foo'}, status=404)
+                      {'pw': 'foo', 'pw2': 'foo', '_session_id': self.app.cookies['_session_id']},
+                      status=404)
         self.app.post('/auth/password_recovery_hash',
-                      {'email': 'foo'}, status=404)
+                      {'email': 'foo', '_session_id': self.app.cookies['_session_id']},
+                      status=404)
 
 
 class TestOAuth(TestController):
@@ -1268,7 +1414,9 @@ class TestOAuth(TestController):
         # register
         r = self.app.get('/auth/oauth/')
         r = self.app.post('/auth/oauth/register',
-                          params={'application_name': 'oautstapp', 'application_description': 'Oauth rulez'}).follow()
+                          params={'application_name': 'oautstapp', 'application_description': 'Oauth rulez',
+                                  '_session_id': self.app.cookies['_session_id'],
+                                  }).follow()
         assert 'oautstapp' in r
         # deregister
         assert_equal(r.forms[0].action, 'deregister')
@@ -1278,8 +1426,11 @@ class TestOAuth(TestController):
 
     def test_generate_revoke_access_token(self):
         # generate
+        self.app.get('/')  # establish session
         r = self.app.post('/auth/oauth/register',
-                          params={'application_name': 'oautstapp', 'application_description': 'Oauth rulez'}).follow()
+                          params={'application_name': 'oautstapp', 'application_description': 'Oauth rulez',
+                                  '_session_id': self.app.cookies['_session_id'],
+                                  }).follow()
         assert_equal(r.forms[1].action, 'generate_access_token')
         r.forms[1].submit()
         r = self.app.get('/auth/oauth/')
@@ -1309,10 +1460,13 @@ class TestOAuth(TestController):
             'oauth_consumer_key': 'api_key',
             'oauth_callback': 'http://my.domain.com/callback',
         }
-        r = self.app.post('/rest/oauth/request_token', params={})
+        self.app.get('/')  # establish session
+        r = self.app.post('/rest/oauth/request_token', params={'_session_id': self.app.cookies['_session_id']})
         rtok = parse_qs(r.body)['oauth_token'][0]
         r = self.app.post('/rest/oauth/authorize',
-                          params={'oauth_token': rtok})
+                          params={'oauth_token': rtok,
+                                  '_session_id': self.app.cookies['_session_id'],
+                                  })
         r = r.forms[0].submit('yes')
         assert r.location.startswith('http://my.domain.com/callback')
         pin = parse_qs(urlparse(r.location).query)['oauth_verifier'][0]
@@ -1337,7 +1491,9 @@ class TestOAuth(TestController):
         )
         ThreadLocalORMSession.flush_all()
         req = Request.from_request.return_value = {'oauth_consumer_key': 'api_key'}
-        r = self.app.post('/rest/oauth/request_token', params={'key': 'value'})
+        r = self.app.post('/rest/oauth/request_token', params={'key': 'value',
+                                                               #'_session_id': self.app.cookies['_session_id'],
+                                                               })
         Request.from_request.assert_called_once_with(
             'POST', 'http://localhost/rest/oauth/request_token',
             headers={'Host': 'localhost:80', 'Content-Type': 'application/x-www-form-urlencoded; charset="utf-8"'},
@@ -1353,8 +1509,12 @@ class TestOAuth(TestController):
     def test_request_token_no_consumer_token(self, Request, Server):
         req = Request.from_request.return_value = {
             'oauth_consumer_key': 'api_key'}
+        self.app.get('/')  # establish session
         r = self.app.post('/rest/oauth/request_token',
-                          params={'key': 'value'}, status=403)
+                          params={'key': 'value',
+                                  '_session_id': self.app.cookies['_session_id'],
+                                  },
+                          status=403)
 
     @mock.patch('allura.controllers.rest.oauth.Server')
     @mock.patch('allura.controllers.rest.oauth.Request')
@@ -1368,7 +1528,12 @@ class TestOAuth(TestController):
         )
         ThreadLocalORMSession.flush_all()
         req = Request.from_request.return_value = {'oauth_consumer_key': 'api_key'}
-        self.app.post('/rest/oauth/request_token', params={'key': 'value'}, status=403)
+        self.app.get('/')  # establish session
+        self.app.post('/rest/oauth/request_token',
+                      params={'key': 'value',
+                              '_session_id': self.app.cookies['_session_id'],
+                              },
+                      status=403)
 
     def test_authorize_ok(self):
         user = M.User.by_username('test-admin')
@@ -1384,12 +1549,17 @@ class TestOAuth(TestController):
             user_id=user._id,
         )
         ThreadLocalORMSession.flush_all()
-        r = self.app.post('/rest/oauth/authorize', params={'oauth_token': 'api_key'})
+        self.app.get('/')  # establish session
+        r = self.app.post('/rest/oauth/authorize', params={'oauth_token': 'api_key',
+                                                           '_session_id': self.app.cookies['_session_id']})
         assert_in('ctok_desc', r.body)
         assert_in('api_key', r.body)
 
     def test_authorize_invalid(self):
-        self.app.post('/rest/oauth/authorize', params={'oauth_token': 'api_key'}, status=403)
+        self.app.get('/')  # establish session
+        self.app.post('/rest/oauth/authorize', params={'oauth_token': 'api_key',
+                                                       '_session_id': self.app.cookies['_session_id']},
+                      status=403)
 
     def test_do_authorize_no(self):
         user = M.User.by_username('test-admin')
@@ -1405,8 +1575,11 @@ class TestOAuth(TestController):
             user_id=user._id,
         )
         ThreadLocalORMSession.flush_all()
+        self.app.get('/')  # establish session
         self.app.post('/rest/oauth/do_authorize',
-                      params={'no': '1', 'oauth_token': 'api_key'})
+                      params={'no': '1', 'oauth_token': 'api_key',
+                              '_session_id': self.app.cookies['_session_id'],
+                              })
         assert_is_none(M.OAuthRequestToken.query.get(api_key='api_key'))
 
     def test_do_authorize_oob(self):
@@ -1423,7 +1596,10 @@ class TestOAuth(TestController):
             user_id=user._id,
         )
         ThreadLocalORMSession.flush_all()
-        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key'})
+        self.app.get('/')  # establish session
+        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key',
+                                                              '_session_id': self.app.cookies['_session_id'],
+                                                              })
         assert_is_not_none(r.html.find(text=re.compile('^PIN: ')))
 
     def test_do_authorize_cb(self):
@@ -1440,7 +1616,10 @@ class TestOAuth(TestController):
             user_id=user._id,
         )
         ThreadLocalORMSession.flush_all()
-        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key'})
+        self.app.get('/')  # establish session
+        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key',
+                                                              '_session_id': self.app.cookies['_session_id'],
+                                                              })
         assert r.location.startswith('http://my.domain.com/callback?oauth_token=api_key&oauth_verifier=')
 
     def test_do_authorize_cb_params(self):
@@ -1457,7 +1636,10 @@ class TestOAuth(TestController):
             user_id=user._id,
         )
         ThreadLocalORMSession.flush_all()
-        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key'})
+        self.app.get('/')  # establish session
+        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key',
+                                                              '_session_id': self.app.cookies['_session_id'],
+                                                              })
         assert r.location.startswith('http://my.domain.com/callback?myparam=foo&oauth_token=api_key&oauth_verifier=')
 
     @mock.patch('allura.controllers.rest.oauth.Request')
@@ -1583,13 +1765,17 @@ class TestDisableAccount(TestController):
         assert form is not None
 
     def test_bad_password(self):
-        r = self.app.post('/auth/disable/do_disable', {'password': 'bad'})
+        self.app.get('/')  # establish session
+        r = self.app.post('/auth/disable/do_disable',{'password': 'bad',
+                                                      '_session_id': self.app.cookies['_session_id'],})
         assert_in('Invalid password', r)
         user = M.User.by_username('test-admin')
         assert_equal(user.disabled, False)
 
     def test_disable(self):
-        r = self.app.post('/auth/disable/do_disable', {'password': 'foo'})
+        self.app.get('/')  # establish session
+        r = self.app.post('/auth/disable/do_disable', {'password': 'foo',
+                                                       '_session_id': self.app.cookies['_session_id'],})
         assert_equal(r.status_int, 302)
         assert_equal(r.location, 'http://localhost/')
         flash = json.loads(self.webflash(r))

http://git-wip-us.apache.org/repos/asf/allura/blob/b6623f9f/ForgeUserStats/forgeuserstats/tests/test_stats.py
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/tests/test_stats.py b/ForgeUserStats/forgeuserstats/tests/test_stats.py
index a13d5b4..ade4a33 100644
--- a/ForgeUserStats/forgeuserstats/tests/test_stats.py
+++ b/ForgeUserStats/forgeuserstats/tests/test_stats.py
@@ -46,8 +46,11 @@ class TestStats(TestController):
     def test_login(self):
         user = User.by_username('test-user')
         init_logins = user.stats.tot_logins_count
+        self.app.get('/')  # establish session
         self.app.post('/auth/do_login', params=dict(
-            username=user.username, password='foo'))
+            username=user.username, password='foo',
+            _session_id=self.app.cookies['_session_id']
+        ))
 
         assert user.stats.tot_logins_count == 1 + init_logins
         assert user.stats.getLastMonthLogins() == 1 + init_logins


[05/46] allura git commit: [#7893] remove unnecessary _session_id params from OAuth tests

Posted by he...@apache.org.
[#7893] remove unnecessary _session_id params from OAuth tests


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

Branch: refs/heads/hs/7873
Commit: cc37f7ec41cd1275bf8df43b2dd6649d246906f6
Parents: 0d593dc
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Jun 9 14:28:09 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jun 9 14:31:32 2015 +0000

----------------------------------------------------------------------
 Allura/allura/tests/functional/test_auth.py | 53 +++++-------------------
 1 file changed, 11 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/cc37f7ec/Allura/allura/tests/functional/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_auth.py b/Allura/allura/tests/functional/test_auth.py
index 3727c6c..4522dd8 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -1457,13 +1457,10 @@ class TestOAuth(TestController):
             'oauth_consumer_key': 'api_key',
             'oauth_callback': 'http://my.domain.com/callback',
         }
-        self.app.get('/')  # establish session
-        r = self.app.post('/rest/oauth/request_token', params={'_session_id': self.app.cookies['_session_id']})
+        r = self.app.post('/rest/oauth/request_token', params={})
         rtok = parse_qs(r.body)['oauth_token'][0]
         r = self.app.post('/rest/oauth/authorize',
-                          params={'oauth_token': rtok,
-                                  '_session_id': self.app.cookies['_session_id'],
-                                  })
+                          params={'oauth_token': rtok})
         r = r.forms[0].submit('yes')
         assert r.location.startswith('http://my.domain.com/callback')
         pin = parse_qs(urlparse(r.location).query)['oauth_verifier'][0]
@@ -1488,9 +1485,7 @@ class TestOAuth(TestController):
         )
         ThreadLocalORMSession.flush_all()
         req = Request.from_request.return_value = {'oauth_consumer_key': 'api_key'}
-        r = self.app.post('/rest/oauth/request_token', params={'key': 'value',
-                                                               #'_session_id': self.app.cookies['_session_id'],
-                                                               })
+        r = self.app.post('/rest/oauth/request_token', params={'key': 'value'})
         Request.from_request.assert_called_once_with(
             'POST', 'http://localhost/rest/oauth/request_token',
             headers={'Host': 'localhost:80', 'Content-Type': 'application/x-www-form-urlencoded; charset="utf-8"'},
@@ -1506,12 +1501,8 @@ class TestOAuth(TestController):
     def test_request_token_no_consumer_token(self, Request, Server):
         req = Request.from_request.return_value = {
             'oauth_consumer_key': 'api_key'}
-        self.app.get('/')  # establish session
         r = self.app.post('/rest/oauth/request_token',
-                          params={'key': 'value',
-                                  '_session_id': self.app.cookies['_session_id'],
-                                  },
-                          status=403)
+                          params={'key': 'value'}, status=403)
 
     @mock.patch('allura.controllers.rest.oauth.Server')
     @mock.patch('allura.controllers.rest.oauth.Request')
@@ -1525,12 +1516,7 @@ class TestOAuth(TestController):
         )
         ThreadLocalORMSession.flush_all()
         req = Request.from_request.return_value = {'oauth_consumer_key': 'api_key'}
-        self.app.get('/')  # establish session
-        self.app.post('/rest/oauth/request_token',
-                      params={'key': 'value',
-                              '_session_id': self.app.cookies['_session_id'],
-                              },
-                      status=403)
+        self.app.post('/rest/oauth/request_token', params={'key': 'value'}, status=403)
 
     def test_authorize_ok(self):
         user = M.User.by_username('test-admin')
@@ -1546,17 +1532,12 @@ class TestOAuth(TestController):
             user_id=user._id,
         )
         ThreadLocalORMSession.flush_all()
-        self.app.get('/')  # establish session
-        r = self.app.post('/rest/oauth/authorize', params={'oauth_token': 'api_key',
-                                                           '_session_id': self.app.cookies['_session_id']})
+        r = self.app.post('/rest/oauth/authorize', params={'oauth_token': 'api_key'})
         assert_in('ctok_desc', r.body)
         assert_in('api_key', r.body)
 
     def test_authorize_invalid(self):
-        self.app.get('/')  # establish session
-        self.app.post('/rest/oauth/authorize', params={'oauth_token': 'api_key',
-                                                       '_session_id': self.app.cookies['_session_id']},
-                      status=403)
+        self.app.post('/rest/oauth/authorize', params={'oauth_token': 'api_key'}, status=403)
 
     def test_do_authorize_no(self):
         user = M.User.by_username('test-admin')
@@ -1572,11 +1553,8 @@ class TestOAuth(TestController):
             user_id=user._id,
         )
         ThreadLocalORMSession.flush_all()
-        self.app.get('/')  # establish session
         self.app.post('/rest/oauth/do_authorize',
-                      params={'no': '1', 'oauth_token': 'api_key',
-                              '_session_id': self.app.cookies['_session_id'],
-                              })
+                      params={'no': '1', 'oauth_token': 'api_key'})
         assert_is_none(M.OAuthRequestToken.query.get(api_key='api_key'))
 
     def test_do_authorize_oob(self):
@@ -1593,10 +1571,7 @@ class TestOAuth(TestController):
             user_id=user._id,
         )
         ThreadLocalORMSession.flush_all()
-        self.app.get('/')  # establish session
-        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key',
-                                                              '_session_id': self.app.cookies['_session_id'],
-                                                              })
+        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key'})
         assert_is_not_none(r.html.find(text=re.compile('^PIN: ')))
 
     def test_do_authorize_cb(self):
@@ -1613,10 +1588,7 @@ class TestOAuth(TestController):
             user_id=user._id,
         )
         ThreadLocalORMSession.flush_all()
-        self.app.get('/')  # establish session
-        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key',
-                                                              '_session_id': self.app.cookies['_session_id'],
-                                                              })
+        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key'})
         assert r.location.startswith('http://my.domain.com/callback?oauth_token=api_key&oauth_verifier=')
 
     def test_do_authorize_cb_params(self):
@@ -1633,10 +1605,7 @@ class TestOAuth(TestController):
             user_id=user._id,
         )
         ThreadLocalORMSession.flush_all()
-        self.app.get('/')  # establish session
-        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key',
-                                                              '_session_id': self.app.cookies['_session_id'],
-                                                              })
+        r = self.app.post('/rest/oauth/do_authorize', params={'yes': '1', 'oauth_token': 'api_key'})
         assert r.location.startswith('http://my.domain.com/callback?myparam=foo&oauth_token=api_key&oauth_verifier=')
 
     @mock.patch('allura.controllers.rest.oauth.Request')


[30/46] allura git commit: [#7806] ticket:778 Add conteiners for in/out mail

Posted by he...@apache.org.
[#7806] ticket:778 Add conteiners for in/out mail


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

Branch: refs/heads/hs/7873
Commit: 25a242ff5a131bfcaafe76f60b0459ded6f93086
Parents: a165692
Author: Igor Bondarenko <je...@gmail.com>
Authored: Sat May 30 15:00:20 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:35 2015 -0400

----------------------------------------------------------------------
 Allura/docker-dev.ini |  7 +++++--
 docker-compose.yml    | 19 +++++++++++++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/25a242ff/Allura/docker-dev.ini
----------------------------------------------------------------------
diff --git a/Allura/docker-dev.ini b/Allura/docker-dev.ini
index 0ce00eb..d35fd17 100644
--- a/Allura/docker-dev.ini
+++ b/Allura/docker-dev.ini
@@ -43,8 +43,11 @@ scm.repos.tarball.url_prefix = http://localhost:8080/
 
 solr.server = http://solr:8983/solr
 
-;forgemail.host = smtp
-;forgemail.port = 8825
+smtp_server = outmail
+smtp_port = 8826
+
+forgemail.host = 0.0.0.0
+forgemail.port = 8825
 
 [filter-app:profile]
 use=egg:keas.profile#profiler

http://git-wip-us.apache.org/repos/asf/allura/blob/25a242ff/docker-compose.yml
----------------------------------------------------------------------
diff --git a/docker-compose.yml b/docker-compose.yml
index 586afed..230b3d5 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -34,6 +34,7 @@ web:
   links:
     - mongo
     - solr
+    - outmail
 
 taskd:
   image: allura_web
@@ -44,6 +45,7 @@ taskd:
   links:
     - mongo
     - solr
+    - outmail
 
 solr:
   build: solr_config
@@ -60,3 +62,20 @@ mongo:
     - "27017"
   volumes:
     - /allura-data/mongo:/data/db
+
+outmail:
+  image: allura_web
+  command: python -m smtpd -n -c DebuggingServer 0.0.0.0:8826
+  expose:
+    - "8826"
+
+inmail:
+  image: allura_web
+  working_dir: /allura/Allura
+  command: paster smtp_server docker-dev.ini
+  volumes_from:
+    - web
+  ports:
+    - "8825:8825"
+  links:
+    - mongo


[26/46] allura git commit: [#7806] ticket:773 Add license header to new files

Posted by he...@apache.org.
[#7806] ticket:773 Add license header to new files


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

Branch: refs/heads/hs/7873
Commit: d2be0850f6f538c5f13ce43a57ff342b501e5932
Parents: 92e7184
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon May 25 15:48:33 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:32 2015 -0400

----------------------------------------------------------------------
 Dockerfile             | 17 +++++++++++++++++
 docker-compose.yml     | 17 +++++++++++++++++
 solr_config/Dockerfile | 17 +++++++++++++++++
 3 files changed, 51 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/d2be0850/Dockerfile
----------------------------------------------------------------------
diff --git a/Dockerfile b/Dockerfile
index 0be1159..26ee833 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,3 +1,20 @@
+#       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 ubuntu:12.04
 
 RUN apt-get update && apt-get install -y \

http://git-wip-us.apache.org/repos/asf/allura/blob/d2be0850/docker-compose.yml
----------------------------------------------------------------------
diff --git a/docker-compose.yml b/docker-compose.yml
index d0a8a3b..835f91a 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,3 +1,20 @@
+#       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.
+
 web:
   build: .
   working_dir: /allura

http://git-wip-us.apache.org/repos/asf/allura/blob/d2be0850/solr_config/Dockerfile
----------------------------------------------------------------------
diff --git a/solr_config/Dockerfile b/solr_config/Dockerfile
index 27876e5..107768f 100644
--- a/solr_config/Dockerfile
+++ b/solr_config/Dockerfile
@@ -1,3 +1,20 @@
+#       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 ubuntu:12.04
 
 RUN apt-get update && apt-get install -y \


[20/46] allura git commit: [#7806] ticket:773 Basic docker containers for Allura web and mongo

Posted by he...@apache.org.
[#7806] ticket:773 Basic docker containers for Allura web and mongo


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

Branch: refs/heads/hs/7873
Commit: 6e364168ed22274c5b291cfbcdecfaf984d2f9b2
Parents: 69dd7f8
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu May 21 15:03:35 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:29 2015 -0400

----------------------------------------------------------------------
 Allura/docker-dev.ini | 588 +++++++++++++++++++++++++++++++++++++++++++++
 Dockerfile            |  18 ++
 docker-compose.yml    |  16 ++
 3 files changed, 622 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/6e364168/Allura/docker-dev.ini
----------------------------------------------------------------------
diff --git a/Allura/docker-dev.ini b/Allura/docker-dev.ini
new file mode 100644
index 0000000..0343dd3
--- /dev/null
+++ b/Allura/docker-dev.ini
@@ -0,0 +1,588 @@
+;       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.
+
+
+;
+; Allura configuration
+;
+; Default config values are shown in this file.
+; Commented-out configurations are examples that you can use if you want.
+;
+; Logging configuration is at the end of the file (starting at [loggers])
+;
+; There are many settings you should change for your site (name, domain, secret keys, etc)
+; More settings should be changed for good performance in a production site (no autoreload, no debugging, etc)
+;
+; You may copy this file to make a new configuration file (e.g. production.ini)
+; Or inherit from this file by starting your .ini file like this:
+;    [app:main]
+;    use = config:development.ini#main
+; Then just use the new file name instead of development.ini for any paster commands you run.
+
+
+[DEFAULT]
+; this section is for a few settings that are shared with error handling middleware
+
+; WARNING: *THE LINE BELOW MUST BE CHANGED ON A PRODUCTION ENVIRONMENT*
+; Debug mode will enable the interactive debugging tool, allowing ANYONE to
+; execute malicious code after an exception is raised.
+debug = true
+; If you want to receive an email for every unhandled HTTP 500 error, set your email address here:
+;email_to = you@yourdomain.com
+error_email_from = paste@localhost
+
+; SMTP settings for outgoing mail
+smtp_tls = false
+smtp_ssl = false
+;smtp_user = some_user
+;smtp_password = some_password
+smtp_timeout = 10
+smtp_server = localhost
+smtp_port = 8826
+; Reply-To and From address often used in email notifications:
+forgemail.return_path = noreply@localhost
+
+
+;
+; Settings for `paster serve` command
+;
+[server:main]
+use = egg:Paste#http
+host = 0.0.0.0
+port = 8080
+
+
+;
+; The main allura settings
+;
+[app:main]
+use = egg:Allura
+full_stack = true
+
+; Change this to your website's name
+site_name = Allura
+; Change these to your website's domain
+domain = localhost
+; Change this to your website's full URL
+base_url = http://localhost:8080
+; This should be the same as base_url
+forgemail.url = http://localhost:8080
+
+; Used to uniquify references to static resources, can be a timestamp or any unique value
+; This should be updated each time you deploy (or make significant changes, like new tools, new css)
+build_key=1276635823
+
+; Used by Turbogears / Pylons in some cases.  Not particularly relevant for Allura.
+cache_dir = %(here)s/data
+
+; Cache Neighborhood objects for N seconds (speeds up requests).
+; Set to 0 to disable (the default).
+;neighborhood.cache.duration = 0
+
+; Template cache settings
+; See http://jinja.pocoo.org/docs/api/#jinja2.Environment
+jinja_cache_size = -1
+;jinja_bytecode_cache_type = filesystem
+;jinja_bytecode_cache_type = memcached
+;memcached_host =
+
+; Docs at http://beaker.readthedocs.org/en/latest/configuration.html#session-options
+; and http://beaker.readthedocs.org/en/latest/modules/session.html#beaker.session.CookieSession
+beaker.session.key = allura
+beaker.session.type = cookie
+beaker.session.httponly = true
+; set this to true if you use HTTPS.  If you use force_ssl.logged_in, this will be set automatically when logged in and not when not.
+beaker.session.secure = false
+; CHANGE THIS VALUE FOR YOUR SITE
+beaker.session.validate_key = 714bfe3612c42390726f
+
+; Google Analytics account for tracking
+;ga.account = UA-XXXXX-X
+
+; Project registration system.  Only local is available, unless you write a custom one for custom integration.
+registration.method = local
+theme = allura
+
+; For LDAP see https://forge-allura.apache.org/docs/getting_started/installation.html#using-ldap
+;auth.method = ldap
+auth.method = local
+auth.remember_for = 365  ; in days, for the "remember me" checkbox on login
+
+; Customize login/logout URLs only if you have some custom authentication set up.
+auth.login_url = /auth/
+auth.logout_url = /auth/logout
+; the login fragement URL shows just the form, not a whole page.  It is used within a login overlay on some pages
+auth.login_fragment_url = /auth/login_fragment/
+auth.post_logout_url = /
+
+auth.min_password_len = 6
+auth.max_password_len = 30
+
+; password expiration options (disabled if neither is set)
+;auth.pwdexpire.days = 1
+;auth.pwdexpire.before = 1401949912  ; unix timestamp
+
+; if using LDAP, also run `pip install python-ldap` in your Allura environment
+
+auth.ldap.server = ldaps://localhost/
+auth.ldap.suffix = ou=people,dc=localdomain
+auth.ldap.admin_dn = cn=admin,dc=localdomain
+auth.ldap.admin_password = secret
+auth.ldap.schroot_name = scm
+auth.ldap.use_schroot = false
+auth.ldap.password.algorithm = 6
+auth.ldap.password.rounds = 6000
+auth.ldap.password.salt_len = 16
+; "autoregister" allows users to log in to Allura with an existing LDAP account
+; If using ldap, with autoregister, you should also set "allow_user_registration"
+; to false below.
+; Set "autoregister" to false to require user to register in Allura to create
+; the LDAP record and Allura record for the user.
+auth.ldap.autoregister = true
+
+auth.allow_user_registration = true
+auth.allow_user_to_disable_account = true
+auth.allow_edit_prefs = true
+auth.allow_password_change = true
+auth.allow_upload_ssh_key = false
+auth.allow_user_messages_config = true
+auth.allow_birth_date = true
+auth.allow_non_primary_email_password_reset = true
+auth.require_email_addr = true
+; List of social network options to use on user account settings
+socialnetworks = Facebook, Linkedin, Twitter, Google+
+
+; In seconds
+auth.recovery_hash_expiry_period = 600
+
+user_prefs_storage.method = local
+; user_prefs_storage.method = ldap
+; If using ldap, you can specify which fields to use for a preference.
+; Any fields not specified here will be stored locally in mongo
+user_prefs_storage.ldap.fields.display_name = cn
+
+; Limit the number of emails a user can claim.
+user_prefs.maximum_claimed_emails = 20
+
+; Control the order of sections on the user profile page
+;user_profile_sections.order = activity, personal-data, skills
+
+; Site admins will be the same as the admins of this project:
+site_admin_project = allura
+site_admin_project_nbhd = Projects
+
+; Spam filtering service: mollom or akismet
+;spam.method = akismet
+; for akismet:
+;spam.key =
+; for mollom:
+;spam.public_key =
+;spam.private_key =
+
+; Webhook timeout in seconds
+webhook.timeout = 30
+; List of pauses between retries, if hook fails (in seconds)
+webhook.retry = 60 120 240
+; Limit rate of webhook firing (in seconds, default = 30)
+; Option format: webhook.<hook type>.limit,
+; all '-' in hook type must be changed to '_'
+; e.g. for repo-push webhook:
+webhook.repo_push.limit = 30
+; Limit max number of hooks that can be created for given project/app
+; Option name format: same as above.
+; Value format: json dict, where keys are app names (as appears in
+; `WebhookSender.triggered_by`) and values are actual limits (default=3), e.g.:
+webhook.repo_push.max_hooks = {"git": 3, "hg": 3, "svn": 3}
+
+; Additional fields for admin project/user search
+; Note: whitespace after comma is important!
+;search.project.additional_search_fields = private, url, title
+;search.user.additional_search_fields = email_addresses
+
+; Additional fields to show in the result of admin project/user search
+; Note: whitespace after comma is important!
+;search.project.additional_display_fields = private, url, title
+;search.user.additional_display_fields = email_addresses
+
+; To make all pages use ssl:   (also set beaker.session.secure above)
+;force_ssl.pattern = .
+; To use ssl if and only if a user is logged in:
+;force_ssl.logged_in = true
+; If you set force_ssl.logged_in, you probably want some URLs to be ssl when logged out:
+;force_ssl.pattern = ^/auth|^/[a-z0-9-]+/import_project/  ; import_project uses a login overlay
+; And to permit some URLs to be accessed over http anyway:
+;no_redirect.pattern = ^/nf/\d+/_(ew|static)_/|^/rest/|^/nf/tool_icon_css|^/auth/refresh_repo
+
+
+; Set the locations of some static resources.  ("ew" stands for EasyWidgets library)
+;  script_name is the path that is handled by the application
+;  url_base is the prefix that references to the static resources should have
+; If you use a CDN, put your CDN prefix in the url_base values
+ew.script_name = /nf/%(build_key)s/_ew_/
+ew.url_base = /nf/%(build_key)s/_ew_/
+static.script_name = /nf/%(build_key)s/_static_/
+static.url_base = /nf/%(build_key)s/_static_/
+
+; Expires header for "static" resources served through allura (e.g. icons, attachments, /nf/tool_icon_css)
+files_expires_header_secs = 1209600 ; 2 weeks
+
+ew.extra_headers = [ ('Access-Control-Allow-Origin', '*') ]
+
+; If your environment (e.g. behind a server-side proxy) needs to look at an http header to get the actual remote addr
+;ip_address_header = X-Forwarded-For
+
+; SCM settings for local development
+scm.host.ro.git = /srv/git$path
+scm.host.rw.git = /srv/git$path
+; remote access varies by configuration.  If you are using a vagrant VM, this should work:
+;scm.host.rw.git = ssh://vagrant@localhost:2222/srv/git$path
+scm.host.ro.hg = /srv/hg$path
+scm.host.rw.hg = /srv/hg$path
+scm.host.ro.svn = file:///srv/svn$path/
+scm.host.rw.svn = file:///srv/svn$path/
+
+; SCM settings for chroot + ldap configuration.  See Allura/docs/getting_started/scm_host.rst
+;scm.host.ro.git = git://git.localhost$path
+;scm.host.rw.git = ssh://$username@localhost:8022/scm-repo$path
+;scm.host.ro.hg = http://hg.localhost$path
+;scm.host.rw.hg = ssh://$username@localhost:8022/scm-repo$path
+;scm.host.ro.svn = http://svn.localhost$path/
+;scm.host.rw.svn = svn+ssh://localhost:8022/scm-repo$path/
+
+; SCM settings for https (sorry no docs for setting these up)
+; these settings are currently required by the template, no matter what
+scm.host.https.git = https://$username@localhost:8022/scm-repo$path
+scm.host.https_anon.git = https://localhost:8022/scm-repo$path
+scm.host.https.hg = https://$username@localhost:8022/scm-repo$path
+scm.host.https_anon.hg = https://localhost:8022/scm-repo$path
+scm.host.https.svn = https://localhost:8022/scm-repo$path/
+scm.host.https_anon.svn = https://localhost:8022/scm-repo$path/
+
+scm.clone.git = git clone $source_url $dest_path
+scm.clone.hg = hg clone $source_url $dest_path
+scm.clone.ro.svn = svn checkout $source_url $dest_path
+scm.clone.https_anon.svn = svn checkout $source_url $dest_path
+scm.clone.svn = svn checkout --username=$username $source_url $dest_path
+
+scm.repos.root = /srv
+scm.repos.tarball.enable = false
+scm.repos.tarball.root = /usr/share/nginx/www/
+scm.repos.tarball.url_prefix = http://localhost/
+scm.repos.tarball.zip_binary = /usr/bin/zip
+
+; SCM imports (currently just SVN) will retry if it fails
+; You can control the number of tries and delay between tries here:
+scm.import.retry_count = 50
+scm.import.retry_sleep_secs = 5
+
+; One-click merge is enabled by default, but can be turned off on for each type of repo
+scm.merge.git.disabled = false
+scm.merge.hg.disabled = false
+
+
+; bulk_export_enabled = true
+; If you keep bulk_export_enabled, you should set up your server to securely share bulk_export_path with users somehow
+bulk_export_path = /tmp/bulk_export/{nbhd}/{project}
+bulk_export_filename = {project}-backup-{date:%Y-%m-%d-%H%M%S}.zip
+; You will need to specify site-specific instructions here for accessing the exported files.
+bulk_export_download_instructions = Sample instructions for {project}
+
+importer_upload_path = /tmp/importer_upload/{nbhd}/{project}
+
+; To disable any plugin, tool, importer, etc from being available, you can use the disable_entry_points config option.
+; Specify the keys and values as they are declared in the tool's "setup.py" file.
+; Examples:
+;disable_entry_points.importers = google-code-tracker, google-code-repo
+;disable_entry_points.allura.project_importers = google-code
+
+; Importers specifically, can be left enabled but not linked to.  You have to know the URL to use it.  Example:
+;hidden_importers = trac-tickets
+
+; GitHub importer keys.  For github ticket import, it is best to set
+; up an app at https://github.com/settings/applications  Use the root URL
+; of your Allura instance for both URLs, and enter client values here:
+;github_importer.client_id =
+;github_importer.client_secret =
+
+; If your site has docs about specific importers, you can add them here and
+; they'll appear on the import forms
+;doc.url.importers.Google Code = http://...
+
+; List of oauth API keys permitted to use special forum import API
+; (should be converted to newer importer system)
+;oauth.can_import_forum = api-key-1234, fa832r0fdsafd, f23f80sdf32fd
+
+
+; space-separated list of tool names that are valid options
+; for project admins to set for their 'support_page' field
+; this field is not used by default in Allura, so this option
+; is disabled by default
+;support_tool_choices = wiki tickets discussion
+
+; Control how /categories URL can be accessed to edit trove categories (used in project categories and user skills)
+; Default: everyone
+trovecategories.enableediting = true
+; Nobody:
+;trovecategories.enableediting = false
+; Site admins only:
+;trovecategories.enableediting = admin
+
+; ActivityStream
+activitystream.master = mongodb://mongo:27017
+activitystream.database = activitystream
+activitystream.activity_collection = activities
+activitystream.node_collection = nodes
+activitystream.timeline_collection = timelines
+activitystream.enabled = true
+activitystream.recording.enabled = true
+
+; Ming setup
+; These don't necessarily have to be separate databases, they could
+; be all in the same database if desired
+ming.main.uri = mongodb://mongo:27017/allura
+ming.main.auto_ensure_indexes = False
+ming.project.uri = mongodb://mongo:27017/project-data
+ming.project.auto_ensure_indexes = False
+ming.task.uri = mongodb://mongo:27017/task
+ming.task.auto_ensure_indexes = False
+;ming.zarkov.uri = mongodb://127.0.0.1:27017/zarkov
+;ming.zarkov.auto_ensure_indexes = False
+
+; Zarkov host setting, requires the zarkov and gevent libraries.
+;zarkov.host = tcp://127.0.0.1:9000
+
+; A float from 0-1 representing a % of requests to measure timing on.
+; Sampled requests will have timing logged to stats.log (can change file in [handler_timermiddleware] logging section)
+stats.sample_rate = 1
+
+; Taskd setup
+; number of seconds to sleep between checking for new tasks
+monq.poll_interval=2
+
+; SOLR setup
+solr.server = http://localhost:8983/solr
+; Alternate server to use just for querying
+;solr.query_server =
+; Shorter timeout for search queries (longer timeout for saving to solr)
+solr.short_timeout = 10
+; commit on every add/delete?
+solr.commit = false
+; commit add operations within N ms
+solr.commitWithin = 10000
+; Use improved data types for labels and custom fields?
+; New Allura deployments should leave this set to true. Existing deployments
+; should set to false until existing data has been reindexed. Reindexing will
+; convert existing label and custom field data to more appropriate solr types.
+solr.use_new_types = true
+
+; Incoming email settings.  Used when you run: paster smtp_server development.ini
+; address to listen to
+forgemail.host = 0.0.0.0
+forgemail.port = 8825
+; domain suffix for your mail, change this.  You also need to route *.*.*.forgemail.domain to the above host/port via
+; your mail and DNS configuration
+forgemail.domain = .in.localhost
+
+; Specify the number of projects allowed to be created by a user
+; depending on the age of their user account.
+; Keys are number of seconds, values are max number of projects allowed
+; (including the default user-project, so you probably want to add 1)
+; This example allows for 1 project if the account is less than an hour old
+; and 5 projects if the account is less than a day old.  No limits after that
+;project.rate_limits = {"3600": 2, "86400": 6}
+
+; set this to "false" if you are deploying to production and want performance improvements
+auto_reload_templates = true
+
+; How frequently users can send messages, in seconds
+user_message.time_interval = 3600
+; Max number of messages that can be sent within that time interval.
+user_message.max_messages = 20
+
+; Default number of times to show a sitewide notification
+; See https://forge-allura.apache.org/docs/getting_started/administration.html#site-notifications
+site_notification.impressions = 0
+
+; When rendering discussion post Markdown to html, if the render takes longer
+; than `markdown_cache_threshold` (in seconds), the resulting html will be
+; cached and served from cache on subsequent requests. Set to 0 to cache all
+; posts. Remove entirely to cache nothing.
+markdown_cache_threshold = .1
+; markdown text longer than max length will not be converted to html
+markdown_render_max_length = 999999999
+; Don't add rel=nofollow to these domains when generating links from Markdown content
+;nofollow_exempt_domains =
+
+; Export control choices on the project admin overview page.
+show_export_control = false
+
+; By default project admins can soft-delete their projects.
+; A soft-deleted project will still be in the database and visible to admins, but not to others.
+allow_project_delete = true
+allow_project_undelete = true
+
+; Advanced settings for controlling "Last Commit Doc" algorithm used when visiting any repo browse page
+lcd_thread_chunk_size = 10
+lcd_timeout = 60
+
+
+;
+; Settings for the Blog tool
+;
+; Enable or disable external RSS feed importing in ForgeBlog tool.
+; Default is "false". This feature requires GPL library "html2text". Install it with following command:
+;   pip install -e git://github.com/brondsem/html2text.git#egg=html2text
+; You will also need to run `paster pull-rss-feeds development.ini` in a cron job to fetch them.
+forgeblog.exfeed = false
+
+;
+; Settings for the Chat tool
+;
+forgechat.host = irc.freenode.net
+forgechat.port = 6667
+ircbot.nick = allurabot
+
+;
+; Settings for ShortUrl tool
+;
+; Override this if you set up an additional shortening mechanism (e.g. custom short domain)
+short_url.url_pattern = {base_url}/{nbhd}/{project}/{mount_point}/{short_name}
+
+
+;
+; Settings for UserStats tool
+;
+userstats.count_lines_of_code = true
+
+
+;
+; Optional settings for profiling with https://pypi.python.org/pypi/keas.profile
+;
+[filter-app:profile]
+use=egg:keas.profile#profiler
+next=main
+
+
+;
+; setup for the taskd background daemon request controller
+;
+[app:task]
+use = main
+override_root = task ; TurboGears will use controllers/task.py as root controller
+
+
+
+;
+; Logging configuration
+;
+; Add additional loggers, handlers, formatters here
+; Uses python's logging config file format
+; https://docs.python.org/2/library/logging.config.html#configuration-file-format
+;
+[loggers]
+keys = root, allura, sqlalchemy, paste, pylons, taskdstatus, timermiddleware, tmw_details
+
+[handlers]
+keys = console, stats, taskdstatus, timermiddleware
+
+[formatters]
+keys = generic, stats, timermiddleware
+
+; If you create additional loggers, add them as a key to [loggers]
+[logger_root]
+level = INFO
+handlers = console, stats
+
+[logger_allura]
+level = INFO
+handlers =
+qualname = allura
+
+[logger_sqlalchemy]
+level = INFO
+handlers =
+qualname = sqlalchemy.engine
+; "level = INFO" logs SQL queries.
+; "level = DEBUG" logs SQL queries and results.
+; "level = WARN" logs neither.  (Recommended for production systems.)
+
+[logger_paste]
+level = INFO
+qualname = paste
+handlers =
+
+[logger_pylons]
+level = INFO
+qualname = pylons
+handlers =
+
+[logger_tmw_details]
+; DEBUG will include every instrumented call in our logging
+level = INFO
+qualname = timermiddleware
+handlers =
+
+[logger_taskdstatus]
+level = INFO
+qualname = taskdstatus
+handlers = taskdstatus
+
+[logger_timermiddleware]
+level = INFO
+handlers = timermiddleware
+qualname = stats
+propagate = 0
+
+; If you create additional handlers, add them as a key to [handlers]
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[handler_stats]
+class = allura.lib.utils.StatsHandler
+args = ('rtstats.log', 'allura', 1)
+level = NOTSET
+formatter = stats
+
+[handler_taskdstatus]
+class = handlers.WatchedFileHandler
+args = ('taskd_status.log', 'a')
+level = NOTSET
+formatter = generic
+
+[handler_timermiddleware]
+class = handlers.WatchedFileHandler
+; if you run 'paster serve' in allura/Allura/ then that's where this file will be
+; you may want to hard-code a specific directory here.
+args = ('stats.log', 'a')
+level = NOTSET
+formatter = timermiddleware
+
+; If you create additional formatters, add them as a key to [formatters]
+[formatter_generic]
+format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S
+
+[formatter_stats]
+format = %(asctime)s %(created)d %(kwpairs)s
+datefmt = %d/%b/%Y:%H:%M:%S UTC
+
+[formatter_timermiddleware]
+format = {"time": "%(asctime)s,%(msecs)03d", "level": "%(levelname)-5.5s", "name": "%(name)s", "message": %(message)s}
+datefmt = %Y-%m-%d %H:%M:%S

http://git-wip-us.apache.org/repos/asf/allura/blob/6e364168/Dockerfile
----------------------------------------------------------------------
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..1c8e06f
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,18 @@
+FROM ubuntu:12.04
+
+RUN apt-get update && apt-get install -y \
+    python-dev \
+    libssl-dev \
+    libldap2-dev \
+    libsasl2-dev \
+    libjpeg8-dev \
+    zlib1g-dev \
+    python-pip
+
+ENV basedir /allura
+
+ADD . ${basedir}
+WORKDIR ${basedir}
+
+RUN pip install -r requirements.txt
+RUN ./rebuild-all.bash

http://git-wip-us.apache.org/repos/asf/allura/blob/6e364168/docker-compose.yml
----------------------------------------------------------------------
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..8b7ac88
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,16 @@
+web:
+  build: .
+  working_dir: ${basedir}
+  command: paster serve Allura/docker-dev.ini --reload
+  ports:
+    - "8080:8080"
+  volumes:
+    - .:/${basedir}
+  links:
+    - mongo
+mongo:
+  image: mongo:2.6
+  expose:
+    - "27017"
+  volumes:
+    - /allura-data/mongo:/data/db


[13/46] allura git commit: [#6057] ticket:788 Add/fix tests

Posted by he...@apache.org.
[#6057] ticket:788 Add/fix tests


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

Branch: refs/heads/hs/7873
Commit: a0b3aed29a4a7e9657838f584f49e668f54bfd41
Parents: 1ac85b8
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jun 5 12:19:37 2015 +0000
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Tue Jun 9 21:06:06 2015 +0000

----------------------------------------------------------------------
 Allura/allura/app.py                            |  1 +
 Allura/allura/model/project.py                  |  6 +--
 Allura/allura/tests/functional/test_admin.py    | 10 ++++
 Allura/allura/tests/model/test_project.py       | 17 ++++++
 Allura/allura/tests/test_app.py                 | 35 +++++++++++++
 .../forgelink/tests/functional/test_root.py     | 54 ++++++++++++++++++++
 6 files changed, 120 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/a0b3aed2/Allura/allura/app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index a9d3ff0..58aa49d 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -76,6 +76,7 @@ class ConfigOption(object):
     def validate(self, value):
         if self.validator:
             return self.validator.to_python(value)
+        return value
 
 
 class SitemapEntry(object):

http://git-wip-us.apache.org/repos/asf/allura/blob/a0b3aed2/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index e280d63..2ad3be4 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -742,10 +742,10 @@ class Project(SearchIndexable, MappedClass, ActivityNode, ActivityObject):
         options['mount_label'] = mount_label or App.default_mount_label or mount_point
         options['ordinal'] = int(ordinal)
         options_on_install = {o.name: o for o in App.options_on_install()}
-        for o, v in override_options.iteritems():
+        for o, val in override_options.iteritems():
             if o in options_on_install:
-                v = self._validate_tool_option(options_on_install[o], v)
-            options[o] = v
+                val = self._validate_tool_option(options_on_install[o], val)
+            options[o] = val
         cfg = AppConfig(
             project_id=self._id,
             tool_name=ep_name.lower(),

http://git-wip-us.apache.org/repos/asf/allura/blob/a0b3aed2/Allura/allura/tests/functional/test_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_admin.py b/Allura/allura/tests/functional/test_admin.py
index 819a92a..d239591 100644
--- a/Allura/allura/tests/functional/test_admin.py
+++ b/Allura/allura/tests/functional/test_admin.py
@@ -358,6 +358,16 @@ class TestProjectAdmin(TestController):
             assert 'error' in self.webflash(r)
             assert 'limit exceeded' in self.webflash(r)
 
+    def test_tool_options_on_install(self):
+        self.app.get('/admin/options_on_install', status=404)
+        self.app.get('/admin/options_on_install?tool_name=fake', status=404)
+        r = self.app.get('/admin/options_on_install?tool_name=tickets')
+        assert_equals(r.body, '')
+        opts = ['EnableVoting']
+        with mock.patch.object(ForgeTrackerApp, 'config_on_install', new=opts):
+            r = self.app.get('/admin/options_on_install?tool_name=tickets')
+            assert_in(u'<input id="EnableVoting" name="EnableVoting" type="checkbox">', r)
+
     def test_grouping_threshold(self):
         r = self.app.get('/admin/tools')
         grouping_threshold = r.html.find(

http://git-wip-us.apache.org/repos/asf/allura/blob/a0b3aed2/Allura/allura/tests/model/test_project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_project.py b/Allura/allura/tests/model/test_project.py
index d8a754f..2fe3dc8 100644
--- a/Allura/allura/tests/model/test_project.py
+++ b/Allura/allura/tests/model/test_project.py
@@ -24,6 +24,7 @@ from nose import with_setup
 from nose.tools import assert_equals, assert_in
 from pylons import tmpl_context as c
 from ming.orm.ormsession import ThreadLocalORMSession
+from formencode import validators as fev
 
 from allura import model as M
 from allura.lib import helpers as h
@@ -96,6 +97,22 @@ def test_project():
     c.app.config.breadcrumbs()
 
 
+@with_setup(setUp)
+def test_install_app_validates_options():
+    from forgetracker.tracker_main import ForgeTrackerApp
+    name = 'TicketMonitoringEmail'
+    opt = [o for o in ForgeTrackerApp.config_options if o.name == name][0]
+    opt.validator = fev.Email(not_empty=True)
+    with patch.object(ForgeTrackerApp, 'config_on_install', new=[opt.name]):
+        for v in [None, '', 'bad@email']:
+            with td.raises(ToolError):
+                c.project.install_app('Tickets', 'test-tickets', **{name: v})
+            assert_equals(c.project.app_instance('test-tickets'), None)
+        c.project.install_app('Tickets', 'test-tickets', **{name: 'e@e.com'})
+        app = c.project.app_instance('test-tickets')
+        assert_equals(app.config.options[name], 'e@e.com')
+
+
 def test_project_index():
     project, idx = c.project, c.project.index()
     assert 'id' in idx

http://git-wip-us.apache.org/repos/asf/allura/blob/a0b3aed2/Allura/allura/tests/test_app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_app.py b/Allura/allura/tests/test_app.py
index a31f112..2642a95 100644
--- a/Allura/allura/tests/test_app.py
+++ b/Allura/allura/tests/test_app.py
@@ -18,6 +18,8 @@
 from pylons import tmpl_context as c
 import mock
 from ming.base import Object
+from nose.tools import assert_equal, assert_raises
+from formencode import validators as fev
 
 from alluratest.controller import setup_unit_test
 from allura import app
@@ -52,6 +54,39 @@ def test_config_options():
     assert options[1].default == 'MyTestValue'
 
 
+def test_config_option_without_validator():
+    opt = app.ConfigOption('test1', str, None)
+    assert_equal(opt.validate(None), None)
+    assert_equal(opt.validate(''), '')
+    assert_equal(opt.validate('val'), 'val')
+
+
+def test_config_option_with_validator():
+    v = fev.NotEmpty()
+    opt = app.ConfigOption('test1', str, None, validator=v)
+    assert_equal(opt.validate('val'), 'val')
+    assert_raises(fev.Invalid, opt.validate, None)
+    assert_raises(fev.Invalid, opt.validate, '')
+
+
+def test_options_on_install_default():
+    a = app.Application(c.project, c.app.config)
+    assert_equal(a.options_on_install(), [])
+
+
+def test_options_on_install():
+    opts = [app.ConfigOption('url', str, None),
+            app.ConfigOption('private', bool, None)]
+    class TestApp(app.Application):
+        config_options = app.Application.config_options + opts + [
+            app.ConfigOption('not_on_install', str, None),
+        ]
+        config_on_install = ['url', 'private']
+
+    a = TestApp(c.project, c.app.config)
+    assert_equal(a.options_on_install(), opts)
+
+
 def test_sitemap():
     sm = app.SitemapEntry('test', '')[
         app.SitemapEntry('a', 'a/'),

http://git-wip-us.apache.org/repos/asf/allura/blob/a0b3aed2/ForgeLink/forgelink/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/tests/functional/test_root.py b/ForgeLink/forgelink/tests/functional/test_root.py
index 021b91f..1372be8 100644
--- a/ForgeLink/forgelink/tests/functional/test_root.py
+++ b/ForgeLink/forgelink/tests/functional/test_root.py
@@ -15,6 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+import json
 from nose.tools import assert_equal
 
 from allura import model as M
@@ -61,3 +62,56 @@ class TestRootController(TestController):
         response = self.app.get('/link/help')
         # HACK: support for remote redirects is limited in follow()
         assert 'http://www.google.de/search?q=help' in response
+
+
+class TestConfigOptions(TestController):
+
+    @property
+    def project(self):
+        return M.Project.query.get(shortname='test')
+
+    def assert_url(self, mount_point, val):
+        app = self.project.app_instance(mount_point)
+        assert_equal(app.config.options['url'], val)
+
+    def test_sets_url_on_install(self):
+        r = self.app.post('/p/test/admin/update_mounts', params={
+            'new.install': 'install',
+            'new.ep_name': 'link',
+            'new.ordinal': '1',
+            'new.mount_point': 'link-google',
+            'new.mount_label': 'Google',
+            'url': 'google.com'})
+        self.assert_url('link-google', 'http://google.com')
+
+    def test_validates_url_on_install(self):
+        r = self.app.post('/p/test/admin/update_mounts', params={
+            'new.install': 'install',
+            'new.ep_name': 'link',
+            'new.ordinal': '1',
+            'new.mount_point': 'link-google',
+            'new.mount_label': 'Google',
+            'url': 'invalid url'})
+        flash = json.loads(self.webflash(r))
+        assert_equal(flash['status'], 'error')
+        assert_equal(flash['message'], 'ToolError: url: That is not a valid URL')
+        app = self.project.app_instance('link-google')
+        assert_equal(app, None)
+
+    @td.with_link
+    def test_sets_url_on_config(self):
+        self.assert_url('link', None)
+        params = {'url': 'https://allura.apache.org'}
+        r = self.app.post('/p/test/admin/link/configure', params=params)
+        assert_equal(self.webflash(r), '')
+        self.assert_url('link', 'https://allura.apache.org')
+
+    @td.with_link
+    def test_validates_url_on_config(self):
+        self.assert_url('link', None)
+        params = {'url': 'invalid link'}
+        r = self.app.post('/p/test/admin/link/configure', params=params)
+        flash = json.loads(self.webflash(r))
+        assert_equal(flash['status'], 'error')
+        assert_equal(flash['message'], 'url: That is not a valid URL')
+        self.assert_url('link', None)


[27/46] allura git commit: [#7806] ticket:778 Fix hg repo path in docker-dev.ini

Posted by he...@apache.org.
[#7806] ticket:778 Fix hg repo path in docker-dev.ini


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

Branch: refs/heads/hs/7873
Commit: 260e5f53c8955f3ec6de79dbba675f362e374ea2
Parents: d2be085
Author: Igor Bondarenko <je...@gmail.com>
Authored: Sat May 30 11:16:18 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:33 2015 -0400

----------------------------------------------------------------------
 Allura/docker-dev.ini | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/260e5f53/Allura/docker-dev.ini
----------------------------------------------------------------------
diff --git a/Allura/docker-dev.ini b/Allura/docker-dev.ini
index 34cb040..2e22df7 100644
--- a/Allura/docker-dev.ini
+++ b/Allura/docker-dev.ini
@@ -33,7 +33,7 @@ scm.repos.root = /allura-data/scm
 scm.host.ro.git = /allura-data/scm/git$path
 scm.host.rw.git = /allura-data/scm/git$path
 scm.host.ro.hg = /allura-data/scm/hg$path
-scm.host.rw.hg = /allura-data/scm/srv/hg$path
+scm.host.rw.hg = /allura-data/scm/hg$path
 scm.host.ro.svn = file:///allura-data/scm/svn$path/
 scm.host.rw.svn = file:///allura-data/scm/svn$path/
 


[09/46] allura git commit: [#6057] ticket:788 Handle extra options on tool install

Posted by he...@apache.org.
[#6057] ticket:788 Handle extra options on tool install


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

Branch: refs/heads/hs/7873
Commit: 72decc8f1ac5ee4d2600dbfd3f6fbcd199e4337b
Parents: 0f559d6
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jun 5 08:52:53 2015 +0000
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Tue Jun 9 21:06:05 2015 +0000

----------------------------------------------------------------------
 Allura/allura/app.py                  |  7 ++++++-
 Allura/allura/ext/admin/admin_main.py | 12 +++++++++++-
 Allura/allura/model/project.py        | 15 ++++++++++++---
 ForgeLink/forgelink/link_main.py      |  4 +++-
 4 files changed, 32 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/72decc8f/Allura/allura/app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index 4d96a8f..c52f1c7 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -55,12 +55,13 @@ class ConfigOption(object):
 
     """
 
-    def __init__(self, name, ming_type, default, label=None):
+    def __init__(self, name, ming_type, default, label=None, validator=None):
         """Create a new ConfigOption.
 
         """
         self.name, self.ming_type, self._default, self.label = (
             name, ming_type, default, label or name)
+        self.validator = validator
 
     @property
     def default(self):
@@ -71,6 +72,10 @@ class ConfigOption(object):
             return self._default()
         return self._default
 
+    def validate(self, value):
+        if self.validator:
+            return self.validator.to_python(value)
+
 
 class SitemapEntry(object):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/72decc8f/Allura/allura/ext/admin/admin_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/admin_main.py b/Allura/allura/ext/admin/admin_main.py
index 4ec1568..46cdf9c 100644
--- a/Allura/allura/ext/admin/admin_main.py
+++ b/Allura/allura/ext/admin/admin_main.py
@@ -687,8 +687,18 @@ class ProjectAdminController(BaseController):
                 h.log_action(log, 'install tool').info(
                     'install tool %s', mount_point,
                     meta=dict(tool_type=ep_name, mount_point=mount_point, mount_label=new['mount_label']))
+                App = g.entry_points['tool'][ep_name]
+                # pass only options which app expects
+                config_on_install = {
+                    k: v for (k, v) in kw.iteritems()
+                    if k in [o.name for o in App.options_on_install()]
+                }
                 return c.project.install_app(
-                    ep_name, mount_point, mount_label=new['mount_label'], ordinal=new['ordinal'])
+                    ep_name,
+                    mount_point,
+                    mount_label=new['mount_label'],
+                    ordinal=new['ordinal'],
+                    **config_on_install)
         g.post_event('project_updated')
 
     @h.vardec

http://git-wip-us.apache.org/repos/asf/allura/blob/72decc8f/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index db460a1..e280d63 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -725,6 +725,12 @@ class Project(SearchIndexable, MappedClass, ActivityNode, ActivityObject):
             except fe.Invalid as e:
                 raise exceptions.ToolError(str(e))
 
+    def _validate_tool_option(self, opt, value):
+        try:
+            return opt.validate(value)
+        except fe.Invalid as e:
+            raise exceptions.ToolError(u'{}: {}'.format(opt.name, str(e)))
+
     def install_app(self, ep_name, mount_point=None, mount_label=None, ordinal=None, **override_options):
         App = g.entry_points['tool'][ep_name]
         mount_point = self._mount_point_for_install(App, mount_point)
@@ -733,10 +739,13 @@ class Project(SearchIndexable, MappedClass, ActivityNode, ActivityObject):
                           [-1]['ordinal']) + 1
         options = App.default_options()
         options['mount_point'] = mount_point
-        options[
-            'mount_label'] = mount_label or App.default_mount_label or mount_point
+        options['mount_label'] = mount_label or App.default_mount_label or mount_point
         options['ordinal'] = int(ordinal)
-        options.update(override_options)
+        options_on_install = {o.name: o for o in App.options_on_install()}
+        for o, v in override_options.iteritems():
+            if o in options_on_install:
+                v = self._validate_tool_option(options_on_install[o], v)
+            options[o] = v
         cfg = AppConfig(
             project_id=self._id,
             tool_name=ep_name.lower(),

http://git-wip-us.apache.org/repos/asf/allura/blob/72decc8f/ForgeLink/forgelink/link_main.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/link_main.py b/ForgeLink/forgelink/link_main.py
index 87fbdbb..cd43d3f 100644
--- a/ForgeLink/forgelink/link_main.py
+++ b/ForgeLink/forgelink/link_main.py
@@ -49,7 +49,9 @@ class ForgeLinkApp(Application):
         'read': 'View link.',
     }
     config_options = Application.config_options + [
-        ConfigOption('url', str, None)
+        ConfigOption(
+            'url', str, None,
+            validator=fev.URL(not_empty=True, add_http=True)),
     ]
     config_on_install = ['url']
     searchable = True


[28/46] allura git commit: [#7806] ticket:778 Add USER env var for GitPython

Posted by he...@apache.org.
[#7806] ticket:778 Add USER env var for GitPython


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

Branch: refs/heads/hs/7873
Commit: a165692627cfdcda264aed0dc2f1fd85214f2d43
Parents: 05ca971
Author: Igor Bondarenko <je...@gmail.com>
Authored: Sat May 30 13:45:37 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:34 2015 -0400

----------------------------------------------------------------------
 Dockerfile | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/a1656926/Dockerfile
----------------------------------------------------------------------
diff --git a/Dockerfile b/Dockerfile
index e054b6f..916ed33 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -35,4 +35,8 @@ RUN apt-get update && apt-get install -y \
 RUN locale-gen en_US.UTF-8
 ENV LANG en_US.UTF-8
 
+# GitPython uses this to determine current user when committing (used in
+# tests). If this is not set, it uses os.getlogin, which fails inside docker.
+ENV USER root
+
 WORKDIR /allura


[07/46] allura git commit: [#7892] script to disable users in batch

Posted by he...@apache.org.
[#7892] script to disable users in batch


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

Branch: refs/heads/hs/7873
Commit: 66c8d485f821fc6be3f16bffa5faa2d4d74c6023
Parents: cc37f7e
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Jun 8 16:43:47 2015 +0000
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Tue Jun 9 15:34:51 2015 +0000

----------------------------------------------------------------------
 Allura/allura/scripts/disable_users.py | 67 +++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/66c8d485/Allura/allura/scripts/disable_users.py
----------------------------------------------------------------------
diff --git a/Allura/allura/scripts/disable_users.py b/Allura/allura/scripts/disable_users.py
new file mode 100644
index 0000000..9ce1a1b
--- /dev/null
+++ b/Allura/allura/scripts/disable_users.py
@@ -0,0 +1,67 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+import argparse
+import logging
+import sys
+
+from ming.odm import session
+
+from allura.lib.plugin import AuthenticationProvider
+from allura.scripts import ScriptTask
+from allura import model as M
+
+
+log = logging.getLogger(__name__)
+
+
+class DisableUsers(ScriptTask):
+
+    @classmethod
+    def execute(cls, options):
+        if options.usernames == ['-']:
+            usernames = [line.strip() for line in sys.stdin]
+        else:
+            usernames = options.usernames
+        cls.disable_users(usernames)
+
+    @classmethod
+    def disable_users(cls, usernames):
+        auth_provider = AuthenticationProvider.get(request=None)
+
+        # would be nice to use the BatchIndexer extension around this but that only works for artifacts not users
+
+        for username in usernames:
+            user = M.User.query.get(username=username)
+            if not user:
+                log.info('Could not find user: %s', username)
+            else:
+                log.info('Disabling user: %s', username)
+                auth_provider.disable_user(user)
+                session(user).flush(user)
+
+    @classmethod
+    def parser(cls):
+        parser = argparse.ArgumentParser(description='Disable listed users')
+        parser.add_argument(
+            '--usernames', dest='usernames', type=str, nargs='+', metavar='<username>', required=True,
+            help='List of usernames, or "-" to read from stdin')
+        return parser
+
+
+if __name__ == '__main__':
+    DisableUsers.main()


[36/46] allura git commit: [#7886] ticket:789 Factor out rate_limit into general helper

Posted by he...@apache.org.
[#7886] ticket:789 Factor out rate_limit into general helper


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

Branch: refs/heads/hs/7873
Commit: be93d3d31a75d174e13953a7d7f620d1e53006db
Parents: 51fc93b
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Jun 10 06:42:09 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jun 12 18:44:25 2015 +0000

----------------------------------------------------------------------
 Allura/allura/lib/exceptions.py |  6 +++++-
 Allura/allura/lib/helpers.py    | 17 +++++++++++++++++
 Allura/allura/lib/plugin.py     | 18 ++++++------------
 3 files changed, 28 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/be93d3d3/Allura/allura/lib/exceptions.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/exceptions.py b/Allura/allura/lib/exceptions.py
index f796d99..21dd1d2 100644
--- a/Allura/allura/lib/exceptions.py
+++ b/Allura/allura/lib/exceptions.py
@@ -39,7 +39,11 @@ class ProjectOverlimitError(ForgeError):
     pass
 
 
-class ProjectRatelimitError(ForgeError):
+class RatelimitError(ForgeError):
+    pass
+
+
+class ProjectRatelimitError(RatelimitError):
     pass
 
 

http://git-wip-us.apache.org/repos/asf/allura/blob/be93d3d3/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 396d7d6..1c562f0 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -1226,3 +1226,20 @@ def get_user_status(user):
         return 'disabled'
     elif pending:
         return 'pending'
+
+
+def rate_limit(cfg_opt, artifact_count, start_date, exception=None):
+    """
+    Check the various config-defined artifact creation rate limits, and if any
+    are exceeded, raise exception.
+    """
+    if exception is None:
+        exception = exc.RatelimitError
+    rate_limits = json.loads(tg.config.get(cfg_opt, '{}'))
+    now = datetime.utcnow()
+    for rate, count in rate_limits.items():
+        age = now - start_date
+        age = (age.microseconds +
+                (age.seconds + age.days * 24 * 3600) * 10 ** 6) / 10 ** 6
+        if age < int(rate) and artifact_count >= count:
+            raise exception()

http://git-wip-us.apache.org/repos/asf/allura/blob/be93d3d3/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 860292f..d66704e 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -44,7 +44,6 @@ import tg
 from tg import config, request, redirect, response
 from pylons import tmpl_context as c, app_globals as g
 from webob import exc
-from bson.tz_util import FixedOffset
 from paste.deploy.converters import asbool, asint
 
 from ming.utils import LazyProperty
@@ -696,18 +695,13 @@ class ProjectRegistrationProvider(object):
         """
         if security.has_access(neighborhood, 'admin', user=user)():
             return
-        # have to have the replace because, despite being UTC,
-        # the result from utcnow() is still offset-naive  :-(
-        # maybe look into making the mongo connection offset-naive?
-        now = datetime.utcnow().replace(tzinfo=FixedOffset(0, 'UTC'))
+        opt = 'project.rate_limits'
         project_count = len(list(user.my_projects()))
-        rate_limits = json.loads(config.get('project.rate_limits', '{}'))
-        for rate, count in rate_limits.items():
-            user_age = now - user._id.generation_time
-            user_age = (user_age.microseconds +
-                        (user_age.seconds + user_age.days * 24 * 3600) * 10 ** 6) / 10 ** 6
-            if user_age < int(rate) and project_count >= count:
-                raise forge_exc.ProjectRatelimitError()
+        # have to have the replace because, the generation_time is offset-aware
+        # UTC and h.rate_limit uses offset-naive UTC dates
+        start_date = user._id.generation_time.replace(tzinfo=None)
+        e = forge_exc.ProjectRatelimitError
+        h.rate_limit(opt, project_count, start_date, exception=e)
 
     def phone_verified(self, user, neighborhood):
         """


[02/46] allura git commit: [#7893] stop CSRF login requests; add tests for CSRF

Posted by he...@apache.org.
[#7893] stop CSRF login requests; add tests for CSRF


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

Branch: refs/heads/hs/7873
Commit: 10e1f51e1cd3c1ca31ea65a4ab0e1074a9ff92b7
Parents: 3ed25d5
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Jun 8 20:31:39 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Jun 8 22:05:59 2015 +0000

----------------------------------------------------------------------
 Allura/allura/lib/custom_middleware.py        | 15 +++++++++-
 Allura/allura/lib/widgets/forms.py            |  2 +-
 Allura/allura/templates/jinja_master/lib.html |  2 +-
 Allura/allura/tests/functional/test_auth.py   | 34 ++++++++++++++++++++++
 4 files changed, 50 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/10e1f51e/Allura/allura/lib/custom_middleware.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/custom_middleware.py b/Allura/allura/lib/custom_middleware.py
index 8212cd2..13c3db5 100644
--- a/Allura/allura/lib/custom_middleware.py
+++ b/Allura/allura/lib/custom_middleware.py
@@ -129,6 +129,8 @@ class CSRFMiddleware(object):
 
     def __call__(self, environ, start_response):
         req = Request(environ)
+
+        # enforce POSTs
         cookie = req.cookies.get(self._cookie_name, None)
         if cookie is None:
             cookie = h.cryptographic_nonce()
@@ -136,7 +138,17 @@ class CSRFMiddleware(object):
             param = req.str_POST.pop(self._param_name, None)
             if cookie != param:
                 log.warning('CSRF attempt detected, %r != %r', cookie, param)
-                environ.pop('HTTP_COOKIE', None)
+                environ.pop('HTTP_COOKIE', None)  # effectively kill the existing session
+                if req.path.startswith('/auth/'):
+                    # for operations where you're not logged in yet (e.g. login form, pwd recovery, etc), then killing
+                    # the session doesn't help, so we block the request entirely
+                    resp = exc.HTTPForbidden()
+                    return resp(environ, start_response)
+
+        # Set cookie for use in later forms:
+
+        # in addition to setting a cookie, set this so its available on first response before cookie gets created in browser
+        environ[self._cookie_name] = cookie
 
         def session_start_response(status, headers, exc_info=None):
             if dict(headers).get('Content-Type', '').startswith('text/html'):
@@ -144,6 +156,7 @@ class CSRFMiddleware(object):
                     ('Set-cookie',
                      str('%s=%s; Path=/' % (self._cookie_name, cookie))))
             return start_response(status, headers, exc_info)
+
         return self._app(environ, session_start_response)
 
 

http://git-wip-us.apache.org/repos/asf/allura/blob/10e1f51e/Allura/allura/lib/widgets/forms.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/forms.py b/Allura/allura/lib/widgets/forms.py
index 0cf8c18..714a32b 100644
--- a/Allura/allura/lib/widgets/forms.py
+++ b/Allura/allura/lib/widgets/forms.py
@@ -1090,7 +1090,7 @@ class CsrfForm(ew.SimpleForm):
     def context_for(self, field):
         ctx = super(CsrfForm, self).context_for(field)
         if field.name == '_session_id':
-            ctx['value'] = tg.request.cookies.get('_session_id')
+            ctx['value'] = tg.request.cookies.get('_session_id') or tg.request.environ['_session_id']
         return ctx
 
 

http://git-wip-us.apache.org/repos/asf/allura/blob/10e1f51e/Allura/allura/templates/jinja_master/lib.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/lib.html b/Allura/allura/templates/jinja_master/lib.html
index 78ab9c0..75acb9e 100644
--- a/Allura/allura/templates/jinja_master/lib.html
+++ b/Allura/allura/templates/jinja_master/lib.html
@@ -19,7 +19,7 @@
 
 {% macro csrf() -%}
   {% if request -%}
-    {{request.cookies['_session_id']}}
+    {{ request.cookies['_session_id'] or request.environ['_session_id'] }}
   {%- endif %}
 {%- endmacro %}
 

http://git-wip-us.apache.org/repos/asf/allura/blob/10e1f51e/Allura/allura/tests/functional/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_auth.py b/Allura/allura/tests/functional/test_auth.py
index 0f9a8ee..20ceda3 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -1792,3 +1792,37 @@ class TestPasswordExpire(TestController):
             f['return_to'] = return_to
             r = f.submit(extra_environ={'username': 'test-user'}, status=302)
             assert_equal(r.location, 'http://localhost/p/test/tickets/?milestone=1.0&page=2')
+
+
+class TestCSRFProtection(TestController):
+
+    def test_blocks_invalid(self):
+        # so test-admin isn't automatically logged in for all requests
+        self.app.extra_environ = {'disable_auth_magic': 'True'}
+
+        # regular login
+        r = self.app.get('/auth/')
+        r.form['username'] = 'test-admin'
+        r.form['password'] = 'foo'
+        r.form.submit()
+
+        # regular form submit
+        r = self.app.get('/admin/overview')
+        r = r.form.submit()
+        assert_equal(r.location, 'http://localhost/admin/overview')
+
+        # invalid form submit
+        r = self.app.get('/admin/overview')
+        r.form['_session_id'] = 'bogus'
+        r = r.form.submit()
+        assert_equal(r.location, 'http://localhost/auth/')
+
+    def test_blocks_invalid_on_login(self):
+        r = self.app.get('/auth/')
+        r.form['_session_id'] = 'bogus'
+        r.form.submit(status=403)
+
+    def test_token_present_on_first_request(self):
+        r = self.app.get('/auth/')
+        assert_true(r.form['_session_id'].value)
+


[24/46] allura git commit: [#7806] ticket:773 Add solr container

Posted by he...@apache.org.
[#7806] ticket:773 Add solr container


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

Branch: refs/heads/hs/7873
Commit: 03296bffe61737e166a9555fc7d725e50b41f076
Parents: 5e297da
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu May 21 19:18:41 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:31 2015 -0400

----------------------------------------------------------------------
 Allura/docker-dev.ini  |  2 +-
 docker-compose.yml     | 11 +++++++++++
 solr_config/Dockerfile | 15 +++++++++++++++
 3 files changed, 27 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/03296bff/Allura/docker-dev.ini
----------------------------------------------------------------------
diff --git a/Allura/docker-dev.ini b/Allura/docker-dev.ini
index f33f264..34cb040 100644
--- a/Allura/docker-dev.ini
+++ b/Allura/docker-dev.ini
@@ -37,7 +37,7 @@ scm.host.rw.hg = /allura-data/scm/srv/hg$path
 scm.host.ro.svn = file:///allura-data/scm/svn$path/
 scm.host.rw.svn = file:///allura-data/scm/svn$path/
 
-;solr.server = http://solr:8983/solr
+solr.server = http://solr:8983/solr
 
 ;forgemail.host = smtp
 ;forgemail.port = 8825

http://git-wip-us.apache.org/repos/asf/allura/blob/03296bff/docker-compose.yml
----------------------------------------------------------------------
diff --git a/docker-compose.yml b/docker-compose.yml
index 853c0de..38b3764 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -12,6 +12,7 @@ web:
     - /allura-data/scm/svn:/allura-data/scm/svn
   links:
     - mongo
+    - solr
 
 taskd:
   image: allura_web
@@ -24,6 +25,16 @@ taskd:
     - /allura-data/scm/svn:/allura-data/scm/svn
   links:
     - mongo
+    - solr
+
+solr:
+  build: solr_config
+  working_dir: /solr/solr-4.2.1/example
+  command: java -jar start.jar
+  ports:
+    - "8983:8983"
+  volumes:
+    - /allura-data/solr:/solr/solr-4.2.1/example/solr/collection1/data
 
 mongo:
   image: mongo:2.6

http://git-wip-us.apache.org/repos/asf/allura/blob/03296bff/solr_config/Dockerfile
----------------------------------------------------------------------
diff --git a/solr_config/Dockerfile b/solr_config/Dockerfile
new file mode 100644
index 0000000..27876e5
--- /dev/null
+++ b/solr_config/Dockerfile
@@ -0,0 +1,15 @@
+FROM ubuntu:12.04
+
+RUN apt-get update && apt-get install -y \
+    default-jre-headless \
+    wget \
+    tar
+
+ENV basedir /solr
+
+ADD . ${basedir}
+WORKDIR ${basedir}
+
+RUN wget -nv http://archive.apache.org/dist/lucene/solr/4.2.1/solr-4.2.1.tgz
+RUN tar xf solr-4.2.1.tgz && rm -f solr-4.2.1.tgz
+RUN cp -f schema.xml solr-4.2.1/example/solr/collection1/conf


[35/46] allura git commit: [#7886] ticket:789 Rate limit ticket creation

Posted by he...@apache.org.
[#7886] ticket:789 Rate limit ticket creation


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

Branch: refs/heads/hs/7873
Commit: 1004b07892ca6dafb9a19d963fb880f7d3a3cd93
Parents: d22046c
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Jun 10 08:41:17 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jun 12 18:44:25 2015 +0000

----------------------------------------------------------------------
 Allura/allura/lib/exceptions.py                 |  7 +++
 .../forgetracker/tests/functional/test_rest.py  | 25 +++++++--
 .../forgetracker/tests/functional/test_root.py  | 55 +++++++++++++++++++-
 ForgeTracker/forgetracker/tracker_main.py       | 14 +++++
 4 files changed, 95 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/1004b078/Allura/allura/lib/exceptions.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/exceptions.py b/Allura/allura/lib/exceptions.py
index 21dd1d2..45843bf 100644
--- a/Allura/allura/lib/exceptions.py
+++ b/Allura/allura/lib/exceptions.py
@@ -15,6 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+import webob
 from formencode import Invalid
 
 
@@ -99,3 +100,9 @@ class CompoundError(ForgeError):
                 parts.append('    ' + line)
         parts.append('</%s>\n' % self.__class__.__name__)
         return ''.join(parts)
+
+
+class HTTPTooManyRequests(webob.exc.HTTPClientError):
+    code = 429
+    title = 'Too Many Requests'
+    explanation = 'Too Many Requests'

http://git-wip-us.apache.org/repos/asf/allura/blob/1004b078/ForgeTracker/forgetracker/tests/functional/test_rest.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_rest.py b/ForgeTracker/forgetracker/tests/functional/test_rest.py
index 0932435..7d8d91a 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_rest.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_rest.py
@@ -18,7 +18,9 @@
 from pylons import tmpl_context as c
 
 from datadiff.tools import assert_equal
+from nose.tools import assert_not_equal
 from mock import patch
+from tg import config
 
 from allura.lib import helpers as h
 from allura.tests import decorators as td
@@ -41,18 +43,18 @@ class TestTrackerApiBase(TestRestApiBase):
         h.set_context('test', 'bugs', neighborhood='Projects')
         self.tracker_globals = c.app.globals
 
-    def create_ticket(self):
+    def create_ticket(self, summary=None, status=None):
         return self.api_post(
             '/rest/p/test/bugs/new',
             wrap_args='ticket_form',
             params=dict(
-                summary='test new ticket',
+                summary=summary or 'test new ticket',
                 status=self.tracker_globals.open_status_names.split()[0],
                 labels='',
                 description='',
                 assigned_to='',
-                **{'custom_fields._milestone': ''})
-        )
+                **{'custom_fields._milestone': ''}),
+            status=status)
 
 
 class TestRestNewTicket(TestTrackerApiBase):
@@ -81,6 +83,21 @@ class TestRestNewTicket(TestTrackerApiBase):
     def test_invalid_ticket(self):
         self.app.get('/rest/p/test/bugs/2', status=404)
 
+    def test_create_limit(self):
+        self.create_ticket(summary='First ticket')
+        # Set rate limit to unlimit
+        with h.push_config(config, **{'forgetracker.rate_limits': '{}'}):
+            summary = 'Second ticket'
+            self.create_ticket(summary=summary)
+            t = TM.Ticket.query.get(summary=summary)
+            assert_not_equal(t, None)
+        # Set rate limit to 1 in first hour of project
+        with h.push_config(config, **{'forgetracker.rate_limits': '{"3600": 1}'}):
+            summary = 'Third ticket'
+            self.create_ticket(summary=summary, status=429)
+            t = TM.Ticket.query.get(summary=summary)
+            assert_equal(t, None)
+
 
 class TestRestUpdateTicket(TestTrackerApiBase):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/1004b078/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 7f67b3a..122d707 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -28,11 +28,20 @@ import mock
 
 import PIL
 from mock import patch
-from nose.tools import assert_true, assert_false, assert_equal, assert_in
-from nose.tools import assert_raises, assert_not_in, assert_items_equal
+from nose.tools import (
+    assert_true,
+    assert_false,
+    assert_equal,
+    assert_in,
+    assert_raises,
+    assert_not_in,
+    assert_items_equal,
+    assert_not_equal,
+)
 from formencode.variabledecode import variable_encode
 from pylons import tmpl_context as c
 from pylons import app_globals as g
+from tg import config
 
 from alluratest.controller import TestController, setup_basic_test
 from allura import model as M
@@ -2363,6 +2372,48 @@ class TestFunctionalController(TrackerTestController):
         assert query_filter_choices.call_count == 1
         assert query_filter_choices.call_args[0][0] == '!status_s:wont-fix && !status_s:closed'
 
+    def test_rate_limit_new(self):
+        self.new_ticket(summary='First ticket')
+        # Set rate limit to unlimit
+        with h.push_config(config, **{'forgetracker.rate_limits': '{}'}):
+            r = self.app.get('/bugs/new/')
+            assert_equal(r.status_int, 200)
+        # Set rate limit to 1 in first hour of project
+        with h.push_config(config, **{'forgetracker.rate_limits': '{"3600": 1}'}):
+            r = self.app.get('/bugs/new/')
+            assert_equal(r.status_int, 302)
+            assert_equal(r.location, 'http://localhost/bugs/')
+            wf = json.loads(self.webflash(r))
+            assert_equal(wf['status'], 'error')
+            assert_equal(
+                wf['message'],
+                'Ticket creation rate limit exceeded. Please try again later.')
+
+    def test_rate_limit_save_ticket(self):
+        # Set rate limit to unlimit
+        with h.push_config(config, **{'forgetracker.rate_limits': '{}'}):
+            summary = 'Ticket w/o limit'
+            post_data = {'ticket_form.summary': summary}
+            r = self.app.post('/bugs/save_ticket', post_data).follow()
+            assert_in(summary, r)
+            t = tm.Ticket.query.get(summary=summary)
+            assert_not_equal(t, None)
+        # Set rate limit to 1 in first hour of project
+        with h.push_config(config, **{'forgetracker.rate_limits': '{"3600": 1}'}):
+            summary = 'Ticket with limit'
+            post_data = {'ticket_form.summary': summary}
+            r = self.app.post('/bugs/save_ticket', post_data)
+            assert_equal(r.status_int, 302)
+            assert_equal(r.location, 'http://localhost/bugs/')
+            wf = json.loads(self.webflash(r))
+            assert_equal(wf['status'], 'error')
+            assert_equal(
+                wf['message'],
+                'Ticket creation rate limit exceeded. Please try again later.')
+            assert_not_in(summary, r.follow())
+            t = tm.Ticket.query.get(summary=summary)
+            assert_equal(t, None)
+
 
 class TestMilestoneAdmin(TrackerTestController):
     def _post(self, params, **kw):

http://git-wip-us.apache.org/repos/asf/allura/blob/1004b078/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index e69e349..68b1a0c 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -57,6 +57,7 @@ from allura.lib import validators as V
 from allura.lib.widgets import form_fields as ffw
 from allura.lib.widgets.subscriptions import SubscribeForm
 from allura.lib.plugin import ImportIdConverter
+from allura.lib import exceptions as forge_exc
 from allura.controllers import AppDiscussionController, AppDiscussionRestController
 from allura.controllers import attachments as att
 from allura.controllers import BaseController
@@ -630,6 +631,13 @@ class RootController(BaseController, FeedController):
     def _check_security(self):
         require_access(c.app, 'read')
 
+    def rate_limit(self, redir='..'):
+        if TM.Ticket.is_limit_exceeded(c.app.config):
+            msg = 'Ticket creation rate limit exceeded. '
+            log.warn(msg + c.app.config.url())
+            flash(msg + 'Please try again later.', 'error')
+            redirect(redir)
+
     @expose('json:')
     def bin_counts(self, *args, **kw):
         bin_counts = []
@@ -865,6 +873,7 @@ class RootController(BaseController, FeedController):
     @expose('jinja:forgetracker:templates/tracker/new_ticket.html')
     def new(self, description=None, summary=None, labels=None, **kw):
         require_access(c.app, 'create')
+        self.rate_limit(redir='..')
         c.ticket_form = W.ticket_form
         help_msg = c.app.config.options.get('TicketHelpNew', '').strip()
         return dict(action=c.app.config.url() + 'save_ticket',
@@ -901,6 +910,7 @@ class RootController(BaseController, FeedController):
             require_access(ticket, 'update')
         else:
             require_access(c.app, 'create')
+            self.rate_limit(redir='.')
             ticket = TM.Ticket.new()
         ticket.update(ticket_form)
         c.app.globals.invalidate_bin_counts()
@@ -1786,6 +1796,10 @@ class RootRestController(BaseController, AppRestControllerMixin):
     @validate(W.ticket_form, error_handler=h.json_validation_error)
     def new(self, ticket_form=None, **post_data):
         require_access(c.app, 'create')
+        if TM.Ticket.is_limit_exceeded(c.app.config):
+            msg = 'Ticket creation rate limit exceeded. '
+            log.warn(msg + c.app.config.url())
+            raise forge_exc.HTTPTooManyRequests()
         if c.app.globals.milestone_names is None:
             c.app.globals.milestone_names = ''
         ticket = TM.Ticket.new()


[17/46] allura git commit: Add SMS charges disclaimer to phone help text

Posted by he...@apache.org.
Add SMS charges disclaimer to phone help text


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

Branch: refs/heads/hs/7873
Commit: 69dd7f89ac7f7d1c5852ae9b6ec40d6bcfb59d79
Parents: a31af67
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu Jun 11 21:35:55 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Jun 11 21:35:55 2015 +0000

----------------------------------------------------------------------
 Allura/allura/templates/phone_verification_fragment.html | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/69dd7f89/Allura/allura/templates/phone_verification_fragment.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/phone_verification_fragment.html b/Allura/allura/templates/phone_verification_fragment.html
index 1c61db4..fad9acd 100644
--- a/Allura/allura/templates/phone_verification_fragment.html
+++ b/Allura/allura/templates/phone_verification_fragment.html
@@ -63,6 +63,7 @@
               below (e.g. 1-311-555-2368 or +61 8 5550 1757). You'll receive
               an SMS message with a PIN you need to provide on the next step.
               Your phone number will only be recorded by our SMS provider.
+              Standard SMS rates may apply.
             </p>
             {% endblock phone_validation_message_number %}
           </div>


[33/46] allura git commit: [#7806] reference Docker instead of Vagrant

Posted by he...@apache.org.
[#7806] reference Docker instead of Vagrant


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

Branch: refs/heads/hs/7873
Commit: b2a1b10d574a1dd107fa76226f46840fbdfae08b
Parents: e7f1995
Author: Dave Brondsema <da...@brondsema.net>
Authored: Fri Jun 12 11:43:04 2015 -0400
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:37 2015 -0400

----------------------------------------------------------------------
 INSTALL.markdown | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/b2a1b10d/INSTALL.markdown
----------------------------------------------------------------------
diff --git a/INSTALL.markdown b/INSTALL.markdown
index 220d11f..d9a64ee 100644
--- a/INSTALL.markdown
+++ b/INSTALL.markdown
@@ -17,9 +17,9 @@
     under the License.
 -->
 
-# Sandbox Creation
+# Step-by-Step Installation
 
-For a faster setup with a pre-packaged machine image, see [Install and Run Allura - Vagrant](https://forge-allura.apache.org/p/allura/wiki/Install%20and%20Run%20Allura%20-%20Vagrant/) instead.
+For a simpler setup using Docker images, see INSTALL-Docker.markdown instead.
 
 In these instructions, we'll use [VirtualBox](http://www.virtualbox.org) and [Ubuntu 12.04](http://ubuntu.com) (11.10 works too) to create a disposable sandbox for Allura development/testing.  Allura should work on other Linux systems (including OSX), but setting up all the dependencies will be different.
 


[16/46] allura git commit: Update phone help text to reflect that SMS provider does store the phone number

Posted by he...@apache.org.
Update phone help text to reflect that SMS provider does store the phone number


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

Branch: refs/heads/hs/7873
Commit: a31af679a99b4d6c959d7b22f06ec44419dbf8c6
Parents: 672649f
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Wed Jun 10 15:35:20 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed Jun 10 15:35:20 2015 +0000

----------------------------------------------------------------------
 Allura/allura/templates/phone_verification_fragment.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/a31af679/Allura/allura/templates/phone_verification_fragment.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/phone_verification_fragment.html b/Allura/allura/templates/phone_verification_fragment.html
index 561b0df..1c61db4 100644
--- a/Allura/allura/templates/phone_verification_fragment.html
+++ b/Allura/allura/templates/phone_verification_fragment.html
@@ -62,7 +62,7 @@
               validation (just this once).  Please, enter your phone number
               below (e.g. 1-311-555-2368 or +61 8 5550 1757). You'll receive
               an SMS message with a PIN you need to provide on the next step.
-              Your phone number will not be stored.
+              Your phone number will only be recorded by our SMS provider.
             </p>
             {% endblock phone_validation_message_number %}
           </div>


[11/46] allura git commit: [#6057] ticket:792 Allow ConfigOption to specify help text

Posted by he...@apache.org.
[#6057] ticket:792 Allow ConfigOption to specify help text


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

Branch: refs/heads/hs/7873
Commit: 3090de782e6e901cf8063977fbe86574dcb01176
Parents: bc3c028
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Jun 9 14:01:56 2015 +0000
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Tue Jun 9 21:06:06 2015 +0000

----------------------------------------------------------------------
 Allura/allura/app.py                                      | 9 +++++----
 Allura/allura/templates/app_admin_options.html            | 3 +++
 Allura/allura/templates/app_admin_options_on_install.html | 5 ++++-
 ForgeLink/forgelink/link_main.py                          | 2 ++
 4 files changed, 14 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/3090de78/Allura/allura/app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index 2683e36..62b82fe 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -57,12 +57,13 @@ class ConfigOption(object):
 
     """
 
-    def __init__(self, name, ming_type, default, label=None, validator=None, extra_attrs=None):
-        """Create a new ConfigOption.
-
-        """
+    def __init__(self, name, ming_type, default,
+                 label=None, help_text=None, validator=None,
+                 extra_attrs=None):
+        """Create a new ConfigOption."""
         self.name, self.ming_type, self._default, self.label = (
             name, ming_type, default, label or name)
+        self.help_text = help_text
         self.validator = validator
         self.extra_attrs = extra_attrs
 

http://git-wip-us.apache.org/repos/asf/allura/blob/3090de78/Allura/allura/templates/app_admin_options.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/app_admin_options.html b/Allura/allura/templates/app_admin_options.html
index bf013c4..d818a56 100644
--- a/Allura/allura/templates/app_admin_options.html
+++ b/Allura/allura/templates/app_admin_options.html
@@ -30,6 +30,9 @@
         {% else %}
             <input {{o.render_attrs()}} id="{{o.name}}" name="{{o.name}}" value="{{app.config.options.get(o.name, o.default)}}">
         {% endif %}
+        {% if o.help_text %}
+          <div class="grid-9"><small>{{o.help_text}}</small></div>
+        {% endif %}
       {% endif %}
     </div>
   {% else %}

http://git-wip-us.apache.org/repos/asf/allura/blob/3090de78/Allura/allura/templates/app_admin_options_on_install.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/app_admin_options_on_install.html b/Allura/allura/templates/app_admin_options_on_install.html
index 218dd61..16b62b6 100644
--- a/Allura/allura/templates/app_admin_options_on_install.html
+++ b/Allura/allura/templates/app_admin_options_on_install.html
@@ -17,7 +17,7 @@
        under the License.
 -#}
 {% for o in options %}
-  <label class="grid-13" for="{{o.name}}">{{o.label|capitalize}}</label>
+  <label class="grid-13" for="{{o.name}}">{{o.label}}</label>
   <div class="grid-13">
     {% if o.ming_type.__name__ == 'bool' %}
       <input {{o.render_attrs()}}id="{{o.name}}" name="{{o.name}}" type="checkbox"{{ ' checked="checked"' if o.default}}>
@@ -25,4 +25,7 @@
       <input {{o.render_attrs()}} id="{{o.name}}" name="{{o.name}}" value="{{o.default or ''}}">
     {% endif %}
   </div>
+  {% if o.help_text %}
+    <div class="grid-13"><small>{{o.help_text}}</small></div>
+  {% endif %}
 {% endfor %}

http://git-wip-us.apache.org/repos/asf/allura/blob/3090de78/ForgeLink/forgelink/link_main.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/link_main.py b/ForgeLink/forgelink/link_main.py
index ec32974..735816d 100644
--- a/ForgeLink/forgelink/link_main.py
+++ b/ForgeLink/forgelink/link_main.py
@@ -51,6 +51,8 @@ class ForgeLinkApp(Application):
     config_options = Application.config_options + [
         ConfigOption(
             'url', str, None,
+            label='External Url',
+            help_text='URL to which you wish to link',
             validator=fev.URL(not_empty=True, add_http=True),
             extra_attrs={'type': 'url'}),
     ]


[38/46] allura git commit: [#7886] ticket:789 Rate limit wiki page creation

Posted by he...@apache.org.
[#7886] ticket:789 Rate limit wiki page creation


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

Branch: refs/heads/hs/7873
Commit: 6936ce2df44b2b55f3940c600a023c26c2445150
Parents: 1004b07
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Jun 10 09:36:02 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jun 12 18:44:26 2015 +0000

----------------------------------------------------------------------
 .../forgewiki/tests/functional/test_rest.py     | 20 +++++++-
 .../forgewiki/tests/functional/test_root.py     | 48 +++++++++++++++++++-
 ForgeWiki/forgewiki/wiki_main.py                | 13 ++++++
 3 files changed, 79 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/6936ce2d/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 23021d2..6a5de3b 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_rest.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_rest.py
@@ -19,7 +19,7 @@
 
 import json
 
-from nose.tools import assert_equal, assert_in
+from nose.tools import assert_equal, assert_in, assert_not_equal
 import simplejson
 import tg
 
@@ -27,6 +27,8 @@ from allura.lib import helpers as h
 from allura.tests import decorators as td
 from alluratest.controller import TestRestApiBase
 
+from forgewiki.model import Page
+
 
 class TestWikiApi(TestRestApiBase):
 
@@ -84,6 +86,22 @@ class TestWikiApi(TestRestApiBase):
         assert_equal(r.json['text'], data['text'])
         assert_equal(r.json['labels'], data['labels'].split(','))
 
+    def test_create_page_limit(self):
+        data = {
+            'text': 'Embrace the Dark Side',
+            'labels': 'head hunting,dark side'
+        }
+        # Set rate limit to unlimit
+        with h.push_config(tg.config, **{'forgewiki.rate_limits': '{}'}):
+            r = self.api_post(u'/rest/p/test/wiki/page1/', status=200, **data)
+            p = Page.query.get(title='page1')
+            assert_not_equal(p, None)
+        # Set rate limit to 1 in first hour of project
+        with h.push_config(tg.config, **{'forgewiki.rate_limits': '{"3600": 1}'}):
+            r = self.api_post(u'/rest/p/test/wiki/page2/', status=429, **data)
+            p = Page.query.get(title='page2')
+            assert_equal(p, None)
+
     # http://blog.watchfire.com/wfblog/2011/10/json-based-xss-exploitation.html
     def test_json_encoding_security(self):
         self.api_post('/rest/p/test/wiki/foo.html',

http://git-wip-us.apache.org/repos/asf/allura/blob/6936ce2d/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 f5f49e6..aea9028 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_root.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_root.py
@@ -20,11 +20,13 @@
 import os
 import StringIO
 import allura
+import json
 
 import PIL
-from nose.tools import assert_true, assert_equal, assert_in
+from nose.tools import assert_true, assert_equal, assert_in, assert_not_equal
 from ming.orm.ormsession import ThreadLocalORMSession
 from mock import patch
+from tg import config
 
 from allura import model as M
 from allura.lib import helpers as h
@@ -770,3 +772,47 @@ class TestRootController(TestController):
         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
+
+    def test_rate_limit_new_page(self):
+        # Set rate limit to unlimit
+        with h.push_config(config, **{'forgewiki.rate_limits': '{}'}):
+            r = self.app.get('/p/test/wiki/new-page-title/')
+            assert_equal(r.status_int, 302)
+            assert_equal(
+                r.location,
+                'http://localhost/p/test/wiki/new-page-title/edit')
+            assert_equal(self.webflash(r), '')
+        # Set rate limit to 1 in first hour of project
+        with h.push_config(config, **{'forgewiki.rate_limits': '{"3600": 1}'}):
+            r = self.app.get('/p/test/wiki/new-page-title/')
+            assert_equal(r.status_int, 302)
+            assert_equal(r.location, 'http://localhost/p/test/wiki/')
+            wf = json.loads(self.webflash(r))
+            assert_equal(wf['status'], 'error')
+            assert_equal(
+                wf['message'],
+                'Page creation rate limit exceeded. Please try again later.')
+
+    def test_rate_limit_update(self):
+        # Set rate limit to unlimit
+        with h.push_config(config, **{'forgewiki.rate_limits': '{}'}):
+            r = self.app.post(
+                '/p/test/wiki/page1/update',
+                dict(text='Some text', title='page1')).follow()
+            assert_in('Some text', r)
+            p = model.Page.query.get(title='page1')
+            assert_not_equal(p, None)
+        # Set rate limit to 1 in first hour of project
+        with h.push_config(config, **{'forgewiki.rate_limits': '{"3600": 1}'}):
+            r = self.app.post(
+                '/p/test/wiki/page2/update',
+                dict(text='Some text', title='page2'))
+            assert_equal(r.status_int, 302)
+            assert_equal(r.location, 'http://localhost/p/test/wiki/')
+            wf = json.loads(self.webflash(r))
+            assert_equal(wf['status'], 'error')
+            assert_equal(
+                wf['message'],
+                'Page creation rate limit exceeded. Please try again later.')
+            p = model.Page.query.get(title='page2')
+            assert_equal(p, None)

http://git-wip-us.apache.org/repos/asf/allura/blob/6936ce2d/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index 8ab3f3d..cfaec31 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -37,6 +37,7 @@ from allura.app import Application, SitemapEntry, DefaultAdminController, Config
 from allura.lib.search import search_app
 from allura.lib.decorators import require_post
 from allura.lib.security import require_access, has_access
+from allura.lib import exceptions as forge_exc
 from allura.controllers import AppDiscussionController, BaseController, AppDiscussionRestController
 from allura.controllers import DispatchIndex
 from allura.controllers import attachments as ac
@@ -489,6 +490,14 @@ class PageController(BaseController, FeedController):
                 require_access(self.page, 'delete')
         else:
             require_access(c.app, 'create')
+            self.rate_limit()
+
+    def rate_limit(self):
+        if WM.Page.is_limit_exceeded(c.app.config):
+            msg = 'Page creation rate limit exceeded. '
+            log.warn(msg + c.app.config.url())
+            flash(msg + 'Please try again later.', 'error')
+            redirect('..')
 
     def fake_page(self):
         return dict(
@@ -803,6 +812,10 @@ class PageRestController(BaseController):
         with h.notifications_disabled(c.project):
             if not self.page:
                 require_access(c.app, 'create')
+                if WM.Page.is_limit_exceeded(c.app.config):
+                    log.warn('Page creation rate limit exceeded. %s',
+                             c.app.config.url())
+                    raise forge_exc.HTTPTooManyRequests()
                 self.page = WM.Page.upsert(title)
                 self.page.viewable_by = ['all']
             else:


[42/46] allura git commit: [#7873] Added option to set cache for git references

Posted by he...@apache.org.
[#7873] Added option to set cache for git references


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

Branch: refs/heads/hs/7873
Commit: 6352e508b96246f272997b52ed7b2e49ceb1215b
Parents: 6e5d659
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Mon Jun 15 08:08:26 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Jun 15 08:26:31 2015 -0400

----------------------------------------------------------------------
 Allura/development.ini | 6 ++++++
 1 file changed, 6 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/6352e508/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 20ef1ca..284f620 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -297,6 +297,12 @@ scm.repos.tarball.zip_binary = /usr/bin/zip
 scm.import.retry_count = 50
 scm.import.retry_sleep_secs = 5
 
+; When getting a list of valid references (branches/tags) from a repo, you can cache
+; the resaults in mongo based on a threshold. Set `repo_refs_cache_threshold` (in seconds) and the resulting
+; lists will be cached and served from cache on subsequent requests until reset by `repo_refresh`.
+; Set to 0 to cache all references. Remove entirely to cache nothing.
+repo_refs_cache_threshold = .5
+
 ; One-click merge is enabled by default, but can be turned off on for each type of repo
 scm.merge.git.disabled = false
 scm.merge.hg.disabled = false


[43/46] allura git commit: [#7873] Add fields to Repository for storing reference cache

Posted by he...@apache.org.
[#7873] Add fields to Repository for storing reference cache


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

Branch: refs/heads/hs/7873
Commit: 64fd1d8a42c5671e9782c5d003ad80ae8c5bd21d
Parents: 52b6b04
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Mon Jun 15 08:14:38 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Jun 15 08:26:32 2015 -0400

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


http://git-wip-us.apache.org/repos/asf/allura/blob/64fd1d8a/Allura/allura/model/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repository.py b/Allura/allura/model/repository.py
index 022343f..a3d574c 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -349,6 +349,8 @@ class Repository(Artifact, ActivityObject):
     repo_tags = FieldProperty(S.Deprecated)
     upstream_repo = FieldProperty(dict(name=str, url=str))
     default_branch_name = FieldProperty(str)
+    cached_branches = FieldProperty([dict(name=str, object_id=str)])
+    cached_tags = FieldProperty([dict(name=str, object_id=str)])
 
     def __init__(self, **kw):
         if 'name' in kw and 'tool' in kw:


[25/46] allura git commit: [#7806] ticket:773 Make env host-mounted to share with taskd container and allow update

Posted by he...@apache.org.
[#7806] ticket:773 Make env host-mounted to share with taskd container and allow update


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

Branch: refs/heads/hs/7873
Commit: 92e7184fea115287ec33fcecc2566103cf338873
Parents: 2f4c16b
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon May 25 15:33:40 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:32 2015 -0400

----------------------------------------------------------------------
 .gitignore         |  1 +
 Dockerfile         |  8 +-------
 docker-compose.yml | 12 ++++++------
 3 files changed, 8 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/92e7184f/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index cb2f607..44b29e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,7 @@ var/
 .nose-stopwatch-times
 .noseids
 env
+env-docker
 Allura/allura/templates/home
 Allura/allura/templates/var
 Allura/production.ini

http://git-wip-us.apache.org/repos/asf/allura/blob/92e7184f/Dockerfile
----------------------------------------------------------------------
diff --git a/Dockerfile b/Dockerfile
index 1fc3181..0be1159 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -13,10 +13,4 @@ RUN apt-get update && apt-get install -y \
     subversion \
     python-svn
 
-ENV basedir /allura
-
-ADD . ${basedir}
-WORKDIR ${basedir}
-
-RUN pip install -r requirements.txt
-RUN ./rebuild-all.bash
+WORKDIR /allura

http://git-wip-us.apache.org/repos/asf/allura/blob/92e7184f/docker-compose.yml
----------------------------------------------------------------------
diff --git a/docker-compose.yml b/docker-compose.yml
index 38b3764..d0a8a3b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,11 +1,14 @@
 web:
   build: .
   working_dir: /allura
-  command: paster serve Allura/docker-dev.ini --reload
+  command: bash -c 'cd Allura && paster serve docker-dev.ini --reload'
   ports:
     - "8080:8080"
   volumes:
     - .:/allura
+    # mount env to allow update and sharing with taskd container
+    - env-docker/python:/usr/local/lib/python2.7
+    - env-docker/bin:/usr/local/bin
     # mounting it separatelly to create git, svn, hg directories automatically
     - /allura-data/scm/git:/allura-data/scm/git
     - /allura-data/scm/hg:/allura-data/scm/hg
@@ -18,11 +21,8 @@ taskd:
   image: allura_web
   working_dir: /allura/Allura
   command: paster taskd docker-dev.ini
-  volumes:
-    - .:/allura
-    - /allura-data/scm/git:/allura-data/scm/git
-    - /allura-data/scm/hg:/allura-data/scm/hg
-    - /allura-data/scm/svn:/allura-data/scm/svn
+  volumes_from:
+    - web
   links:
     - mongo
     - solr


[10/46] allura git commit: [#6057] ticket:788 Show extra options on tool installation

Posted by he...@apache.org.
[#6057] ticket:788 Show extra options on tool installation


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

Branch: refs/heads/hs/7873
Commit: 0f559d61ee7dda1c2d5aeb088de0d1b765eeedf5
Parents: 3f2f1ab
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jun 5 08:02:18 2015 +0000
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Tue Jun 9 21:06:05 2015 +0000

----------------------------------------------------------------------
 Allura/allura/app.py                            | 14 ++++++++++
 Allura/allura/ext/admin/admin_main.py           |  9 +++++++
 .../ext/admin/templates/project_tools.html      |  4 +++
 Allura/allura/public/nf/js/project_tools.js     |  5 ++++
 .../templates/app_admin_options_on_install.html | 28 ++++++++++++++++++++
 ForgeLink/forgelink/link_main.py                |  1 +
 6 files changed, 61 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/0f559d61/Allura/allura/app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index 3e226db..4d96a8f 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -220,6 +220,8 @@ class Application(object):
         /<neighborhood>/<project>/<admin>/<app>/. Default is a
         :class:`DefaultAdminController` instance.
     :cvar dict icons: Mapping of icon sizes to application-specific icon paths.
+    :cvar list config_on_install: :class:`ConfigOption` names that should be
+        configured by user during app installation
     """
 
     __version__ = None
@@ -227,6 +229,7 @@ class Application(object):
         ConfigOption('mount_point', str, 'app'),
         ConfigOption('mount_label', str, 'app'),
         ConfigOption('ordinal', int, '0')]
+    config_on_install = []
     status_map = ['production', 'beta', 'alpha', 'user']
     status = 'production'
     script_name = None
@@ -481,6 +484,17 @@ class Application(object):
             (co.name, co.default)
             for co in cls.config_options)
 
+    @classmethod
+    def options_on_install(cls):
+        """
+        Return a list of :class:`config_options <ConfigOption>` which should be
+        configured by user during app installation.
+
+        :rtype: list
+        """
+        return [o for o in cls.config_options
+                if o.name in cls.config_on_install]
+
     def install(self, project):
         'Whatever logic is required to initially set up a tool'
         # Create the discussion object

http://git-wip-us.apache.org/repos/asf/allura/blob/0f559d61/Allura/allura/ext/admin/admin_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/admin_main.py b/Allura/allura/ext/admin/admin_main.py
index b51c816..4ec1568 100644
--- a/Allura/allura/ext/admin/admin_main.py
+++ b/Allura/allura/ext/admin/admin_main.py
@@ -293,6 +293,15 @@ class ProjectAdminController(BaseController):
             flash('Invalid threshold', 'error')
         redirect('tools?limit=%s&page=%s' % (limit, page))
 
+    @expose('jinja:allura:templates/app_admin_options_on_install.html')
+    def options_on_install(self, tool_name):
+        """Renders form fields for options configuration on install"""
+        tool = [t['app'] for t in AdminApp.installable_tools_for(c.project)
+                if t['name'].lower() == tool_name.lower()]
+        if len(tool) == 1:
+            return {'options': tool[0].options_on_install()}
+        raise exc.HTTPNotFound
+
     @expose()
     @require_post()
     def update_labels(self, labels=None, **kw):

http://git-wip-us.apache.org/repos/asf/allura/blob/0f559d61/Allura/allura/ext/admin/templates/project_tools.html
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/templates/project_tools.html b/Allura/allura/ext/admin/templates/project_tools.html
index ca372ce..057af51 100644
--- a/Allura/allura/ext/admin/templates/project_tools.html
+++ b/Allura/allura/ext/admin/templates/project_tools.html
@@ -73,6 +73,9 @@
         </span>
       </small>
     </div>
+    <div class="grid-13">&nbsp;</div>
+    <div id="install_options">{# js inserts form fields here #}</div>
+    <div class="grid-13">&nbsp;</div>
     <hr>
     <div class="grid-13">&nbsp;</div>
     <div class="grid-13">
@@ -183,6 +186,7 @@
         '{{tool.name}}':{'default_label':'{{tool.app.default_mount_label}}','default_mount':'{{tool.app.default_mount_point}}'}{% if not loop.last %},{% endif %}
         {% endfor %}
     };
+    var install_options_url = "{{ c.project.url().rstrip('/') }}/admin/options_on_install";
 </script>
 <script>
 /* Real-time preview of a Url Path (aka mount point). */

http://git-wip-us.apache.org/repos/asf/allura/blob/0f559d61/Allura/allura/public/nf/js/project_tools.js
----------------------------------------------------------------------
diff --git a/Allura/allura/public/nf/js/project_tools.js b/Allura/allura/public/nf/js/project_tools.js
index 4e4ab46..b7c4e0c 100644
--- a/Allura/allura/public/nf/js/project_tools.js
+++ b/Allura/allura/public/nf/js/project_tools.js
@@ -29,6 +29,7 @@
     var new_mount_label = install_form.find('input.new_mount_label');
     var install_tool_label = $('#install_tool_label');
     var mount_point_rule_names = $('#install_form .mount-point-rule-names');
+    var install_options = $('#install_options');
     install_popup.append(install_form.show());
     $('a.install_trig').click(function () {
         var datatool = $(this).data('tool');
@@ -36,6 +37,10 @@
         install_form.find('.mount-point-name-rules').hide();
         if (datatool) {
             var tool = defaults[datatool];
+            install_options.html('Loading options...');
+            $.get(install_options_url, {tool_name: datatool}, function (data) {
+                install_options.html(data);
+            });
             install_tool_label.html(tool.default_label);
             new_ep_name.val(datatool);
             new_mount_point.val(tool.default_mount);

http://git-wip-us.apache.org/repos/asf/allura/blob/0f559d61/Allura/allura/templates/app_admin_options_on_install.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/app_admin_options_on_install.html b/Allura/allura/templates/app_admin_options_on_install.html
new file mode 100644
index 0000000..bc0d8ea
--- /dev/null
+++ b/Allura/allura/templates/app_admin_options_on_install.html
@@ -0,0 +1,28 @@
+{#-
+       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.
+-#}
+{% for o in options %}
+  <label class="grid-13" for="{{o.name}}">{{o.label|capitalize}}</label>
+  <div class="grid-13">
+    {% if o.ming_type.__name__ == 'bool' %}
+      <input id="{{o.name}}" name="{{o.name}}" type="checkbox"{{ ' checked="checked"' if o.default}}>
+    {% else %}
+      <input id="{{o.name}}" name="{{o.name}}" value="{{o.default or ''}}">
+    {% endif %}
+  </div>
+{% endfor %}

http://git-wip-us.apache.org/repos/asf/allura/blob/0f559d61/ForgeLink/forgelink/link_main.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/link_main.py b/ForgeLink/forgelink/link_main.py
index ef1c510..87fbdbb 100644
--- a/ForgeLink/forgelink/link_main.py
+++ b/ForgeLink/forgelink/link_main.py
@@ -51,6 +51,7 @@ class ForgeLinkApp(Application):
     config_options = Application.config_options + [
         ConfigOption('url', str, None)
     ]
+    config_on_install = ['url']
     searchable = True
     exportable = True
     tool_label = 'External Link'


[21/46] allura git commit: [#7806] ticket:773 taskd container

Posted by he...@apache.org.
[#7806] ticket:773 taskd container


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

Branch: refs/heads/hs/7873
Commit: 5e297da5d92f3e912a099686944ae07d15ee2569
Parents: e43ece7
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu May 21 18:38:48 2015 +0300
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jun 12 11:43:30 2015 -0400

----------------------------------------------------------------------
 docker-compose.yml | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/5e297da5/docker-compose.yml
----------------------------------------------------------------------
diff --git a/docker-compose.yml b/docker-compose.yml
index 0444ba8..853c0de 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,13 +6,25 @@ web:
     - "8080:8080"
   volumes:
     - .:/allura
-
     # mounting it separatelly to create git, svn, hg directories automatically
     - /allura-data/scm/git:/allura-data/scm/git
     - /allura-data/scm/hg:/allura-data/scm/hg
     - /allura-data/scm/svn:/allura-data/scm/svn
   links:
     - mongo
+
+taskd:
+  image: allura_web
+  working_dir: /allura/Allura
+  command: paster taskd docker-dev.ini
+  volumes:
+    - .:/allura
+    - /allura-data/scm/git:/allura-data/scm/git
+    - /allura-data/scm/hg:/allura-data/scm/hg
+    - /allura-data/scm/svn:/allura-data/scm/svn
+  links:
+    - mongo
+
 mongo:
   image: mongo:2.6
   expose: