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 2013/05/24 20:48:55 UTC

[11/15] git commit: [#5656] ticket:353 refactored bulk move tickets

[#5656]  ticket:353 refactored bulk move tickets


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

Branch: refs/heads/master
Commit: 224499a93142cefe434b604602f27bdda2957fa0
Parents: f7e873b
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Mon May 20 13:07:41 2013 +0400
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:42:27 2013 +0000

----------------------------------------------------------------------
 Allura/allura/tasks/tracker_task.py                |   25 +++++
 .../forgetracker/data/mass_move_report.html        |   20 ++++-
 ForgeTracker/forgetracker/data/mass_report         |    2 +-
 ForgeTracker/forgetracker/model/ticket.py          |   79 ++++++++++++++-
 .../forgetracker/tests/functional/test_root.py     |   16 ++--
 ForgeTracker/forgetracker/tracker_main.py          |   79 +--------------
 6 files changed, 135 insertions(+), 86 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/224499a9/Allura/allura/tasks/tracker_task.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tasks/tracker_task.py b/Allura/allura/tasks/tracker_task.py
new file mode 100644
index 0000000..0a37850
--- /dev/null
+++ b/Allura/allura/tasks/tracker_task.py
@@ -0,0 +1,25 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+
+from allura.lib.decorators import task
+from pylons import tmpl_context as c
+
+
+@task
+def move_tickets(ticket_ids, destination_tracker_id):
+    c.app.globals.move_tickets(ticket_ids, destination_tracker_id)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/224499a9/ForgeTracker/forgetracker/data/mass_move_report.html
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/data/mass_move_report.html b/ForgeTracker/forgetracker/data/mass_move_report.html
index 3ace7c6..1312f54 100644
--- a/ForgeTracker/forgetracker/data/mass_move_report.html
+++ b/ForgeTracker/forgetracker/data/mass_move_report.html
@@ -1,5 +1,23 @@
+{#
+       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.
+#}
 Tickets were moved from [{{original_tracker}}] to [{{destination_tracker}}]
 
 {% for t in tickets %}
-- [{{original_tracker}}:#{{t['original_num']}}] --> [{{destination_tracker}}:#{{t['destination_num']}}] {{t['summary']}}
+- {{original_tracker}}:#{{t['original_num']}} --> {{destination_tracker}}:#{{t['destination_num']}} {{t['summary']}}
 {% endfor %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/224499a9/ForgeTracker/forgetracker/data/mass_report
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/data/mass_report b/ForgeTracker/forgetracker/data/mass_report
index 7e8e47d..70fe1f7 100644
--- a/ForgeTracker/forgetracker/data/mass_report
+++ b/ForgeTracker/forgetracker/data/mass_report
@@ -19,7 +19,7 @@
 {{ data.header }}
 
 {% for ticket, change_text in data.changes %}
-ticket: [{{ context.app.config.options.mount_point }}:#{{ ticket.ticket_num }}] {{ ticket.summary }}
+ticket: {{ context.app.config.options.mount_point }}:#{{ ticket.ticket_num }} {{ ticket.summary }}
 
 {{ change_text }}
 {% endfor %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/224499a9/ForgeTracker/forgetracker/model/ticket.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 75c8bca..3a6803d 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -20,6 +20,7 @@ import urllib
 import json
 import difflib
 from datetime import datetime, timedelta
+from bson import ObjectId
 
 import pymongo
 from pymongo.errors import OperationFailure
@@ -33,7 +34,7 @@ from ming.orm import FieldProperty, ForeignIdProperty, RelationProperty
 from ming.orm.declarative import MappedClass
 
 from allura.model import (Artifact, VersionedArtifact, Snapshot,
-                          project_orm_session, BaseAttachment, VotableArtifact)
+                          project_orm_session, BaseAttachment, VotableArtifact, AppConfig, Mailbox, User)
 from allura.model import User, Feed, Thread, Notification, ProjectRole
 from allura.model import ACE, ALL_PERMISSIONS, DENY_ALL
 from allura.model.timeline import ActivityObject
@@ -42,6 +43,7 @@ from allura.lib import security
 from allura.lib.search import search_artifact, SearchError
 from allura.lib import utils
 from allura.lib import helpers as h
+from allura.tasks import mail_tasks
 
 from forgetracker.plugins import ImportIdConverter
 
@@ -225,6 +227,81 @@ class Globals(MappedClass):
         return Ticket.query.find(dict(
             app_config_id=c.app.config._id, deleted=True)).count() > 0
 
+    def move_tickets(self, ticket_ids, destination_tracker_id):
+        tracker = AppConfig.query.get(_id=destination_tracker_id)
+        tickets = Ticket.query.find(dict(
+            _id={'$in': [ObjectId(id) for id in ticket_ids]},
+            app_config_id=c.app.config._id)).all()
+        filtered = self.filtered_by_subscription({t._id: t for t in tickets})
+        original_ticket_nums = {t._id: t.ticket_num for t in tickets}
+        users = User.query.find({'_id': {'$in': filtered.keys()}}).all()
+        moved_tickets = {}
+        for ticket in tickets:
+            moved = ticket.move(tracker, notify=False)
+            moved_tickets[moved._id] = moved
+        mail = dict(
+            fromaddr = str(c.user.email_address_header()),
+            reply_to = str(c.user.email_address_header()),
+            subject = '%s:%s Mass ticket moving by %s' % (c.project.shortname,
+                                                          c.app.config.options.mount_point,
+                                                          c.user.display_name))
+        tmpl = g.jinja2_env.get_template('forgetracker:data/mass_move_report.html')
+
+        tmpl_context = {
+            'original_tracker': '%s:%s' % (c.project.shortname,
+                                           c.app.config.options.mount_point),
+            'destination_tracker': '%s:%s' % (tracker.project.shortname,
+                                              tracker.options.mount_point),
+            'tickets': [],
+        }
+        for user in users:
+            tmpl_context['tickets'] = ({
+                    'original_num': original_ticket_nums[_id],
+                    'destination_num': moved_tickets[_id].ticket_num,
+                    'summary': moved_tickets[_id].summary
+                } for _id in filtered.get(user._id, []))
+            mail.update(dict(
+            message_id = h.gen_message_id(),
+            text = tmpl.render(tmpl_context),
+            destinations = [str(user._id)]))
+            mail_tasks.sendmail.post(**mail)
+
+        if c.app.config.options.get('TicketMonitoringType') == 'AllTicketChanges':
+            monitoring_email = c.app.config.options.get('TicketMonitoringEmail')
+            tmpl_context['tickets'] = ({
+                    'original_num': original_ticket_nums[_id],
+                    'destination_num': moved_tickets[_id].ticket_num,
+                    'summary': moved_tickets[_id].summary
+                } for _id in moved_tickets.keys())
+            mail.update(dict(
+                message_id = h.gen_message_id(),
+                text = tmpl.render(tmpl_context),
+                destinations = [monitoring_email]))
+            mail_tasks.sendmail.post(**mail)
+
+    def filtered_by_subscription(self, tickets, project_id=None, app_config_id=None):
+        p_id = project_id if project_id else c.project._id
+        ac_id = app_config_id if app_config_id else c.app.config._id
+        ticket_ids = tickets.keys()
+        users = Mailbox.query.find(dict(project_id=p_id, app_config_id=ac_id))
+        users = [u.user_id for u in users]
+        filtered = {}
+        for uid in users:
+            params = dict(
+                user_id=uid,
+                project_id=p_id,
+                app_config_id=ac_id)
+            if Mailbox.subscribed(**params):
+                filtered[uid] = set(ticket_ids)  # subscribed to entire tool, will see all changes
+                continue
+            for t_id, ticket in tickets.iteritems():
+                params.update({'artifact': ticket})
+                if Mailbox.subscribed(**params):
+                    if filtered.get(uid) is None:
+                        filtered[uid] = set()
+                    filtered[uid].add(t_id)
+        return filtered
+
 
 class TicketHistory(Snapshot):
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/224499a9/ForgeTracker/forgetracker/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py
index da6544b..37b3399 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -28,12 +28,12 @@ from mock import patch
 from nose.tools import assert_true, assert_false, assert_equal, assert_in
 from nose.tools import assert_raises, assert_not_in
 from formencode.variabledecode import variable_encode
+from pylons import tmpl_context as c
 
 from alluratest.controller import TestController
 from allura import model as M
 from forgewiki import model as wm
 from forgetracker import model as tm
-from forgetracker.tracker_main import filtered_by_subscription
 
 from allura.lib.security import has_access
 from allura.lib import helpers as h
@@ -1264,17 +1264,17 @@ class TestFunctionalController(TrackerTestController):
 - **Milestone**: 2.0
 
 '''
-        first_ticket_changes = '''ticket: [bugs:#1] test first ticket
+        first_ticket_changes = '''ticket: bugs:#1 test first ticket
 
 - **Owner**: Anonymous --> Test Admin
 - **Status**: open --> accepted
 '''
-        second_ticket_changes = '''ticket: [bugs:#2] test second ticket
+        second_ticket_changes = '''ticket: bugs:#2 test second ticket
 
 - **Owner**: Anonymous --> Test Admin
 - **Milestone**: 1.0 --> 2.0
 '''
-        third_ticket_changes = '''ticket: [bugs:#3] test third ticket
+        third_ticket_changes = '''ticket: bugs:#3 test third ticket
 
 - **Owner**: Anonymous --> Test Admin
 - **Status**: unread --> accepted
@@ -1432,7 +1432,7 @@ class TestFunctionalController(TrackerTestController):
             tickets[0]._id: tickets[0],
             tickets[1]._id: tickets[1],
         }
-        filtered_changes = filtered_by_subscription(changes)
+        filtered_changes = c.app.globals.filtered_by_subscription(changes)
         filtered_users = [uid for uid, data in filtered_changes.iteritems()]
         assert_equal(sorted(filtered_users), sorted([u._id for u in users[:-1] + [admin]]))
         ticket_ids = [t._id for t in tickets]
@@ -2280,6 +2280,8 @@ class TestBulkMove(TrackerTestController):
                     '__ticket_ids': [t._id for t in tickets],
                     '__search': '',
                 })
+        M.MonQTask.run_ready()
+        ThreadLocalORMSession.flush_all()
         ac_id = tracker.config._id
         original_ac_id = original_tracker.config._id
         moved_tickets = tm.Ticket.query.find({'app_config_id': ac_id}).all()
@@ -2319,7 +2321,7 @@ class TestBulkMove(TrackerTestController):
         emails = M.MonQTask.query.find(dict(task_name='allura.tasks.mail_tasks.sendmail')).all()
         assert_equal(len(emails), 3)
         for email in emails:
-            assert_equal(email.kwargs.subject, '[test:bugs] Mass ticket moving by Test Admin')
+            assert_equal(email.kwargs.subject, 'test:bugs Mass ticket moving by Test Admin')
         first_user_email = M.MonQTask.query.find({
             'task_name': 'allura.tasks.mail_tasks.sendmail',
             'kwargs.destinations': str(first_user._id)
@@ -2374,7 +2376,7 @@ class TestBulkMove(TrackerTestController):
         emails = M.MonQTask.query.find(dict(task_name='allura.tasks.mail_tasks.sendmail')).all()
         assert_equal(len(emails), 2)
         for email in emails:
-            assert_equal(email.kwargs.subject, '[test:bugs] Mass ticket moving by Test Admin')
+            assert_equal(email.kwargs.subject, 'test:bugs Mass ticket moving by Test Admin')
         admin_email = M.MonQTask.query.find({
             'task_name': 'allura.tasks.mail_tasks.sendmail',
             'kwargs.destinations': str(M.User.by_username('test-admin')._id)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/224499a9/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 845d380..62469a9 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -62,7 +62,7 @@ from allura.controllers import AppDiscussionController, AppDiscussionRestControl
 from allura.controllers import attachments as ac
 from allura.controllers import BaseController
 from allura.controllers.feed import FeedArgs, FeedController
-from allura.tasks import mail_tasks
+from allura.tasks import mail_tasks, tracker_task
 
 # Local imports
 from forgetracker import model as TM
@@ -824,55 +824,7 @@ class RootController(BaseController, FeedController):
             _id={'$in': [ObjectId(id) for id in ticket_ids]},
             app_config_id=c.app.config._id)).all()
 
-        filtered = filtered_by_subscription({t._id: t for t in tickets})
-        original_ticket_nums = {t._id: t.ticket_num for t in tickets}
-        users = M.User.query.find({'_id': {'$in': filtered.keys()}}).all()
-        moved_tickets = {}
-        for ticket in tickets:
-            moved = ticket.move(tracker, notify=False)
-            moved_tickets[moved._id] = moved
-
-        mail = dict(
-            fromaddr = str(c.user._id),
-            reply_to = str(c.user._id),
-            subject = '[%s:%s] Mass ticket moving by %s' % (c.project.shortname,
-                                                           c.app.config.options.mount_point,
-                                                           c.user.display_name))
-        tmpl = jinja2.Environment(
-                loader=jinja2.PackageLoader('forgetracker', 'data'),
-                auto_reload=asbool(config.get('auto_reload_templates', True))
-        ).get_template('mass_move_report.html')
-        tmpl_context = {
-            'original_tracker': '%s:%s' % (c.project.shortname,
-                                           c.app.config.options.mount_point),
-            'destination_tracker': '%s:%s' % (tracker.project.shortname,
-                                              tracker.options.mount_point),
-            'tickets': [],
-        }
-        for user in users:
-            tmpl_context['tickets'] = ({
-                    'original_num': original_ticket_nums[_id],
-                    'destination_num': moved_tickets[_id].ticket_num,
-                    'summary': moved_tickets[_id].summary
-                } for _id in filtered.get(user._id, []))
-            mail.update(dict(
-                message_id = h.gen_message_id(),
-                text = tmpl.render(tmpl_context),
-                destinations = [str(user._id)]))
-            mail_tasks.sendmail.post(**mail)
-
-        if c.app.config.options.get('TicketMonitoringType') == 'AllTicketChanges':
-            monitoring_email = c.app.config.options.get('TicketMonitoringEmail')
-            tmpl_context['tickets'] = ({
-                    'original_num': original_ticket_nums[_id],
-                    'destination_num': moved_tickets[_id].ticket_num,
-                    'summary': moved_tickets[_id].summary
-                } for _id in moved_tickets.keys())
-            mail.update(dict(
-                message_id = h.gen_message_id(),
-                text = tmpl.render(tmpl_context),
-                destinations = [monitoring_email]))
-            mail_tasks.sendmail.post(**mail)
+        tracker_task.move_tickets.post(ticket_ids, destination_tracker_id)
 
         c.app.globals.invalidate_bin_counts()
         ThreadLocalORMSession.flush_all()
@@ -948,7 +900,7 @@ class RootController(BaseController, FeedController):
                 ticket.discussion_thread.post(message, notify=False)
                 ticket.commit()
 
-        filtered_changes = filtered_by_subscription(changed_tickets)
+        filtered_changes = c.app.globals.filtered_by_subscription(changed_tickets)
         users = M.User.query.find({'_id': {'$in': filtered_changes.keys()}}).all()
         def changes_iter(user):
             for t_id in filtered_changes.get(user._id, []):
@@ -1312,31 +1264,6 @@ class changelog(object):
                     t.append((key, (orig_value, curr_value)))
         return t
 
-
-def filtered_by_subscription(tickets, project_id=None, app_config_id=None):
-    p_id = project_id if project_id else c.project._id
-    ac_id = app_config_id if app_config_id else c.app.config._id
-    ticket_ids = tickets.keys()
-    users = M.Mailbox.query.find(dict(project_id=p_id, app_config_id=ac_id))
-    users = [u.user_id for u in users]
-    filtered = {}
-    for uid in users:
-        params = dict(
-            user_id=uid,
-            project_id=p_id,
-            app_config_id=ac_id)
-        if M.Mailbox.subscribed(**params):
-            filtered[uid] = set(ticket_ids)  # subscribed to entire tool, will see all changes
-            continue
-        for t_id, ticket in tickets.iteritems():
-            params.update({'artifact': ticket})
-            if M.Mailbox.subscribed(**params):
-                if filtered.get(uid) is None:
-                    filtered[uid] = set()
-                filtered[uid].add(t_id)
-    return filtered
-
-
 class TicketController(BaseController, FeedController):
 
     def __init__(self, ticket_num=None):