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/12 12:29:15 UTC

[01/28] git commit: [#7585] ticket:624 Require password entry for changes to email settings

Repository: allura
Updated Branches:
  refs/heads/je/42cc_4905 8773ed46f -> 2602ee1e7 (forced update)


[#7585] ticket:624 Require password entry for changes to email settings


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

Branch: refs/heads/je/42cc_4905
Commit: 774191ee37e17b9be776b8ec4f02951e94aa7aea
Parents: 608090e
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Jul 31 17:09:23 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Aug 26 19:24:57 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py           | 10 ++++
 Allura/allura/templates/user_prefs.html     |  4 ++
 Allura/allura/tests/functional/test_auth.py | 71 ++++++++++++++++++++++++
 3 files changed, 85 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/774191ee/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 801bdf2..f05a0cc 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -413,6 +413,7 @@ class PreferencesController(BaseController):
             if not preferences.get('display_name'):
                 flash("Display Name cannot be empty.", 'error')
                 redirect('.')
+            provider = plugin.AuthenticationProvider.get(request)
             old = c.user.get_pref('display_name')
             c.user.set_pref('display_name', preferences['display_name'])
             if old != preferences['display_name']:
@@ -420,6 +421,9 @@ class PreferencesController(BaseController):
             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:
+                    if not kw.get('password') or not provider.validate_password(c.user, kw.get('password')):
+                        flash('You must provide your current password to delete an email', 'error')
+                        redirect('.')
                     if primary_addr == c.user.email_addresses[i]:
                         if select_new_primary_addr(c.user, ignore_emails=primary_addr) is None \
                                 and asbool(config.get('auth.require_email_addr', False)):
@@ -434,6 +438,9 @@ class PreferencesController(BaseController):
                     if obj:
                         obj.delete()
             if new_addr.get('claim') or new_addr.get('addr'):
+                if not kw.get('password') or not provider.validate_password(c.user, kw.get('password')):
+                    flash('You must provide your current password to claim new email', 'error')
+                    redirect('.')
                 if M.EmailAddress.query.get(_id=new_addr['addr']):
                     flash('Email address already claimed', 'error')
                 elif mail_util.isvalid(new_addr['addr']):
@@ -449,6 +456,9 @@ class PreferencesController(BaseController):
                 primary_addr = select_new_primary_addr(c.user)
             if primary_addr:
                 if c.user.get_pref('email_address') != primary_addr:
+                    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(
                         'Primary email changed: %s => %s',
                         c.user.get_pref('email_address'),

http://git-wip-us.apache.org/repos/asf/allura/blob/774191ee/Allura/allura/templates/user_prefs.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/user_prefs.html b/Allura/allura/templates/user_prefs.html
index d921889..f76e9d6 100644
--- a/Allura/allura/templates/user_prefs.html
+++ b/Allura/allura/templates/user_prefs.html
@@ -108,6 +108,10 @@
           </table>
           <div class="grid-22">
             <p></p>
+            <label for="password">Current password:</label>
+            <input type="password" name="password">
+          </div>
+          <div class="grid-22">
             {{lib.submit_button('Save')}}
           </div>
           {{lib.csrf_token()}}

http://git-wip-us.apache.org/repos/asf/allura/blob/774191ee/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 58d824a..8af23ca 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -132,6 +132,7 @@ class TestAuth(TestController):
                 'new_addr.addr': 'test@example.com',
                 'new_addr.claim': 'Claim Address',
                 'primary_addr': 'test-admin@users.localhost',
+                'password': 'foo',
                 'preferences.email_format': 'plain'},
                 extra_environ=dict(username='test-admin'))
         r = self.app.get('/auth/preferences/')
@@ -148,6 +149,7 @@ class TestAuth(TestController):
                 'addr-2.ord': '2',
                 'new_addr.addr': '',
                 'primary_addr': 'test-admin@users.localhost',
+                'password': 'foo',
                 'preferences.email_format': 'plain'},
                 extra_environ=dict(username='test-admin'))
         r = self.app.get('/auth/preferences/')
@@ -163,6 +165,75 @@ class TestAuth(TestController):
                 extra_environ=dict(username='test-admin'))
 
     @td.with_user_project('test-admin')
+    def test_email_prefs_change_requires_password(self):
+        # Claim new email
+        new_email_params = {
+            'preferences.display_name': 'Test Admin',
+            'new_addr.addr': 'test@example.com',
+            'new_addr.claim': 'Claim Address',
+            'primary_addr': 'test-admin@users.localhost',
+        }
+        r = self.app.post('/auth/preferences/update', params=new_email_params,
+            extra_environ=dict(username='test-admin'))
+        assert_in('You must provide your current password to claim new email', self.webflash(r))
+        assert_not_in('test@example.com', r.follow())
+        new_email_params['password'] = 'bad pass'
+        r = self.app.post('/auth/preferences/update', params=new_email_params,
+            extra_environ=dict(username='test-admin'))
+        assert_in('You must provide your current password to claim new email', self.webflash(r))
+        assert_not_in('test@example.com', r.follow())
+        new_email_params['password'] = 'foo'  # valid password
+        r = self.app.post('/auth/preferences/update', params=new_email_params,
+            extra_environ=dict(username='test-admin'))
+        assert_not_in('You must provide your current password to claim new email', self.webflash(r))
+        assert_in('test@example.com', r.follow())
+
+        # Change primary address
+        change_primary_params = {
+            'preferences.display_name': 'Test Admin',
+            'new_addr.addr': '',
+            'primary_addr': 'test@example.com',
+        }
+        r = self.app.post('/auth/preferences/update', params=change_primary_params,
+            extra_environ=dict(username='test-admin'))
+        assert_in('You must provide your current password to change primary address', self.webflash(r))
+        assert_equal(M.User.by_username('test-admin').get_pref('email_address'), 'test-admin@users.localhost')
+        change_primary_params['password'] = 'bad pass'
+        r = self.app.post('/auth/preferences/update', params=change_primary_params,
+            extra_environ=dict(username='test-admin'))
+        assert_in('You must provide your current password to change primary address', self.webflash(r))
+        assert_equal(M.User.by_username('test-admin').get_pref('email_address'), 'test-admin@users.localhost')
+        change_primary_params['password'] = 'foo'  # valid password
+        r = self.app.post('/auth/preferences/update', params=change_primary_params,
+            extra_environ=dict(username='test-admin'))
+        assert_not_in('You must provide your current password to change primary address', self.webflash(r))
+        assert_equal(M.User.by_username('test-admin').get_pref('email_address'), 'test@example.com')
+
+        # Remove email
+        remove_email_params = {
+            'preferences.display_name': 'Test Admin',
+            'addr-1.ord': '1',
+            'addr-2.ord': '2',
+            'addr-2.delete': 'on',
+            'new_addr.addr': '',
+            'primary_addr': 'test-admin@users.localhost',
+        }
+        r = self.app.post('/auth/preferences/update', params=remove_email_params,
+            extra_environ=dict(username='test-admin'))
+        assert_in('You must provide your current password to delete an email', self.webflash(r))
+        assert_in('test@example.com', r.follow())
+        remove_email_params['password'] = 'bad pass'
+        r = self.app.post('/auth/preferences/update', params=remove_email_params,
+            extra_environ=dict(username='test-admin'))
+        assert_in('You must provide your current password to delete an email', self.webflash(r))
+        assert_in('test@example.com', r.follow())
+        remove_email_params['password'] = 'foo'  # vallid password
+        r = self.app.post('/auth/preferences/update', params=remove_email_params,
+            extra_environ=dict(username='test-admin'))
+        assert_not_in('You must provide your current password to delete an email', self.webflash(r))
+        assert_not_in('test@example.com', r.follow())
+
+    @td.with_user_project('test-admin')
     def test_prefs_subscriptions(self):
         r = self.app.get('/auth/subscriptions/',
                          extra_environ=dict(username='test-admin'))


[14/28] git commit: [#7527] Bugfix for migrations to prevent duplicates

Posted by je...@apache.org.
[#7527] Bugfix for migrations to prevent duplicates


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

Branch: refs/heads/je/42cc_4905
Commit: 99de4f45c5cd348a7d422073adb2f7476d507801
Parents: f825a56
Author: Alexander Luberg <al...@slashdotmedia.com>
Authored: Wed Aug 27 05:28:00 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Aug 28 20:27:02 2014 +0000

----------------------------------------------------------------------
 .../030-email-address-_id-to-email--before-upgrade.js          | 4 ++--
 scripts/migrations/030-email-address-_id-to-email--cleanup.js  | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/99de4f45/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js b/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js
index 6681864..3cc2618 100644
--- a/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js
+++ b/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js
@@ -2,5 +2,5 @@ db.email_address.find().snapshot().forEach(function (e) {
     e.email = e._id;
     e._id = new ObjectId();
     db.email_address_new.insert(e);
-    db.email_address.update({'_id': e._id}, {'migrated': true});
-});
\ No newline at end of file
+    db.email_address.update({'_id': e.email}, {$set: {migrated: true}});
+});

