Return-Path: X-Original-To: apmail-incubator-allura-commits-archive@minotaur.apache.org Delivered-To: apmail-incubator-allura-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id A4BC2DC32 for ; Fri, 24 May 2013 18:48:53 +0000 (UTC) Received: (qmail 82552 invoked by uid 500); 24 May 2013 18:48:50 -0000 Delivered-To: apmail-incubator-allura-commits-archive@incubator.apache.org Received: (qmail 82451 invoked by uid 500); 24 May 2013 18:48:50 -0000 Mailing-List: contact allura-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: allura-dev@incubator.apache.org Delivered-To: mailing list allura-commits@incubator.apache.org Received: (qmail 82122 invoked by uid 99); 24 May 2013 18:48:45 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 24 May 2013 18:48:45 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 5481FE8DE; Fri, 24 May 2013 18:48:45 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: brondsem@apache.org To: allura-commits@incubator.apache.org Date: Fri, 24 May 2013 18:48:55 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [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 Authored: Mon May 20 13:07:41 2013 +0400 Committer: Dave Brondsema 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):