You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by je...@apache.org on 2014/09/18 09:29:36 UTC

[01/43] git commit: [#7628] ticket:646 Fix trove update to handle duplicates

Repository: allura
Updated Branches:
  refs/heads/je/42cc_7656 d7df14a09 -> 46ec4a382 (forced update)


[#7628] ticket:646 Fix trove update to handle duplicates

It helps find each one of them.


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

Branch: refs/heads/je/42cc_7656
Commit: 862c725565937bb188cd31d09e00a998ae74a45a
Parents: e790049
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Sep 3 13:11:42 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Wed Sep 3 13:11:42 2014 +0300

----------------------------------------------------------------------
 Allura/allura/command/create_trove_categories.py | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/862c7255/Allura/allura/command/create_trove_categories.py
----------------------------------------------------------------------
diff --git a/Allura/allura/command/create_trove_categories.py b/Allura/allura/command/create_trove_categories.py
index e520214..0501f49 100644
--- a/Allura/allura/command/create_trove_categories.py
+++ b/Allura/allura/command/create_trove_categories.py
@@ -38,7 +38,7 @@ class CreateTroveCategoriesCommand(base.Command):
 
     # NOTE: order is important
     # To add new migration append it's name to following list,
-    # and cretate method m__<migration_name>
+    # and create method m__<migration_name>
     migrations = [
         'add_agpl_and_lppl',
         'sync',
@@ -58,12 +58,13 @@ class CreateTroveCategoriesCommand(base.Command):
         M.TroveCategory(**data)
 
     def update_trove_cat(self, trove_cat_id, attr_dict):
-        t = M.TroveCategory.query.get(trove_cat_id=trove_cat_id)
-        if not t:
+        ts = M.TroveCategory.query.find(dict(trove_cat_id=trove_cat_id))
+        if ts.count() < 1:
             sys.exit("Couldn't find TroveCategory with trove_cat_id=%s" %
                      trove_cat_id)
-        for k, v in attr_dict.iteritems():
-            setattr(t, k, v)
+        for t in ts:
+            for k, v in attr_dict.iteritems():
+                setattr(t, k, v)
 
     # patching to avoid a *lot* of event hooks firing, and taking a long long time
     @patch.object(M.project.TroveCategoryMapperExtension, 'after_insert', Mock())


[38/43] git commit: [#7656] ticket:654 Removed quotes for search term

Posted by je...@apache.org.
[#7656] ticket:654 Removed quotes for search term


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

Branch: refs/heads/je/42cc_7656
Commit: 209e68eac8d649832a2de9825976bee30b9833cf
Parents: 79a7d3b
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Fri Sep 12 16:27:21 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:58 2014 +0300

----------------------------------------------------------------------
 Allura/allura/lib/search.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/209e68ea/Allura/allura/lib/search.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/search.py b/Allura/allura/lib/search.py
index 525fab3..9c4a5f3 100644
--- a/Allura/allura/lib/search.py
+++ b/Allura/allura/lib/search.py
@@ -192,7 +192,7 @@ def site_admin_search(model, q, field, **kw):
         q = obj.translate_query(q, fields)
     else:
         # construct query for a specific selected field
-        q = obj.translate_query(u'%s:"%s"' % (field, q), fields)
+        q = obj.translate_query(u'%s:%s' % (field, q), fields)
     fq = [u'type_s:%s' % model.type_s]
     return search(q, fq=fq, ignore_errors=False, **kw)
 


[18/43] git commit: [#4905] don't show subscribe button to anonymous visitors

Posted by je...@apache.org.
[#4905] don't show subscribe button to anonymous visitors


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

Branch: refs/heads/je/42cc_7656
Commit: ceb0d22b3a89bff1589fa08a4278cc3e7bcee495
Parents: a96d81b
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Wed Sep 17 15:50:19 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed Sep 17 15:50:19 2014 +0000

----------------------------------------------------------------------
 ForgeWiki/forgewiki/wiki_main.py | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/ceb0d22b/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index f0169a4..e32a741 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -227,14 +227,15 @@ The wiki uses [Markdown](%s) syntax.
                 SitemapEntry(
                     'Moderate', discussion.url() + 'moderate', ui_icon=g.icons['pencil'],
                     small=pending_mod_count))
-        subscribed = M.Mailbox.subscribed()
-        subscribe_action = 'unsubscribe' if subscribed else 'subscribe'
-        subscribe_title = '{}{}'.format(
-            subscribe_action.capitalize(),
-            '' if subscribed else ' to wiki')
-        subscribe_url = '{}subscribe?{}=True'.format(self.url, subscribe_action)
-        links += [SitemapEntry(''),
-                  SitemapEntry(subscribe_title, subscribe_url, ui_icon=g.icons['mail'])]
+        if not c.user.is_anonymous():
+            subscribed = M.Mailbox.subscribed()
+            subscribe_action = 'unsubscribe' if subscribed else 'subscribe'
+            subscribe_title = '{}{}'.format(
+                subscribe_action.capitalize(),
+                '' if subscribed else ' to wiki')
+            subscribe_url = '{}subscribe?{}=True'.format(self.url, subscribe_action)
+            links += [SitemapEntry(''),
+                      SitemapEntry(subscribe_title, subscribe_url, ui_icon=g.icons['mail'])]
         if not admin_menu:
             links += [SitemapEntry(''),
                       SitemapEntry('Formatting Help', self.url + 'markdown_syntax/')]


[23/43] git commit: [#7656] ticket:648 Change display name index type to allow not strict matches when searching

Posted by je...@apache.org.
[#7656] ticket:648 Change display name index type to allow not strict matches when searching


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

Branch: refs/heads/je/42cc_7656
Commit: 278f041afcbfc23d36633a50a88bf6827c667c44
Parents: dbad6b5
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 14:15:41 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:57 2014 +0300

----------------------------------------------------------------------
 Allura/allura/model/auth.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/278f041a/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 43de922..16ee2e0 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -302,7 +302,7 @@ class User(MappedClass, ActivityNode, ActivityObject, SearchIndexable):
             email_address_s=self.get_pref('email_address'),
             email_format_s=self.get_pref('email_format'),
             disable_user_messages_b=self.get_pref('disable_user_messages'),
-            display_name_s=self.get_pref('display_name'),
+            display_name_t=self.get_pref('display_name'),
             sex_s=self.get_pref('sex'),
             birthdate_dt=self.get_pref('birthdate'),
             localization_s=localization,


[42/43] git commit: [#7656] ticket:654 Fix tests

Posted by je...@apache.org.
[#7656] ticket:654 Fix tests


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

Branch: refs/heads/je/42cc_7656
Commit: f6dd4ef42d99194fd767869ccfbc0a6844fdf65d
Parents: d967e79
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Sep 18 09:40:49 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:40:49 2014 +0300

----------------------------------------------------------------------
 Allura/allura/tests/functional/test_site_admin.py | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/f6dd4ef4/Allura/allura/tests/functional/test_site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_site_admin.py b/Allura/allura/tests/functional/test_site_admin.py
index c8b3bad..5b0a9b0 100644
--- a/Allura/allura/tests/functional/test_site_admin.py
+++ b/Allura/allura/tests/functional/test_site_admin.py
@@ -167,8 +167,9 @@ class TestSiteAdmin(TestController):
         assert json.loads(r.body)['doc'] == 'test_task doc string'
 
     @patch('allura.model.auth.request')
-    def test_users(self, request):
-        request.url = 'http://host.domain/path/'
+    @patch('allura.lib.helpers.request')
+    def test_users(self, req1, req2):
+        req1.url = req2.url = 'http://host.domain/path/'
         c.user = M.User.by_username('test-user-1')
         h.auditlog_user('test activity user 1')
         h.auditlog_user('test activity user 2', user=M.User.by_username('test-user-2'))
@@ -255,13 +256,13 @@ class TestProjectsSearch(TestController):
     @patch('allura.controllers.site_admin.search')
     def test_additional_fields(self, search):
         search.site_admin_search.return_value = self.TEST_HIT
-        with h.push_config(config, **{'search.project.additional_fields': 'private, url'}):
+        with h.push_config(config, **{'search.project.additional_search_fields': 'private, url',
+                                      'search.project.additional_display_fields': 'url'}):
             r = self.app.get('/nf/admin/search_projects?q=fake&f=shortname')
         options = [o['value'] for o in r.html.findAll('option')]
         assert_equal(options, ['shortname', 'name', 'private', 'url', '__custom__'])
         ths = [th.text for th in r.html.findAll('th')]
-        assert_equal(ths, ['Short name', 'Full name', 'Registered', 'Deleted?',
-                           'private', 'url', 'Details'])
+        assert_equal(ths, ['Short name', 'Full name', 'Registered', 'Deleted?', 'url', 'Details'])
 
 
 class TestUsersSearch(TestController):
@@ -308,13 +309,14 @@ class TestUsersSearch(TestController):
     @patch('allura.controllers.site_admin.search')
     def test_additional_fields(self, search):
         search.site_admin_search.return_value = self.TEST_HIT
-        with h.push_config(config, **{'search.user.additional_fields': 'email_addresses, url'}):
+        with h.push_config(config, **{'search.user.additional_search_fields': 'email_addresses, url',
+                                      'search.user.additional_display_fields': 'url'}):
             r = self.app.get('/nf/admin/search_users?q=fake&f=username')
         options = [o['value'] for o in r.html.findAll('option')]
         assert_equal(options, ['username', 'display_name', 'email_addresses', 'url', '__custom__'])
         ths = [th.text for th in r.html.findAll('th')]
         assert_equal(ths, ['Username', 'Display name', 'Email', 'Registered',
-                           'Disabled?', 'email_addresses', 'url', 'Details'])
+                           'Disabled?', 'url', 'Details'])
 
 
 @task


[41/43] git commit: [#7656] ticket:648 Fix typo

Posted by je...@apache.org.
[#7656] ticket:648 Fix typo


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

Branch: refs/heads/je/42cc_7656
Commit: 307b5beaf2bf313e6bc36950e7320c6f6ee0126c
Parents: ab7dcfc
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 16:57:58 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:58 2014 +0300

----------------------------------------------------------------------
 Allura/allura/lib/search.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/307b5bea/Allura/allura/lib/search.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/search.py b/Allura/allura/lib/search.py
index 1c3ba8a..525fab3 100644
--- a/Allura/allura/lib/search.py
+++ b/Allura/allura/lib/search.py
@@ -182,7 +182,7 @@ def site_admin_search(model, q, field, **kw):
 
     Raises SearchError if SOLR returns an error.
     """
-    # first, grab a object and get the fields that it indexes
+    # first, grab an object and get the fields that it indexes
     obj = model.query.find().first()
     if obj is None:
         return  # if there are no objects, we won't find anything


[37/43] git commit: [#7656] ticket:648 Add tests for user search

Posted by je...@apache.org.
[#7656] ticket:648 Add tests for user search


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

Branch: refs/heads/je/42cc_7656
Commit: ab7dcfc67748f7fdd16e5d754681e3f3b5e62715
Parents: aad4902
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 16:54:56 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:58 2014 +0300

----------------------------------------------------------------------
 .../allura/tests/functional/test_site_admin.py  | 58 +++++++++++++++++++-
 Allura/allura/tests/unit/test_solr.py           | 13 ++++-
 2 files changed, 68 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/ab7dcfc6/Allura/allura/tests/functional/test_site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_site_admin.py b/Allura/allura/tests/functional/test_site_admin.py
index 9503b7e..c8b3bad 100644
--- a/Allura/allura/tests/functional/test_site_admin.py
+++ b/Allura/allura/tests/functional/test_site_admin.py
@@ -233,10 +233,11 @@ class TestProjectsSearch(TestController):
     def setUp(self):
         super(TestProjectsSearch, self).setUp()
         # Create project that matches TEST_HIT id
-        p = M.Project.query.get(_id=ObjectId('53ccf6e8100d2b0741746e9f'))
+        _id = ObjectId('53ccf6e8100d2b0741746e9f')
+        p = M.Project.query.get(_id=_id)
         if not p:
             M.Project(
-                _id=ObjectId('53ccf6e8100d2b0741746e9f'),
+                _id=_id,
                 neighborhood_id=M.Neighborhood.query.get(url_prefix='/u/')._id,
                 shortname='test-project',
             )
@@ -263,6 +264,59 @@ class TestProjectsSearch(TestController):
                            'private', 'url', 'Details'])
 
 
+class TestUsersSearch(TestController):
+
+    TEST_HIT = MagicMock(hits=1, docs=[{
+        '_version_': 1478773871277506560,
+        'disabled_b': False,
+        'display_name_t': 'Darth Vader',
+        'id': 'allura/model/auth/User#540efdf2100d2b1483155d39',
+        'last_access_login_date_dt': '2014-09-09T13:17:40.176Z',
+        'last_access_login_ip_s': '10.0.2.2',
+        'last_access_login_ua_t': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36',
+        'last_access_session_date_dt': '2014-09-09T13:17:40.33Z',
+        'last_access_session_ip_s': '10.0.2.2',
+        'last_access_session_ua_t': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36',
+        'last_password_updated_dt': '2014-09-09T13:17:38.857Z',
+        'localization_s': 'None/None',
+        'sex_s': 'Unknown',
+        'title': ['User darth'],
+        'type_s': 'User',
+        'url_s': '/u/darth/',
+        'user_registration_date_dt': '2014-09-09T13:17:38Z',
+        'username_s': 'darth'}])
+
+    def setUp(self):
+        super(TestUsersSearch, self).setUp()
+        # Create user that matches TEST_HIT id
+        _id = ObjectId('540efdf2100d2b1483155d39')
+        u = M.User.query.get(_id=_id)
+        if not u:
+            M.User(_id=_id, username='darth')
+            ThreadLocalORMSession().flush_all()
+
+    @patch('allura.controllers.site_admin.search')
+    def test_default_fields(self, search):
+        search.site_admin_search.return_value = self.TEST_HIT
+        r = self.app.get('/nf/admin/search_users?q=fake&f=username')
+        options = [o['value'] for o in r.html.findAll('option')]
+        assert_equal(options, ['username', 'display_name', '__custom__'])
+        ths = [th.text for th in r.html.findAll('th')]
+        assert_equal(ths, ['Username', 'Display name', 'Email', 'Registered',
+                           'Disabled?', 'Details'])
+
+    @patch('allura.controllers.site_admin.search')
+    def test_additional_fields(self, search):
+        search.site_admin_search.return_value = self.TEST_HIT
+        with h.push_config(config, **{'search.user.additional_fields': 'email_addresses, url'}):
+            r = self.app.get('/nf/admin/search_users?q=fake&f=username')
+        options = [o['value'] for o in r.html.findAll('option')]
+        assert_equal(options, ['username', 'display_name', 'email_addresses', 'url', '__custom__'])
+        ths = [th.text for th in r.html.findAll('th')]
+        assert_equal(ths, ['Username', 'Display name', 'Email', 'Registered',
+                           'Disabled?', 'email_addresses', 'url', 'Details'])
+
+
 @task
 def test_task(*args, **kw):
     """test_task doc string"""

http://git-wip-us.apache.org/repos/asf/allura/blob/ab7dcfc6/Allura/allura/tests/unit/test_solr.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_solr.py b/Allura/allura/tests/unit/test_solr.py
index 8b237cc..dfe71c7 100644
--- a/Allura/allura/tests/unit/test_solr.py
+++ b/Allura/allura/tests/unit/test_solr.py
@@ -94,7 +94,7 @@ class TestSolr(unittest.TestCase):
     @mock.patch('allura.lib.search.search')
     def test_site_admin_search(self, search):
         from allura.lib.search import site_admin_search
-        from allura.model import Project
+        from allura.model import Project, User
         fq = ['type_s:Project']
         site_admin_search(Project, 'test', 'shortname', rows=25)
         search.assert_called_once_with(
@@ -105,6 +105,17 @@ class TestSolr(unittest.TestCase):
         search.assert_called_once_with(
             'shortname_s:test || shortname_s:test2', fq=fq, ignore_errors=False)
 
+        fq = ['type_s:User']
+        search.reset_mock()
+        site_admin_search(User, 'test-user', 'username', rows=25)
+        search.assert_called_once_with(
+            'username_s:"test-user"', fq=fq, ignore_errors=False, rows=25)
+
+        search.reset_mock()
+        site_admin_search(User, 'username:admin1 || username:root', '__custom__')
+        search.assert_called_once_with(
+            'username_s:admin1 || username_s:root', fq=fq, ignore_errors=False)
+
 
 class TestSearchIndexable(unittest.TestCase):
 


[12/43] git commit: [#4905] ticket:655 Move 'subscribe to wiki' button to sidebar

Posted by je...@apache.org.
[#4905] ticket:655 Move 'subscribe to wiki' button to sidebar


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

Branch: refs/heads/je/42cc_7656
Commit: a39bce7864527401cd109902e85e20cb90c7f8dc
Parents: 6b9a52c
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Sep 12 09:53:05 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Sep 16 15:33:36 2014 +0000

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


http://git-wip-us.apache.org/repos/asf/allura/blob/a39bce78/ForgeWiki/forgewiki/templates/wiki/page_view.html
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/templates/wiki/page_view.html b/ForgeWiki/forgewiki/templates/wiki/page_view.html
index 4e19b2f..2f4d95f 100644
--- a/ForgeWiki/forgewiki/templates/wiki/page_view.html
+++ b/ForgeWiki/forgewiki/templates/wiki/page_view.html
@@ -63,7 +63,6 @@
   {% endif %}
   {% if c.user and c.user != c.user.anonymous() %}
     {{c.subscribe_form.display(value=page_subscribed, action='subscribe', style='icon')}}
-    {{c.wiki_subscribe_form.display(value=subscribed, action='wiki_subscribe', style='icon')}}
   {% endif %}
 	<a href="feed" title="RSS"><b data-icon="{{g.icons['feed'].char}}" class="ico {{g.icons['feed'].css}}" title="Feed"></b></a>
   <a href="../search" title="Search"><b data-icon="{{g.icons['search'].char}}" class="ico {{g.icons['search'].css}}" title="Search"></b></a>

http://git-wip-us.apache.org/repos/asf/allura/blob/a39bce78/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index 41f056e..f0169a4 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -69,7 +69,6 @@ class W:
     attachment_list = ffw.AttachmentList()
     subscribe_form = SubscribeForm()
     page_subscribe_form = SubscribeForm(thing='page')
-    wiki_subscribe_form = SubscribeForm(thing='wiki')
     page_list = ffw.PageList()
     page_size = ffw.PageSize()
     search_results = SearchResults()
@@ -228,6 +227,14 @@ The wiki uses [Markdown](%s) syntax.
                 SitemapEntry(
                     'Moderate', discussion.url() + 'moderate', ui_icon=g.icons['pencil'],
                     small=pending_mod_count))
+        subscribed = M.Mailbox.subscribed()
+        subscribe_action = 'unsubscribe' if subscribed else 'subscribe'
+        subscribe_title = '{}{}'.format(
+            subscribe_action.capitalize(),
+            '' if subscribed else ' to wiki')
+        subscribe_url = '{}subscribe?{}=True'.format(self.url, subscribe_action)
+        links += [SitemapEntry(''),
+                  SitemapEntry(subscribe_title, subscribe_url, ui_icon=g.icons['mail'])]
         if not admin_menu:
             links += [SitemapEntry(''),
                       SitemapEntry('Formatting Help', self.url + 'markdown_syntax/')]
@@ -439,6 +446,15 @@ class RootController(BaseController, DispatchIndex, FeedController):
         'Display a page about how to use markdown.'
         return dict(example=MARKDOWN_EXAMPLE)
 
+    @expose()
+    @validate(W.subscribe_form)
+    def subscribe(self, subscribe=None, unsubscribe=None):
+        if subscribe:
+            M.Mailbox.subscribe(type='direct')
+        elif unsubscribe:
+            M.Mailbox.unsubscribe()
+        redirect(request.referer)
+
 
 class PageController(BaseController, FeedController):
 
@@ -495,7 +511,6 @@ class PageController(BaseController, FeedController):
         c.thread = W.thread
         c.attachment_list = W.attachment_list
         c.subscribe_form = W.page_subscribe_form
-        c.wiki_subscribe_form = W.wiki_subscribe_form
         post_count = self.page.discussion_thread.post_count
         limit, pagenum = h.paging_sanitizer(limit, page, post_count)
         page = self.get_version(version)
@@ -513,15 +528,11 @@ class PageController(BaseController, FeedController):
             prev = None
         next = cur + 1
         hide_left_bar = not (c.app.show_left_bar)
-        subscribed = M.Mailbox.subscribed()
-        subscribed_to_page = False
-        if not subscribed:
-            subscribed_to_page = M.Mailbox.subscribed(artifact=self.page)
+        subscribed_to_page = M.Mailbox.subscribed(artifact=self.page)
         return dict(
             page=page,
             cur=cur, prev=prev, next=next,
             page_subscribed=subscribed_to_page,
-            subscribed=subscribed,
             hide_left_bar=hide_left_bar, show_meta=c.app.show_right_bar,
             pagenum=pagenum, limit=limit, count=post_count)
 
@@ -708,15 +719,6 @@ class PageController(BaseController, FeedController):
             self.page.unsubscribe()
         redirect(request.referer)
 
-    @expose()
-    @validate(W.subscribe_form)
-    def wiki_subscribe(self, subscribe=None, unsubscribe=None):
-        if subscribe:
-            M.Mailbox.subscribe(type='direct')
-        elif unsubscribe:
-            M.Mailbox.unsubscribe()
-        redirect(request.referer)
-
 
 class WikiAttachmentController(ac.AttachmentController):
     AttachmentClass = WM.WikiAttachment


[13/43] git commit: [#4905] ticket:634 Make logic cleaner a bit

Posted by je...@apache.org.
[#4905] ticket:634 Make logic cleaner a bit


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

Branch: refs/heads/je/42cc_7656
Commit: 6b9a52c10d0643ac7dda24ef35f6151360555f0e
Parents: 263b6d4
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Aug 26 09:36:16 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Sep 16 15:33:36 2014 +0000

----------------------------------------------------------------------
 ForgeWiki/forgewiki/wiki_main.py | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/6b9a52c1/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index 615af76..41f056e 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -513,16 +513,15 @@ class PageController(BaseController, FeedController):
             prev = None
         next = cur + 1
         hide_left_bar = not (c.app.show_left_bar)
-        tool_subscribed = M.Mailbox.subscribed()
-        if tool_subscribed:
-            subscribed = False
-        else:
-            subscribed = M.Mailbox.subscribed(artifact=self.page)
+        subscribed = M.Mailbox.subscribed()
+        subscribed_to_page = False
+        if not subscribed:
+            subscribed_to_page = M.Mailbox.subscribed(artifact=self.page)
         return dict(
             page=page,
             cur=cur, prev=prev, next=next,
-            page_subscribed=subscribed,
-            subscribed=M.Mailbox.subscribed(),
+            page_subscribed=subscribed_to_page,
+            subscribed=subscribed,
             hide_left_bar=hide_left_bar, show_meta=c.app.show_right_bar,
             pagenum=pagenum, limit=limit, count=post_count)
 


[39/43] git commit: [#7656] ticket:648 Fix test failing due to refactoring

Posted by je...@apache.org.
[#7656] ticket:648 Fix test failing due to refactoring


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

Branch: refs/heads/je/42cc_7656
Commit: aad4902a1959af66f5452c04071f88a5aeb116f2
Parents: 9e95379
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 16:29:25 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:58 2014 +0300

----------------------------------------------------------------------
 Allura/allura/tests/functional/test_site_admin.py | 4 ++--
 Allura/allura/tests/model/test_auth.py            | 2 +-
 Allura/allura/tests/unit/test_solr.py             | 9 +++++----
 3 files changed, 8 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/aad4902a/Allura/allura/tests/functional/test_site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_site_admin.py b/Allura/allura/tests/functional/test_site_admin.py
index b7ae16a..9503b7e 100644
--- a/Allura/allura/tests/functional/test_site_admin.py
+++ b/Allura/allura/tests/functional/test_site_admin.py
@@ -244,7 +244,7 @@ class TestProjectsSearch(TestController):
 
     @patch('allura.controllers.site_admin.search')
     def test_default_fields(self, search):
-        search.search_projects.return_value = self.TEST_HIT
+        search.site_admin_search.return_value = self.TEST_HIT
         r = self.app.get('/nf/admin/search_projects?q=fake&f=shortname')
         options = [o['value'] for o in r.html.findAll('option')]
         assert_equal(options, ['shortname', 'name', '__custom__'])
@@ -253,7 +253,7 @@ class TestProjectsSearch(TestController):
 
     @patch('allura.controllers.site_admin.search')
     def test_additional_fields(self, search):
-        search.search_projects.return_value = self.TEST_HIT
+        search.site_admin_search.return_value = self.TEST_HIT
         with h.push_config(config, **{'search.project.additional_fields': 'private, url'}):
             r = self.app.get('/nf/admin/search_projects?q=fake&f=shortname')
         options = [o['value'] for o in r.html.findAll('option')]

http://git-wip-us.apache.org/repos/asf/allura/blob/aad4902a/Allura/allura/tests/model/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_auth.py b/Allura/allura/tests/model/test_auth.py
index 4660510..75cf5a2 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -295,7 +295,7 @@ def test_user_index():
     assert_in('results_per_page_i', idx)
     assert_in('email_format_s', idx)
     assert_in('disable_user_messages_b', idx)
-    assert_equal(idx['display_name_s'], 'Test Admin')
+    assert_equal(idx['display_name_t'], 'Test Admin')
     assert_equal(idx['sex_s'], 'Unknown')
     assert_in('birthdate_dt', idx)
     assert_in('localization_s', idx)

http://git-wip-us.apache.org/repos/asf/allura/blob/aad4902a/Allura/allura/tests/unit/test_solr.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_solr.py b/Allura/allura/tests/unit/test_solr.py
index 7e104d1..8b237cc 100644
--- a/Allura/allura/tests/unit/test_solr.py
+++ b/Allura/allura/tests/unit/test_solr.py
@@ -92,15 +92,16 @@ class TestSolr(unittest.TestCase):
         solr.query_server.search.assert_called_once_with('bar', kw='kw')
 
     @mock.patch('allura.lib.search.search')
-    def test_search_projects(self, search):
-        from allura.lib.search import search_projects
+    def test_site_admin_search(self, search):
+        from allura.lib.search import site_admin_search
+        from allura.model import Project
         fq = ['type_s:Project']
-        search_projects('test', 'shortname', rows=25)
+        site_admin_search(Project, 'test', 'shortname', rows=25)
         search.assert_called_once_with(
             'shortname_s:"test"', fq=fq, ignore_errors=False, rows=25)
 
         search.reset_mock()
-        search_projects('shortname:test || shortname:test2', '__custom__')
+        site_admin_search(Project, 'shortname:test || shortname:test2', '__custom__')
         search.assert_called_once_with(
             'shortname_s:test || shortname_s:test2', fq=fq, ignore_errors=False)
 


[36/43] git commit: [#7656] ticket:648 Format registration date

Posted by je...@apache.org.
[#7656] ticket:648 Format registration date


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

Branch: refs/heads/je/42cc_7656
Commit: 9e953798aa48d1fc2686380d4f4cdd9693fb1815
Parents: d92d11b
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 16:18:48 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:58 2014 +0300

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


http://git-wip-us.apache.org/repos/asf/allura/blob/9e953798/Allura/allura/templates/site_admin_search_users_results.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_users_results.html b/Allura/allura/templates/site_admin_search_users_results.html
index ce9a8d0..9e986ab 100644
--- a/Allura/allura/templates/site_admin_search_users_results.html
+++ b/Allura/allura/templates/site_admin_search_users_results.html
@@ -15,7 +15,7 @@
   <td><a href="{{ u['url'] }}">{{ u['username'] }}</a></td>
   <td>{{ u['display_name'] }}</td>
   <td>{{ u['object'].get_pref('email_address') }}</td>
-  <td>{{ provider.user_registration_date(u['object']) }}</td>
+  <td>{{ h.ago(provider.user_registration_date(u['object']).replace(tzinfo=None)) }}</td>
   <td>{{ u['disabled'] }}</td>
   {% for field in additional_fields %}
   <td>{{ u[field] }}</td>


[07/43] git commit: Remove NoWarnings package, old and unneeded

Posted by je...@apache.org.
Remove NoWarnings package, old and unneeded


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

Branch: refs/heads/je/42cc_7656
Commit: 0855719ccdccdeb5e57a75b9d9fed36cd9c505bf
Parents: b74f2de
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Sep 9 15:34:46 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Sep 9 15:34:46 2014 +0000

----------------------------------------------------------------------
 NoWarnings/LICENSE       | 202 ------------------------------------------
 NoWarnings/NOTICE        |   5 --
 NoWarnings/nowarnings.py |  30 -------
 NoWarnings/setup.py      |  38 --------
 rebuild-all.bash         |   2 +-
 5 files changed, 1 insertion(+), 276 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/0855719c/NoWarnings/LICENSE
----------------------------------------------------------------------
diff --git a/NoWarnings/LICENSE b/NoWarnings/LICENSE
deleted file mode 100644
index d645695..0000000
--- a/NoWarnings/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.

http://git-wip-us.apache.org/repos/asf/allura/blob/0855719c/NoWarnings/NOTICE
----------------------------------------------------------------------
diff --git a/NoWarnings/NOTICE b/NoWarnings/NOTICE
deleted file mode 100644
index 69af9fe..0000000
--- a/NoWarnings/NOTICE
+++ /dev/null
@@ -1,5 +0,0 @@
-Apache Allura
-Copyright 2012-2014 The Apache Software Foundation
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).

http://git-wip-us.apache.org/repos/asf/allura/blob/0855719c/NoWarnings/nowarnings.py
----------------------------------------------------------------------
diff --git a/NoWarnings/nowarnings.py b/NoWarnings/nowarnings.py
deleted file mode 100644
index e81d745..0000000
--- a/NoWarnings/nowarnings.py
+++ /dev/null
@@ -1,30 +0,0 @@
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.
-
-import warnings
-from nose.plugins import Plugin
-
-
-class NoWarnings(Plugin):
-
-    def beforeTest(self, result):
-        # Suppress warnings during tests to reduce noise
-        warnings.simplefilter("ignore")
-
-    def afterTest(self, result):
-        # Clear list of warning filters
-        warnings.resetwarnings()

http://git-wip-us.apache.org/repos/asf/allura/blob/0855719c/NoWarnings/setup.py
----------------------------------------------------------------------
diff --git a/NoWarnings/setup.py b/NoWarnings/setup.py
deleted file mode 100644
index 0ce5835..0000000
--- a/NoWarnings/setup.py
+++ /dev/null
@@ -1,38 +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.
-
-try:
-    import ez_setup
-    ez_setup.use_setuptools()
-except ImportError:
-    pass
-
-from setuptools import setup
-
-setup(
-    name='NoWarnings plugin',
-    version='1.0',
-    author='Wolf',
-    author_email='wolf@geek.net',
-    description='A nose plugin to squelch warnings',
-    py_modules=['nowarnings'],
-    entry_points={
-        'nose.plugins.0.10': [
-            'nowarnings = nowarnings:NoWarnings'
-        ]
-    }
-)

http://git-wip-us.apache.org/repos/asf/allura/blob/0855719c/rebuild-all.bash
----------------------------------------------------------------------
diff --git a/rebuild-all.bash b/rebuild-all.bash
index d33af79..36001f4 100755
--- a/rebuild-all.bash
+++ b/rebuild-all.bash
@@ -17,7 +17,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-for APP in Allura* *Forge* NoWarnings
+for APP in Allura* *Forge*
 do
     echo "# setting up $APP dependencies"
     pushd $APP > /dev/null


[33/43] git commit: [#7656] ticket:654 Added license information to new templates

Posted by je...@apache.org.
[#7656] ticket:654 Added license information to new templates


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

Branch: refs/heads/je/42cc_7656
Commit: 79a7d3b60bcebd9946bdb1af2fa69e66a62a7b1a
Parents: 307b5be
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Thu Sep 11 19:43:03 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:58 2014 +0300

----------------------------------------------------------------------
 .../site_admin_search_projects_results.html       | 18 ++++++++++++++++++
 .../site_admin_search_users_results.html          | 18 ++++++++++++++++++
 2 files changed, 36 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/79a7d3b6/Allura/allura/templates/site_admin_search_projects_results.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_projects_results.html b/Allura/allura/templates/site_admin_search_projects_results.html
index 622e9a6..5bde5f0 100644
--- a/Allura/allura/templates/site_admin_search_projects_results.html
+++ b/Allura/allura/templates/site_admin_search_projects_results.html
@@ -1,3 +1,21 @@
+{#-
+       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.
+-#}
 <tr>
   <th>Short name</th>
   <th>Full name</th>

http://git-wip-us.apache.org/repos/asf/allura/blob/79a7d3b6/Allura/allura/templates/site_admin_search_users_results.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_users_results.html b/Allura/allura/templates/site_admin_search_users_results.html
index 9e986ab..dc83184 100644
--- a/Allura/allura/templates/site_admin_search_users_results.html
+++ b/Allura/allura/templates/site_admin_search_users_results.html
@@ -1,3 +1,21 @@
+{#-
+       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.
+-#}
 <tr>
   <th>Username</th>
   <th>Display name</th>


[30/43] git commit: [#7656] ticket:648 Refactor projects search fn to generic one and add fn for users

Posted by je...@apache.org.
[#7656] ticket:648 Refactor projects search fn to generic one and add fn for users


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

Branch: refs/heads/je/42cc_7656
Commit: c3bfa048732c9cfe6b860d36b1ba793f8f2e02fb
Parents: 5b6f3d1
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 13:08:44 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:57 2014 +0300

----------------------------------------------------------------------
 Allura/allura/lib/search.py | 31 ++++++++++++++++++++-----------
 1 file changed, 20 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/c3bfa048/Allura/allura/lib/search.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/search.py b/Allura/allura/lib/search.py
index c0f45cc..49a3ad5 100644
--- a/Allura/allura/lib/search.py
+++ b/Allura/allura/lib/search.py
@@ -159,26 +159,35 @@ def search_artifact(atype, q, history=False, rows=10, short_timeout=False, filte
     return search(q, fq=fq, rows=rows, short_timeout=short_timeout, ignore_errors=False, **kw)
 
 
-def search_projects(q, field, **kw):
-    """Performs SOLR search for a project.
+def site_admin_search(model, q, field, **kw):
+    """Performs SOLR search for a given model.
+
+    Probably you should not use it directly. Use one of the specific functions below.
 
     Raises SearchError if SOLR returns an error.
     """
-    # first, grab a project and get the fields that it indexes
-    from allura.model import Project
-    p = Project.query.find().first()
-    if p is None:
-        return  # if there are no projects, we won't find anything
-    fields = p.index()
+    # first, grab a object and get the fields that it indexes
+    obj = model.query.find().first()
+    if obj is None:
+        return  # if there are no objects, we won't find anything
+    fields = obj.index()
     if field == '__custom__':
         # custom query -> query as is
-        q = p.translate_query(q, fields)
+        q = obj.translate_query(q, fields)
     else:
         # construct query for a specific selected field
-        q = p.translate_query(u'%s:"%s"' % (field, q), fields)
-    fq = [u'type_s:Project']
+        q = obj.translate_query(u'%s:"%s"' % (field, q), fields)
+    fq = [u'type_s:%s' % model.type_s]
     return search(q, fq=fq, ignore_errors=False, **kw)
 
+def search_projects(q, field, **kw):
+    from allura.model import Project
+    return site_admin_search(Project, q, field, **kw)
+
+def search_users(q, field, **kw):
+    from allura.model import User
+    return site_admin_search(User, q, field, **kw)
+
 
 def search_app(q='', fq=None, app=True, **kw):
     """Helper for app/project search.


[43/43] git commit: [#7656] ticket:654 Small amends to layout

Posted by je...@apache.org.
[#7656] ticket:654 Small amends to layout


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

Branch: refs/heads/je/42cc_7656
Commit: 46ec4a382b2d04c2bc6ceaf3d6493b7a25b71ed6
Parents: f6dd4ef
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Sep 18 10:02:47 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 10:02:47 2014 +0300

----------------------------------------------------------------------
 Allura/allura/lib/widgets/forms.py             |  3 ++-
 Allura/allura/templates/site_admin_search.html | 11 +++++++----
 2 files changed, 9 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/46ec4a38/Allura/allura/lib/widgets/forms.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/forms.py b/Allura/allura/lib/widgets/forms.py
index 0d25079..55700b1 100644
--- a/Allura/allura/lib/widgets/forms.py
+++ b/Allura/allura/lib/widgets/forms.py
@@ -1086,6 +1086,7 @@ class AdminSearchForm(ForgeForm):
         ForgeForm.defaults,
         action='',
         method='get',
+        style='wide',
         submit_text=None)
 
     def __init__(self, fields, *args, **kw):
@@ -1102,7 +1103,7 @@ class AdminSearchForm(ForgeForm):
                     name='f',
                     show_label=False,
                     options=search_fields),
-                ew.InputField(name='q', show_label=False, attrs={'style': 'width: 500px'}),
+                ew.InputField(name='q', show_label=False, attrs={'style': 'width: 600px'}),
                 ew.SubmitButton(
                     show_label=False,
                     attrs={

http://git-wip-us.apache.org/repos/asf/allura/blob/46ec4a38/Allura/allura/templates/site_admin_search.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search.html b/Allura/allura/templates/site_admin_search.html
index b0d86a8..7345c4d 100644
--- a/Allura/allura/templates/site_admin_search.html
+++ b/Allura/allura/templates/site_admin_search.html
@@ -26,9 +26,9 @@
 {% block header %}Search {{ type_s }}s{% endblock %}
 
 {% block content %}
-  <div class="grid-19"><p><a href="/nf/admin">Back to Site Admin Home</a></p></div>
+  <div class="grid-23"><p><a href="/nf/admin">Back to Site Admin Home</a></p></div>
 
-  <div class="grid-19">
+  <div class="grid-23">
     {{ c.search_form.display(q=q, f=f) }}
   </div>
 
@@ -38,7 +38,7 @@
     </table>
   {% endif %}
 
-  <div class="grid-19">
+  <div class="grid-23">
     {{c.page_list.display(limit=limit, page=page_num, count=count)}}
     {{c.page_size.display(limit=limit, page=page_num, count=count)}}
   </div>
@@ -46,7 +46,10 @@
 
 {% block extra_css %}
 <style>
-  table { clear: both; }
+  .pad table {
+    clear: both;
+    width: 900px;
+  }
   table th {
     text-align: left;
     padding: 5px 10px;


[09/43] git commit: [#7677] change verification link to be protocol relative so referrer is always there (https/http switch may drop it) and after flash you go back to the right page

Posted by je...@apache.org.
[#7677] change verification link to be protocol relative so referrer is always there (https/http switch may drop it) and after flash you go back to the right page


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

Branch: refs/heads/je/42cc_7656
Commit: fab7d22e437047ca1a6d50273f9626711314f1eb
Parents: 01e009f
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Sep 15 18:45:39 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Sep 15 22:13:20 2014 +0000

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


http://git-wip-us.apache.org/repos/asf/allura/blob/fab7d22e/Allura/allura/templates/user_prefs.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/user_prefs.html b/Allura/allura/templates/user_prefs.html
index fec5dcd..913bf8b 100644
--- a/Allura/allura/templates/user_prefs.html
+++ b/Allura/allura/templates/user_prefs.html
@@ -93,7 +93,7 @@
                 {% if obj.confirmed %}
                   yes
                 {% else %}
-                  no (<a href="{{g.url('/auth/send_verification_link', a=a)}}">verify</a>)
+                  no (<a href="/auth/send_verification_link?a={{a}}">verify</a>)
                 {% endif %}
               </td>
               {% else %}


[35/43] git commit: [#7656] ticket:654 Split additional_fields options into additional_search_fields and additional_display_fields

Posted by je...@apache.org.
[#7656] ticket:654 Split additional_fields options into additional_search_fields and additional_display_fields


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

Branch: refs/heads/je/42cc_7656
Commit: d967e795af1cb45f0aa935fd43c7c6a34052267a
Parents: a449d15
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Tue Sep 16 16:42:51 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:58 2014 +0300

----------------------------------------------------------------------
 Allura/allura/controllers/site_admin.py                     | 8 ++++++--
 .../templates/site_admin_search_projects_results.html       | 4 ++--
 .../allura/templates/site_admin_search_users_results.html   | 4 ++--
 Allura/development.ini                                      | 9 +++++++--
 4 files changed, 17 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/d967e795/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index b6fecd7..755c405 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -346,9 +346,11 @@ class SiteAdminController(object):
                               page=validators.Int(if_empty=0, if_invalid=0)))
     def search_projects(self, q=None, f=None, page=0, limit=None, **kw):
         fields = [('shortname', 'shortname'), ('name', 'full name')]
-        add_fields = aslist(tg.config.get('search.project.additional_fields'), ',')
+        add_fields = aslist(tg.config.get('search.project.additional_search_fields'), ',')
         r = self._search(M.Project, fields, add_fields, q, f, page, limit, **kw)
         r['search_results_template'] = 'allura:templates/site_admin_search_projects_results.html'
+        r['additional_display_fields'] = \
+            aslist(tg.config.get('search.project.additional_display_fields'), ',')
         r['provider'] = ProjectRegistrationProvider.get()
         return r
 
@@ -359,9 +361,11 @@ class SiteAdminController(object):
                               page=validators.Int(if_empty=0, if_invalid=0)))
     def search_users(self, q=None, f=None, page=0, limit=None, **kw):
         fields = [('username', 'username'), ('display_name', 'display name')]
-        add_fields = aslist(tg.config.get('search.user.additional_fields'), ',')
+        add_fields = aslist(tg.config.get('search.user.additional_search_fields'), ',')
         r = self._search(M.User, fields, add_fields, q, f, page, limit, **kw)
         r['search_results_template'] = 'allura:templates/site_admin_search_users_results.html'
+        r['additional_display_fields'] = \
+            aslist(tg.config.get('search.user.additional_display_fields'), ',')
         r['provider'] = AuthenticationProvider.get(request)
         return r
 

http://git-wip-us.apache.org/repos/asf/allura/blob/d967e795/Allura/allura/templates/site_admin_search_projects_results.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_projects_results.html b/Allura/allura/templates/site_admin_search_projects_results.html
index 5bde5f0..3fedf82 100644
--- a/Allura/allura/templates/site_admin_search_projects_results.html
+++ b/Allura/allura/templates/site_admin_search_projects_results.html
@@ -21,7 +21,7 @@
   <th>Full name</th>
   <th>Registered</th>
   <th>Deleted?</th>
-  {% for field in additional_fields %}
+  {% for field in additional_display_fields %}
   <th>{{ field }}</th>
   {% endfor %}
   <th>Details</th>
@@ -33,7 +33,7 @@
   <td>{{ p['name'] }}</td>
   <td>{{ h.ago_string(p['registration']) }}</td>
   <td>{{ p['deleted'] }}</td>
-  {% for field in additional_fields %}
+  {% for field in additional_display_fields %}
   <td>{{ p[field] }}</td>
   {% endfor %}
   <td>

http://git-wip-us.apache.org/repos/asf/allura/blob/d967e795/Allura/allura/templates/site_admin_search_users_results.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_users_results.html b/Allura/allura/templates/site_admin_search_users_results.html
index dc83184..c718b02 100644
--- a/Allura/allura/templates/site_admin_search_users_results.html
+++ b/Allura/allura/templates/site_admin_search_users_results.html
@@ -22,7 +22,7 @@
   <th>Email</th>
   <th>Registered</th>
   <th>Disabled?</th>
-  {% for field in additional_fields %}
+  {% for field in additional_display_fields %}
   <th>{{ field }}</th>
   {% endfor %}
   <th>Details</th>
@@ -35,7 +35,7 @@
   <td>{{ u['object'].get_pref('email_address') }}</td>
   <td>{{ h.ago(provider.user_registration_date(u['object']).replace(tzinfo=None)) }}</td>
   <td>{{ u['disabled'] }}</td>
-  {% for field in additional_fields %}
+  {% for field in additional_display_fields %}
   <td>{{ u[field] }}</td>
   {% endfor %}
   <td>

http://git-wip-us.apache.org/repos/asf/allura/blob/d967e795/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index ab0c114..841714d 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -122,8 +122,13 @@ user_prefs_storage.ldap.fields.display_name = cn
 
 # Additional fields for admin project/user search
 # Note: whitespace after comma is important!
-# search.project.additional_fields = private, url, title
-# search.user.additional_fields = email_addresses
+# 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
 
 # Set the locations of some static resources
 #  script_name is the path that is handled by the application


[06/43] git commit: Update version of nose

Posted by je...@apache.org.
Update version of nose


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

Branch: refs/heads/je/42cc_7656
Commit: b74f2def3c3698c895bfebb457c477e22640043e
Parents: e15c415
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Sep 9 15:33:43 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Sep 9 15:33:43 2014 +0000

----------------------------------------------------------------------
 requirements.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/b74f2def/requirements.txt
----------------------------------------------------------------------
diff --git a/requirements.txt b/requirements.txt
index 0800820..5e67556 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -73,7 +73,7 @@ smmap==0.8.1
 datadiff==1.1.5
 ipython==1.2.1
 mock==1.0.1
-nose==1.3.0
+nose==1.3.4
 pyflakes==0.5.0
 WebTest==1.4.0
 testfixtures==3.0.0


[31/43] git commit: [#7656] ticket:648 Display search results and small fixes

Posted by je...@apache.org.
[#7656] ticket:648 Display search results and small fixes


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

Branch: refs/heads/je/42cc_7656
Commit: d92d11b4266cd0ce63ab170bc627dbf4d6005512
Parents: 462be29
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 15:59:14 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:57 2014 +0300

----------------------------------------------------------------------
 Allura/allura/controllers/site_admin.py         |  3 ++-
 Allura/allura/lib/plugin.py                     | 10 ++++++++
 Allura/allura/model/auth.py                     |  3 ++-
 .../site_admin_search_users_results.html        | 24 +++++++++++++++++++-
 4 files changed, 37 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/d92d11b4/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index 40c69f2..b6fecd7 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -34,7 +34,7 @@ from allura.app import SitemapEntry
 from allura.lib import helpers as h
 from allura.lib import validators as v
 from allura.lib.decorators import require_post
-from allura.lib.plugin import SiteAdminExtension, ProjectRegistrationProvider
+from allura.lib.plugin import SiteAdminExtension, ProjectRegistrationProvider, AuthenticationProvider
 from allura.lib import search
 from allura.lib.security import require_access
 from allura.lib.widgets import form_fields as ffw
@@ -362,6 +362,7 @@ class SiteAdminController(object):
         add_fields = aslist(tg.config.get('search.user.additional_fields'), ',')
         r = self._search(M.User, fields, add_fields, q, f, page, limit, **kw)
         r['search_results_template'] = 'allura:templates/site_admin_search_users_results.html'
+        r['provider'] = AuthenticationProvider.get(request)
         return r
 
 

http://git-wip-us.apache.org/repos/asf/allura/blob/d92d11b4/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index ccdf62c..78aae92 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -288,6 +288,16 @@ class AuthenticationProvider(object):
         """Put here additional fields for user index in SOLR."""
         return {}
 
+    def details_links(self, user):
+        '''Return list of pairs (url, label) with details
+        about the user.
+        Links will show up at admin user search page.
+        '''
+        return [
+           (user.url(), 'Public profile'),
+           ('/nf/admin/user/%s' % user.username, 'Details/Edit'),
+        ]
+
 
 class LocalAuthenticationProvider(AuthenticationProvider):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/d92d11b4/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 16ee2e0..77c42c7 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -293,6 +293,7 @@ class User(MappedClass, ActivityNode, ActivityObject, SearchIndexable):
         fields = dict(
             id=self.index_id(),
             title='User %s' % self.username,
+            url_s=self.url(),
             type_s=self.type_s,
             username_s=self.username,
             email_addresses_t=' '.join(self.email_addresses),
@@ -311,7 +312,7 @@ class User(MappedClass, ActivityNode, ActivityObject, SearchIndexable):
             telnumbers_t=' '.join(self.get_pref('telnumbers')),
             skypeaccount_s=self.get_pref('skypeaccount'),
             webpages_t=' '.join(self.get_pref('webpages')),
-            skills_t=' '.join([s['skill'].fullpath for s in self.get_skills()]),
+            skills_t=' '.join([s['skill'].fullpath for s in self.get_skills() if s.get('skill')]),
             last_access_login_date_dt=self.last_access['login_date'],
             last_access_login_ip_s=self.last_access['login_ip'],
             last_access_login_ua_t=self.last_access['login_ua'],

http://git-wip-us.apache.org/repos/asf/allura/blob/d92d11b4/Allura/allura/templates/site_admin_search_users_results.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_users_results.html b/Allura/allura/templates/site_admin_search_users_results.html
index b73c5c4..ce9a8d0 100644
--- a/Allura/allura/templates/site_admin_search_users_results.html
+++ b/Allura/allura/templates/site_admin_search_users_results.html
@@ -1,7 +1,29 @@
 <tr>
+  <th>Username</th>
+  <th>Display name</th>
+  <th>Email</th>
+  <th>Registered</th>
+  <th>Disabled?</th>
+  {% for field in additional_fields %}
+  <th>{{ field }}</th>
+  {% endfor %}
+  <th>Details</th>
 </tr>
 
-{% for user in objects %}
+{% for u in objects %}
 <tr>
+  <td><a href="{{ u['url'] }}">{{ u['username'] }}</a></td>
+  <td>{{ u['display_name'] }}</td>
+  <td>{{ u['object'].get_pref('email_address') }}</td>
+  <td>{{ provider.user_registration_date(u['object']) }}</td>
+  <td>{{ u['disabled'] }}</td>
+  {% for field in additional_fields %}
+  <td>{{ u[field] }}</td>
+  {% endfor %}
+  <td>
+    {% for url, label in provider.details_links(u['object']) %}
+      <a href="{{ url }}">{{ label }}</a><br>
+    {% endfor %}
+  </td>
 </tr>
 {% endfor %}


[32/43] git commit: [#7656] ticket:648 Move translate_query to SearchIndexable

Posted by je...@apache.org.
[#7656] ticket:648 Move translate_query to SearchIndexable


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

Branch: refs/heads/je/42cc_7656
Commit: b1fcc9fb936bc814f3eb88e97787ffcdf726970c
Parents: c3bfa04
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 13:15:17 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:57 2014 +0300

----------------------------------------------------------------------
 Allura/allura/lib/search.py     | 18 ++++++++++++++++++
 Allura/allura/model/artifact.py | 18 ------------------
 Allura/allura/model/project.py  |  5 -----
 3 files changed, 18 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/b1fcc9fb/Allura/allura/lib/search.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/search.py b/Allura/allura/lib/search.py
index 49a3ad5..f4f177a 100644
--- a/Allura/allura/lib/search.py
+++ b/Allura/allura/lib/search.py
@@ -100,6 +100,24 @@ class SearchIndexable(object):
         doc['text'] = jinja2.Markup.escape(text).striptags()
         return doc
 
+    @classmethod
+    def translate_query(cls, q, fields):
+        """Return a translated Solr query (``q``), where generic field
+        identifiers are replaced by the 'strongly typed' versions defined in
+        ``fields``.
+
+        """
+        # Replace longest fields first to avoid problems when field names have
+        # the same suffixes, but different field types. E.g.:
+        # query 'shortname:test' with fields.keys() == ['name_t', 'shortname_s']
+        # will be translated to 'shortname_t:test', which makes no sense
+        fields = sorted(fields.keys(), key=len, reverse=True)
+        for f in fields:
+            if '_' in f:
+                base, typ = f.rsplit('_', 1)
+                q = q.replace(base + ':', f + ':')
+        return q
+
 
 class SearchError(SolrError):
     pass

http://git-wip-us.apache.org/repos/asf/allura/blob/b1fcc9fb/Allura/allura/model/artifact.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/artifact.py b/Allura/allura/model/artifact.py
index 2639021..ccb6b42 100644
--- a/Allura/allura/model/artifact.py
+++ b/Allura/allura/model/artifact.py
@@ -130,24 +130,6 @@ class Artifact(MappedClass, SearchIndexable):
     def attachment_class(cls):
         raise NotImplementedError, 'attachment_class'
 
-    @classmethod
-    def translate_query(cls, q, fields):
-        """Return a translated Solr query (``q``), where generic field
-        identifiers are replaced by the 'strongly typed' versions defined in
-        ``fields``.
-
-        """
-        # Replace longest fields first to avoid problems when field names have
-        # the same suffixes, but different field types. E.g.:
-        # query 'shortname:test' with fields.keys() == ['name_t', 'shortname_s']
-        # will be translated to 'shortname_t:test', which makes no sense
-        fields = sorted(fields.keys(), key=len, reverse=True)
-        for f in fields:
-            if '_' in f:
-                base, typ = f.rsplit('_', 1)
-                q = q.replace(base + ':', f + ':')
-        return q
-
     @LazyProperty
     def ref(self):
         """Return :class:`allura.model.index.ArtifactReference` for this

http://git-wip-us.apache.org/repos/asf/allura/blob/b1fcc9fb/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index d8c3180..2ecb530 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -252,11 +252,6 @@ class Project(SearchIndexable, MappedClass, ActivityNode, ActivityObject):
     # transient properties
     notifications_disabled = False
 
-    @classmethod
-    def translate_query(cls, q, fields):
-        from .artifact import Artifact
-        return Artifact.translate_query(q, fields)
-
     @property
     def activity_name(self):
         return self.name


[25/43] git commit: [#7656] ticket:648 Add initial stubs for user search page

Posted by je...@apache.org.
[#7656] ticket:648 Add initial stubs for user search page


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

Branch: refs/heads/je/42cc_7656
Commit: 0c3f0ad39bd45e5c9aa15fb19174066598cdef5d
Parents: 9590479
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 12:58:18 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:57 2014 +0300

----------------------------------------------------------------------
 Allura/allura/controllers/site_admin.py         |  9 +++++++
 .../templates/site_admin_search_users.html      | 25 ++++++++++++++++++++
 2 files changed, 34 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/0c3f0ad3/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index 4a96298..bf7076e 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -87,6 +87,7 @@ class SiteAdminController(object):
             SitemapEntry('Task Manager', base_url + 'task_manager?state=busy', ui_icon=g.icons['stats']),
             SitemapEntry('Users Audit Log', base_url + 'users', ui_icon=g.icons['admin']),
             SitemapEntry('Search Projects', base_url + 'search_projects', ui_icon=g.icons['search']),
+            SitemapEntry('Search Users', base_url + 'search_users', ui_icon=g.icons['search']),
         ]
         for ep_name in sorted(g.entry_points['site_admin']):
             g.entry_points['site_admin'][ep_name]().update_sidebar_menu(links)
@@ -341,6 +342,14 @@ class SiteAdminController(object):
             'provider': ProjectRegistrationProvider.get(),
         }
 
+    @without_trailing_slash
+    @expose('jinja:allura:templates/site_admin_search_users.html')
+    @validate(validators=dict(q=validators.UnicodeString(if_empty=None),
+                              limit=validators.Int(if_invalid=None),
+                              page=validators.Int(if_empty=0, if_invalid=0)))
+    def search_users(self, q=None, f=None, page=0, limit=None, **kw):
+        return {}
+
 
 class TaskManagerController(object):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/0c3f0ad3/Allura/allura/templates/site_admin_search_users.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_users.html b/Allura/allura/templates/site_admin_search_users.html
new file mode 100644
index 0000000..ec18e90
--- /dev/null
+++ b/Allura/allura/templates/site_admin_search_users.html
@@ -0,0 +1,25 @@
+{#-
+       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.
+-#}
+{% extends 'allura:templates/site_admin.html' %}
+
+{% block title %}Search Users{% endblock %}
+{% block header %}Search Users{% endblock %}
+
+{% block content %}
+{% endblock %}


[16/43] git commit: [#7659] ticket:653 Allow tools to add fields to project json API

Posted by je...@apache.org.
[#7659] ticket:653 Allow tools to add fields to project json API


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

Branch: refs/heads/je/42cc_7656
Commit: 67355b5f320e46dc118fb180c83586fcc6c645e1
Parents: ef66cbb
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 16 09:35:08 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Sep 16 22:19:37 2014 +0000

----------------------------------------------------------------------
 Allura/allura/app.py           | 11 +++++++++++
 Allura/allura/model/project.py |  3 +--
 2 files changed, 12 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/67355b5f/Allura/allura/app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index 79283a3..4fad3f4 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -641,6 +641,17 @@ class Application(object):
         ET.SubElement(feature, 'name').text = self.config.options.mount_label
         ET.SubElement(feature, 'foaf:page', {'rdf:resource': h.absurl(self.url)})
 
+    def __json__(self):
+        """App's representation for JSON API.
+
+        Returns dict that will be included in project's API under tools key.
+        """
+        return {'name': self.config.tool_name,
+                'mount_point': self.config.options.mount_point,
+                'label': self.config.options.mount_label}
+
+
+
 
 class DefaultAdminController(BaseController):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/67355b5f/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index ff566c2..d8c3180 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -1090,8 +1090,7 @@ class Project(SearchIndexable, MappedClass, ActivityNode, ActivityObject):
             preferred_support_url=self.support_page_url,
             developers=[u.__json__()
                         for u in self.users_with_role('Developer')],
-            tools=[dict(name=t.tool_name, mount_point=t.options.mount_point, label=t.options.mount_label)
-                   for t in self.app_configs if h.has_access(t, 'read')],
+            tools=[self.app_instance(t) for t in self.app_configs if h.has_access(t, 'read')],
             labels=list(self.labels),
             categories={
                 n: [t.__json__(


[08/43] git commit: [#7674] Include IP address in user audit logs

Posted by je...@apache.org.
[#7674] Include IP address in user audit logs

Extracted a new method so that we don't further clutter the model with
references to the current web request


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

Branch: refs/heads/je/42cc_7656
Commit: 505174a00b0de8303147dc24a41dfe9026b42ab3
Parents: 0855719
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri Sep 12 19:50:41 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Sep 12 19:50:41 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py               | 18 ++++++------
 Allura/allura/lib/helpers.py                    | 14 +++++++++
 Allura/allura/lib/plugin.py                     |  4 +--
 Allura/allura/tests/decorators.py               | 30 +++++++++++++++++---
 Allura/allura/tests/functional/test_auth.py     | 10 +++----
 .../allura/tests/functional/test_site_admin.py  |  4 +--
 6 files changed, 58 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/505174a0/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index d2c97a7..61f068e 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -166,7 +166,7 @@ class AuthController(BaseController):
         user = self._validate_hash(hash)
         user.set_password(pw)
         user.set_tool_data('AuthPasswordReset', hash='', hash_expiry='')
-        M.AuditLog.log_user('Password changed (through recovery process)', user=user)
+        h.auditlog_user('Password changed (through recovery process)', user=user)
         flash('Password changed')
         redirect('/auth/')
 
@@ -205,7 +205,7 @@ class AuthController(BaseController):
                 message_id=h.gen_message_id(),
                 text=text)
 
-        M.AuditLog.log_user('Password recovery link sent to: %s', email, user=user_record)
+        h.auditlog_user('Password recovery link sent to: %s', email, user=user_record)
         flash('A password reset email has been sent, if the given email address is on record in our system.')
         redirect('/')
 
@@ -256,7 +256,7 @@ class AuthController(BaseController):
             })
 
             flash('Email address confirmed')
-            M.AuditLog.log_user('Email address verified: %s', addr._id)
+            h.auditlog_user('Email address verified: %s', addr._id)
         else:
             flash('Unknown verification link', 'error')
         redirect('/auth/preferences/')
@@ -387,7 +387,7 @@ class AuthController(BaseController):
         flash('Password changed')
         del session['pwd-expired']
         session.save()
-        M.AuditLog.log_user('Password reset (via expiration process)')
+        h.auditlog_user('Password reset (via expiration process)')
         if return_to and return_to != request.url:
             redirect(return_to)
         else:
@@ -435,7 +435,7 @@ class PreferencesController(BaseController):
             old = c.user.get_pref('display_name')
             c.user.set_pref('display_name', preferences['display_name'])
             if old != preferences['display_name']:
-                M.AuditLog.log_user('Display Name changed %s => %s', old, preferences['display_name'])
+                h.auditlog_user('Display Name changed %s => %s', old, preferences['display_name'])
             for i, (old_a, data) in enumerate(zip(c.user.email_addresses, addr or [])):
                 obj = c.user.address_object(old_a)
                 if data.get('delete') or not obj:
@@ -451,7 +451,7 @@ class PreferencesController(BaseController):
                             # clear it now, a new one will get set below
                             c.user.set_pref('email_address', None)
                             primary_addr = None
-                    M.AuditLog.log_user('Email address deleted: %s', c.user.email_addresses[i])
+                    h.auditlog_user('Email address deleted: %s', c.user.email_addresses[i])
                     del c.user.email_addresses[i]
                     if obj:
                         obj.delete()
@@ -467,7 +467,7 @@ class PreferencesController(BaseController):
                     em = M.EmailAddress.create(new_addr['addr'])
                     em.claimed_by_user_id = c.user._id
                     em.send_verification_link()
-                    M.AuditLog.log_user('New email address: %s', new_addr['addr'])
+                    h.auditlog_user('New email address: %s', new_addr['addr'])
                     flash('A verification email has been sent.  Please check your email and click to confirm.')
                 else:
                     flash('Email address %s is invalid' % new_addr['addr'], 'error')
@@ -478,7 +478,7 @@ class PreferencesController(BaseController):
                     if not kw.get('password') or not provider.validate_password(c.user, kw.get('password')):
                         flash('You must provide your current password to change primary address', 'error')
                         redirect('.')
-                    M.AuditLog.log_user(
+                    h.auditlog_user(
                         'Primary email changed: %s => %s',
                         c.user.get_pref('email_address'),
                         primary_addr)
@@ -501,7 +501,7 @@ class PreferencesController(BaseController):
             flash('Incorrect password', 'error')
             redirect('.')
         flash('Password changed')
-        M.AuditLog.log_user('Password changed')
+        h.auditlog_user('Password changed')
         redirect('.')
 
     @expose()

http://git-wip-us.apache.org/repos/asf/allura/blob/505174a0/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 5d978fa..dbed410 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -1190,3 +1190,17 @@ def unidiff(old, new):
         fromfile='old',
         tofile='new',
         lineterm=''))
+
+
+def auditlog_user(message, *args, **kwargs):
+    """
+    Create an audit log entry for a user, including the IP address
+
+    :param str message:
+    :param user: a :class:`allura.model.auth.User`
+    """
+    from allura import model as M
+    ip_address = request.headers.get('X-Remote-Addr', request.remote_addr)
+    message = 'IP Address: {}\n'.format(ip_address) + message
+    M.AuditLog.log_user(message, *args, **kwargs)
+

http://git-wip-us.apache.org/repos/asf/allura/blob/505174a0/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 7f34559..14a2328 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -142,7 +142,7 @@ class AuthenticationProvider(object):
             if self.is_password_expired(user):
                 self.session['pwd-expired'] = True
                 from allura.model import AuditLog
-                AuditLog.log_user('Password expired', user=user)
+                h.auditlog_user('Password expired', user=user)
             if 'rememberme' in self.request.params:
                 remember_for = int(config.get('auth.remember_for', 365))
                 self.session['login_expires'] = datetime.utcnow() + timedelta(remember_for)
@@ -306,7 +306,7 @@ class LocalAuthenticationProvider(AuthenticationProvider):
         user.disabled = True
         session(user).flush(user)
         from allura.model import AuditLog
-        AuditLog.log_user('Account disabled', user=user)
+        h.auditlog_user('Account disabled', user=user)
 
     def validate_password(self, user, password):
         return self._validate_password(user, password)

http://git-wip-us.apache.org/repos/asf/allura/blob/505174a0/Allura/allura/tests/decorators.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/decorators.py b/Allura/allura/tests/decorators.py
index 3796de7..df0f0b9 100644
--- a/Allura/allura/tests/decorators.py
+++ b/Allura/allura/tests/decorators.py
@@ -154,18 +154,40 @@ class patch_middleware_config(object):
 
 
 @contextlib.contextmanager
-def audits(*messages):
+def audits(*messages, **kwargs):
+    """
+    Asserts all the messages exist in audit log
+
+    :param messages: regex strings
+    :param bool user: if this is a user log
+
+    """
     M.AuditLog.query.remove()
     yield
+    if kwargs.get('user'):
+        preamble = 'IP Address: .*\n'
+    else:
+        preamble = ''
     for message in messages:
         assert M.AuditLog.query.find(dict(
-            message=re.compile(message))).count(), 'Could not find "%s"' % message
+            message=re.compile(preamble + message))).count(), 'Could not find "%s"' % message
 
 
 @contextlib.contextmanager
-def out_audits(*messages):
+def out_audits(*messages, **kwargs):
+    """
+    Asserts none the messages exist in audit log.  "without audits"
+
+    :param messages: list of regex strings
+    :param bool user: if this is a user log
+
+    """
     M.AuditLog.query.remove()
     yield
+    if kwargs.get('user'):
+        preamble = 'IP Address: .*\n'
+    else:
+        preamble = ''
     for message in messages:
         assert not M.AuditLog.query.find(dict(
-            message=re.compile(message))).count(), 'Found unexpected: "%s"' % message
+            message=re.compile(preamble + message))).count(), 'Found unexpected: "%s"' % message

http://git-wip-us.apache.org/repos/asf/allura/blob/505174a0/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 77367ec..9ab122f 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -181,7 +181,7 @@ class TestAuth(TestController):
                      'test-admin@users.localhost')
 
         # add test@example
-        with td.audits('New email address: test@example.com'):
+        with td.audits('New email address: test@example.com', user=True):
             r = self.app.post('/auth/preferences/update', params={
                 'preferences.display_name': 'Test Admin',
                 'new_addr.addr': 'test@example.com',
@@ -196,7 +196,7 @@ class TestAuth(TestController):
         assert_equal(user.get_pref('email_address'), 'test-admin@users.localhost')
 
         # remove test-admin@users.localhost
-        with td.audits('Email address deleted: test-admin@users.localhost'):
+        with td.audits('Email address deleted: test-admin@users.localhost', user=True):
             r = self.app.post('/auth/preferences/update', params={
                 'preferences.display_name': 'Test Admin',
                 'addr-1.ord': '1',
@@ -213,7 +213,7 @@ class TestAuth(TestController):
         user = M.User.query.get(username='test-admin')
         assert_equal(user.get_pref('email_address'), None)
 
-        with td.audits('Display Name changed Test Admin => Admin'):
+        with td.audits('Display Name changed Test Admin => Admin', user=True):
             r = self.app.post('/auth/preferences/update', params={
                 'preferences.display_name': 'Admin',
                 'new_addr.addr': ''},
@@ -872,7 +872,7 @@ class TestPasswordReset(TestController):
         email.confirmed = True
         ThreadLocalORMSession.flush_all()
         old_pw_hash = user.password
-        with td.audits('Password recovery link sent to: test-admin@users.localhost'):
+        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})
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
         hash_expiry = user.get_tool_data('AuthPasswordReset', 'hash_expiry')
@@ -885,7 +885,7 @@ class TestPasswordReset(TestController):
         assert_in('New Password (again):', r)
         form = r.forms[0]
         form['pw'] = form['pw2'] = new_password = '154321'
-        with td.audits('Password changed \(through recovery process\)'):
+        with td.audits('Password changed \(through recovery process\)', user=True):
             # escape parentheses, so they would not be treated as regex group
             r = form.submit()
         user = M.User.query.get(username='test-admin')

http://git-wip-us.apache.org/repos/asf/allura/blob/505174a0/Allura/allura/tests/functional/test_site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_site_admin.py b/Allura/allura/tests/functional/test_site_admin.py
index ab1ffc4..b7ae16a 100644
--- a/Allura/allura/tests/functional/test_site_admin.py
+++ b/Allura/allura/tests/functional/test_site_admin.py
@@ -170,8 +170,8 @@ class TestSiteAdmin(TestController):
     def test_users(self, request):
         request.url = 'http://host.domain/path/'
         c.user = M.User.by_username('test-user-1')
-        M.AuditLog.log_user('test activity user 1')
-        M.AuditLog.log_user('test activity user 2', user=M.User.by_username('test-user-2'))
+        h.auditlog_user('test activity user 1')
+        h.auditlog_user('test activity user 2', user=M.User.by_username('test-user-2'))
         r = self.app.get('/nf/admin/users')
         assert_not_in('test activity', r)
         r = self.app.get('/nf/admin/users?username=admin1')


[34/43] git commit: [#7656] ticket:654 Updated search test

Posted by je...@apache.org.
[#7656] ticket:654 Updated search test


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

Branch: refs/heads/je/42cc_7656
Commit: 72c54da386d5a9339c257e4e2aee6fdae3e64592
Parents: 209e68e
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Sun Sep 14 20:17:08 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:58 2014 +0300

----------------------------------------------------------------------
 Allura/allura/tests/unit/test_solr.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/72c54da3/Allura/allura/tests/unit/test_solr.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_solr.py b/Allura/allura/tests/unit/test_solr.py
index dfe71c7..3d5317c 100644
--- a/Allura/allura/tests/unit/test_solr.py
+++ b/Allura/allura/tests/unit/test_solr.py
@@ -98,7 +98,7 @@ class TestSolr(unittest.TestCase):
         fq = ['type_s:Project']
         site_admin_search(Project, 'test', 'shortname', rows=25)
         search.assert_called_once_with(
-            'shortname_s:"test"', fq=fq, ignore_errors=False, rows=25)
+            'shortname_s:test', fq=fq, ignore_errors=False, rows=25)
 
         search.reset_mock()
         site_admin_search(Project, 'shortname:test || shortname:test2', '__custom__')
@@ -109,7 +109,7 @@ class TestSolr(unittest.TestCase):
         search.reset_mock()
         site_admin_search(User, 'test-user', 'username', rows=25)
         search.assert_called_once_with(
-            'username_s:"test-user"', fq=fq, ignore_errors=False, rows=25)
+            'username_s:test-user', fq=fq, ignore_errors=False, rows=25)
 
         search.reset_mock()
         site_admin_search(User, 'username:admin1 || username:root', '__custom__')


[02/43] git commit: [#7628] ticket:646 Remove duplicates from command

Posted by je...@apache.org.
[#7628] ticket:646 Remove duplicates from command


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

Branch: refs/heads/je/42cc_7656
Commit: da026b8388e023aeb283ec99aff03d198db0a99f
Parents: 862c725
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Sep 3 13:20:16 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Wed Sep 3 13:20:16 2014 +0300

----------------------------------------------------------------------
 .../allura/command/create_trove_categories.py   | 69 --------------------
 1 file changed, 69 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/da026b83/Allura/allura/command/create_trove_categories.py
----------------------------------------------------------------------
diff --git a/Allura/allura/command/create_trove_categories.py b/Allura/allura/command/create_trove_categories.py
index 0501f49..2f2fb9f 100644
--- a/Allura/allura/command/create_trove_categories.py
+++ b/Allura/allura/command/create_trove_categories.py
@@ -40,7 +40,6 @@ class CreateTroveCategoriesCommand(base.Command):
     # To add new migration append it's name to following list,
     # and create method m__<migration_name>
     migrations = [
-        'add_agpl_and_lppl',
         'sync',
         'set_parent_only',
         'add_license',
@@ -1458,68 +1457,6 @@ class CreateTroveCategoriesCommand(base.Command):
             getattr(self, 'm__' + name)()
             session(M.TroveCategory).flush()
 
-    def m__add_agpl_and_lppl(self):
-        M.TroveCategory(trove_cat_id=670,
-                        trove_parent_id=14,
-                        shortname="agpl",
-                        fullname="Affero GNU Public License",
-                        fullpath="License :: OSI-Approved Open Source :: Affero GNU Public License")
-        M.TroveCategory(trove_cat_id=862,
-                        trove_parent_id=14,
-                        shortname="lppl",
-                        fullname="LaTeX Project Public License",
-                        fullpath="License :: OSI-Approved Open Source :: LaTeX Project Public License")
-        M.TroveCategory(trove_cat_id=655,
-                        trove_parent_id=432,
-                        shortname="win64",
-                        fullname="64-bit MS Windows",
-                        fullpath="Operating System :: Grouping and Descriptive Categories :: 64-bit MS Windows")
-        M.TroveCategory(trove_cat_id=657,
-                        trove_parent_id=418,
-                        shortname="vista",
-                        fullname="Vista",
-                        fullpath="Operating System :: Modern (Vendor-Supported) Desktop Operating Systems :: Vista")
-        M.TroveCategory(trove_cat_id=851,
-                        trove_parent_id=418,
-                        shortname="win7",
-                        fullname="Windows 7",
-                        fullpath="Operating System :: Modern (Vendor-Supported) Desktop Operating Systems :: Windows 7")
-        M.TroveCategory(trove_cat_id=728,
-                        trove_parent_id=315,
-                        shortname="android",
-                        fullname="Android",
-                        fullpath="Operating System :: Handheld/Embedded Operating Systems :: Android")
-        M.TroveCategory(trove_cat_id=780,
-                        trove_parent_id=315,
-                        shortname="ios",
-                        fullname="Apple iPhone",
-                        fullpath="Operating System :: Handheld/Embedded Operating Systems :: Apple iPhone")
-        M.TroveCategory(trove_cat_id=863,
-                        trove_parent_id=534,
-                        shortname="architects",
-                        fullname="Architects",
-                        fullpath="Intended Audience :: by End-User Class :: Architects")
-        M.TroveCategory(trove_cat_id=864,
-                        trove_parent_id=534,
-                        shortname="auditors",
-                        fullname="Auditors",
-                        fullpath="Intended Audience :: by End-User Class :: Auditors")
-        M.TroveCategory(trove_cat_id=865,
-                        trove_parent_id=534,
-                        shortname="testers",
-                        fullname="Testers",
-                        fullpath="Intended Audience :: by End-User Class :: Testers")
-        M.TroveCategory(trove_cat_id=866,
-                        trove_parent_id=534,
-                        shortname="secpros",
-                        fullname="Security Professionals",
-                        fullpath="Intended Audience :: by End-User Class :: Security Professionals")
-        M.TroveCategory(trove_cat_id=867,
-                        trove_parent_id=535,
-                        shortname="secindustry",
-                        fullname="Security",
-                        fullpath="Intended Audience :: by Industry or Sector :: Security")
-
     def m__sync(self):
         self.create_trove_cat(
             (639, 14, "cpal", "Common Public Attribution License 1.0 (CPAL)",
@@ -1605,12 +1542,6 @@ class CreateTroveCategoriesCommand(base.Command):
             (678, 14, "boostlicense", "Boost Software License (BSL1.0)",
              "License :: OSI-Approved Open Source :: Boost Software License (BSL1.0)"))
         self.create_trove_cat(
-            (679, 14, "gplv3", "GNU General Public License version 3.0 (GPLv3)",
-             "License :: OSI-Approved Open Source :: GNU General Public License version 3.0 (GPLv3)"))
-        self.create_trove_cat(
-            (680, 14, "lgplv3", "GNU Library or ""Lesser"" General Public License version 3.0 (LGPLv3)",
-             "License :: OSI-Approved Open Source :: GNU Library or ""Lesser"" General Public License version 3.0 (LGPLv3)"))
-        self.create_trove_cat(
             (681, 14, "isclicense", "ISC License", "License :: OSI-Approved Open Source :: ISC License"))
         self.create_trove_cat((682, 14, "multicslicense", "Multics License",
                               "License :: OSI-Approved Open Source :: Multics License"))


[21/43] git commit: [#7589] ticket:622 Make User indexable

Posted by je...@apache.org.
[#7589] ticket:622 Make User indexable


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

Branch: refs/heads/je/42cc_7656
Commit: 01cd81f07cc254d599ba55de57139ed9f8e64bea
Parents: ceb0d22
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon Aug 4 14:16:46 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:56 2014 +0300

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py |  8 ++++++++
 Allura/allura/model/auth.py | 38 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 44 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/01cd81f0/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 8537f63..ccdf62c 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -284,6 +284,10 @@ class AuthenticationProvider(object):
             return True
         return False
 
+    def index_user(self, user):
+        """Put here additional fields for user index in SOLR."""
+        return {}
+
 
 class LocalAuthenticationProvider(AuthenticationProvider):
 
@@ -374,6 +378,10 @@ class LocalAuthenticationProvider(AuthenticationProvider):
             d = datetime.utcfromtimestamp(calendar.timegm(d.utctimetuple()))
         return d
 
+    def index_user(self, user):
+        fields = super(LocalAuthenticationProvider, self).index_user(user)
+        return dict(user_registration_date_dt=self.user_registration_date(user), **fields)
+
 
 def ldap_conn(who=None, cred=None):
     '''

http://git-wip-us.apache.org/repos/asf/allura/blob/01cd81f0/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index b7ea34b..fb59d0e 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -46,6 +46,7 @@ import allura.tasks.mail_tasks
 from allura.lib import helpers as h
 from allura.lib import plugin
 from allura.lib.decorators import memoize
+from allura.lib.search import SearchIndexable
 
 from .session import main_orm_session, main_doc_session
 from .session import project_orm_session
@@ -210,7 +211,7 @@ class FieldPropertyDisplayName(FieldProperty):
         return display_name
 
 
-class User(MappedClass, ActivityNode, ActivityObject):
+class User(MappedClass, ActivityNode, ActivityObject, SearchIndexable):
     SALT_LEN = 8
 
     class __mongometa__:
@@ -219,6 +220,8 @@ class User(MappedClass, ActivityNode, ActivityObject):
         indexes = ['tool_data.sfx.userid', 'tool_data.AuthPasswordReset.hash']
         unique_indexes = ['username']
 
+    type_s = 'User'
+
     _id = FieldProperty(S.ObjectId)
     sfx_userid = FieldProperty(S.Deprecated)
     username = FieldProperty(str)
@@ -227,7 +230,7 @@ class User(MappedClass, ActivityNode, ActivityObject):
     last_password_updated = FieldProperty(datetime)
     projects = FieldProperty(S.Deprecated)
     # full mount point: prefs dict
-    tool_preferences = FieldProperty({str: {str: None}})
+    tool_preferences = FieldProperty(S.Deprecated)
     tool_data = FieldProperty({str: {str: None}})  # entry point: prefs dict
     disabled = FieldProperty(bool, if_missing=False)
 
@@ -280,6 +283,37 @@ class User(MappedClass, ActivityNode, ActivityObject):
         session_ip=str,
         session_ua=str))
 
+    def index(self):
+        provider = plugin.AuthenticationProvider.get(None)  # no need in request here
+        localization = '%s/%s' % (
+            self.get_pref('localization')['country'],
+            self.get_pref('localization')['city'])
+        fields = dict(
+            id=self.index_id(),
+            title='User %s' % self.username,
+            type_s=self.type_s,
+            username_s=self.username,
+            email_addresses=self.email_addresses,
+            last_password_updated_dt=self.last_password_updated,
+            disabled_b=self.disabled,
+            results_per_page_i=self.get_pref('results_per_page'),
+            email_address_s=self.get_pref('email_address'),
+            email_format_s=self.get_pref('email_format'),
+            disable_user_messages_b=self.get_pref('disable_user_messages'),
+            display_name_s=self.get_pref('display_name'),
+            sex_s=self.get_pref('sex'),
+            birthday_dt=self.get_pref('birthday'),
+            localization_s=localization,
+            timezone_s=self.get_pref('timezone'),
+            socialnetworks=self.get_pref('socialnetworks'),
+            telnumbers=self.get_pref('telnumbers'),
+            skypeaccount_s=self.get_pref('skypeaccount'),
+            webpages=self.get_pref('webpages'),
+            skills=self.get_skills(),
+            last_access=self.last_access,
+        )
+        return dict(provider.index_user(self), **fields)
+
     def track_login(self, req):
         user_ip = req.headers.get('X_FORWARDED_FOR', req.remote_addr)
         user_agent = req.headers.get('User-Agent')


[26/43] git commit: [#7589] ticket:622 Test for User.index()

Posted by je...@apache.org.
[#7589] ticket:622 Test for User.index()


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

Branch: refs/heads/je/42cc_7656
Commit: 596ec0ff4ae815b848a4bc17a25c61bbdd220a84
Parents: 54885ba
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon Aug 4 15:44:08 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:57 2014 +0300

----------------------------------------------------------------------
 Allura/allura/tests/model/test_auth.py | 36 +++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/596ec0ff/Allura/allura/tests/model/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_auth.py b/Allura/allura/tests/model/test_auth.py
index 9c5a74c..4660510 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -277,3 +277,39 @@ def test_user_track_active():
     c.user = M.User.by_username(c.user.username)
     assert_equal(c.user.last_access['session_ip'], 'new addr')
     assert_equal(c.user.last_access['session_ua'], 'new browser')
+
+
+@with_setup(setUp)
+def test_user_index():
+    c.user.email_addresses = ['email1', 'email2']
+    c.user.set_pref('email_address', 'email2')
+    idx = c.user.index()
+    assert_equal(idx['id'], c.user.index_id())
+    assert_equal(idx['title'], 'User test-admin')
+    assert_equal(idx['type_s'], 'User')
+    assert_equal(idx['username_s'], 'test-admin')
+    assert_equal(idx['email_addresses_t'], 'email1 email2')
+    assert_equal(idx['email_address_s'], 'email2')
+    assert_in('last_password_updated_dt', idx)
+    assert_equal(idx['disabled_b'], False)
+    assert_in('results_per_page_i', idx)
+    assert_in('email_format_s', idx)
+    assert_in('disable_user_messages_b', idx)
+    assert_equal(idx['display_name_s'], 'Test Admin')
+    assert_equal(idx['sex_s'], 'Unknown')
+    assert_in('birthdate_dt', idx)
+    assert_in('localization_s', idx)
+    assert_in('timezone_s', idx)
+    assert_in('socialnetworks_t', idx)
+    assert_in('telnumbers_t', idx)
+    assert_in('skypeaccount_s', idx)
+    assert_in('webpages_t', idx)
+    assert_in('skills_t', idx)
+    assert_in('last_access_login_date_dt', idx)
+    assert_in('last_access_login_ip_s', idx)
+    assert_in('last_access_login_ua_t', idx)
+    assert_in('last_access_session_date_dt', idx)
+    assert_in('last_access_session_ip_s', idx)
+    assert_in('last_access_session_ua_t', idx)
+    # provided bby auth provider
+    assert_in('user_registration_date_dt', idx)


[22/43] git commit: [#7656] ticket:648 Get rid of specific search functions, which aren't used now

Posted by je...@apache.org.
[#7656] ticket:648 Get rid of specific search functions, which aren't used now


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

Branch: refs/heads/je/42cc_7656
Commit: dbad6b5a122c25b9b243901d88dfcac01a5329ba
Parents: fe13d6e
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 14:10:44 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:57 2014 +0300

----------------------------------------------------------------------
 Allura/allura/lib/search.py | 10 ----------
 1 file changed, 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/dbad6b5a/Allura/allura/lib/search.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/search.py b/Allura/allura/lib/search.py
index f4f177a..1c3ba8a 100644
--- a/Allura/allura/lib/search.py
+++ b/Allura/allura/lib/search.py
@@ -180,8 +180,6 @@ def search_artifact(atype, q, history=False, rows=10, short_timeout=False, filte
 def site_admin_search(model, q, field, **kw):
     """Performs SOLR search for a given model.
 
-    Probably you should not use it directly. Use one of the specific functions below.
-
     Raises SearchError if SOLR returns an error.
     """
     # first, grab a object and get the fields that it indexes
@@ -198,14 +196,6 @@ def site_admin_search(model, q, field, **kw):
     fq = [u'type_s:%s' % model.type_s]
     return search(q, fq=fq, ignore_errors=False, **kw)
 
-def search_projects(q, field, **kw):
-    from allura.model import Project
-    return site_admin_search(Project, q, field, **kw)
-
-def search_users(q, field, **kw):
-    from allura.model import User
-    return site_admin_search(User, q, field, **kw)
-
 
 def search_app(q='', fq=None, app=True, **kw):
     """Helper for app/project search.


[17/43] git commit: [#7688] Use username instead of userid in session. Handle expired password after logging in.

Posted by je...@apache.org.
[#7688] Use username instead of userid in session. Handle expired
password after logging in.


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

Branch: refs/heads/je/42cc_7656
Commit: a96d81b77fb493e831ba56b34c34fe6f9d492d8a
Parents: 67355b5
Author: Alexander Luberg <al...@slashdotmedia.com>
Authored: Fri Aug 22 13:36:56 2014 +0000
Committer: Alexander Luberg <do...@users.sourceforge.net>
Committed: Tue Sep 16 22:41:31 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py               | 24 ++++++++++++++++----
 .../allura/controllers/basetest_project_root.py |  2 +-
 Allura/allura/lib/custom_middleware.py          |  4 ++--
 Allura/allura/lib/plugin.py                     | 14 ++++++++----
 Allura/allura/lib/widgets/auth_widgets.py       |  3 +--
 Allura/allura/tests/functional/test_auth.py     |  7 +++---
 .../tests/functional/test_neighborhood.py       |  6 +++--
 7 files changed, 41 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/a96d81b7/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 61f068e..1f8c8aa 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -270,12 +270,21 @@ class AuthController(BaseController):
     @require_post()
     @validate(F.login_form, error_handler=index)
     def do_login(self, return_to=None, **kw):
+        location = '/'
+
+        if session.get('expired-username'):
+            if return_to and return_to not in plugin.AuthenticationProvider.pwd_expired_allowed_urls:
+                location = tg.url(plugin.AuthenticationProvider.pwd_expired_allowed_urls[0], dict(return_to=return_to))
+            else:
+                location = tg.url(plugin.AuthenticationProvider.pwd_expired_allowed_urls[0])
+
         if return_to and return_to != request.url:
             rt_host = urlparse(urljoin(config['base_url'], return_to)).netloc
             base_host = urlparse(config['base_url']).netloc
             if rt_host == base_host:
-                redirect(return_to)
-        redirect('/')
+                location = return_to
+
+        redirect(location)
 
     @expose(content_type='text/plain')
     def refresh_repo(self, *repo_path):
@@ -368,6 +377,7 @@ class AuthController(BaseController):
     @expose('jinja:allura:templates/pwd_expired.html')
     @without_trailing_slash
     def pwd_expired(self, **kw):
+        require_authenticated()
         c.form = F.password_change_form
         return {'return_to': kw.get('return_to')}
 
@@ -376,16 +386,22 @@ class AuthController(BaseController):
     @without_trailing_slash
     @validate(V.NullValidator(), error_handler=pwd_expired)
     def pwd_expired_change(self, **kw):
+        require_authenticated()
         return_to = kw.get('return_to')
         kw = F.password_change_form.to_python(kw, None)
         ap = plugin.AuthenticationProvider.get(request)
         try:
-            ap.set_password(c.user, kw['oldpw'], kw['pw'])
+            expired_username = session.get('expired-username')
+            expired_user = M.User.query.get(username=expired_username) if expired_username else None
+            ap.set_password(expired_user or c.user, kw['oldpw'], kw['pw'])
         except wexc.HTTPUnauthorized:
             flash('Incorrect password', 'error')
             redirect(tg.url('/auth/pwd_expired', dict(return_to=return_to)))
         flash('Password changed')
-        del session['pwd-expired']
+        session.pop('pwd-expired', None)
+        session['username'] = session.get('expired-username')
+        session.pop('expired-username', None)
+
         session.save()
         h.auditlog_user('Password reset (via expiration process)')
         if return_to and return_to != request.url:

http://git-wip-us.apache.org/repos/asf/allura/blob/a96d81b7/Allura/allura/controllers/basetest_project_root.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/basetest_project_root.py b/Allura/allura/controllers/basetest_project_root.py
index 60f64bc..91c16da 100644
--- a/Allura/allura/controllers/basetest_project_root.py
+++ b/Allura/allura/controllers/basetest_project_root.py
@@ -126,7 +126,7 @@ class BasetestProjectRootController(WsgiDispatchController, ProjectController):
         user = auth.by_username(environ.get('username', 'test-admin'))
         if not user:
             user = M.User.anonymous()
-        environ['beaker.session']['userid'] = user._id
+        environ['beaker.session']['username'] = user.username
         c.user = auth.authenticate_request()
         return WsgiDispatchController.__call__(self, environ, start_response)
 

http://git-wip-us.apache.org/repos/asf/allura/blob/a96d81b7/Allura/allura/lib/custom_middleware.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/custom_middleware.py b/Allura/allura/lib/custom_middleware.py
index 45c2141..981c602 100644
--- a/Allura/allura/lib/custom_middleware.py
+++ b/Allura/allura/lib/custom_middleware.py
@@ -296,9 +296,9 @@ class RememberLoginMiddleware(object):
 
         def remember_login_start_response(status, headers, exc_info=None):
             session = environ['beaker.session']
-            userid = session.get('userid')
+            username = session.get('username')
             login_expires = session.get('login_expires')
-            if userid and login_expires is not None:
+            if username and login_expires is not None:
                 if login_expires is True:
                     # no specific expiration, lasts for duration of "browser session"
                     session.cookie[session.key]['expires'] = ''

http://git-wip-us.apache.org/repos/asf/allura/blob/a96d81b7/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 14a2328..8537f63 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -98,12 +98,15 @@ class AuthenticationProvider(object):
 
     def authenticate_request(self):
         from allura import model as M
-        user = M.User.query.get(_id=self.session.get('userid', None))
+        username = self.session.get('username') or self.session.get('expired-username')
+        user = M.User.query.get(username=username)
+
         if user is None:
             return M.User.anonymous()
         if user.disabled:
             self.logout()
             return M.User.anonymous()
+
         if self.session.get('pwd-expired') and request.path not in self.pwd_expired_allowed_urls:
             if self.request.environ['REQUEST_METHOD'] == 'GET':
                 return_to = self.request.environ['PATH_INFO']
@@ -138,11 +141,13 @@ class AuthenticationProvider(object):
         try:
             if user is None:
                 user = self._login()
-            self.session['userid'] = user._id
             if self.is_password_expired(user):
                 self.session['pwd-expired'] = True
-                from allura.model import AuditLog
+                self.session['expired-username'] = user.username
                 h.auditlog_user('Password expired', user=user)
+            else:
+                self.session['username'] = user.username
+
             if 'rememberme' in self.request.params:
                 remember_for = int(config.get('auth.remember_for', 365))
                 self.session['login_expires'] = datetime.utcnow() + timedelta(remember_for)
@@ -158,8 +163,8 @@ class AuthenticationProvider(object):
             raise
 
     def logout(self):
-        self.session['userid'] = None
         self.session['login_expires'] = None
+        self.session['username'] = None
         self.session['pwd-expired'] = False
         self.session.save()
 
@@ -305,7 +310,6 @@ class LocalAuthenticationProvider(AuthenticationProvider):
     def disable_user(self, user):
         user.disabled = True
         session(user).flush(user)
-        from allura.model import AuditLog
         h.auditlog_user('Account disabled', user=user)
 
     def validate_password(self, user, password):

http://git-wip-us.apache.org/repos/asf/allura/blob/a96d81b7/Allura/allura/lib/widgets/auth_widgets.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/auth_widgets.py b/Allura/allura/lib/widgets/auth_widgets.py
index 2041e4d..33444f9 100644
--- a/Allura/allura/lib/widgets/auth_widgets.py
+++ b/Allura/allura/lib/widgets/auth_widgets.py
@@ -58,8 +58,7 @@ class LoginForm(ForgeForm):
     @validator
     def validate(self, value, state=None):
         try:
-            value['username'] = plugin.AuthenticationProvider.get(
-                request).login()
+            value['username'] = plugin.AuthenticationProvider.get(request).login()
         except exc.HTTPUnauthorized:
             msg = 'Invalid login'
             raise Invalid(

http://git-wip-us.apache.org/repos/asf/allura/blob/a96d81b7/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 9ab122f..39f5794 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -92,12 +92,12 @@ class TestAuth(TestController):
         assert_equal(user.last_access['login_ua'], 'browser')
 
     def test_rememberme(self):
-        userid = M.User.query.get(username='test-user')._id
+        username = M.User.query.get(username='test-user').username
 
         # Login as test-user with remember me checkbox off
         r = self.app.post('/auth/do_login', params=dict(
             username='test-user', password='foo'))
-        assert_equal(r.session['userid'], userid)
+        assert_equal(r.session['username'], username)
         assert_equal(r.session['login_expires'], True)
 
         for header, contents in r.headerlist:
@@ -107,7 +107,7 @@ 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'))
-        assert_equal(r.session['userid'], userid)
+        assert_equal(r.session['username'], username)
         assert_not_equal(r.session['login_expires'], True)
 
         for header, contents in r.headerlist:
@@ -937,6 +937,7 @@ To reset your password on %s, please visit the following URL:
         ap = AP.get()
         ap.forgotten_password_process = False
         ap.authenticate_request()._id = user._id
+        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)

http://git-wip-us.apache.org/repos/asf/allura/blob/a96d81b7/Allura/allura/tests/functional/test_neighborhood.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_neighborhood.py b/Allura/allura/tests/functional/test_neighborhood.py
index b3ebd3c..332a60b 100644
--- a/Allura/allura/tests/functional/test_neighborhood.py
+++ b/Allura/allura/tests/functional/test_neighborhood.py
@@ -583,8 +583,10 @@ class TestNeighborhood(TestController):
                 private_project='on'),
             antispam=True,
             extra_environ=dict(username='root'))
-        flash_msg_cookie = urllib2.unquote(r.headers['Set-Cookie'])
-        assert 'Internal Error.' in flash_msg_cookie
+        cookies = r.headers.getall('Set-Cookie')
+        flash_msg_cookies = map(urllib2.unquote, cookies)
+
+        assert any('Internal Error' in cookie for cookie in flash_msg_cookies)
 
         proj = M.Project.query.get(
             shortname='myprivate1', neighborhood_id=neighborhood._id)


[27/43] git commit: [#7656] ticket:648 Refactor controller & template to reuse as much as we can

Posted by je...@apache.org.
[#7656] ticket:648 Refactor controller & template to reuse as much as we can


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

Branch: refs/heads/je/42cc_7656
Commit: fe13d6e68eae4c908974945aab60d84147a6f269
Parents: b1fcc9f
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 14:09:55 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:57 2014 +0300

----------------------------------------------------------------------
 Allura/allura/controllers/site_admin.py         | 74 ++++++++++++--------
 Allura/allura/templates/site_admin_search.html  | 49 +++++++++++++
 .../templates/site_admin_search_projects.html   | 74 --------------------
 .../site_admin_search_projects_results.html     | 27 +++++++
 .../templates/site_admin_search_users.html      | 25 -------
 .../site_admin_search_users_results.html        |  7 ++
 6 files changed, 126 insertions(+), 130 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/fe13d6e6/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index 5913411..b19b84b 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -290,41 +290,35 @@ class SiteAdminController(object):
             flash('Can not add comment "%s" for user %s' % (comment, user))
         redirect(request.referer)
 
-    @without_trailing_slash
-    @expose('jinja:allura:templates/site_admin_search_projects.html')
-    @validate(validators=dict(q=validators.UnicodeString(if_empty=None),
-                              limit=validators.Int(if_invalid=None),
-                              page=validators.Int(if_empty=0, if_invalid=0)))
-    def search_projects(self, q=None, f=None, page=0, limit=None, **kw):
-        fields = [('shortname', 'shortname'), ('name', 'full name')]
-        fields.extend(aslist(tg.config.get('search.project.additional_fields'), ','))
-        c.search_form = W.admin_search_form(fields)
+    def _search(self, model, fields, add_fields, q=None, f=None, page=0, limit=None, **kw):
+        all_fields = fields + [(fld, fld) for fld in add_fields]
+        c.search_form = W.admin_search_form(all_fields)
         c.page_list = W.page_list
         c.page_size = W.page_size
         count = 0
-        projects = []
+        objects = []
         limit, page, start = g.handle_paging(limit, page, default=25)
         if q:
-            match = search.search_projects(q, f, rows=limit, start=start)
+            match = search.site_admin_search(model, q, f, rows=limit, start=start)
             if match:
                 count = match.hits
-                projects = match.docs
-                pids = [bson.ObjectId(p['id'].split('#')[1]) for p in projects]
-                mongo_projects = {}
-                for p in M.Project.query.find({'_id': {'$in': pids}}):
-                    mongo_projects[str(p._id)] = p
-
-                for i in range(len(projects)):
-                    p = projects[i]
-                    _id = p['id'].split('#')[1]
-                    p['project'] = mongo_projects.get(_id)
-                # Some projects can be deleted, but still have index in solr, should skip those
-                projects = [p for p in projects if p.get('project')]
-
-        def convert_fields(p):
+                objects = match.docs
+                ids = [bson.ObjectId(obj['id'].split('#')[1]) for obj in objects]
+                mongo_objects = {}
+                for obj in model.query.find({'_id': {'$in': ids}}):
+                    mongo_objects[str(obj._id)] = obj
+
+                for i in range(len(objects)):
+                    obj = objects[i]
+                    _id = obj['id'].split('#')[1]
+                    obj['object'] = mongo_objects.get(_id)
+                # Some objects can be deleted, but still have index in solr, should skip those
+                objects = [obj for obj in objects if obj.get('object')]
+
+        def convert_fields(obj):
             # throw the type away (e.g. '_s' from 'url_s')
             result = {}
-            for k,v in p.iteritems():
+            for k,v in obj.iteritems():
                 name = k.rsplit('_', 1)
                 if len(name) == 2:
                     name = name[0]
@@ -336,21 +330,39 @@ class SiteAdminController(object):
         return {
             'q': q,
             'f': f,
-            'projects': map(convert_fields, projects),
+            'objects': map(convert_fields, objects),
             'count': count,
             'page': page,
             'limit': limit,
-            'additional_fields': aslist(config.get('search.project.additional_fields'), ','),
-            'provider': ProjectRegistrationProvider.get(),
+            'fields': fields,
+            'additional_fields': add_fields,
+            'type_s': model.type_s,
         }
 
     @without_trailing_slash
-    @expose('jinja:allura:templates/site_admin_search_users.html')
+    @expose('jinja:allura:templates/site_admin_search.html')
+    @validate(validators=dict(q=validators.UnicodeString(if_empty=None),
+                              limit=validators.Int(if_invalid=None),
+                              page=validators.Int(if_empty=0, if_invalid=0)))
+    def search_projects(self, q=None, f=None, page=0, limit=None, **kw):
+        fields = [('shortname', 'shortname'), ('name', 'full name')]
+        add_fields = aslist(tg.config.get('search.project.additional_fields'), ',')
+        r = self._search(M.Project, fields, add_fields, q, f, page, limit, **kw)
+        r['search_results_template'] = 'allura:templates/site_admin_search_projects_results.html'
+        r['provider'] = ProjectRegistrationProvider.get()
+        return r
+
+    @without_trailing_slash
+    @expose('jinja:allura:templates/site_admin_search.html')
     @validate(validators=dict(q=validators.UnicodeString(if_empty=None),
                               limit=validators.Int(if_invalid=None),
                               page=validators.Int(if_empty=0, if_invalid=0)))
     def search_users(self, q=None, f=None, page=0, limit=None, **kw):
-        return {}
+        fields = []
+        add_fields = aslist(tg.config.get('search.user.additional_fields'), ',')
+        r = self._search(M.User, fields, add_fields, q, f, page, limit, **kw)
+        r['search_results_template'] = 'allura:templates/site_admin_search_users_results.html'
+        return r
 
 
 class TaskManagerController(object):

http://git-wip-us.apache.org/repos/asf/allura/blob/fe13d6e6/Allura/allura/templates/site_admin_search.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search.html b/Allura/allura/templates/site_admin_search.html
new file mode 100644
index 0000000..685f65b
--- /dev/null
+++ b/Allura/allura/templates/site_admin_search.html
@@ -0,0 +1,49 @@
+{#-
+       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.
+-#}
+{% extends 'allura:templates/site_admin.html' %}
+
+{% block title %}Search {{ type_s }}s{% endblock %}
+{% block header %}Search {{ type_s }}s{% endblock %}
+
+{% block content %}
+  <div class="grid-19">
+    {{ c.search_form.display(q=q, f=f) }}
+  </div>
+
+  {% if objects %}
+    <table>
+      {% include search_results_template %}
+    </table>
+  {% endif %}
+
+  <div class="grid-19">
+    {{c.page_list.display(limit=limit, page=page, count=count)}}
+    {{c.page_size.display(limit=limit, page=page, count=count)}}
+  </div>
+{% endblock %}
+
+{% block extra_css %}
+<style>
+  table { clear: both; }
+  table th {
+    text-align: left;
+    padding: 5px 10px;
+  }
+</style>
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/allura/blob/fe13d6e6/Allura/allura/templates/site_admin_search_projects.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_projects.html b/Allura/allura/templates/site_admin_search_projects.html
deleted file mode 100644
index a6e6b02..0000000
--- a/Allura/allura/templates/site_admin_search_projects.html
+++ /dev/null
@@ -1,74 +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.
--#}
-{% extends 'allura:templates/site_admin.html' %}
-
-{% block title %}Search Projects{% endblock %}
-{% block header %}Search Projects{% endblock %}
-
-{% block content %}
-  <div class="grid-19">
-    {{ c.search_form.display(q=q, f=f) }}
-  </div>
-
-  {% if projects %}
-    <table>
-      <tr>
-        <th>Short name</th>
-        <th>Full name</th>
-        <th>Registered</th>
-        <th>Deleted?</th>
-        {% for field in additional_fields %}
-        <th>{{ field }}</th>
-        {% endfor %}
-        <th>Details</th>
-      </tr>
-    {% for p in projects %}
-      <tr>
-        <td><a href="{{ p['url'] }}">{{ p['shortname'] }}</a></td>
-        <td>{{ p['name'] }}</td>
-        <td>{{ h.ago_string(p['registration']) }}</td>
-        <td>{{ p['deleted'] }}</td>
-        {% for field in additional_fields %}
-        <td>{{ p[field] }}</td>
-        {% endfor %}
-        <td>
-          {% for url, label in provider.details_links(p['project']) %}
-            <a href="{{ url }}">{{ label }}</a><br>
-          {% endfor %}
-        </td>
-      </tr>
-    {% endfor %}
-    </table>
-  {% endif %}
-
-  <div class="grid-19">
-    {{c.page_list.display(limit=limit, page=page, count=count)}}
-    {{c.page_size.display(limit=limit, page=page, count=count)}}
-  </div>
-{% endblock %}
-
-{% block extra_css %}
-<style>
-  table { clear: both; }
-  table th {
-    text-align: left;
-    padding: 5px 10px;
-  }
-</style>
-{% endblock %}

http://git-wip-us.apache.org/repos/asf/allura/blob/fe13d6e6/Allura/allura/templates/site_admin_search_projects_results.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_projects_results.html b/Allura/allura/templates/site_admin_search_projects_results.html
new file mode 100644
index 0000000..622e9a6
--- /dev/null
+++ b/Allura/allura/templates/site_admin_search_projects_results.html
@@ -0,0 +1,27 @@
+<tr>
+  <th>Short name</th>
+  <th>Full name</th>
+  <th>Registered</th>
+  <th>Deleted?</th>
+  {% for field in additional_fields %}
+  <th>{{ field }}</th>
+  {% endfor %}
+  <th>Details</th>
+</tr>
+
+{% for p in objects %}
+<tr>
+  <td><a href="{{ p['url'] }}">{{ p['shortname'] }}</a></td>
+  <td>{{ p['name'] }}</td>
+  <td>{{ h.ago_string(p['registration']) }}</td>
+  <td>{{ p['deleted'] }}</td>
+  {% for field in additional_fields %}
+  <td>{{ p[field] }}</td>
+  {% endfor %}
+  <td>
+    {% for url, label in provider.details_links(p['object']) %}
+      <a href="{{ url }}">{{ label }}</a><br>
+    {% endfor %}
+  </td>
+</tr>
+{% endfor %}

http://git-wip-us.apache.org/repos/asf/allura/blob/fe13d6e6/Allura/allura/templates/site_admin_search_users.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_users.html b/Allura/allura/templates/site_admin_search_users.html
deleted file mode 100644
index ec18e90..0000000
--- a/Allura/allura/templates/site_admin_search_users.html
+++ /dev/null
@@ -1,25 +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.
--#}
-{% extends 'allura:templates/site_admin.html' %}
-
-{% block title %}Search Users{% endblock %}
-{% block header %}Search Users{% endblock %}
-
-{% block content %}
-{% endblock %}

http://git-wip-us.apache.org/repos/asf/allura/blob/fe13d6e6/Allura/allura/templates/site_admin_search_users_results.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_users_results.html b/Allura/allura/templates/site_admin_search_users_results.html
new file mode 100644
index 0000000..b73c5c4
--- /dev/null
+++ b/Allura/allura/templates/site_admin_search_users_results.html
@@ -0,0 +1,7 @@
+<tr>
+</tr>
+
+{% for user in objects %}
+<tr>
+</tr>
+{% endfor %}


[20/43] git commit: [#7589] ticket:622 Tasks for indexing users

Posted by je...@apache.org.
[#7589] ticket:622 Tasks for indexing users


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

Branch: refs/heads/je/42cc_7656
Commit: 53d1cc91aec2e85819b8fa2b8f5c3507b1892ba9
Parents: 01cd81f
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon Aug 4 14:50:18 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:56 2014 +0300

----------------------------------------------------------------------
 Allura/allura/model/session.py     |  4 +++-
 Allura/allura/tasks/index_tasks.py | 12 ++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/53d1cc91/Allura/allura/model/session.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/session.py b/Allura/allura/model/session.py
index 8e0f551..eb1f4ba 100644
--- a/Allura/allura/model/session.py
+++ b/Allura/allura/model/session.py
@@ -68,7 +68,9 @@ class IndexerSessionExtension(ManagedSessionExtension):
 
     TASKS = {
         'allura.model.project.Project': {'add': index_tasks.add_projects,
-                                         'del': index_tasks.del_projects}
+                                         'del': index_tasks.del_projects},
+        'allura.model.auth.User': {'add': index_tasks.add_users,
+                                   'del': index_tasks.del_users},
     }
 
     def _objects_by_types(self, obj_list):

http://git-wip-us.apache.org/repos/asf/allura/blob/53d1cc91/Allura/allura/tasks/index_tasks.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tasks/index_tasks.py b/Allura/allura/tasks/index_tasks.py
index 3f02cef..c9e853d 100644
--- a/Allura/allura/tasks/index_tasks.py
+++ b/Allura/allura/tasks/index_tasks.py
@@ -57,6 +57,18 @@ def del_projects(project_solr_ids):
 
 
 @task
+def add_users(user_ids):
+    from allura.model import User
+    users = User.query.find(dict(_id={'$in': user_ids})).all()
+    __add_objects(users)
+
+
+@task
+def del_users(user_solr_ids):
+    __del_objects(user_solr_ids)
+
+
+@task
 def add_artifacts(ref_ids, update_solr=True, update_refs=True, solr_hosts=None):
     '''
     Add the referenced artifacts to SOLR and shortlinks.


[10/43] git commit: [#7677] update mail tasks to handle actual ObjectId in addr params

Posted by je...@apache.org.
[#7677] update mail tasks to handle actual ObjectId in addr params


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

Branch: refs/heads/je/42cc_7656
Commit: 01e009f33421ac9c6c92c1284bda2f0242267def
Parents: 505174a
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Sep 15 18:41:44 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Sep 15 22:13:20 2014 +0000

----------------------------------------------------------------------
 Allura/allura/tasks/mail_tasks.py | 14 ++++++++++----
 Allura/allura/tests/test_tasks.py | 14 ++++++++++++++
 2 files changed, 24 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/01e009f3/Allura/allura/tasks/mail_tasks.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tasks/mail_tasks.py b/Allura/allura/tasks/mail_tasks.py
index 4fce0d7..663c690 100644
--- a/Allura/allura/tasks/mail_tasks.py
+++ b/Allura/allura/tasks/mail_tasks.py
@@ -88,6 +88,9 @@ def sendmail(fromaddr, destinations, text, reply_to, subject,
     '''
     Send an email to the specified list of destinations with respect to the preferred email format specified by user.
     It is best for broadcast messages.
+
+    :param fromaddr: ObjectId or str(ObjectId) of user, or email address str
+
     '''
     from allura import model as M
     addrs_plain = []
@@ -95,7 +98,7 @@ def sendmail(fromaddr, destinations, text, reply_to, subject,
     addrs_multi = []
     if fromaddr is None:
         fromaddr = g.noreply
-    elif '@' not in fromaddr:
+    elif not isinstance(fromaddr, basestring) or '@' not in fromaddr:
         log.warning('Looking up user with fromaddr: %s', fromaddr)
         user = M.User.query.get(_id=ObjectId(fromaddr), disabled=False)
         if not user:
@@ -164,11 +167,15 @@ def sendsimplemail(
     '''
     Send a single mail to the specified address.
     It is best for single user notifications.
+
+    :param fromaddr: ObjectId or str(ObjectId) of user, or email address str
+    :param toaddr: ObjectId or str(ObjectId) of user, or email address str
+
     '''
     from allura import model as M
     if fromaddr is None:
         fromaddr = g.noreply
-    elif '@' not in fromaddr:
+    elif not isinstance(fromaddr, basestring) or '@' not in fromaddr:
         log.warning('Looking up user with fromaddr: %s', fromaddr)
         user = M.User.query.get(_id=ObjectId(fromaddr), disabled=False)
         if not user:
@@ -177,8 +184,7 @@ def sendsimplemail(
         else:
             fromaddr = user.email_address_header()
 
-
-    if '@' not in toaddr:
+    if not isinstance(toaddr, basestring) or '@' not in toaddr:
         log.warning('Looking up user with toaddr: %s', toaddr)
         user = M.User.query.get(_id=ObjectId(toaddr), disabled=False)
         if not user:

http://git-wip-us.apache.org/repos/asf/allura/blob/01e009f3/Allura/allura/tests/test_tasks.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_tasks.py b/Allura/allura/tests/test_tasks.py
index 5dd70b6..13d5c17 100644
--- a/Allura/allura/tests/test_tasks.py
+++ b/Allura/allura/tests/test_tasks.py
@@ -388,6 +388,20 @@ class TestMailTasks(unittest.TestCase):
             assert_in('CC: someone@example.com', body)
             assert_in('someone@example.com', rcpts)
 
+    def test_fromaddr_objectid_not_str(self):
+        c.user = M.User.by_username('test-admin')
+        with mock.patch.object(mail_tasks.smtp_client, '_client') as _client:
+            mail_tasks.sendsimplemail(
+                fromaddr=c.user._id,
+                toaddr='test@mail.com',
+                text=u'This is a test',
+                reply_to=g.noreply,
+                subject=u'Test subject',
+                message_id=h.gen_message_id())
+            assert_equal(_client.sendmail.call_count, 1)
+            return_path, rcpts, body = _client.sendmail.call_args[0]
+            assert_in('From: "Test Admin" <te...@users.localhost>', body)
+
     @td.with_wiki
     def test_receive_email_ok(self):
         c.user = M.User.by_username('test-admin')


[05/43] git commit: [#7628] ticket:646 Fix agpl duplicates discovery

Posted by je...@apache.org.
[#7628] ticket:646 Fix agpl duplicates discovery


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

Branch: refs/heads/je/42cc_7656
Commit: e15c415761bb09c7ee12758f578815dd26ca119a
Parents: 64efd59
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Sep 3 16:42:08 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Wed Sep 3 16:42:08 2014 +0300

----------------------------------------------------------------------
 Allura/allura/scripts/remove_duplicate_troves.py | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e15c4157/Allura/allura/scripts/remove_duplicate_troves.py
----------------------------------------------------------------------
diff --git a/Allura/allura/scripts/remove_duplicate_troves.py b/Allura/allura/scripts/remove_duplicate_troves.py
index 5249498..7866b2e 100644
--- a/Allura/allura/scripts/remove_duplicate_troves.py
+++ b/Allura/allura/scripts/remove_duplicate_troves.py
@@ -82,10 +82,13 @@ class RemoveDuplicateTroves(ScriptTask):
 
     @classmethod
     def _find_duplicates(cls):
-        # agpl is present twice with different cat_id
-        # (update in creation command updated only one of duplicates),
-        # so code below will not catch it
-        dups = M.TroveCategory.query.find({'shortname': 'agpl'}).all()
+        dups = []
+        agpl = M.TroveCategory.query.find({'shortname': 'agpl'}).all()
+        if len(agpl) > 1:
+            # agpl is present twice with different cat_id
+            # (update in creation command updated only one of duplicates),
+            # so code below will not catch it
+            dups.extend(agpl)
         for cat in M.TroveCategory.query.find():
             if M.TroveCategory.query.find({
                 'shortname': cat.shortname,


[15/43] git commit: [#4905] ticket:634 removed unused pieces of code

Posted by je...@apache.org.
[#4905] ticket:634 removed unused pieces of code


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

Branch: refs/heads/je/42cc_7656
Commit: 263b6d43bb9c2c802af6286da64ac41389184889
Parents: 3699628
Author: discort <le...@bk.ru>
Authored: Mon Aug 25 16:31:28 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Sep 16 15:33:36 2014 +0000

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


http://git-wip-us.apache.org/repos/asf/allura/blob/263b6d43/ForgeWiki/forgewiki/templates/wiki/page_view.html
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/templates/wiki/page_view.html b/ForgeWiki/forgewiki/templates/wiki/page_view.html
index 61407c4..4e19b2f 100644
--- a/ForgeWiki/forgewiki/templates/wiki/page_view.html
+++ b/ForgeWiki/forgewiki/templates/wiki/page_view.html
@@ -62,7 +62,7 @@
 
   {% endif %}
   {% if c.user and c.user != c.user.anonymous() %}
-    {{c.subscribe_form.display(value=page_subscribed, tool_subscribed=tool_subscribed, action='subscribe', style='icon')}}
+    {{c.subscribe_form.display(value=page_subscribed, action='subscribe', style='icon')}}
     {{c.wiki_subscribe_form.display(value=subscribed, action='wiki_subscribe', style='icon')}}
   {% endif %}
 	<a href="feed" title="RSS"><b data-icon="{{g.icons['feed'].char}}" class="ico {{g.icons['feed'].css}}" title="Feed"></b></a>

http://git-wip-us.apache.org/repos/asf/allura/blob/263b6d43/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index c6abf88..615af76 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -521,7 +521,6 @@ class PageController(BaseController, FeedController):
         return dict(
             page=page,
             cur=cur, prev=prev, next=next,
-            tool_subscribed=tool_subscribed,
             page_subscribed=subscribed,
             subscribed=M.Mailbox.subscribed(),
             hide_left_bar=hide_left_bar, show_meta=c.app.show_right_bar,


[11/43] git commit: [#4905] ticket:634 added new subscribe menu for all wiki pages

Posted by je...@apache.org.
[#4905] ticket:634 added new subscribe menu for all wiki pages


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

Branch: refs/heads/je/42cc_7656
Commit: 369962867b663fc17799c42381231c5851d95751
Parents: fab7d22
Author: discort <le...@bk.ru>
Authored: Fri Aug 22 00:44:41 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Sep 16 15:33:35 2014 +0000

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


http://git-wip-us.apache.org/repos/asf/allura/blob/36996286/ForgeWiki/forgewiki/templates/wiki/page_view.html
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/templates/wiki/page_view.html b/ForgeWiki/forgewiki/templates/wiki/page_view.html
index c076f57..61407c4 100644
--- a/ForgeWiki/forgewiki/templates/wiki/page_view.html
+++ b/ForgeWiki/forgewiki/templates/wiki/page_view.html
@@ -62,7 +62,8 @@
 
   {% endif %}
   {% if c.user and c.user != c.user.anonymous() %}
-    {{c.subscribe_form.display(value=subscribed, action='subscribe', style='icon')}}
+    {{c.subscribe_form.display(value=page_subscribed, tool_subscribed=tool_subscribed, action='subscribe', style='icon')}}
+    {{c.wiki_subscribe_form.display(value=subscribed, action='wiki_subscribe', style='icon')}}
   {% endif %}
 	<a href="feed" title="RSS"><b data-icon="{{g.icons['feed'].char}}" class="ico {{g.icons['feed'].css}}" title="Feed"></b></a>
   <a href="../search" title="Search"><b data-icon="{{g.icons['search'].char}}" class="ico {{g.icons['search'].css}}" title="Search"></b></a>

http://git-wip-us.apache.org/repos/asf/allura/blob/36996286/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index 8c46f00..c6abf88 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -69,6 +69,7 @@ class W:
     attachment_list = ffw.AttachmentList()
     subscribe_form = SubscribeForm()
     page_subscribe_form = SubscribeForm(thing='page')
+    wiki_subscribe_form = SubscribeForm(thing='wiki')
     page_list = ffw.PageList()
     page_size = ffw.PageSize()
     search_results = SearchResults()
@@ -494,6 +495,7 @@ class PageController(BaseController, FeedController):
         c.thread = W.thread
         c.attachment_list = W.attachment_list
         c.subscribe_form = W.page_subscribe_form
+        c.wiki_subscribe_form = W.wiki_subscribe_form
         post_count = self.page.discussion_thread.post_count
         limit, pagenum = h.paging_sanitizer(limit, page, post_count)
         page = self.get_version(version)
@@ -511,10 +513,17 @@ class PageController(BaseController, FeedController):
             prev = None
         next = cur + 1
         hide_left_bar = not (c.app.show_left_bar)
+        tool_subscribed = M.Mailbox.subscribed()
+        if tool_subscribed:
+            subscribed = False
+        else:
+            subscribed = M.Mailbox.subscribed(artifact=self.page)
         return dict(
             page=page,
             cur=cur, prev=prev, next=next,
-            subscribed=M.Mailbox.subscribed(artifact=self.page),
+            tool_subscribed=tool_subscribed,
+            page_subscribed=subscribed,
+            subscribed=M.Mailbox.subscribed(),
             hide_left_bar=hide_left_bar, show_meta=c.app.show_right_bar,
             pagenum=pagenum, limit=limit, count=post_count)
 
@@ -701,6 +710,15 @@ class PageController(BaseController, FeedController):
             self.page.unsubscribe()
         redirect(request.referer)
 
+    @expose()
+    @validate(W.subscribe_form)
+    def wiki_subscribe(self, subscribe=None, unsubscribe=None):
+        if subscribe:
+            M.Mailbox.subscribe(type='direct')
+        elif unsubscribe:
+            M.Mailbox.unsubscribe()
+        redirect(request.referer)
+
 
 class WikiAttachmentController(ac.AttachmentController):
     AttachmentClass = WM.WikiAttachment


[03/43] git commit: [#7628] ticket:646 Command to remove duplicate trove categories

Posted by je...@apache.org.
[#7628] ticket:646 Command to remove duplicate trove categories


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

Branch: refs/heads/je/42cc_7656
Commit: 487de12fbded799c03b92bfb7e525c0233707418
Parents: da026b8
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Sep 3 16:14:43 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Wed Sep 3 16:14:43 2014 +0300

----------------------------------------------------------------------
 .../allura/scripts/remove_duplicate_troves.py   | 103 +++++++++++++++++++
 1 file changed, 103 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/487de12f/Allura/allura/scripts/remove_duplicate_troves.py
----------------------------------------------------------------------
diff --git a/Allura/allura/scripts/remove_duplicate_troves.py b/Allura/allura/scripts/remove_duplicate_troves.py
new file mode 100644
index 0000000..aab0bf1
--- /dev/null
+++ b/Allura/allura/scripts/remove_duplicate_troves.py
@@ -0,0 +1,103 @@
+#       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
+from itertools import groupby
+from collections import defaultdict
+from operator import itemgetter
+
+from ming.odm import ThreadLocalORMSession
+
+from allura.scripts import ScriptTask
+from allura import model as M
+
+
+log = logging.getLogger(__name__)
+
+
+class RemoveDuplicateTroves(ScriptTask):
+
+    @classmethod
+    def execute(cls, options):
+        duplicates = cls._find_duplicates()
+        log.info('Found %s duplicate categories: %s', len(duplicates), duplicates.keys())
+        for name, dups in duplicates.iteritems():
+            projects_with_category = {}
+            for dup in dups:
+                projects = cls._projects_with_category(dup._id)
+                projects_with_category[dup._id] = projects
+            log.info('Following projects are using category %s:', name)
+            for _id, ps in projects_with_category.iteritems():
+                log.info('  with id %s: %s', _id, [p.shortname for p in ps])
+            priority = [(i, len(ps)) for i, ps in projects_with_category.items()]
+            priority = sorted(priority, key=itemgetter(1), reverse=True)
+            priority = [p[0] for p in priority]
+            live, kill = priority[0], priority[1:]
+            log.info('%s will live %s will die', live, kill)
+            if sum([len(projects_with_category[_id]) for _id in kill]) == 0:
+                # Duplicates are used nowhere
+                log.info('Removing categories %s', kill)
+                if not options.dry_run:
+                    M.TroveCategory.query.remove({'_id': {'$in': kill}})
+            else:
+                # Duplicates are used somewhere, need to reasign for all projects that use them
+                pass
+            ThreadLocalORMSession.flush_all()
+
+    @classmethod
+    def _find_duplicates(cls):
+        dups = []
+        for cat in M.TroveCategory.query.find():
+            if M.TroveCategory.query.find({
+                'shortname': cat.shortname,
+                'trove_cat_id': cat.trove_cat_id,
+                'trove_parent_id': cat.trove_parent_id,
+                'fullname': cat.fullname,
+                'fullpath': cat.fullpath,
+            }).count() > 1:
+                dups.append(cat)
+        result = defaultdict(list)
+        for k, v in groupby(dups, lambda x: x.shortname):
+            result[k].extend(list(v))
+        return result
+
+    @classmethod
+    def _projects_with_category(cls, _id):
+        p = M.Project.query.find({'$or': [
+            {'trove_root_database': _id},
+            {'trove_developmentstatus': _id},
+            {'trove_audience': _id},
+            {'trove_license': _id},
+            {'trove_os': _id},
+            {'trove_language': _id},
+            {'trove_topic': _id},
+            {'trove_natlanguage': _id},
+            {'trove_environment':_id},
+        ]})
+        return p.all()
+
+    @classmethod
+    def parser(cls):
+        parser = argparse.ArgumentParser(description='Remove duplicate troves')
+        parser.add_argument('--dry-run', action='store_true', dest='dry_run',
+                            default=False, help='Print what will be changed but do not change anything')
+        return parser
+
+
+if __name__ == '__main__':
+    RemoveDuplicateTroves.main()


[24/43] git commit: [#7656] ticket:648 Add default search fields for user & additional fields examples

Posted by je...@apache.org.
[#7656] ticket:648 Add default search fields for user & additional fields examples


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

Branch: refs/heads/je/42cc_7656
Commit: 462be2937c8db06c50fd59ad92b3a84f70e8aec9
Parents: 278f041
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 14:24:39 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:57 2014 +0300

----------------------------------------------------------------------
 Allura/allura/controllers/site_admin.py | 2 +-
 Allura/development.ini                  | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/462be293/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index b19b84b..40c69f2 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -358,7 +358,7 @@ class SiteAdminController(object):
                               limit=validators.Int(if_invalid=None),
                               page=validators.Int(if_empty=0, if_invalid=0)))
     def search_users(self, q=None, f=None, page=0, limit=None, **kw):
-        fields = []
+        fields = [('username', 'username'), ('display_name', 'display name')]
         add_fields = aslist(tg.config.get('search.user.additional_fields'), ',')
         r = self._search(M.User, fields, add_fields, q, f, page, limit, **kw)
         r['search_results_template'] = 'allura:templates/site_admin_search_users_results.html'

http://git-wip-us.apache.org/repos/asf/allura/blob/462be293/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 80275d5..ab0c114 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -120,9 +120,10 @@ user_prefs_storage.method = local
 user_prefs_storage.ldap.fields.display_name = cn
 
 
-# Additional fields for admin project search (/nf/admin/search_projects/)
+# Additional fields for admin project/user search
 # Note: whitespace after comma is important!
 # search.project.additional_fields = private, url, title
+# search.user.additional_fields = email_addresses
 
 # Set the locations of some static resources
 #  script_name is the path that is handled by the application


[19/43] git commit: [#7589] ticket:622 Fix field types/appearance in the index

Posted by je...@apache.org.
[#7589] ticket:622 Fix field types/appearance in the index


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

Branch: refs/heads/je/42cc_7656
Commit: 54885ba4f8adacca4f1d7542394d61e93cbc8d06
Parents: 53d1cc9
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon Aug 4 15:19:22 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:56 2014 +0300

----------------------------------------------------------------------
 Allura/allura/model/auth.py | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/54885ba4/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index fb59d0e..43de922 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -288,12 +288,14 @@ class User(MappedClass, ActivityNode, ActivityObject, SearchIndexable):
         localization = '%s/%s' % (
             self.get_pref('localization')['country'],
             self.get_pref('localization')['city'])
+        socialnetworks = ' '.join(['%s: %s' % (n['socialnetwork'], n['accounturl'])
+                                   for n in self.get_pref('socialnetworks')])
         fields = dict(
             id=self.index_id(),
             title='User %s' % self.username,
             type_s=self.type_s,
             username_s=self.username,
-            email_addresses=self.email_addresses,
+            email_addresses_t=' '.join(self.email_addresses),
             last_password_updated_dt=self.last_password_updated,
             disabled_b=self.disabled,
             results_per_page_i=self.get_pref('results_per_page'),
@@ -302,15 +304,20 @@ class User(MappedClass, ActivityNode, ActivityObject, SearchIndexable):
             disable_user_messages_b=self.get_pref('disable_user_messages'),
             display_name_s=self.get_pref('display_name'),
             sex_s=self.get_pref('sex'),
-            birthday_dt=self.get_pref('birthday'),
+            birthdate_dt=self.get_pref('birthdate'),
             localization_s=localization,
             timezone_s=self.get_pref('timezone'),
-            socialnetworks=self.get_pref('socialnetworks'),
-            telnumbers=self.get_pref('telnumbers'),
+            socialnetworks_t=socialnetworks,
+            telnumbers_t=' '.join(self.get_pref('telnumbers')),
             skypeaccount_s=self.get_pref('skypeaccount'),
-            webpages=self.get_pref('webpages'),
-            skills=self.get_skills(),
-            last_access=self.last_access,
+            webpages_t=' '.join(self.get_pref('webpages')),
+            skills_t=' '.join([s['skill'].fullpath for s in self.get_skills()]),
+            last_access_login_date_dt=self.last_access['login_date'],
+            last_access_login_ip_s=self.last_access['login_ip'],
+            last_access_login_ua_t=self.last_access['login_ua'],
+            last_access_session_date_dt=self.last_access['session_date'],
+            last_access_session_ip_s=self.last_access['session_ip'],
+            last_access_session_ua_t=self.last_access['session_ua'],
         )
         return dict(provider.index_user(self), **fields)
 


[29/43] git commit: [#7656] ticket:648 Refactor projects search form to something more generic

Posted by je...@apache.org.
[#7656] ticket:648 Refactor projects search form to something more generic


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

Branch: refs/heads/je/42cc_7656
Commit: 5b6f3d16af5773aa0018c91b6f51793dafc362fc
Parents: 0c3f0ad
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 9 13:00:11 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:57 2014 +0300

----------------------------------------------------------------------
 Allura/allura/controllers/site_admin.py              |  6 ++++--
 Allura/allura/lib/widgets/forms.py                   | 15 +++++++--------
 .../allura/templates/site_admin_search_projects.html |  2 +-
 3 files changed, 12 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/5b6f3d16/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index bf7076e..5913411 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -54,7 +54,7 @@ class W:
     page_list = ffw.PageList()
     page_size = ffw.PageSize()
     audit = AuditLog()
-    search_projects_form = forms.SearchProjectsForm()
+    admin_search_form = forms.AdminSearchForm
 
 
 class SiteAdminController(object):
@@ -296,7 +296,9 @@ class SiteAdminController(object):
                               limit=validators.Int(if_invalid=None),
                               page=validators.Int(if_empty=0, if_invalid=0)))
     def search_projects(self, q=None, f=None, page=0, limit=None, **kw):
-        c.search_projects_form = W.search_projects_form
+        fields = [('shortname', 'shortname'), ('name', 'full name')]
+        fields.extend(aslist(tg.config.get('search.project.additional_fields'), ','))
+        c.search_form = W.admin_search_form(fields)
         c.page_list = W.page_list
         c.page_size = W.page_size
         count = 0

http://git-wip-us.apache.org/repos/asf/allura/blob/5b6f3d16/Allura/allura/lib/widgets/forms.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/forms.py b/Allura/allura/lib/widgets/forms.py
index 794f926..0d25079 100644
--- a/Allura/allura/lib/widgets/forms.py
+++ b/Allura/allura/lib/widgets/forms.py
@@ -1081,21 +1081,20 @@ class AwardGrantForm(ForgeForm):
         ]
 
 
-class SearchProjectsForm(ForgeForm):
+class AdminSearchForm(ForgeForm):
     defaults = dict(
         ForgeForm.defaults,
         action='',
         method='get',
         submit_text=None)
 
+    def __init__(self, fields, *args, **kw):
+        super(AdminSearchForm, self).__init__(*args, **kw)
+        self._fields = fields
+
     @property
     def fields(self):
-        add_fields = aslist(tg.config.get('search.project.additional_fields'), ',')
-        search_fields = [
-            ew.Option(py_value='shortname', label='shortname'),
-            ew.Option(py_value='name', label='full name'),
-        ]
-        search_fields.extend([ew.Option(py_value=f, label=f) for f in add_fields])
+        search_fields = [ew.Option(py_value=v, label=l) for v, l in self._fields]
         search_fields.append(ew.Option(py_value='__custom__', label='custom query'))
         return [
             ew.RowField(fields=[
@@ -1114,7 +1113,7 @@ class SearchProjectsForm(ForgeForm):
             ])]
 
     def context_for(self, field):
-        ctx = super(SearchProjectsForm, self).context_for(field)
+        ctx = super(AdminSearchForm, self).context_for(field)
         if field.name is None and not ctx.get('value'):
             # RowField does not pass context down to the children :(
             render_ctx = ew_core.widget_context.render_context

http://git-wip-us.apache.org/repos/asf/allura/blob/5b6f3d16/Allura/allura/templates/site_admin_search_projects.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search_projects.html b/Allura/allura/templates/site_admin_search_projects.html
index 73f30eb..a6e6b02 100644
--- a/Allura/allura/templates/site_admin_search_projects.html
+++ b/Allura/allura/templates/site_admin_search_projects.html
@@ -23,7 +23,7 @@
 
 {% block content %}
   <div class="grid-19">
-    {{ c.search_projects_form.display(q=q, f=f) }}
+    {{ c.search_form.display(q=q, f=f) }}
   </div>
 
   {% if projects %}


[28/43] git commit: [#7589] ticket:622 Add command to reindex all users

Posted by je...@apache.org.
[#7589] ticket:622 Add command to reindex all users


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

Branch: refs/heads/je/42cc_7656
Commit: 9590479434670c2844a14469c714be4c747a623e
Parents: 596ec0f
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon Aug 4 17:16:51 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:57 2014 +0300

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


http://git-wip-us.apache.org/repos/asf/allura/blob/95904794/Allura/allura/scripts/reindex_users.py
----------------------------------------------------------------------
diff --git a/Allura/allura/scripts/reindex_users.py b/Allura/allura/scripts/reindex_users.py
new file mode 100644
index 0000000..8a0762b
--- /dev/null
+++ b/Allura/allura/scripts/reindex_users.py
@@ -0,0 +1,89 @@
+#       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
+
+from pymongo.errors import InvalidDocument
+
+from allura.scripts import ScriptTask
+from allura import model as M
+from allura.tasks.index_tasks import add_users
+from allura.lib.utils import chunked_find, chunked_list
+from allura.lib.exceptions import CompoundError
+
+
+log = logging.getLogger(__name__)
+
+
+class ReindexUsers(ScriptTask):
+
+    @classmethod
+    def execute(cls, options):
+        for chunk in chunked_find(M.User, {}):
+            user_ids = []
+            for u in chunk:
+                log.info('Reindex user %s', u.username)
+                if options.dry_run:
+                    continue
+                user_ids.append(u._id)
+            try:
+                for chunk in chunked_list(user_ids, options.max_chunk):
+                    if options.tasks:
+                        cls._post_add_users(chunk)
+                    else:
+                        add_users(chunk)
+            except CompoundError, err:
+                log.exception('Error indexing users:\n%r', err)
+                log.error('%s', err.format_error())
+            M.main_orm_session.flush()
+            M.main_orm_session.clear()
+        log.info('Reindex %s', 'queued' if options.tasks else 'done')
+
+    @classmethod
+    def _post_add_users(cls, chunk):
+        """
+        Post task, recursively splitting and re-posting if the resulting
+        mongo document is too large.
+        """
+        try:
+            add_users.post(chunk)
+        except InvalidDocument as e:
+            # there are many types of InvalidDocument, only recurse if its
+            # expected to help
+            if e.args[0].startswith('BSON document too large'):
+                cls._post_add_users(chunk[:len(chunk) // 2])
+                cls._post_add_users(chunk[len(chunk) // 2:])
+            else:
+                raise
+
+    @classmethod
+    def parser(cls):
+        parser = argparse.ArgumentParser(description='Reindex all users')
+        parser.add_argument('--dry-run', action='store_true', dest='dry_run',
+                            default=False, help='Log names of projects that would be reindexed, '
+                            'but do not perform the actual reindex.')
+        parser.add_argument('--tasks', action='store_true', dest='tasks',
+                            help='Run each individual index operation as a background task.')
+        parser.add_argument(
+            '--max-chunk', dest='max_chunk', type=int, default=100 * 1000,
+            help='Max number of artifacts to index in one Solr update command')
+        return parser
+
+
+if __name__ == '__main__':
+    ReindexUsers.main()


[14/43] git commit: [#4905] ticket:655 Add test for wiki subscribe

Posted by je...@apache.org.
[#4905] ticket:655 Add test for wiki subscribe


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

Branch: refs/heads/je/42cc_7656
Commit: ef66cbbddcc93adfb0f91b7bb90fee78630a8807
Parents: a39bce7
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Sep 12 10:16:10 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Sep 16 15:33:36 2014 +0000

----------------------------------------------------------------------
 .../forgewiki/tests/functional/test_root.py     | 24 ++++++++++++++++++++
 1 file changed, 24 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/ef66cbbd/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 072be6a..0ad3cc2 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_root.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_root.py
@@ -745,3 +745,27 @@ class TestRootController(TestController):
     def test_user_browse_page(self):
         r = self.app.get('/wiki/browse_pages/')
         assert '<td>Test Admin (test-admin)</td>' in r
+
+    def test_subscribe(self):
+        user = M.User.query.get(username='test-user')
+        # user is not subscribed
+        assert not M.Mailbox.subscribed(user_id=user._id)
+        r = self.app.get('/p/test/wiki/Home/', extra_environ={'username': str(user.username)})
+        link = r.html.find('a', {'href': '/p/test/wiki/subscribe?subscribe=True'})
+        assert link is not None
+        # subscribe
+        self.app.get('/p/test/wiki/subscribe?subscribe=True',
+                     extra_environ={'username': str(user.username)}).follow()
+        # user is subscribed
+        assert M.Mailbox.subscribed(user_id=user._id)
+        r = self.app.get('/p/test/wiki/Home/', extra_environ={'username': str(user.username)})
+        link = r.html.find('a', {'href': '/p/test/wiki/subscribe?unsubscribe=True'})
+        assert link is not None
+        # unsubscribe
+        self.app.get('/p/test/wiki/subscribe?unsubscribe=True',
+                     extra_environ={'username': str(user.username)}).follow()
+        # user is not subscribed
+        assert not M.Mailbox.subscribed(user_id=user._id)
+        r = self.app.get('/p/test/wiki/Home/', extra_environ={'username': str(user.username)})
+        link = r.html.find('a', {'href': '/p/test/wiki/subscribe?subscribe=True'})
+        assert link is not None


[40/43] git commit: [#7656] ticket:654 Removed sidebar from search result pages

Posted by je...@apache.org.
[#7656] ticket:654 Removed sidebar from search result pages


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

Branch: refs/heads/je/42cc_7656
Commit: a449d15c8d4cfce40a2ca46f54d47fbb197a9ab8
Parents: 72c54da
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Tue Sep 16 16:19:07 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Sep 18 09:33:58 2014 +0300

----------------------------------------------------------------------
 Allura/allura/templates/site_admin.html        |  2 +-
 Allura/allura/templates/site_admin_search.html | 10 ++++++++--
 2 files changed, 9 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/a449d15c/Allura/allura/templates/site_admin.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin.html b/Allura/allura/templates/site_admin.html
index d83f06e..0256563 100644
--- a/Allura/allura/templates/site_admin.html
+++ b/Allura/allura/templates/site_admin.html
@@ -20,7 +20,7 @@
 {% from 'allura:templates/jinja_master/sidebar_menu.html' import sidebar_item with context %}
 
 {% set hide_left_bar=False %}
-{% if page == 'new_projects' %}
+{% if page in ['new_projects', 'search_results'] %}
   {% set hide_left_bar=True %}
 {% endif %}
 {% extends g.theme.master %}

http://git-wip-us.apache.org/repos/asf/allura/blob/a449d15c/Allura/allura/templates/site_admin_search.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_search.html b/Allura/allura/templates/site_admin_search.html
index 685f65b..b0d86a8 100644
--- a/Allura/allura/templates/site_admin_search.html
+++ b/Allura/allura/templates/site_admin_search.html
@@ -16,12 +16,18 @@
        specific language governing permissions and limitations
        under the License.
 -#}
+
+{% set page_num = page %}
+{% set page = 'search_results' %}
+
 {% extends 'allura:templates/site_admin.html' %}
 
 {% block title %}Search {{ type_s }}s{% endblock %}
 {% block header %}Search {{ type_s }}s{% endblock %}
 
 {% block content %}
+  <div class="grid-19"><p><a href="/nf/admin">Back to Site Admin Home</a></p></div>
+
   <div class="grid-19">
     {{ c.search_form.display(q=q, f=f) }}
   </div>
@@ -33,8 +39,8 @@
   {% endif %}
 
   <div class="grid-19">
-    {{c.page_list.display(limit=limit, page=page, count=count)}}
-    {{c.page_size.display(limit=limit, page=page, count=count)}}
+    {{c.page_list.display(limit=limit, page=page_num, count=count)}}
+    {{c.page_size.display(limit=limit, page=page_num, count=count)}}
   </div>
 {% endblock %}
 


[04/43] git commit: [#7628] ticket:646 Reassign categories if different projects use different duplicates

Posted by je...@apache.org.
[#7628] ticket:646 Reassign categories if different projects use different duplicates


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

Branch: refs/heads/je/42cc_7656
Commit: 64efd59e036b1c90e4c11bf641cece04db661fae
Parents: 487de12
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Sep 3 16:40:13 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Wed Sep 3 16:40:13 2014 +0300

----------------------------------------------------------------------
 .../allura/scripts/remove_duplicate_troves.py   | 40 ++++++++++++++++----
 1 file changed, 32 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/64efd59e/Allura/allura/scripts/remove_duplicate_troves.py
----------------------------------------------------------------------
diff --git a/Allura/allura/scripts/remove_duplicate_troves.py b/Allura/allura/scripts/remove_duplicate_troves.py
index aab0bf1..5249498 100644
--- a/Allura/allura/scripts/remove_duplicate_troves.py
+++ b/Allura/allura/scripts/remove_duplicate_troves.py
@@ -31,6 +31,18 @@ log = logging.getLogger(__name__)
 
 
 class RemoveDuplicateTroves(ScriptTask):
+    
+    trove_types = [
+        'trove_root_database',
+        'trove_developmentstatus',
+        'trove_audience',
+        'trove_license',
+        'trove_os',
+        'trove_language',
+        'trove_topic',
+        'trove_natlanguage',
+        'trove_environment',
+    ]
 
     @classmethod
     def execute(cls, options):
@@ -49,19 +61,31 @@ class RemoveDuplicateTroves(ScriptTask):
             priority = [p[0] for p in priority]
             live, kill = priority[0], priority[1:]
             log.info('%s will live %s will die', live, kill)
-            if sum([len(projects_with_category[_id]) for _id in kill]) == 0:
-                # Duplicates are used nowhere
-                log.info('Removing categories %s', kill)
-                if not options.dry_run:
-                    M.TroveCategory.query.remove({'_id': {'$in': kill}})
-            else:
+            if sum([len(projects_with_category[_id]) for _id in kill]) > 0:
                 # Duplicates are used somewhere, need to reasign for all projects that use them
-                pass
+                projects = []
+                ids_to_kill = set(kill)
+                for p in [projects_with_category[_id] for _id in kill]:
+                    projects.extend(p)
+                for p in projects:
+                    for tt in cls.trove_types:
+                        _ids = ids_to_kill.intersection(getattr(p, tt))
+                        for _id in _ids:
+                            log.info('Removing %s from %s.%s and adding %s instead', _id, p.shortname, tt, live)
+                            if not options.dry_run:
+                                getattr(p, tt).remove(_id)
+                                getattr(p, tt).append(live)
+            log.info('Removing categories %s', kill)
+            if not options.dry_run:
+                M.TroveCategory.query.remove({'_id': {'$in': kill}})
             ThreadLocalORMSession.flush_all()
 
     @classmethod
     def _find_duplicates(cls):
-        dups = []
+        # agpl is present twice with different cat_id
+        # (update in creation command updated only one of duplicates),
+        # so code below will not catch it
+        dups = M.TroveCategory.query.find({'shortname': 'agpl'}).all()
         for cat in M.TroveCategory.query.find():
             if M.TroveCategory.query.find({
                 'shortname': cat.shortname,