http://git-wip-us.apache.org/repos/asf/allura/blob/99de4f45/scripts/migrations/030-email-address-_id-to-email--cleanup.js
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email--cleanup.js b/scripts/migrations/030-email-address-_id-to-email--cleanup.js
index 26b0064..34cf7a0 100644
--- a/scripts/migrations/030-email-address-_id-to-email--cleanup.js
+++ b/scripts/migrations/030-email-address-_id-to-email--cleanup.js
@@ -1,8 +1,8 @@
-db.email_address_old.find({'migrated': {'$ne': false}}).snapshot().forEach(function (e) {
+db.email_address_old.find({'migrated': {'$ne': true}}).snapshot().forEach(function (e) {
     e.email = e._id;
     e._id = new ObjectId();
     db.email_address.insert(e);
-    db.email_address_old.update({'_id': e._id}, {'migrated': true});
+    db.email_address_old.update({'_id': e.email}, {$set: {migrated: true}});
 });
 // Drop the collection manually if everything is okay
-// db.email_address_old.drop();
\ No newline at end of file
+// db.email_address_old.drop();


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

Posted by je...@apache.org.
[#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_4905
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())


[16/28] git commit: [#7527] add apache license header to new .js files

Posted by je...@apache.org.
[#7527] add apache license header to new .js files


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

Branch: refs/heads/je/42cc_4905
Commit: e7900491e99c55446d1572310602167567567e86
Parents: ab1957f
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri Aug 29 14:23:54 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Aug 29 14:23:54 2014 +0000

----------------------------------------------------------------------
 ...email-address-_id-to-email--after-upgrade.js | 21 +++++++++++++++++++-
 ...mail-address-_id-to-email--before-upgrade.js | 19 ++++++++++++++++++
 .../030-email-address-_id-to-email--cleanup.js  | 19 ++++++++++++++++++
 3 files changed, 58 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e7900491/scripts/migrations/030-email-address-_id-to-email--after-upgrade.js
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email--after-upgrade.js b/scripts/migrations/030-email-address-_id-to-email--after-upgrade.js
index 7e47a82..8fa07f1 100644
--- a/scripts/migrations/030-email-address-_id-to-email--after-upgrade.js
+++ b/scripts/migrations/030-email-address-_id-to-email--after-upgrade.js
@@ -1,2 +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.
+*/
+
 db.email_address.renameCollection("email_address_old", {dropTarget: true});
-db.email_address_new.renameCollection("email_address", {dropTarget: true});
\ No newline at end of file
+db.email_address_new.renameCollection("email_address", {dropTarget: true});

http://git-wip-us.apache.org/repos/asf/allura/blob/e7900491/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js b/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js
index 3cc2618..08457ca 100644
--- a/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js
+++ b/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js
@@ -1,3 +1,22 @@
+/*
+       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.
+*/
+
 db.email_address.find().snapshot().forEach(function (e) {
     e.email = e._id;
     e._id = new ObjectId();

http://git-wip-us.apache.org/repos/asf/allura/blob/e7900491/scripts/migrations/030-email-address-_id-to-email--cleanup.js
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email--cleanup.js b/scripts/migrations/030-email-address-_id-to-email--cleanup.js
index 34cf7a0..5ec6b1a 100644
--- a/scripts/migrations/030-email-address-_id-to-email--cleanup.js
+++ b/scripts/migrations/030-email-address-_id-to-email--cleanup.js
@@ -1,3 +1,22 @@
+/*
+       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.
+*/
+
 db.email_address_old.find({'migrated': {'$ne': true}}).snapshot().forEach(function (e) {
     e.email = e._id;
     e._id = new ObjectId();


[08/28] git commit: [#7527] Added EmailAddress data migration

Posted by je...@apache.org.
[#7527] Added EmailAddress data migration


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

Branch: refs/heads/je/42cc_4905
Commit: 888f60433405b009e681bda4af72b10d2ff8b7a1
Parents: 3e6fdda
Author: Alexander Luberg <al...@slashdotmedia.com>
Authored: Tue Jul 22 19:06:31 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Aug 28 20:27:00 2014 +0000

----------------------------------------------------------------------
 .../030-email-address-_id-to-email.py           | 39 ++++++++++++++++++++
 1 file changed, 39 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/888f6043/scripts/migrations/030-email-address-_id-to-email.py
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email.py b/scripts/migrations/030-email-address-_id-to-email.py
new file mode 100644
index 0000000..e70af50
--- /dev/null
+++ b/scripts/migrations/030-email-address-_id-to-email.py
@@ -0,0 +1,39 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+from bson import ObjectId
+
+import logging
+
+from ming.odm import ThreadLocalORMSession
+
+from allura import model as M
+
+log = logging.getLogger(__name__)
+
+
+def main():
+    email_addresses = M.EmailAddress.query.find(dict(email=None)).all()
+    for email in email_addresses:
+        email.email = email._id
+        email._id = ObjectId()
+        ThreadLocalORMSession.flush_all()
+    ThreadLocalORMSession.close_all()
+
+
+if __name__ == '__main__':
+    main()


[10/28] git commit: [#7527] Split the migration into 3 steps

Posted by je...@apache.org.
[#7527] Split the migration into 3 steps


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

Branch: refs/heads/je/42cc_4905
Commit: e76619abd227889c72b1a168f9732659ce200940
Parents: e3eaaa0
Author: Alexander Luberg <al...@slashdotmedia.com>
Authored: Fri Aug 22 14:37:38 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Aug 28 20:27:01 2014 +0000

----------------------------------------------------------------------
 ...email-address-_id-to-email--after-upgrade.js |  2 ++
 ...mail-address-_id-to-email--before-upgrade.js |  6 ++++++
 .../030-email-address-_id-to-email--cleanup.js  |  8 ++++++++
 .../030-email-address-_id-to-email.js           | 20 --------------------
 4 files changed, 16 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e76619ab/scripts/migrations/030-email-address-_id-to-email--after-upgrade.js
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email--after-upgrade.js b/scripts/migrations/030-email-address-_id-to-email--after-upgrade.js
new file mode 100644
index 0000000..7e47a82
--- /dev/null
+++ b/scripts/migrations/030-email-address-_id-to-email--after-upgrade.js
@@ -0,0 +1,2 @@
+db.email_address.renameCollection("email_address_old", {dropTarget: true});
+db.email_address_new.renameCollection("email_address", {dropTarget: true});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/allura/blob/e76619ab/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js b/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js
new file mode 100644
index 0000000..6681864
--- /dev/null
+++ b/scripts/migrations/030-email-address-_id-to-email--before-upgrade.js
@@ -0,0 +1,6 @@
+db.email_address.find().snapshot().forEach(function (e) {
+    e.email = e._id;
+    e._id = new ObjectId();
+    db.email_address_new.insert(e);
+    db.email_address.update({'_id': e._id}, {'migrated': true});
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/allura/blob/e76619ab/scripts/migrations/030-email-address-_id-to-email--cleanup.js
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email--cleanup.js b/scripts/migrations/030-email-address-_id-to-email--cleanup.js
new file mode 100644
index 0000000..26b0064
--- /dev/null
+++ b/scripts/migrations/030-email-address-_id-to-email--cleanup.js
@@ -0,0 +1,8 @@
+db.email_address_old.find({'migrated': {'$ne': false}}).snapshot().forEach(function (e) {
+    e.email = e._id;
+    e._id = new ObjectId();
+    db.email_address.insert(e);
+    db.email_address_old.update({'_id': e._id}, {'migrated': true});
+});
+// Drop the collection manually if everything is okay
+// db.email_address_old.drop();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/allura/blob/e76619ab/scripts/migrations/030-email-address-_id-to-email.js
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email.js b/scripts/migrations/030-email-address-_id-to-email.js
deleted file mode 100644
index f831623..0000000
--- a/scripts/migrations/030-email-address-_id-to-email.js
+++ /dev/null
@@ -1,20 +0,0 @@
-//1) Copy to the new collection with data updates
-db.email_address.find().snapshot().forEach(function(e){
-    e.email = e._id;
-    e._id = new ObjectId();
-    db.email_address_new.insert(e);
-    db.email_address.update({'_id': e._id}, {'migrated': true})
-});
-//2) Updated code on production(git pull)
-//3) Rename collections
-db.email_address.renameCollection("email_address_old", {dropTarget: true})
-db.email_address_new.renameCollection("email_address", {dropTarget: true})
-//4) Post Migration - copy/update all the object which were created between 1)&2)
-db.email_address_old.find({'migrated': {'$not': false}}).snapshot().forEach(function(e){
-    e.email = e._id;
-    e._id = new ObjectId();
-    db.email_address.insert(e);
-    db.email_address_old.update({'_id': e._id}, {'migrated': true})
-});
-
-db.email_address_old.drop()


[26/28] 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/0e039301
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/0e039301
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/0e039301

Branch: refs/heads/je/42cc_4905
Commit: 0e03930121837789ec13b8c6a3168f54453cd794
Parents: 6e8af1d
Author: discort <le...@bk.ru>
Authored: Mon Aug 25 16:31:28 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Fri Sep 12 09:22:20 2014 +0300

----------------------------------------------------------------------
 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/0e039301/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/0e039301/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,


[15/28] git commit: [#7527] test fix from Alexander Luberg to pass with latest master changes

Posted by je...@apache.org.
[#7527] test fix from Alexander Luberg to pass with latest master changes


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

Branch: refs/heads/je/42cc_4905
Commit: ab1957fd0e5261c6f5372b4a50b6a2e6db5e4c2c
Parents: 1c6cb8c
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu Aug 28 21:15:15 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Aug 28 21:15:15 2014 +0000

----------------------------------------------------------------------
 Allura/allura/tests/functional/test_auth.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/ab1957fd/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 b4e174e..77367ec 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -149,7 +149,8 @@ class TestAuth(TestController):
                           'new_addr.addr': email_address,
                           'new_addr.claim': 'Claim Address',
                           'primary_addr': 'test-admin@users.localhost',
-                          'preferences.email_format': 'plain'
+                          'preferences.email_format': 'plain',
+                          'password': 'foo',
                       },
                       extra_environ=dict(username='test-admin'))
 
@@ -160,7 +161,8 @@ class TestAuth(TestController):
                               'new_addr.addr': email_address,
                               'new_addr.claim': 'Claim Address',
                               'primary_addr': 'test-admin@users.localhost',
-                              'preferences.email_format': 'plain'
+                              'preferences.email_format': 'plain',
+                              'password': 'foo',
                           },
                           extra_environ=dict(username='test-admin'))
 


[25/28] 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/6e8af1d8
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/6e8af1d8
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/6e8af1d8

Branch: refs/heads/je/42cc_4905
Commit: 6e8af1d8f9e26c2b44ebce15ab864f99246fd29b
Parents: 0855719
Author: discort <le...@bk.ru>
Authored: Fri Aug 22 00:44:41 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Fri Sep 12 09:22:20 2014 +0300

----------------------------------------------------------------------
 .../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/6e8af1d8/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/6e8af1d8/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


[11/28] git commit: [#7527] Bugfixing

Posted by je...@apache.org.
[#7527] Bugfixing


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

Branch: refs/heads/je/42cc_4905
Commit: d307dca7cc9ea10685fa6d611644be3d8335d9e1
Parents: 888f604
Author: Alexander Luberg <al...@slashdotmedia.com>
Authored: Mon Jul 28 21:16:07 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Aug 28 20:27:01 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py               |  8 +++---
 Allura/allura/lib/mail_util.py                  |  2 +-
 Allura/allura/model/auth.py                     | 27 +++-----------------
 Allura/allura/tests/functional/test_auth.py     |  2 +-
 Allura/allura/tests/model/test_auth.py          |  6 ++---
 Allura/allura/tests/test_mail_util.py           |  8 +++---
 Allura/allura/websetup/bootstrap.py             |  4 +++
 .../forgeuserstats/tests/test_model.py          |  2 +-
 .../forgeuserstats/tests/test_stats.py          |  2 +-
 9 files changed, 23 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/d307dca7/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index dc3a177..d2c97a7 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -179,7 +179,7 @@ class AuthController(BaseController):
         if not email:
             redirect('/')
 
-        email_record = M.EmailAddress.query.find({'email': email}).first()
+        email_record = M.EmailAddress.query.get(email=email, confirmed=True)
         user_record = M.User.by_email_address(email)
 
         if user_record and email_record.confirmed:
@@ -236,8 +236,6 @@ class AuthController(BaseController):
     @expose()
     def verify_addr(self, a):
         addr = M.EmailAddress.query.get(nonce=a)
-        # import pydevd
-        # pydevd.settrace('localhost', port=14000, stdoutToServer=True, stderrToServer=True)
 
         if addr:
             addr.confirmed = True
@@ -249,12 +247,14 @@ class AuthController(BaseController):
 
             users = [email.claimed_by_user() for email in claimed_by_others]
             for user in users:
+                log.info("Removed the email %s from user %s " % (addr.email, user.username))
                 user.email_addresses.remove(addr.email)
 
             M.EmailAddress.query.remove({
                 'email': addr.email,
                 'claimed_by_user_id': {'$ne': addr.claimed_by_user_id}
             })
+
             flash('Email address confirmed')
             M.AuditLog.log_user('Email address verified: %s', addr._id)
         else:
@@ -464,7 +464,7 @@ class PreferencesController(BaseController):
                     flash('Email address already claimed', 'error')
                 elif mail_util.isvalid(new_addr['addr']):
                     c.user.email_addresses.append(new_addr['addr'])
-                    em = M.EmailAddress.upsert(new_addr['addr'])
+                    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'])

http://git-wip-us.apache.org/repos/asf/allura/blob/d307dca7/Allura/allura/lib/mail_util.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py
index a932f13..20fc411 100644
--- a/Allura/allura/lib/mail_util.py
+++ b/Allura/allura/lib/mail_util.py
@@ -159,7 +159,7 @@ def identify_sender(peer, email_address, headers, msg):
     from allura import model as M
     # Dumb ID -- just look for email address claimed by a particular user
     addr = M.EmailAddress.query.get(
-        email=M.EmailAddress.canonical(email_address))
+        email=M.EmailAddress.canonical(email_address), confirmed=True)
     if addr and addr.claimed_by_user_id:
         return addr.claimed_by_user()
     from_address = headers.get('From', '').strip()

http://git-wip-us.apache.org/repos/asf/allura/blob/d307dca7/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 1c753d5..7cc169d 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -115,6 +115,7 @@ class EmailAddress(MappedClass):
     class __mongometa__:
         name = 'email_address'
         session = main_orm_session
+        indexes = ['nonce',]
         unique_indexes = [('email', 'claimed_by_user_id'),]
 
     _id = FieldProperty(S.ObjectId)
@@ -127,7 +128,7 @@ class EmailAddress(MappedClass):
         return User.query.get(_id=self.claimed_by_user_id, disabled=False)
 
     @classmethod
-    def upsert(cls, addr):
+    def create(cls, addr):
         addr = cls.canonical(addr)
         return cls(email=addr)
 
@@ -547,7 +548,7 @@ class User(MappedClass, ActivityNode, ActivityObject):
 
     @classmethod
     def by_email_address(cls, addr):
-        ea = EmailAddress.query.get(email=addr)
+        ea = EmailAddress.query.get(email=addr, confirmed=True)
         if ea is None:
             return None
         return ea.claimed_by_user()
@@ -574,32 +575,12 @@ class User(MappedClass, ActivityNode, ActivityObject):
 
     def claim_address(self, email_address):
         addr = EmailAddress.canonical(email_address)
-        email_addr = EmailAddress.upsert(addr)
+        email_addr = EmailAddress.create(addr)
         email_addr.claimed_by_user_id = self._id
         if addr in self.email_addresses:
             return
         self.email_addresses.append(addr)
 
-    def claim_only_addresses(self, *addresses):
-        '''Claims the listed addresses and no others, setting the confirmed
-        attribute to True on all.
-        '''
-        self.email_addresses = [
-            EmailAddress.canonical(a) for a in addresses]
-        addresses = set(self.email_addresses)
-        for addr in EmailAddress.query.find(
-                dict(claimed_by_user_id=self._id)):
-            if addr.email in addresses:
-                if not addr.confirmed:
-                    addr.confirmed = True
-                addresses.remove(addr.email)
-            else:
-                addr.delete()
-        for a in addresses:
-            addr = EmailAddress.upsert(a)
-            addr.claimed_by_user_id = self._id
-            addr.confirmed = True
-
     @classmethod
     def register(cls, doc, make_project=True):
         from allura import model as M

http://git-wip-us.apache.org/repos/asf/allura/blob/d307dca7/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 65d3a50..b4e174e 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -898,7 +898,7 @@ To reset your password on %s, please visit the following URL:
 %s/auth/forgotten_password/%s''' % (config['site_name'], config['base_url'], hash)
 
         sendmail.post.assert_called_once_with(
-            toaddr=email._id,
+            toaddr=email.email,
             fromaddr=config['forgemail.return_path'],
             reply_to=config['forgemail.return_path'],
             subject='Allura Password recovery',

http://git-wip-us.apache.org/repos/asf/allura/blob/d307dca7/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 165e331..9c5a74c 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -55,15 +55,15 @@ def test_email_address():
                           claimed_by_user_id=c.user._id)
     ThreadLocalORMSession.flush_all()
     assert addr.claimed_by_user() == c.user
-    addr2 = M.EmailAddress.upsert('test@domain.net')
-    addr3 = M.EmailAddress.upsert('test_admin@domain.net')
+    addr2 = M.EmailAddress.create('test@domain.net')
+    addr3 = M.EmailAddress.create('test_admin@domain.net')
 
     # Duplicate emails are allowed, until the email is confirmed
     assert addr3 is not addr
 
     assert addr2 is not addr
     assert addr2
-    addr4 = M.EmailAddress.upsert('test@DOMAIN.NET')
+    addr4 = M.EmailAddress.create('test@DOMAIN.NET')
     assert addr4 is not addr2
     with patch('allura.lib.app_globals.request', Request.blank('/')):
         addr.send_verification_link()

http://git-wip-us.apache.org/repos/asf/allura/blob/d307dca7/Allura/allura/tests/test_mail_util.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_mail_util.py b/Allura/allura/tests/test_mail_util.py
index c2fe363..2263940 100644
--- a/Allura/allura/tests/test_mail_util.py
+++ b/Allura/allura/tests/test_mail_util.py
@@ -193,7 +193,7 @@ class TestIdentifySender(object):
         EA.query.get.side_effect = [
             mock.Mock(claimed_by_user_id=True, claimed_by_user=lambda:'user')]
         assert_equal(identify_sender(None, 'arg', None, None), 'user')
-        EA.query.get.assert_called_once_with(email='arg')
+        EA.query.get.assert_called_once_with(email='arg', confirmed=True)
 
     @mock.patch('allura.model.EmailAddress')
     def test_header(self, EA):
@@ -203,7 +203,7 @@ class TestIdentifySender(object):
         assert_equal(
             identify_sender(None, 'arg', {'From': 'from'}, None), 'user')
         assert_equal(EA.query.get.call_args_list,
-                     [mock.call(email='arg'), mock.call(email='from')])
+                     [mock.call(email='arg', confirmed=True), mock.call(email='from')])
 
     @mock.patch('allura.model.User')
     @mock.patch('allura.model.EmailAddress')
@@ -213,7 +213,7 @@ class TestIdentifySender(object):
         EA.query.get.side_effect = [
             None, mock.Mock(claimed_by_user_id=True, claimed_by_user=lambda:'user')]
         assert_equal(identify_sender(None, 'arg', {}, None), anon)
-        assert_equal(EA.query.get.call_args_list, [mock.call(email='arg')])
+        assert_equal(EA.query.get.call_args_list, [mock.call(email='arg', confirmed=True)])
 
     @mock.patch('allura.model.User')
     @mock.patch('allura.model.EmailAddress')
@@ -224,7 +224,7 @@ class TestIdentifySender(object):
         assert_equal(
             identify_sender(None, 'arg', {'From': 'from'}, None), anon)
         assert_equal(EA.query.get.call_args_list,
-                     [mock.call(email='arg'), mock.call(email='from')])
+                     [mock.call(email='arg', confirmed=True), mock.call(email='from')])
 
 
 def test_parse_message_id():

http://git-wip-us.apache.org/repos/asf/allura/blob/d307dca7/Allura/allura/websetup/bootstrap.py
----------------------------------------------------------------------
diff --git a/Allura/allura/websetup/bootstrap.py b/Allura/allura/websetup/bootstrap.py
index f7b1a99..840f171 100644
--- a/Allura/allura/websetup/bootstrap.py
+++ b/Allura/allura/websetup/bootstrap.py
@@ -212,6 +212,10 @@ def bootstrap(command, conf, vars):
         u_admin.email_addresses = ['test-admin@users.localhost']
         u_admin.set_password('foo')
         u_admin.claim_address('test-admin@users.localhost')
+        ThreadLocalORMSession.flush_all()
+
+        admin_email = M.EmailAddress.query.get(email='test-admin@users.localhost')
+        admin_email.confirmed = True
     else:
         u_admin = make_user('Admin 1', username='admin1')
         # Admin1 is almost root, with admin access for Users and Projects

http://git-wip-us.apache.org/repos/asf/allura/blob/d307dca7/ForgeUserStats/forgeuserstats/tests/test_model.py
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/tests/test_model.py b/ForgeUserStats/forgeuserstats/tests/test_model.py
index c9a8cf4..e7670de 100644
--- a/ForgeUserStats/forgeuserstats/tests/test_model.py
+++ b/ForgeUserStats/forgeuserstats/tests/test_model.py
@@ -371,7 +371,7 @@ class TestUserStats(unittest.TestCase):
 
         with mock.patch('allura.lib.plugin.session'):
             self.user.set_password('testpassword')
-        addr = M.EmailAddress.upsert('rcopeland@geek.net')
+        addr = M.EmailAddress.create('rcopeland@geek.net')
         self.user.claim_address('rcopeland@geek.net')
 
         repo_dir = pkg_resources.resource_filename(

http://git-wip-us.apache.org/repos/asf/allura/blob/d307dca7/ForgeUserStats/forgeuserstats/tests/test_stats.py
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/tests/test_stats.py b/ForgeUserStats/forgeuserstats/tests/test_stats.py
index 85f4d09..a09de1e 100644
--- a/ForgeUserStats/forgeuserstats/tests/test_stats.py
+++ b/ForgeUserStats/forgeuserstats/tests/test_stats.py
@@ -195,7 +195,7 @@ class TestGitCommit(TestController, unittest.TestCase):
 
         user = User.by_username('test-admin')
         user.set_password('testpassword')
-        M.EmailAddress.upsert('rcopeland@geek.net')
+        M.EmailAddress.create('rcopeland@geek.net')
         user.claim_address('rcopeland@geek.net')
         self.setup_with_tools()
 


[04/28] git commit: [#7585] ticket:639 added widget for enter password

Posted by je...@apache.org.
[#7585] ticket:639 added widget for enter password


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

Branch: refs/heads/je/42cc_4905
Commit: ce6c4aa3bb8ffa32bcfff9f04fc3126af2bc9db4
Parents: 2b781a4
Author: discort <le...@bk.ru>
Authored: Fri Aug 22 13:52:03 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Aug 26 19:24:58 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py       |   3 +-
 Allura/allura/templates/user_prefs.html | 120 +++++++++++----------------
 2 files changed, 49 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/ce6c4aa3/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index f05a0cc..247a94b 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -44,7 +44,7 @@ from allura.lib.widgets import (
     LoginForm,
     ForgottenPasswordForm,
     DisableAccountForm)
-from allura.lib.widgets import forms
+from allura.lib.widgets import forms, form_fields as ffw
 from allura.lib import mail_util
 from allura.controllers import BaseController
 
@@ -392,6 +392,7 @@ class PreferencesController(BaseController):
     @with_trailing_slash
     @expose('jinja:allura:templates/user_prefs.html')
     def index(self, **kw):
+        c.enter_password = ffw.Lightbox(name='enter_password')
         c.password_change_form = F.password_change_form
         c.upload_key_form = F.upload_key_form
         provider = plugin.AuthenticationProvider.get(request)

http://git-wip-us.apache.org/repos/asf/allura/blob/ce6c4aa3/Allura/allura/templates/user_prefs.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/user_prefs.html b/Allura/allura/templates/user_prefs.html
index 9c477f6..b4dcc85 100644
--- a/Allura/allura/templates/user_prefs.html
+++ b/Allura/allura/templates/user_prefs.html
@@ -161,16 +161,18 @@
         </fieldset>
       {% endif %}
       
-      <form class="cur_password">
-        <h1>Enter password</h1>
-        <p>
-          {{lib.password_field('current_password', 'Current password:')}}
-        </p>
-        <p>  
+      <form class="cur_password" style="display:none">
+        <div class="grid-13"> 
+          <p>{{lib.password_field('current_password', 'Current password:')}}</p>
+        </div>
+        <div class="grid-13">
+          <p>  
           <input type="submit" name="enter_pass_submit" value="Ok">
           <input type="button" name="cancel_lightbox" value="Cancel">
-        </p>
+          </p>
+        </div>
       </form>
+      {{c.enter_password.display(content='<h1>Enter password</h1>')}}
     {% endblock %}
   </div>
 {% endblock %}
@@ -197,84 +199,56 @@
     padding: 0;
     border: 0;
   }
-  .cur_password {
-    display:none;
-    width: 500px;
-    float: left;
-    overflow: hidden;
-    margin: 0 10px;
-    padding: 15px;
-
-    left: 50%;
-    margin-left: -311px;
-    z-index: 1002;
-    position: fixed;
-    top: 40px;
-    margin-top: 0px;
-    background: #636363;
-    border-radius: 4px;
-    color: #ffffff;
-    box-shadow:
-        0 1px 2px rgba(0,0,0,0.2),        
-        0 1px 5px rgba(0,0,0,0.2),        
-        0 0 0 5px rgba(0,0,0,0.4); 
-  }
-  .cur_password h1 {
-    font-size: 18px;
-    line-height: 36px;
-    font-weight: bold;
-    color: #ffffff;
-    padding-bottom: 8px;
-    border-bottom: 1px solid #EBE6E2;
-  }
 </style>
 {% endblock %}
 
 {% block extra_js %}
   <script type="text/javascript">
       $(function() {
-          $("input[name='enter_pass_submit']").click(function (e) {
-            $("input[name='password']").val(
-                $("input[name='current_password']").val()
-              );
-            $("form[name='update-email']").submit();
-            e.preventDefault();
-          });
-
-          $("input[name='cancel_lightbox']").click(function(){
-            $('.cur_password').trigger('close');
-            return false;
-          });
 
-          function launch() {
-               $('.cur_password').lightbox_me({
-                centered: true, 
-                onLoad: function() { 
-                  $('.cur_password').find('input:first').focus();
-                }
-            });
-          }
+        function launch() {
+          var enter_password_popup = $('#lightbox_enter_password');
+          var enter_password_form = $('.cur_password');
 
-          $("input[name='new_addr.claim'], input[name='addr-save']").click(function(e) {
-            if ($("input[name='password']").val() == ''){
-              e.preventDefault();
-            }
-            if ($("input[name='new_addr.addr']").val().length != 0){
-              launch();
+          enter_password_popup.append(enter_password_form.show());
+          enter_password_popup.lightbox_me({
+            onLoad: function() { 
+            $('.cur_password').find('input:first').focus();
             }
           });
-
-          $('input:submit', ".addr-delete").click(function(e) {
-            if ($("input[name='password']").val() == ''){
-              e.preventDefault();
-            }
-            $('input:hidden', ".addr-delete").val("");
-            var attr_del = $(this).attr('name')
-            $(document.getElementById(attr_del)).val("1");
-            //$('#' + attr_del).val("1");
+        };
+
+        $("input[name='enter_pass_submit']").click(function (e) {
+          $("input[name='password']").val(
+              $("input[name='current_password']").val()
+            );
+          $("form[name='update-email']").submit();
+          e.preventDefault();
+        });
+
+        $("input[name='cancel_lightbox']").click(function(){
+          $('.cur_password').trigger('close');
+          return false;
+        });
+
+        $("input[name='new_addr.claim'], input[name='addr-save']").click(function(e) {
+          if ($("input[name='password']").val() == ''){
+            e.preventDefault();
+          }
+          if ($("input[name='new_addr.addr']").val().length != 0){
             launch();
-          });
+          }
+        });
 
+        $('input:submit', ".addr-delete").click(function(e) {
+          if ($("input[name='password']").val() == ''){
+            e.preventDefault();
+          }
+          $('input:hidden', ".addr-delete").val("");
+          var attr_del = $(this).attr('name')
+          $(document.getElementById(attr_del)).val("1");
+          launch();
+        });
       });
   </script>
  {% endblock %}
\ No newline at end of file


[22/28] 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_4905
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


[13/28] git commit: [#7527] Fixed unit tests

Posted by je...@apache.org.
[#7527] Fixed unit tests


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

Branch: refs/heads/je/42cc_4905
Commit: 1c6cb8cf583436ca5484f6455c488c035b449fbc
Parents: 99de4f4
Author: Alexander Luberg <al...@slashdotmedia.com>
Authored: Thu Aug 28 17:57:05 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Aug 28 20:27:02 2014 +0000

----------------------------------------------------------------------
 ForgeUserStats/forgeuserstats/tests/test_model.py | 4 +++-
 ForgeUserStats/forgeuserstats/tests/test_stats.py | 3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/1c6cb8cf/ForgeUserStats/forgeuserstats/tests/test_model.py
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/tests/test_model.py b/ForgeUserStats/forgeuserstats/tests/test_model.py
index e7670de..28b1a65 100644
--- a/ForgeUserStats/forgeuserstats/tests/test_model.py
+++ b/ForgeUserStats/forgeuserstats/tests/test_model.py
@@ -371,9 +371,11 @@ class TestUserStats(unittest.TestCase):
 
         with mock.patch('allura.lib.plugin.session'):
             self.user.set_password('testpassword')
-        addr = M.EmailAddress.create('rcopeland@geek.net')
         self.user.claim_address('rcopeland@geek.net')
 
+        addr = M.EmailAddress.query.get(email='rcopeland@geek.net')
+        addr.confirmed = True
+
         repo_dir = pkg_resources.resource_filename(
             'forgeuserstats', 'tests/data')
 

http://git-wip-us.apache.org/repos/asf/allura/blob/1c6cb8cf/ForgeUserStats/forgeuserstats/tests/test_stats.py
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/tests/test_stats.py b/ForgeUserStats/forgeuserstats/tests/test_stats.py
index a09de1e..3055b88 100644
--- a/ForgeUserStats/forgeuserstats/tests/test_stats.py
+++ b/ForgeUserStats/forgeuserstats/tests/test_stats.py
@@ -195,8 +195,9 @@ class TestGitCommit(TestController, unittest.TestCase):
 
         user = User.by_username('test-admin')
         user.set_password('testpassword')
-        M.EmailAddress.create('rcopeland@geek.net')
         user.claim_address('rcopeland@geek.net')
+        addr = M.EmailAddress.query.get(email='rcopeland@geek.net')
+        addr.confirmed = True
         self.setup_with_tools()
 
     @with_git


[03/28] git commit: [#7585] ticket:639 Small amends

Posted by je...@apache.org.
[#7585] ticket:639 Small amends


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

Branch: refs/heads/je/42cc_4905
Commit: e8938e54f50dde7b919c1173c482c70aadd06529
Parents: ce6c4aa
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon Aug 25 14:31:27 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Aug 26 19:24:58 2014 +0000

----------------------------------------------------------------------
 Allura/allura/templates/user_prefs.html | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e8938e54/Allura/allura/templates/user_prefs.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/user_prefs.html b/Allura/allura/templates/user_prefs.html
index b4dcc85..883dcd9 100644
--- a/Allura/allura/templates/user_prefs.html
+++ b/Allura/allura/templates/user_prefs.html
@@ -113,12 +113,9 @@
             </tr>
           </table>
           <div class="grid-22">
-            <p></p>
-            <input type="hidden" name="password">
-          </div>
-          <div class="grid-22">
             {{lib.submit_button('Save', name='addr-save')}}
           </div>
+          {{lib.hidden_field('password', '')}}
           {{lib.csrf_token()}}
         </fieldset>
       </form>
@@ -235,7 +232,7 @@
           if ($("input[name='password']").val() == ''){
             e.preventDefault();
           }
-          if ($("input[name='new_addr.addr']").val().length != 0){
+          if ($(this).attr('name') == 'addr-save' || $("input[name='new_addr.addr']").val().length != 0) {
             launch();
           }
         });
@@ -251,4 +248,4 @@
         });
       });
   </script>
- {% endblock %}
\ No newline at end of file
+ {% endblock %}


[24/28] 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/4c45eb2d
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/4c45eb2d
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/4c45eb2d

Branch: refs/heads/je/42cc_4905
Commit: 4c45eb2dba9340e7520d4153ef0da658ad4e903c
Parents: 0e03930
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Aug 26 09:36:16 2014 +0000
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Fri Sep 12 09:22:20 2014 +0300

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


http://git-wip-us.apache.org/repos/asf/allura/blob/4c45eb2d/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)
 


[07/28] git commit: [#7527] Allow different users to claim the same email address + tests

Posted by je...@apache.org.
[#7527] Allow different users to claim the same email address + tests


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

Branch: refs/heads/je/42cc_4905
Commit: 3e6fdda33a95a69a0fe68655e802db2afbf52c06
Parents: 7c30568
Author: Alexander Luberg <al...@slashdotmedia.com>
Authored: Tue Jul 22 18:15:06 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Aug 28 20:26:59 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py           | 24 +++++++--
 Allura/allura/lib/mail_util.py              |  4 +-
 Allura/allura/model/auth.py                 | 25 ++++-----
 Allura/allura/tests/functional/test_auth.py | 65 +++++++++++++++++++++---
 Allura/allura/tests/model/test_auth.py      | 12 +++--
 Allura/allura/tests/test_mail_util.py       |  8 +--
 6 files changed, 104 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/3e6fdda3/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 247a94b..dc3a177 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -179,7 +179,7 @@ class AuthController(BaseController):
         if not email:
             redirect('/')
 
-        email_record = M.EmailAddress.query.find({'_id': email}).first()
+        email_record = M.EmailAddress.query.find({'email': email}).first()
         user_record = M.User.by_email_address(email)
 
         if user_record and email_record.confirmed:
@@ -225,7 +225,7 @@ class AuthController(BaseController):
 
     @expose()
     def send_verification_link(self, a):
-        addr = M.EmailAddress.query.get(_id=a)
+        addr = M.EmailAddress.query.get(email=a, claimed_by_user_id=c.user._id)
         if addr:
             addr.send_verification_link()
             flash('Verification link sent')
@@ -236,8 +236,25 @@ class AuthController(BaseController):
     @expose()
     def verify_addr(self, a):
         addr = M.EmailAddress.query.get(nonce=a)
+        # import pydevd
+        # pydevd.settrace('localhost', port=14000, stdoutToServer=True, stderrToServer=True)
+
         if addr:
             addr.confirmed = True
+            # Remove other non-confirmed emails claimed by other users
+            claimed_by_others = M.EmailAddress.query.find({
+                'email': addr.email,
+                'claimed_by_user_id': {"$ne": addr.claimed_by_user_id}
+            }).all()
+
+            users = [email.claimed_by_user() for email in claimed_by_others]
+            for user in users:
+                user.email_addresses.remove(addr.email)
+
+            M.EmailAddress.query.remove({
+                'email': addr.email,
+                'claimed_by_user_id': {'$ne': addr.claimed_by_user_id}
+            })
             flash('Email address confirmed')
             M.AuditLog.log_user('Email address verified: %s', addr._id)
         else:
@@ -442,7 +459,8 @@ 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 claim new email', 'error')
                     redirect('.')
-                if M.EmailAddress.query.get(_id=new_addr['addr']):
+                if M.EmailAddress.query.get(email=new_addr['addr'], confirmed=True) \
+                        or M.EmailAddress.query.get(email=new_addr['addr'], claimed_by_user_id=c.user._id):
                     flash('Email address already claimed', 'error')
                 elif mail_util.isvalid(new_addr['addr']):
                     c.user.email_addresses.append(new_addr['addr'])

http://git-wip-us.apache.org/repos/asf/allura/blob/3e6fdda3/Allura/allura/lib/mail_util.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py
index 4da1819..a932f13 100644
--- a/Allura/allura/lib/mail_util.py
+++ b/Allura/allura/lib/mail_util.py
@@ -159,13 +159,13 @@ def identify_sender(peer, email_address, headers, msg):
     from allura import model as M
     # Dumb ID -- just look for email address claimed by a particular user
     addr = M.EmailAddress.query.get(
-        _id=M.EmailAddress.canonical(email_address))
+        email=M.EmailAddress.canonical(email_address))
     if addr and addr.claimed_by_user_id:
         return addr.claimed_by_user()
     from_address = headers.get('From', '').strip()
     if not from_address:
         return M.User.anonymous()
-    addr = M.EmailAddress.query.get(_id=M.EmailAddress.canonical(from_address))
+    addr = M.EmailAddress.query.get(email=M.EmailAddress.canonical(from_address))
     if addr and addr.claimed_by_user_id:
         return addr.claimed_by_user()
     return M.User.anonymous()

http://git-wip-us.apache.org/repos/asf/allura/blob/3e6fdda3/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 5d7900b..1c753d5 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -115,12 +115,12 @@ class EmailAddress(MappedClass):
     class __mongometa__:
         name = 'email_address'
         session = main_orm_session
-        indexes = [
-            'claimed_by_user_id']
+        unique_indexes = [('email', 'claimed_by_user_id'),]
 
-    _id = FieldProperty(str)
+    _id = FieldProperty(S.ObjectId)
+    email = FieldProperty(str)
     claimed_by_user_id = FieldProperty(S.ObjectId, if_missing=None)
-    confirmed = FieldProperty(bool)
+    confirmed = FieldProperty(bool, if_missing=False)
     nonce = FieldProperty(str)
 
     def claimed_by_user(self):
@@ -129,10 +129,7 @@ class EmailAddress(MappedClass):
     @classmethod
     def upsert(cls, addr):
         addr = cls.canonical(addr)
-        result = cls.query.get(_id=addr)
-        if not result:
-            result = cls(_id=addr)
-        return result
+        return cls(email=addr)
 
     @classmethod
     def canonical(cls, addr):
@@ -147,13 +144,13 @@ class EmailAddress(MappedClass):
 
     def send_verification_link(self):
         self.nonce = sha256(os.urandom(10)).hexdigest()
-        log.info('Sending verification link to %s', self._id)
+        log.info('Sending verification link to %s', self.email)
         text = '''
 To verify the email address %s belongs to the user %s,
 please visit the following URL:
 
     %s
-''' % (self._id, self.claimed_by_user().username, g.url('/auth/verify_addr', a=self.nonce))
+''' % (self.email, self.claimed_by_user().username, g.url('/auth/verify_addr', a=self.nonce))
         log.info('Verification email:\n%s', text)
         allura.tasks.mail_tasks.sendsimplemail.post(
             fromaddr=g.noreply,
@@ -550,7 +547,7 @@ class User(MappedClass, ActivityNode, ActivityObject):
 
     @classmethod
     def by_email_address(cls, addr):
-        ea = EmailAddress.query.get(_id=addr)
+        ea = EmailAddress.query.get(email=addr)
         if ea is None:
             return None
         return ea.claimed_by_user()
@@ -573,7 +570,7 @@ class User(MappedClass, ActivityNode, ActivityObject):
         state(self).soil()
 
     def address_object(self, addr):
-        return EmailAddress.query.get(_id=addr, claimed_by_user_id=self._id)
+        return EmailAddress.query.get(email=addr, claimed_by_user_id=self._id)
 
     def claim_address(self, email_address):
         addr = EmailAddress.canonical(email_address)
@@ -592,10 +589,10 @@ class User(MappedClass, ActivityNode, ActivityObject):
         addresses = set(self.email_addresses)
         for addr in EmailAddress.query.find(
                 dict(claimed_by_user_id=self._id)):
-            if addr._id in addresses:
+            if addr.email in addresses:
                 if not addr.confirmed:
                     addr.confirmed = True
-                addresses.remove(addr._id)
+                addresses.remove(addr.email)
             else:
                 addr.delete()
         for a in addresses:

http://git-wip-us.apache.org/repos/asf/allura/blob/3e6fdda3/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 8af23ca..65d3a50 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -57,8 +57,7 @@ class TestAuth(TestController):
 
     def test_login(self):
         self.app.get('/auth/')
-        r = self.app.post('/auth/send_verification_link',
-                          params=dict(a='test@example.com'))
+        r = self.app.post('/auth/send_verification_link', params=dict(a='test@example.com'))
         email = M.User.query.get(username='test-admin').email_addresses[0]
         r = self.app.post('/auth/send_verification_link', params=dict(a=email))
         ThreadLocalORMSession.flush_all()
@@ -115,6 +114,60 @@ class TestAuth(TestController):
             if header == 'Set-cookie':
                 assert_in('expires', contents)
 
+    def test_claimed_duplicate_emails_by_different_users(self):
+        email_address = 'test-email@domain.com'
+
+        user1 = M.User.query.get(username='test-user-0')
+        user2 = M.User.query.get(username='test-user-1')
+
+        user1.claim_address(email_address)
+        user2.claim_address(email_address)
+
+        ThreadLocalORMSession.flush_all()
+        r = self.app.post('/auth/send_verification_link',
+                          params=dict(a=email_address),
+                          extra_environ={'username': 'test-user-0'})
+        email1 = M.EmailAddress.query.find(dict(email=email_address, claimed_by_user_id=user1._id)).first()
+        email2 = M.EmailAddress.query.find(dict(email=email_address, claimed_by_user_id=user2._id)).first()
+
+        # User1 verifies claimed address. All other duplicates should be removed once it is confirmed
+        r = self.app.get('/auth/verify_addr', params=dict(a=email1.nonce))
+
+        assert email1.confirmed == True
+        assert M.EmailAddress.query.find(dict(email=email_address)).count() == 1
+        assert email_address in M.User.query.get(username='test-user-0').email_addresses
+        assert email_address not in M.User.query.get(username='test-user-1').email_addresses
+
+    @td.with_user_project('test-admin')
+    def test_user_can_not_claim_duplicate_emails(self):
+        email_address = 'test_abcd_123@domain.net'
+        user = M.User.query.get(username='test-admin')
+        addresses_number = len(user.email_addresses)
+        self.app.post('/auth/preferences/update',
+                      params={
+                          'preferences.display_name': 'Test Admin',
+                          'new_addr.addr': email_address,
+                          'new_addr.claim': 'Claim Address',
+                          'primary_addr': 'test-admin@users.localhost',
+                          'preferences.email_format': 'plain'
+                      },
+                      extra_environ=dict(username='test-admin'))
+
+        assert M.EmailAddress.query.find(dict(email=email_address, claimed_by_user_id=user._id)).count() == 1
+        r = self.app.post('/auth/preferences/update',
+                          params={
+                              'preferences.display_name': 'Test Admin',
+                              'new_addr.addr': email_address,
+                              'new_addr.claim': 'Claim Address',
+                              'primary_addr': 'test-admin@users.localhost',
+                              'preferences.email_format': 'plain'
+                          },
+                          extra_environ=dict(username='test-admin'))
+
+        assert json.loads(self.webflash(r))['status'] == 'error', self.webflash(r)
+        assert M.EmailAddress.query.find(dict(email=email_address, claimed_by_user_id=user._id)).count() == 1
+        assert len(M.User.query.get(username='test-admin').email_addresses) == addresses_number + 1
+
     @td.with_user_project('test-admin')
     def test_prefs(self):
         r = self.app.get('/auth/preferences/',
@@ -792,7 +845,7 @@ class TestPasswordReset(TestController):
             {'claimed_by_user_id': user._id}).first()
         email.confirmed = False
         ThreadLocalORMSession.flush_all()
-        self.app.post('/auth/password_recovery_hash', {'email': email._id})
+        self.app.post('/auth/password_recovery_hash', {'email': email.email})
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
         assert hash is None
 
@@ -804,7 +857,7 @@ class TestPasswordReset(TestController):
             {'claimed_by_user_id': user._id}).first()
         user.disabled = True
         ThreadLocalORMSession.flush_all()
-        self.app.post('/auth/password_recovery_hash', {'email': email._id})
+        self.app.post('/auth/password_recovery_hash', {'email': email.email})
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
         assert hash is None
 
@@ -818,7 +871,7 @@ class TestPasswordReset(TestController):
         ThreadLocalORMSession.flush_all()
         old_pw_hash = user.password
         with td.audits('Password recovery link sent to: test-admin@users.localhost'):
-            r = self.app.post('/auth/password_recovery_hash', {'email': email._id})
+            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')
         assert hash is not None
@@ -865,7 +918,7 @@ To reset your password on %s, please visit the following URL:
             {'claimed_by_user_id': user._id}).first()
         email.confirmed = True
         ThreadLocalORMSession.flush_all()
-        r = self.app.post('/auth/password_recovery_hash', {'email': email._id})
+        r = self.app.post('/auth/password_recovery_hash', {'email': email.email})
         user = M.User.by_username('test-admin')
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
         user.set_tool_data('AuthPasswordReset',

http://git-wip-us.apache.org/repos/asf/allura/blob/3e6fdda3/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 f3869ee..165e331 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -51,24 +51,26 @@ def setUp():
 
 @with_setup(setUp)
 def test_email_address():
-    addr = M.EmailAddress(_id='test_admin@domain.net',
+    addr = M.EmailAddress(email='test_admin@domain.net',
                           claimed_by_user_id=c.user._id)
     ThreadLocalORMSession.flush_all()
     assert addr.claimed_by_user() == c.user
     addr2 = M.EmailAddress.upsert('test@domain.net')
     addr3 = M.EmailAddress.upsert('test_admin@domain.net')
-    assert addr3 is addr
+
+    # Duplicate emails are allowed, until the email is confirmed
+    assert addr3 is not addr
+
     assert addr2 is not addr
     assert addr2
     addr4 = M.EmailAddress.upsert('test@DOMAIN.NET')
-    assert addr4 is addr2
+    assert addr4 is not addr2
     with patch('allura.lib.app_globals.request', Request.blank('/')):
         addr.send_verification_link()
     assert addr is c.user.address_object('test_admin@domain.net')
     c.user.claim_address('test@DOMAIN.NET')
     assert 'test@domain.net' in c.user.email_addresses
 
-
 @td.with_user_project('test-admin')
 @with_setup(setUp)
 def test_user():
@@ -173,7 +175,7 @@ def test_default_project_roles():
 
 @with_setup(setUp)
 def test_email_address_claimed_by_user():
-    addr = M.EmailAddress(_id='test_admin@domain.net',
+    addr = M.EmailAddress(email='test_admin@domain.net',
                           claimed_by_user_id=c.user._id)
     c.user.disabled = True
     ThreadLocalORMSession.flush_all()

http://git-wip-us.apache.org/repos/asf/allura/blob/3e6fdda3/Allura/allura/tests/test_mail_util.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_mail_util.py b/Allura/allura/tests/test_mail_util.py
index 64a1c92..c2fe363 100644
--- a/Allura/allura/tests/test_mail_util.py
+++ b/Allura/allura/tests/test_mail_util.py
@@ -193,7 +193,7 @@ class TestIdentifySender(object):
         EA.query.get.side_effect = [
             mock.Mock(claimed_by_user_id=True, claimed_by_user=lambda:'user')]
         assert_equal(identify_sender(None, 'arg', None, None), 'user')
-        EA.query.get.assert_called_once_with(_id='arg')
+        EA.query.get.assert_called_once_with(email='arg')
 
     @mock.patch('allura.model.EmailAddress')
     def test_header(self, EA):
@@ -203,7 +203,7 @@ class TestIdentifySender(object):
         assert_equal(
             identify_sender(None, 'arg', {'From': 'from'}, None), 'user')
         assert_equal(EA.query.get.call_args_list,
-                     [mock.call(_id='arg'), mock.call(_id='from')])
+                     [mock.call(email='arg'), mock.call(email='from')])
 
     @mock.patch('allura.model.User')
     @mock.patch('allura.model.EmailAddress')
@@ -213,7 +213,7 @@ class TestIdentifySender(object):
         EA.query.get.side_effect = [
             None, mock.Mock(claimed_by_user_id=True, claimed_by_user=lambda:'user')]
         assert_equal(identify_sender(None, 'arg', {}, None), anon)
-        assert_equal(EA.query.get.call_args_list, [mock.call(_id='arg')])
+        assert_equal(EA.query.get.call_args_list, [mock.call(email='arg')])
 
     @mock.patch('allura.model.User')
     @mock.patch('allura.model.EmailAddress')
@@ -224,7 +224,7 @@ class TestIdentifySender(object):
         assert_equal(
             identify_sender(None, 'arg', {'From': 'from'}, None), anon)
         assert_equal(EA.query.get.call_args_list,
-                     [mock.call(_id='arg'), mock.call(_id='from')])
+                     [mock.call(email='arg'), mock.call(email='from')])
 
 
 def test_parse_message_id():


[27/28] 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/4cd61a40
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/4cd61a40
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/4cd61a40

Branch: refs/heads/je/42cc_4905
Commit: 4cd61a40161f421332a1a1f31e44bf93cac5e161
Parents: 4c45eb2
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Sep 12 09:53:05 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Fri Sep 12 09:53:05 2014 +0300

----------------------------------------------------------------------
 .../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/4cd61a40/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/4cd61a40/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


[02/28] git commit: [#7585] ticket:642 Move popup to prefs block

Posted by je...@apache.org.
[#7585] ticket:642 Move popup to prefs block


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

Branch: refs/heads/je/42cc_4905
Commit: 7c30568b9f2af9aa44b43a79e629fdb080a1b0b8
Parents: e8938e5
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Aug 26 14:23:59 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Aug 26 19:24:58 2014 +0000

----------------------------------------------------------------------
 Allura/allura/templates/user_prefs.html | 33 +++++++++++++++-------------
 1 file changed, 18 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/7c30568b/Allura/allura/templates/user_prefs.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/user_prefs.html b/Allura/allura/templates/user_prefs.html
index 883dcd9..fec5dcd 100644
--- a/Allura/allura/templates/user_prefs.html
+++ b/Allura/allura/templates/user_prefs.html
@@ -84,7 +84,7 @@
               {% set obj = c.user.address_object(a) %}
               {% if obj.confirmed %}
                 <td>{{lib.radio_button('primary_addr', None, a, c.user.preferences.email_address)}}</td>
-              {% else %} 
+              {% else %}
                 <td> <input type="radio" disabled="disabled"></td>
               {% endif %}
               <td>{{a}}</td>
@@ -119,6 +119,22 @@
           {{lib.csrf_token()}}
         </fieldset>
       </form>
+
+      <!-- popup -->
+      <form class="cur_password" style="display:none">
+        <div class="grid-13">
+          <p>{{lib.password_field('current_password', 'Current password:')}}</p>
+        </div>
+        <div class="grid-13">
+          <p>
+          <input type="submit" name="enter_pass_submit" value="Ok">
+          <input type="button" name="cancel_lightbox" value="Cancel">
+          </p>
+        </div>
+      </form>
+      {{c.enter_password.display(content='<h1>Enter password</h1>')}}
+      <!-- end popup -->
+
       {% endif %}  {# allow_edit_prefs #}
     {% endblock edit_prefs_form %}
 
@@ -157,19 +173,6 @@
           </form>
         </fieldset>
       {% endif %}
-      
-      <form class="cur_password" style="display:none">
-        <div class="grid-13"> 
-          <p>{{lib.password_field('current_password', 'Current password:')}}</p>
-        </div>
-        <div class="grid-13">
-          <p>  
-          <input type="submit" name="enter_pass_submit" value="Ok">
-          <input type="button" name="cancel_lightbox" value="Cancel">
-          </p>
-        </div>
-      </form>
-      {{c.enter_password.display(content='<h1>Enter password</h1>')}}
     {% endblock %}
   </div>
 {% endblock %}
@@ -209,7 +212,7 @@
 
           enter_password_popup.append(enter_password_form.show());
           enter_password_popup.lightbox_me({
-            onLoad: function() { 
+            onLoad: function() {
             $('.cur_password').find('input:first').focus();
             }
           });


[23/28] 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_4905
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


[12/28] git commit: [#7527] Replaced the migration with a raw mongo migration

Posted by je...@apache.org.
[#7527] Replaced the migration with a raw mongo migration


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

Branch: refs/heads/je/42cc_4905
Commit: e3eaaa04584c7de514ec3cb6030d5c0e00fd25ad
Parents: d307dca
Author: Alexander Luberg <al...@slashdotmedia.com>
Authored: Tue Jul 29 21:52:39 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Aug 28 20:27:01 2014 +0000

----------------------------------------------------------------------
 .../030-email-address-_id-to-email.js           | 20 ++++++++++
 .../030-email-address-_id-to-email.py           | 39 --------------------
 2 files changed, 20 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e3eaaa04/scripts/migrations/030-email-address-_id-to-email.js
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email.js b/scripts/migrations/030-email-address-_id-to-email.js
new file mode 100644
index 0000000..f831623
--- /dev/null
+++ b/scripts/migrations/030-email-address-_id-to-email.js
@@ -0,0 +1,20 @@
+//1) Copy to the new collection with data updates
+db.email_address.find().snapshot().forEach(function(e){
+    e.email = e._id;
+    e._id = new ObjectId();
+    db.email_address_new.insert(e);
+    db.email_address.update({'_id': e._id}, {'migrated': true})
+});
+//2) Updated code on production(git pull)
+//3) Rename collections
+db.email_address.renameCollection("email_address_old", {dropTarget: true})
+db.email_address_new.renameCollection("email_address", {dropTarget: true})
+//4) Post Migration - copy/update all the object which were created between 1)&2)
+db.email_address_old.find({'migrated': {'$not': false}}).snapshot().forEach(function(e){
+    e.email = e._id;
+    e._id = new ObjectId();
+    db.email_address.insert(e);
+    db.email_address_old.update({'_id': e._id}, {'migrated': true})
+});
+
+db.email_address_old.drop()

http://git-wip-us.apache.org/repos/asf/allura/blob/e3eaaa04/scripts/migrations/030-email-address-_id-to-email.py
----------------------------------------------------------------------
diff --git a/scripts/migrations/030-email-address-_id-to-email.py b/scripts/migrations/030-email-address-_id-to-email.py
deleted file mode 100644
index e70af50..0000000
--- a/scripts/migrations/030-email-address-_id-to-email.py
+++ /dev/null
@@ -1,39 +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.
-
-from bson import ObjectId
-
-import logging
-
-from ming.odm import ThreadLocalORMSession
-
-from allura import model as M
-
-log = logging.getLogger(__name__)
-
-
-def main():
-    email_addresses = M.EmailAddress.query.find(dict(email=None)).all()
-    for email in email_addresses:
-        email.email = email._id
-        email._id = ObjectId()
-        ThreadLocalORMSession.flush_all()
-    ThreadLocalORMSession.close_all()
-
-
-if __name__ == '__main__':
-    main()


[20/28] 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_4905
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,


[05/28] git commit: [#7585] ticket:639 fixed macros for html, formated js code

Posted by je...@apache.org.
[#7585] ticket:639 fixed macros for html, formated js code


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

Branch: refs/heads/je/42cc_4905
Commit: 2b781a49f0432e47d4357f993c3637e25235495d
Parents: 61656c4
Author: discort <le...@bk.ru>
Authored: Thu Aug 21 20:58:31 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Aug 26 19:24:58 2014 +0000

----------------------------------------------------------------------
 Allura/allura/templates/jinja_master/lib.html |   6 +-
 Allura/allura/templates/user_prefs.html       | 124 +++++++++++----------
 2 files changed, 72 insertions(+), 58 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/2b781a49/Allura/allura/templates/jinja_master/lib.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/lib.html b/Allura/allura/templates/jinja_master/lib.html
index b3a5bf4..e4b1eb3 100644
--- a/Allura/allura/templates/jinja_master/lib.html
+++ b/Allura/allura/templates/jinja_master/lib.html
@@ -130,10 +130,14 @@
   <input type="text" id="{{name}}" name="{{name}}" class="text" value="{{value}}"/><br/>
 {% endmacro %}
 
-{% macro hidden_field(name, label, value='') %}
+{% macro password_field(name, label, value='') %}
   {% if label %}
   <label for="{{name}}">{{label}}</label><br/>
   {% endif %}
+  <input type="password" id="{{name}}" name="{{name}}" class="text" value="{{value}}"/><br/>
+{% endmacro %}
+
+{% macro hidden_field(name, value='') %}
   <input type="hidden" id="{{name}}" name="{{name}}" class="text" value="{{value}}"/><br/>
 {% endmacro %}
 

http://git-wip-us.apache.org/repos/asf/allura/blob/2b781a49/Allura/allura/templates/user_prefs.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/user_prefs.html b/Allura/allura/templates/user_prefs.html
index b3cfb6e..9c477f6 100644
--- a/Allura/allura/templates/user_prefs.html
+++ b/Allura/allura/templates/user_prefs.html
@@ -24,6 +24,7 @@
 {% block header %}User Preferences for {{c.user.username}}{% endblock %}
 
 {% block content %}
+{% do g.register_js('js/jquery.lightbox_me.js') %}
   {{ super() }}
   <div class="grid-23">
     <h2>Preferences</h2>
@@ -159,16 +160,15 @@
           </form>
         </fieldset>
       {% endif %}
-      {% do g.register_js('js/jquery.lightbox_me.js') %}
+      
       <form class="cur_password">
-        <h1><span class="log-in">Enter password</span></h1>
-        <p class="float">
-            <label for="password"><i class="icon-lock"></i>Current password:</label>
-            <input type="password" name="current_password" placeholder="Password">
+        <h1>Enter password</h1>
+        <p>
+          {{lib.password_field('current_password', 'Current password:')}}
         </p>
-        <p class="clearfix">  
-            <input type="submit" name="enter_pass_submit" value="Ok">
-            <input type="button" name="cancel_lightbox" value="Cancel">
+        <p>  
+          <input type="submit" name="enter_pass_submit" value="Ok">
+          <input type="button" name="cancel_lightbox" value="Cancel">
         </p>
       </form>
     {% endblock %}
@@ -198,73 +198,83 @@
     border: 0;
   }
   .cur_password {
-    width: 250px;
-    margin: 60px auto 30px;
-    padding: 15px;
-    position: relative;
     display:none;
-    background: #fffaf6;
+    width: 500px;
+    float: left;
+    overflow: hidden;
+    margin: 0 10px;
+    padding: 15px;
+
+    left: 50%;
+    margin-left: -311px;
+    z-index: 1002;
+    position: fixed;
+    top: 40px;
+    margin-top: 0px;
+    background: #636363;
     border-radius: 4px;
-    color: #7e7975;
+    color: #ffffff;
     box-shadow:
-        0 2px 2px rgba(0,0,0,0.2),        
+        0 1px 2px rgba(0,0,0,0.2),        
         0 1px 5px rgba(0,0,0,0.2),        
-        0 0 0 12px rgba(255,255,255,0.4);
+        0 0 0 5px rgba(0,0,0,0.4); 
   }
   .cur_password h1 {
-    font-size: 15px;
+    font-size: 18px;
+    line-height: 36px;
     font-weight: bold;
-    color: #bdb5aa;
+    color: #ffffff;
     padding-bottom: 8px;
     border-bottom: 1px solid #EBE6E2;
-    text-shadow: 0 2px 0 rgba(255,255,255,0.8);
-    box-shadow: 0 1px 0 rgba(255,255,255,0.8);
   }
 </style>
 {% endblock %}
 
 {% block extra_js %}
-   <script type="text/javascript">
-    $(function() {
+  <script type="text/javascript">
+      $(function() {
+          $("input[name='enter_pass_submit']").click(function (e) {
+            $("input[name='password']").val(
+                $("input[name='current_password']").val()
+              );
+            $("form[name='update-email']").submit();
+            e.preventDefault();
+          });
 
-                $("input[name='enter_pass_submit']").click(function (e) {
-                  $("input[name='password']").val(
-                      $("input[name='current_password']").val()
-                    );
-                  $("form[name='update-email']").submit();
-                  e.preventDefault();
-                });
+          $("input[name='cancel_lightbox']").click(function(){
+            $('.cur_password').trigger('close');
+            return false;
+          });
 
-                $("input[name='cancel_lightbox']").click(function(){
-                  $('.cur_password').trigger('close');
-                  return false;
-                });
-
-                function launch() {
-                     $('.cur_password').lightbox_me({
-                      centered: true, 
-                      onLoad: function() { 
-                        $('.cur_password').find('input:first').focus();
-                      }
-                  });
+          function launch() {
+               $('.cur_password').lightbox_me({
+                centered: true, 
+                onLoad: function() { 
+                  $('.cur_password').find('input:first').focus();
                 }
+            });
+          }
 
-                $("input[name='new_addr.claim'], input[name='addr-save']").click(function(e) {
-                  if ($("input[name='password']").val() == ''){
-                    e.preventDefault();
-                  }
-                  launch();
-                });
+          $("input[name='new_addr.claim'], input[name='addr-save']").click(function(e) {
+            if ($("input[name='password']").val() == ''){
+              e.preventDefault();
+            }
+            if ($("input[name='new_addr.addr']").val().length != 0){
+              launch();
+            }
+          });
 
-                $('input:submit', ".addr-delete").click(function(e) {
-                  if ($("input[name='password']").val() == ''){
-                    e.preventDefault();
-                  }
-                  var attr_del = $(this).attr('name')
-                  $(document.getElementById(attr_del)).val("1");
-                  launch();
-                });
+          $('input:submit', ".addr-delete").click(function(e) {
+            if ($("input[name='password']").val() == ''){
+              e.preventDefault();
+            }
+            $('input:hidden', ".addr-delete").val("");
+            var attr_del = $(this).attr('name')
+            $(document.getElementById(attr_del)).val("1");
+            //$('#' + attr_del).val("1");
+            launch();
+          });
 
-            });
-   </script>
+      });
+  </script>
  {% endblock %}
\ No newline at end of file


[19/28] 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_4905
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()


[09/28] git commit: [#7527] Flush email address

Posted by je...@apache.org.
[#7527] Flush email address


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

Branch: refs/heads/je/42cc_4905
Commit: f825a569fa97dfd30058fcc63771de6a770e1311
Parents: e76619a
Author: Alexander Luberg <al...@slashdotmedia.com>
Authored: Tue Aug 26 15:27:58 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Aug 28 20:27:01 2014 +0000

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


http://git-wip-us.apache.org/repos/asf/allura/blob/f825a569/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 7cc169d..b7ea34b 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -580,6 +580,7 @@ class User(MappedClass, ActivityNode, ActivityObject):
         if addr in self.email_addresses:
             return
         self.email_addresses.append(addr)
+        session(email_addr).flush(email_addr)
 
     @classmethod
     def register(cls, doc, make_project=True):


[21/28] 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_4905
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,


[18/28] 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_4905
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"))


[28/28] 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/2602ee1e
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/2602ee1e
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/2602ee1e

Branch: refs/heads/je/42cc_4905
Commit: 2602ee1e7a2bcbc2210f066197328fda3fb60218
Parents: 4cd61a4
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Sep 12 10:16:10 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Fri Sep 12 10:16:10 2014 +0300

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


http://git-wip-us.apache.org/repos/asf/allura/blob/2602ee1e/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


[06/28] git commit: [#7585] ticket:639 added lightbox popup for buttons clame, save & delete

Posted by je...@apache.org.
[#7585] ticket:639 added lightbox popup for buttons clame, save & delete


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

Branch: refs/heads/je/42cc_4905
Commit: 61656c4436e0172376662a5d2efe8ecd34171460
Parents: 774191e
Author: discort <le...@bk.ru>
Authored: Thu Aug 21 10:34:41 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Aug 26 19:24:58 2014 +0000

----------------------------------------------------------------------
 Allura/allura/templates/jinja_master/lib.html |  7 ++
 Allura/allura/templates/user_prefs.html       | 95 ++++++++++++++++++++--
 2 files changed, 97 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/61656c44/Allura/allura/templates/jinja_master/lib.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/lib.html b/Allura/allura/templates/jinja_master/lib.html
index 229c351..b3a5bf4 100644
--- a/Allura/allura/templates/jinja_master/lib.html
+++ b/Allura/allura/templates/jinja_master/lib.html
@@ -130,6 +130,13 @@
   <input type="text" id="{{name}}" name="{{name}}" class="text" value="{{value}}"/><br/>
 {% endmacro %}
 
+{% macro hidden_field(name, label, value='') %}
+  {% if label %}
+  <label for="{{name}}">{{label}}</label><br/>
+  {% endif %}
+  <input type="hidden" id="{{name}}" name="{{name}}" class="text" value="{{value}}"/><br/>
+{% endmacro %}
+
 {% macro radio_button(name, label, option, value=None) %}
   {% if label %}
     <label for="{{name}}">{{label}}</label><br/>

http://git-wip-us.apache.org/repos/asf/allura/blob/61656c44/Allura/allura/templates/user_prefs.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/user_prefs.html b/Allura/allura/templates/user_prefs.html
index f76e9d6..b3cfb6e 100644
--- a/Allura/allura/templates/user_prefs.html
+++ b/Allura/allura/templates/user_prefs.html
@@ -40,7 +40,7 @@
 
     {% block edit_prefs_form %}
       {% if h.asbool(tg.config.get('auth.allow_edit_prefs', True)) %}
-      <form action="update" method="post">
+      <form action="update" method="post" name="update-email">
         <fieldset>
           <legend>General and Email Settings</legend>
           <label class="grid-4">Display Name</label>
@@ -98,7 +98,12 @@
               {% else %}
                 <td>Unknown addr obj {{a}}</td>
               {% endif %}
-              <td>{{lib.submit_button('Delete', 'addr-%s.delete' % loop.index0)}}</td>
+              <td>
+                <div class="addr-delete">
+                  {{lib.submit_button('Delete', 'addr-%s.delete' % loop.index0)}}
+                  {{lib.hidden_field('addr-%s.delete' % loop.index0, '')}}
+                </div>
+              </td>
             </tr>
             {% endfor %}
             <tr>
@@ -108,11 +113,10 @@
           </table>
           <div class="grid-22">
             <p></p>
-            <label for="password">Current password:</label>
-            <input type="password" name="password">
+            <input type="hidden" name="password">
           </div>
           <div class="grid-22">
-            {{lib.submit_button('Save')}}
+            {{lib.submit_button('Save', name='addr-save')}}
           </div>
           {{lib.csrf_token()}}
         </fieldset>
@@ -155,6 +159,18 @@
           </form>
         </fieldset>
       {% endif %}
+      {% do g.register_js('js/jquery.lightbox_me.js') %}
+      <form class="cur_password">
+        <h1><span class="log-in">Enter password</span></h1>
+        <p class="float">
+            <label for="password"><i class="icon-lock"></i>Current password:</label>
+            <input type="password" name="current_password" placeholder="Password">
+        </p>
+        <p class="clearfix">  
+            <input type="submit" name="enter_pass_submit" value="Ok">
+            <input type="button" name="cancel_lightbox" value="Cancel">
+        </p>
+      </form>
     {% endblock %}
   </div>
 {% endblock %}
@@ -181,5 +197,74 @@
     padding: 0;
     border: 0;
   }
+  .cur_password {
+    width: 250px;
+    margin: 60px auto 30px;
+    padding: 15px;
+    position: relative;
+    display:none;
+    background: #fffaf6;
+    border-radius: 4px;
+    color: #7e7975;
+    box-shadow:
+        0 2px 2px rgba(0,0,0,0.2),        
+        0 1px 5px rgba(0,0,0,0.2),        
+        0 0 0 12px rgba(255,255,255,0.4);
+  }
+  .cur_password h1 {
+    font-size: 15px;
+    font-weight: bold;
+    color: #bdb5aa;
+    padding-bottom: 8px;
+    border-bottom: 1px solid #EBE6E2;
+    text-shadow: 0 2px 0 rgba(255,255,255,0.8);
+    box-shadow: 0 1px 0 rgba(255,255,255,0.8);
+  }
 </style>
 {% endblock %}
+
+{% block extra_js %}
+   <script type="text/javascript">
+    $(function() {
+
+                $("input[name='enter_pass_submit']").click(function (e) {
+                  $("input[name='password']").val(
+                      $("input[name='current_password']").val()
+                    );
+                  $("form[name='update-email']").submit();
+                  e.preventDefault();
+                });
+
+                $("input[name='cancel_lightbox']").click(function(){
+                  $('.cur_password').trigger('close');
+                  return false;
+                });
+
+                function launch() {
+                     $('.cur_password').lightbox_me({
+                      centered: true, 
+                      onLoad: function() { 
+                        $('.cur_password').find('input:first').focus();
+                      }
+                  });
+                }
+
+                $("input[name='new_addr.claim'], input[name='addr-save']").click(function(e) {
+                  if ($("input[name='password']").val() == ''){
+                    e.preventDefault();
+                  }
+                  launch();
+                });
+
+                $('input:submit', ".addr-delete").click(function(e) {
+                  if ($("input[name='password']").val() == ''){
+                    e.preventDefault();
+                  }
+                  var attr_del = $(this).attr('name')
+                  $(document.getElementById(attr_del)).val("1");
+                  launch();
+                });
+
+            });
+   </script>
+ {% endblock %}
\ No newline at end of file