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

[1/8] git commit: [#7524] ticket:620 Add an index on audit_log.user_id

Repository: allura
Updated Branches:
  refs/heads/master 2e1735cbc -> 470519ea8


[#7524] ticket:620 Add an index on audit_log.user_id


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

Branch: refs/heads/master
Commit: 2e92047be7b243ac121eda04146574e669808d42
Parents: 36fadf8
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jul 25 11:44:16 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jul 25 16:02:57 2014 +0000

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


http://git-wip-us.apache.org/repos/asf/allura/blob/2e92047b/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index aa5a7a7..c9ba690 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -868,7 +868,7 @@ audit_log = collection(
     Field('_id', S.ObjectId()),
     Field('project_id', S.ObjectId, if_missing=None,
           index=True),  # main view of audit log queries by project_id
-    Field('user_id', S.ObjectId, if_missing=None),
+    Field('user_id', S.ObjectId, if_missing=None, index=True),
     Field('timestamp', datetime, if_missing=datetime.utcnow),
     Field('url', str),
     Field('message', str))


[8/8] git commit: [#7524] ticket:620 Change default audit log limit to 25

Posted by br...@apache.org.
[#7524] ticket:620 Change default audit log limit to 25


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

Branch: refs/heads/master
Commit: 470519ea8508cd23aa8e11cc016a0c7daab35af7
Parents: e280163
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jul 25 12:44:06 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jul 25 16:02:58 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/site_admin.py | 2 +-
 Allura/allura/ext/admin/admin_main.py   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/470519ea/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index 96229ee..51ad068 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -243,7 +243,7 @@ class SiteAdminController(object):
         return dict(prefix=prefix, shortname=shortname, mount_point=mount_point)
 
     @expose('jinja:allura:templates/site_admin_users_audit.html')
-    def users(self, username=None, limit=10, page=0, **kwargs):
+    def users(self, username=None, limit=25, page=0, **kwargs):
         user = M.User.by_username(username)
         limit = int(limit)
         page = int(page)

http://git-wip-us.apache.org/repos/asf/allura/blob/470519ea/Allura/allura/ext/admin/admin_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/admin_main.py b/Allura/allura/ext/admin/admin_main.py
index 2257287..26b058f 100644
--- a/Allura/allura/ext/admin/admin_main.py
+++ b/Allura/allura/ext/admin/admin_main.py
@@ -1196,7 +1196,7 @@ class GroupController(BaseController):
 class AuditController(BaseController):
     @with_trailing_slash
     @expose('jinja:allura.ext.admin:templates/audit.html')
-    def index(self, limit=10, page=0, **kwargs):
+    def index(self, limit=25, page=0, **kwargs):
         limit = int(limit)
         page = int(page)
         count = M.AuditLog.query.find(dict(project_id=c.project._id)).count()


[7/8] git commit: [#7524] ticket:620 Use autits helper in tests

Posted by br...@apache.org.
[#7524] ticket:620 Use autits helper in tests


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

Branch: refs/heads/master
Commit: e280163e77d717dfeae7ec7481fd055dddf0dbe5
Parents: 563d675
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jul 25 12:39:38 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jul 25 16:02:58 2014 +0000

----------------------------------------------------------------------
 Allura/allura/tests/decorators.py            | 19 ++++++
 Allura/allura/tests/functional/test_admin.py | 19 +-----
 Allura/allura/tests/functional/test_auth.py  | 71 +++++++++--------------
 3 files changed, 49 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e280163e/Allura/allura/tests/decorators.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/decorators.py b/Allura/allura/tests/decorators.py
index 521c76c..3796de7 100644
--- a/Allura/allura/tests/decorators.py
+++ b/Allura/allura/tests/decorators.py
@@ -16,6 +16,7 @@
 #       under the License.
 
 import sys
+import re
 from functools import wraps
 import contextlib
 
@@ -150,3 +151,21 @@ class patch_middleware_config(object):
     def __exit__(self, exc_type, exc_val, exc_t):
         allura.config.middleware.make_app = self._make_app
         return self
+
+
+@contextlib.contextmanager
+def audits(*messages):
+    M.AuditLog.query.remove()
+    yield
+    for message in messages:
+        assert M.AuditLog.query.find(dict(
+            message=re.compile(message))).count(), 'Could not find "%s"' % message
+
+
+@contextlib.contextmanager
+def out_audits(*messages):
+    M.AuditLog.query.remove()
+    yield
+    for message in messages:
+        assert not M.AuditLog.query.find(dict(
+            message=re.compile(message))).count(), 'Found unexpected: "%s"' % message

http://git-wip-us.apache.org/repos/asf/allura/blob/e280163e/Allura/allura/tests/functional/test_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_admin.py b/Allura/allura/tests/functional/test_admin.py
index 09edd47..819a92a 100644
--- a/Allura/allura/tests/functional/test_admin.py
+++ b/Allura/allura/tests/functional/test_admin.py
@@ -34,6 +34,7 @@ import mock
 
 from allura.tests import TestController
 from allura.tests import decorators as td
+from allura.tests.decorators import audits, out_audits
 from alluratest.controller import TestRestApiBase, setup_trove_categories
 from allura import model as M
 from allura.app import SitemapEntry
@@ -47,24 +48,6 @@ from forgewiki.wiki_main import ForgeWikiApp
 log = logging.getLogger(__name__)
 
 
-@contextmanager
-def audits(*messages):
-    M.AuditLog.query.remove()
-    yield
-    for message in messages:
-        assert M.AuditLog.query.find(dict(
-            message=re.compile(message))).count(), 'Could not find "%s"' % message
-
-
-@contextmanager
-def out_audits(*messages):
-    M.AuditLog.query.remove()
-    yield
-    for message in messages:
-        assert not M.AuditLog.query.find(dict(
-            message=re.compile(message))).count(), 'Found unexpected: "%s"' % message
-
-
 class TestProjectAdmin(TestController):
 
     def get_available_tools(self):

http://git-wip-us.apache.org/repos/asf/allura/blob/e280163e/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 9e03bed..80c207c 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -103,50 +103,41 @@ class TestAuth(TestController):
                      'test-admin@users.localhost')
 
         # add test@example
-        r = self.app.post('/auth/preferences/update', params={
-            'preferences.display_name': 'Test Admin',
-            'new_addr.addr': 'test@example.com',
-            'new_addr.claim': 'Claim Address',
-            'primary_addr': 'test-admin@users.localhost',
-            'preferences.email_format': 'plain'},
-            extra_environ=dict(username='test-admin'))
+        with td.audits('New email address: test@example.com'):
+            r = self.app.post('/auth/preferences/update', params={
+                'preferences.display_name': 'Test Admin',
+                'new_addr.addr': 'test@example.com',
+                'new_addr.claim': 'Claim Address',
+                'primary_addr': 'test-admin@users.localhost',
+                'preferences.email_format': 'plain'},
+                extra_environ=dict(username='test-admin'))
         r = self.app.get('/auth/preferences/')
         assert 'test@example.com' in r
         user = M.User.query.get(username='test-admin')
         assert_equal(user.get_pref('email_address'), 'test-admin@users.localhost')
-        log = M.AuditLog.for_user(user).all()
-        assert_equal(len(log), 1)
-        assert_equal(log[0].message, 'New email address: test@example.com')
-        M.AuditLog.query.remove()
 
         # remove test-admin@users.localhost
-        r = self.app.post('/auth/preferences/update', params={
-            'preferences.display_name': 'Test Admin',
-            'addr-1.ord': '1',
-            'addr-1.delete': 'on',
-            'addr-2.ord': '2',
-            'new_addr.addr': '',
-            'primary_addr': 'test-admin@users.localhost',
-            'preferences.email_format': 'plain'},
-            extra_environ=dict(username='test-admin'))
+        with td.audits('Email address deleted: test-admin@users.localhost'):
+            r = self.app.post('/auth/preferences/update', params={
+                'preferences.display_name': 'Test Admin',
+                'addr-1.ord': '1',
+                'addr-1.delete': 'on',
+                'addr-2.ord': '2',
+                'new_addr.addr': '',
+                'primary_addr': 'test-admin@users.localhost',
+                'preferences.email_format': 'plain'},
+                extra_environ=dict(username='test-admin'))
         r = self.app.get('/auth/preferences/')
         assert 'test-admin@users.localhost' not in r
         # preferred address has not changed if email is not verified
         user = M.User.query.get(username='test-admin')
         assert_equal(user.get_pref('email_address'), None)
-        log = M.AuditLog.for_user(user).all()
-        assert_equal(len(log), 1)
-        assert_equal(log[0].message, 'Email address deleted: test-admin@users.localhost')
-        M.AuditLog.query.remove()
-
-        r = self.app.post('/auth/preferences/update', params={
-            'preferences.display_name': 'Admin',
-            'new_addr.addr': ''},
-            extra_environ=dict(username='test-admin'))
-        user = M.User.query.get(username='test-admin')
-        log = M.AuditLog.for_user(user).all()
-        assert_equal(len(log), 1)
-        assert_equal(log[0].message, 'Display Name changed Test Admin => Admin')
+
+        with td.audits('Display Name changed Test Admin => Admin'):
+            r = self.app.post('/auth/preferences/update', params={
+                'preferences.display_name': 'Admin',
+                'new_addr.addr': ''},
+                extra_environ=dict(username='test-admin'))
 
     @td.with_user_project('test-admin')
     def test_prefs_subscriptions(self):
@@ -732,7 +723,8 @@ class TestPasswordReset(TestController):
         email.confirmed = True
         ThreadLocalORMSession.flush_all()
         old_pw_hash = user.password
-        r = self.app.post('/auth/password_recovery_hash', {'email': email._id})
+        with td.audits('Password recovery link sent to: test-admin@users.localhost'):
+            r = self.app.post('/auth/password_recovery_hash', {'email': email._id})
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
         hash_expiry = user.get_tool_data('AuthPasswordReset', 'hash_expiry')
         assert hash is not None
@@ -744,7 +736,9 @@ class TestPasswordReset(TestController):
         assert_in('New Password (again):', r)
         form = r.forms[0]
         form['pw'] = form['pw2'] = new_password = '154321'
-        r = form.submit()
+        with td.audits('Password changed \(through recovery process\)'):
+            # escape parentheses, so they would not be treated as regex group
+            r = form.submit()
         user = M.User.query.get(username='test-admin')
         assert_not_equal(old_pw_hash, user.password)
         provider = plugin.LocalAuthenticationProvider(None)
@@ -768,13 +762,6 @@ To reset your password on %s, please visit the following URL:
         hash_expiry = user.get_tool_data('AuthPasswordReset', 'hash_expiry')
         assert_equal(hash, '')
         assert_equal(hash_expiry, '')
-        log = M.AuditLog.for_user(user).all()
-        assert_equal(len(log), 2)
-        messages = set([l.message for l in log])
-        assert_equal(
-            messages,
-            set(['Password recovery link sent to: test-admin@users.localhost',
-                 'Password changed (through recovery process)']))
 
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     @patch('allura.lib.helpers.gen_message_id')


[2/8] git commit: [#7524] ticket:613 Don't track activity if neither project or user are provided

Posted by br...@apache.org.
[#7524] ticket:613 Don't track activity if neither project or user are provided


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

Branch: refs/heads/master
Commit: d2753a9f183c0af8ae416511ebfbeab31c13f656
Parents: 69bdc9f
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Jul 22 12:33:16 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jul 25 16:02:57 2014 +0000

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


http://git-wip-us.apache.org/repos/asf/allura/blob/d2753a9f/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index c86f7de..aa5a7a7 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -902,6 +902,8 @@ class AuditLog(object):
         elif kwargs:
             message = message % kwargs
         pid = project._id if project is not None else None
+        if pid is None and user is None or user.is_anonymous():
+            return
         return cls(project_id=pid, user_id=user._id, url=url, message=message)
 
     @classmethod


[5/8] git commit: [#7524] ticket:613 Site admin page for users audit log

Posted by br...@apache.org.
[#7524] ticket:613 Site admin page for users audit log


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

Branch: refs/heads/master
Commit: d5d74a29e577064a58a0fcbaa3cf9b4a7da37fcd
Parents: 2e1735c
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon Jul 21 15:07:06 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jul 25 16:02:57 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/site_admin.py         | 30 ++++++++++++++++
 Allura/allura/model/auth.py                     |  4 +++
 .../templates/site_admin_users_audit.html       | 37 ++++++++++++++++++++
 3 files changed, 71 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/d5d74a29/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index 3cf4973..96229ee 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -36,6 +36,7 @@ from allura.lib.decorators import require_post
 from allura.lib.plugin import SiteAdminExtension
 from allura.lib.security import require_access
 from allura.lib.widgets import form_fields as ffw
+from allura.ext.admin.widgets import AuditLog
 from allura import model as M
 from allura.command.show_models import dfs, build_model_inheritance_graph
 import allura
@@ -49,6 +50,7 @@ log = logging.getLogger(__name__)
 class W:
     page_list = ffw.PageList()
     page_size = ffw.PageSize()
+    audit = AuditLog()
 
 
 class SiteAdminController(object):
@@ -79,6 +81,7 @@ class SiteAdminController(object):
             SitemapEntry('New Projects', base_url + 'new_projects', ui_icon=g.icons['admin']),
             SitemapEntry('Reclone Repo', base_url + 'reclone_repo', ui_icon=g.icons['admin']),
             SitemapEntry('Task Manager', base_url + 'task_manager?state=busy', ui_icon=g.icons['stats']),
+            SitemapEntry('Users Audit Log', base_url + 'users', ui_icon=g.icons['admin']),
         ]
         for ep_name in sorted(g.entry_points['site_admin']):
             g.entry_points['site_admin'][ep_name]().update_sidebar_menu(links)
@@ -239,6 +242,33 @@ class SiteAdminController(object):
             mount_point = ''
         return dict(prefix=prefix, shortname=shortname, mount_point=mount_point)
 
+    @expose('jinja:allura:templates/site_admin_users_audit.html')
+    def users(self, username=None, limit=10, page=0, **kwargs):
+        user = M.User.by_username(username)
+        limit = int(limit)
+        page = int(page)
+        if user is None or user.is_anonymous():
+            return dict(
+                entries=[],
+                limit=limit,
+                page=page,
+                count=0,
+                username=username)
+        count = M.AuditLog.for_user(user).count()
+        q = M.AuditLog.for_user(user)
+        q = q.sort('timestamp', -1)
+        q = q.skip(page * limit)
+        if count > limit:
+            q = q.limit(limit)
+        else:
+            limit = count
+        c.widget = W.audit
+        return dict(
+            entries=q.all(),
+            limit=limit,
+            page=page,
+            count=count,
+            username=username)
 
 class TaskManagerController(object):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/d5d74a29/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index f0ad1c2..2e029df 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -903,6 +903,10 @@ class AuditLog(object):
             message = message % kwargs
         return cls(project_id=project._id, user_id=user._id, url=url, message=message)
 
+    @classmethod
+    def for_user(cls, user):
+        return cls.query.find(dict(project_id=None, user_id=user._id))
+
 main_orm_session.mapper(AuditLog, audit_log, properties=dict(
     project_id=ForeignIdProperty('Project'),
     project=RelationProperty('Project'),

http://git-wip-us.apache.org/repos/asf/allura/blob/d5d74a29/Allura/allura/templates/site_admin_users_audit.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_users_audit.html b/Allura/allura/templates/site_admin_users_audit.html
new file mode 100644
index 0000000..d4c52fa
--- /dev/null
+++ b/Allura/allura/templates/site_admin_users_audit.html
@@ -0,0 +1,37 @@
+{#-
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+-#}
+
+{% extends 'allura:templates/site_admin.html' %}
+
+{% block content %}
+<div class='grid-19'>
+  <form action='' method='GET'>
+    <div class='grid-7'>
+      <label for='username'>Username:</label>
+      <input name='username' value='{{ username if username else ''}}'>
+    </div>
+    <div class='grid-5'>
+      <input type='submit' value='Show'>
+    </div>
+  </form>
+  {% if entries %}
+    {{ c.widget.display(entries=entries, limit=limit, page=page, count=count) }}
+  {% endif %}
+</div>
+{% endblock %}


[4/8] git commit: [#7524] ticket:613 Add some tests for user account audit

Posted by br...@apache.org.
[#7524] ticket:613 Add some tests for user account audit


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

Branch: refs/heads/master
Commit: 36fadf8ce30a32660cc70216ed4e3ca15dc19aa3
Parents: d2753a9
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Jul 22 13:31:23 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jul 25 16:02:57 2014 +0000

----------------------------------------------------------------------
 Allura/allura/tests/functional/test_auth.py     | 32 +++++++++++++++++---
 .../allura/tests/functional/test_site_admin.py  | 21 ++++++++++++-
 2 files changed, 48 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/36fadf8c/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 c5c0330..9e03bed 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -112,8 +112,12 @@ class TestAuth(TestController):
             extra_environ=dict(username='test-admin'))
         r = self.app.get('/auth/preferences/')
         assert 'test@example.com' in r
-        assert_equal(M.User.query.get(username='test-admin').get_pref('email_address'),
-                     'test-admin@users.localhost')
+        user = M.User.query.get(username='test-admin')
+        assert_equal(user.get_pref('email_address'), 'test-admin@users.localhost')
+        log = M.AuditLog.for_user(user).all()
+        assert_equal(len(log), 1)
+        assert_equal(log[0].message, 'New email address: test@example.com')
+        M.AuditLog.query.remove()
 
         # remove test-admin@users.localhost
         r = self.app.post('/auth/preferences/update', params={
@@ -128,8 +132,21 @@ class TestAuth(TestController):
         r = self.app.get('/auth/preferences/')
         assert 'test-admin@users.localhost' not in r
         # preferred address has not changed if email is not verified
-        assert_equal(M.User.query.get(username='test-admin').get_pref('email_address'),
-                     None)
+        user = M.User.query.get(username='test-admin')
+        assert_equal(user.get_pref('email_address'), None)
+        log = M.AuditLog.for_user(user).all()
+        assert_equal(len(log), 1)
+        assert_equal(log[0].message, 'Email address deleted: test-admin@users.localhost')
+        M.AuditLog.query.remove()
+
+        r = self.app.post('/auth/preferences/update', params={
+            'preferences.display_name': 'Admin',
+            'new_addr.addr': ''},
+            extra_environ=dict(username='test-admin'))
+        user = M.User.query.get(username='test-admin')
+        log = M.AuditLog.for_user(user).all()
+        assert_equal(len(log), 1)
+        assert_equal(log[0].message, 'Display Name changed Test Admin => Admin')
 
     @td.with_user_project('test-admin')
     def test_prefs_subscriptions(self):
@@ -751,6 +768,13 @@ To reset your password on %s, please visit the following URL:
         hash_expiry = user.get_tool_data('AuthPasswordReset', 'hash_expiry')
         assert_equal(hash, '')
         assert_equal(hash_expiry, '')
+        log = M.AuditLog.for_user(user).all()
+        assert_equal(len(log), 2)
+        messages = set([l.message for l in log])
+        assert_equal(
+            messages,
+            set(['Password recovery link sent to: test-admin@users.localhost',
+                 'Password changed (through recovery process)']))
 
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     @patch('allura.lib.helpers.gen_message_id')

http://git-wip-us.apache.org/repos/asf/allura/blob/36fadf8c/Allura/allura/tests/functional/test_site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_site_admin.py b/Allura/allura/tests/functional/test_site_admin.py
index 79ca43b..8dbc2f6 100644
--- a/Allura/allura/tests/functional/test_site_admin.py
+++ b/Allura/allura/tests/functional/test_site_admin.py
@@ -17,8 +17,10 @@
 
 import json
 
-from nose.tools import assert_equal
+from mock import patch
+from nose.tools import assert_equal, assert_in, assert_not_in
 from ming.odm import ThreadLocalORMSession
+from pylons import tmpl_context as c
 
 from allura import model as M
 from allura.tests import TestController
@@ -160,6 +162,23 @@ class TestSiteAdmin(TestController):
             task_name='allura.tests.functional.test_site_admin.test_task'))
         assert json.loads(r.body)['doc'] == 'test_task doc string'
 
+    @patch('allura.model.auth.request')
+    def test_users(self, request):
+        request.url = 'http://host.domain/path/'
+        c.user = M.User.by_username('test-user-1')
+        M.AuditLog.log_user('test activity user 1')
+        M.AuditLog.log_user('test activity user 2', user=M.User.by_username('test-user-2'))
+        r = self.app.get('/nf/admin/users')
+        assert_not_in('test activity', r)
+        r = self.app.get('/nf/admin/users?username=admin1')
+        assert_not_in('test activity', r)
+        r = self.app.get('/nf/admin/users?username=test-user-1')
+        assert_in('test activity user 1', r)
+        assert_not_in('test activity user 2', r)
+        r = self.app.get('/nf/admin/users?username=test-user-2')
+        assert_not_in('test activity user 1', r)
+        assert_in('test activity user 2', r)
+
 
 @task
 def test_task(*args, **kw):


[6/8] git commit: [#7524] ticket:620 Log password reset and account disabling

Posted by br...@apache.org.
[#7524] ticket:620 Log password reset and account disabling


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

Branch: refs/heads/master
Commit: 563d675405250f641f029a13e07598d9e9125a0f
Parents: 2e92047
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Jul 25 12:02:58 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jul 25 16:02:58 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py | 1 +
 Allura/allura/lib/plugin.py       | 4 ++++
 2 files changed, 5 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/563d6754/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 50a0782..801bdf2 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -370,6 +370,7 @@ class AuthController(BaseController):
         flash('Password changed')
         del session['pwd-expired']
         session.save()
+        M.AuditLog.log_user('Password reset (via expiration process)')
         if return_to and return_to != request.url:
             redirect(return_to)
         else:

http://git-wip-us.apache.org/repos/asf/allura/blob/563d6754/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index a5c3f65..59949ce 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -141,6 +141,8 @@ class AuthenticationProvider(object):
             self.session['userid'] = user._id
             if self.is_password_expired(user):
                 self.session['pwd-expired'] = True
+                from allura.model import AuditLog
+                AuditLog.log_user('Password expired', user=user)
             self.session.save()
             g.zarkov_event('login', user=user)
             g.statsUpdater.addUserLogin(user)
@@ -297,6 +299,8 @@ class LocalAuthenticationProvider(AuthenticationProvider):
     def disable_user(self, user):
         user.disabled = True
         session(user).flush(user)
+        from allura.model import AuditLog
+        AuditLog.log_user('Account disabled', user=user)
 
     def validate_password(self, user, password):
         return self._validate_password(user, password)


[3/8] git commit: [#7524] ticket:613 Track changes to user accounts

Posted by br...@apache.org.
[#7524] ticket:613 Track changes to user accounts


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

Branch: refs/heads/master
Commit: 69bdc9f5c53cab07be76c752615eaf2a6ee8a856
Parents: d5d74a2
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Jul 22 10:44:51 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jul 25 16:02:57 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py | 14 ++++++++++++++
 Allura/allura/model/auth.py       |  8 +++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/69bdc9f5/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 8835b33..50a0782 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -166,6 +166,7 @@ class AuthController(BaseController):
         user = self._validate_hash(hash)
         user.set_password(pw)
         user.set_tool_data('AuthPasswordReset', hash='', hash_expiry='')
+        M.AuditLog.log_user('Password changed (through recovery process)', user=user)
         flash('Password changed')
         redirect('/auth/')
 
@@ -204,6 +205,7 @@ class AuthController(BaseController):
                 message_id=h.gen_message_id(),
                 text=text)
 
+        M.AuditLog.log_user('Password recovery link sent to: %s', email, user=user_record)
         flash('A password reset email has been sent, if the given email address is on record in our system.')
         redirect('/')
 
@@ -237,6 +239,7 @@ class AuthController(BaseController):
         if addr:
             addr.confirmed = True
             flash('Email address confirmed')
+            M.AuditLog.log_user('Email address verified: %s', addr._id)
         else:
             flash('Unknown verification link', 'error')
         redirect('/auth/preferences/')
@@ -409,7 +412,10 @@ class PreferencesController(BaseController):
             if not preferences.get('display_name'):
                 flash("Display Name cannot be empty.", 'error')
                 redirect('.')
+            old = c.user.get_pref('display_name')
             c.user.set_pref('display_name', preferences['display_name'])
+            if old != preferences['display_name']:
+                M.AuditLog.log_user('Display Name changed %s => %s', old, preferences['display_name'])
             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:
@@ -422,6 +428,7 @@ class PreferencesController(BaseController):
                             # clear it now, a new one will get set below
                             c.user.set_pref('email_address', None)
                             primary_addr = None
+                    M.AuditLog.log_user('Email address deleted: %s', c.user.email_addresses[i])
                     del c.user.email_addresses[i]
                     if obj:
                         obj.delete()
@@ -433,12 +440,18 @@ class PreferencesController(BaseController):
                     em = M.EmailAddress.upsert(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'])
                     flash('A verification email has been sent.  Please check your email and click to confirm.')
                 else:
                     flash('Email address %s is invalid' % new_addr['addr'], 'error')
             if not primary_addr and not c.user.get_pref('email_address') and c.user.email_addresses:
                 primary_addr = select_new_primary_addr(c.user)
             if primary_addr:
+                if c.user.get_pref('email_address') != primary_addr:
+                    M.AuditLog.log_user(
+                        'Primary email changed: %s => %s',
+                        c.user.get_pref('email_address'),
+                        primary_addr)
                 c.user.set_pref('email_address', primary_addr)
             for k, v in preferences.iteritems():
                 if k == 'results_per_page':
@@ -458,6 +471,7 @@ class PreferencesController(BaseController):
             flash('Incorrect password', 'error')
             redirect('.')
         flash('Password changed')
+        M.AuditLog.log_user('Password changed')
         redirect('.')
 
     @expose()

http://git-wip-us.apache.org/repos/asf/allura/blob/69bdc9f5/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 2e029df..c86f7de 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -901,12 +901,18 @@ class AuditLog(object):
             message = message % args
         elif kwargs:
             message = message % kwargs
-        return cls(project_id=project._id, user_id=user._id, url=url, message=message)
+        pid = project._id if project is not None else None
+        return cls(project_id=pid, user_id=user._id, url=url, message=message)
 
     @classmethod
     def for_user(cls, user):
         return cls.query.find(dict(project_id=None, user_id=user._id))
 
+    @classmethod
+    def log_user(cls, message, *args, **kwargs):
+        kwargs['project'] = None
+        return cls.log(message, *args, **kwargs)
+
 main_orm_session.mapper(AuditLog, audit_log, properties=dict(
     project_id=ForeignIdProperty('Project'),
     project=RelationProperty('Project'),