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:45 UTC

[01/15] git commit: [#5656] ticket:301 Skeleton for bulk move UI

Updated Branches:
  refs/heads/master e375efbf5 -> 82f675f70


[#5656] ticket:301 Skeleton for bulk move UI


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

Branch: refs/heads/master
Commit: c0797acc6d69a2a6cf55530f7e150721f94f4525
Parents: e375efb
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Apr 30 13:28:14 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:35:50 2013 +0000

----------------------------------------------------------------------
 .../forgetracker/templates/tracker/index.html      |    3 +
 .../forgetracker/templates/tracker/mass_move.html  |   38 +++++++++++++++
 .../forgetracker/templates/tracker/milestone.html  |    3 +
 .../forgetracker/templates/tracker/search.html     |    5 ++-
 ForgeTracker/forgetracker/tracker_main.py          |   23 ++++++++-
 ForgeTracker/forgetracker/widgets/ticket_search.py |    9 ++++
 6 files changed, 79 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0797acc/ForgeTracker/forgetracker/templates/tracker/index.html
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/templates/tracker/index.html b/ForgeTracker/forgetracker/templates/tracker/index.html
index 1d1145c..7b3ad36 100644
--- a/ForgeTracker/forgetracker/templates/tracker/index.html
+++ b/ForgeTracker/forgetracker/templates/tracker/index.html
@@ -36,6 +36,9 @@
   {% if allow_edit %}
     <a href="{{tg.url(c.app.url+'edit/', dict(q=url_q, limit=limit, sort=url_sort, page=page))}}" title="Bulk Edit"><b data-icon="{{g.icons['pencil'].char}}" class="ico {{g.icons['pencil'].css}}"></b></a>
   {% endif %}
+  {% if allow_move %}
+    <a href="{{tg.url(c.app.url + 'move/', dict(q=url_q, limit=limit, sort=url_sort, page=page))}}" title="Bulk Move"><b data-icon="" class=""></b>Bulk Move</a>
+  {% endif %}
 {% endblock %}
 
 {% block content %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0797acc/ForgeTracker/forgetracker/templates/tracker/mass_move.html
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/templates/tracker/mass_move.html b/ForgeTracker/forgetracker/templates/tracker/mass_move.html
new file mode 100644
index 0000000..1953801
--- /dev/null
+++ b/ForgeTracker/forgetracker/templates/tracker/mass_move.html
@@ -0,0 +1,38 @@
+{#-
+       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 'forgetracker:templates/tracker/mass_edit.html' %}
+
+{% block actions %}
+<a href="{{tg.url(c.app.url+'move/', dict(q=q, limit=limit, sort=sort, page=page))}}" title="Bulk Move" class="active"><b data-icon="" class=""></b>Bulk Move</a>
+{% endblock %}
+
+{% block edit_box %}
+<div class="editbox">
+  {{c.mass_move_form.display()}}
+</div>
+{% endblock %}
+
+{% block content %}
+  {{c.mass_move.display(count=count,
+    limit=limit,
+    query=q,
+    tickets=tickets,
+    sort=sort,
+    page=page)}}
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0797acc/ForgeTracker/forgetracker/templates/tracker/milestone.html
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/templates/tracker/milestone.html b/ForgeTracker/forgetracker/templates/tracker/milestone.html
index 4c1e61c..7c1cd00 100644
--- a/ForgeTracker/forgetracker/templates/tracker/milestone.html
+++ b/ForgeTracker/forgetracker/templates/tracker/milestone.html
@@ -28,6 +28,9 @@
 {% if allow_edit %}
   <a href="{{tg.url(c.app.url+'edit/', dict(q=q, limit=limit, sort=url_sort, page=page))}}" title="Bulk Edit"><b data-icon="{{g.icons['pencil'].char}}" class="ico {{g.icons['pencil'].css}}"></b></a>
 {% endif %}
+{% if allow_move %}
+  <a href="{{tg.url(c.app.url + 'move/', dict(q=q, limit=limit, sort=url_sort, page=page))}}" title="Bulk Move"><b data-icon="" class=""></b>Bulk Move</a>
+{% endif %}
 {% endblock %}
 
 {% block edit_box %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0797acc/ForgeTracker/forgetracker/templates/tracker/search.html
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/templates/tracker/search.html b/ForgeTracker/forgetracker/templates/tracker/search.html
index 48516f8..dda451d 100644
--- a/ForgeTracker/forgetracker/templates/tracker/search.html
+++ b/ForgeTracker/forgetracker/templates/tracker/search.html
@@ -33,6 +33,9 @@
 {% if allow_edit and count != 0 %}
   <a href="{{tg.url(c.app.url+'edit/', dict(q=q, limit=limit, sort=sort, page=page))}}" title="Bulk Edit"><b data-icon="{{g.icons['pencil'].char}}" class="ico {{g.icons['pencil'].css}}"></b></a>
 {% endif %}
+{% if allow_move and count != 0 %}
+  <a href="{{tg.url(c.app.url + 'move/', dict(q=q, limit=limit, sort=sort, page=page))}}" title="Bulk Move"><b data-icon="" class=""></b>Bulk Move</a>
+{% endif %}
 {% endblock %}
 
 {% if q and h.has_access(c.app, 'save_searches')() %}
@@ -67,7 +70,7 @@
   <input type="text" name="q" value="{{q}}" style="width: 280px; float: left; margin-right: .5em" id="bin_terms">
   {% if bin and h.has_access(c.app, 'save_searches')() %}
     <input type="button" value="Update Search" id="save_search"/>
-  {% endif %}  
+  {% endif %}
   <input type="submit" value="Search"/>
 </form>
 <a href="#" class="btn search_help_modal"><b data-icon="{{g.icons['help'].char}}" class="ico {{g.icons['help'].css}}"></b> Help</a>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0797acc/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 17f3b6b..b1bd941 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -71,7 +71,7 @@ from forgetracker import version
 from forgetracker.widgets.admin import OptionsAdmin
 from forgetracker.widgets.ticket_form import TicketForm, TicketCustomField
 from forgetracker.widgets.bin_form import BinForm
-from forgetracker.widgets.ticket_search import TicketSearchResults, MassEdit, MassEditForm, SearchHelp
+from forgetracker.widgets.ticket_search import TicketSearchResults, MassEdit, MassEditForm, MassMoveForm, SearchHelp
 from forgetracker.widgets.admin_custom_fields import TrackerFieldAdmin, TrackerFieldDisplay
 from forgetracker.import_support import ImportSupport
 from forgetracker.plugins import ImportIdConverter
@@ -163,6 +163,7 @@ class W:
     search_help_modal = SearchHelp()
     vote_form = w.VoteForm()
     move_ticket_form = w.forms.MoveTicketForm
+    mass_move_form = MassMoveForm
 
 class ForgeTrackerApp(Application):
     __version__ = version.__version__
@@ -547,6 +548,7 @@ class RootController(BaseController, FeedController):
         result['sortable_custom_fields'] = c.app.globals.sortable_custom_fields_shown_in_search()
         result['subscribed'] = M.Mailbox.subscribed()
         result['allow_edit'] = has_access(c.app, 'update')()
+        result['allow_move'] = has_access(c.app, 'admin')()
         result['help_msg'] = c.app.config.options.get('TicketHelpSearch','').strip()
         result['url_q'] = c.app.globals.not_closed_query
         result['url_sort'] = ''
@@ -650,6 +652,7 @@ class RootController(BaseController, FeedController):
         result['columns'] = columns or solr_columns()
         result['sortable_custom_fields'] = c.app.globals.sortable_custom_fields_shown_in_search()
         result['allow_edit'] = has_access(c.app, 'update')()
+        result['allow_move'] = has_access(c.app, 'admin')()
         result['bin'] = bin
         result['help_msg'] = c.app.config.options.get('TicketHelpSearch', '').strip()
         result['deleted'] = deleted
@@ -758,6 +761,23 @@ class RootController(BaseController, FeedController):
         c.mass_edit_form = W.mass_edit_form
         return result
 
+    @with_trailing_slash
+    @expose('jinja:forgetracker:templates/tracker/mass_move.html')
+    @validate(dict(q=validators.UnicodeString(if_empty=None),
+                   limit=validators.Int(if_empty=10),
+                   page=validators.Int(if_empty=0),
+                   sort=validators.UnicodeString(if_empty='ticket_num_i asc')))
+    def move(self, q=None, limit=None, page=None, sort=None, **kw):
+        require_access(c.app, 'admin')
+        result = TM.Ticket.paged_search(c.app.config, c.user, q, sort=sort, limit=limit, page=page, show_deleted=False, **kw)
+        result['columns'] = solr_columns()
+        result['sortable_custom_fields'] = c.app.globals.sortable_custom_fields_shown_in_search()
+        result['globals'] = c.app.globals
+        result['cancel_href'] = url(c.app.url + 'search/', dict(q=q, limit=limit, sort=sort))
+        c.mass_move = W.mass_edit
+        c.mass_move_form = W.mass_move_form(tracker=[])
+        return result
+
     @expose()
     @require_post()
     def update_tickets(self, **post_data):
@@ -1768,6 +1788,7 @@ class MilestoneController(BaseController):
         result['columns'] = columns or mongo_columns()
         result['sortable_custom_fields'] = c.app.globals.sortable_custom_fields_shown_in_search()
         result['allow_edit'] = has_access(c.app, 'update')()
+        result['allow_move'] = has_access(c.app, 'admin')()
         result['help_msg'] = c.app.config.options.get('TicketHelpSearch','').strip()
         result['deleted'] = deleted
         progress = c.app.globals.milestone_count(self.progress_key)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0797acc/ForgeTracker/forgetracker/widgets/ticket_search.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/widgets/ticket_search.py b/ForgeTracker/forgetracker/widgets/ticket_search.py
index 38a91a7..fdc257a 100644
--- a/ForgeTracker/forgetracker/widgets/ticket_search.py
+++ b/ForgeTracker/forgetracker/widgets/ticket_search.py
@@ -23,6 +23,7 @@ import ew as ew_core
 import ew.jinja2_ew as ew
 
 from allura.lib.widgets import form_fields as ffw
+from allura.lib.widgets import forms
 
 class TicketSearchResults(ew_core.SimpleForm):
     template='jinja:forgetracker:templates/tracker_widgets/ticket_search_results.html'
@@ -84,6 +85,14 @@ class MassEditForm(ew_core.Widget):
     def resources(self):
         yield ew.JSLink('tracker_js/mass-edit.js')
 
+class MassMoveForm(forms.MoveTicketForm):
+    defaults=dict(
+        forms.MoveTicketForm.defaults,
+        action='.')
+
+    def resources(self):
+        yield ew.JSLink('tracker_js/mass-edit.js')
+
 class SearchHelp(ffw.Lightbox):
     defaults=dict(
         ffw.Lightbox.defaults,


[02/15] git commit: [#5656] ticket:301 Send summary to monitoring email, if set

Posted by br...@apache.org.
[#5656] ticket:301 Send summary to monitoring email, if set


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

Branch: refs/heads/master
Commit: a770cdfa77269140656088d9161882b2b1461fa5
Parents: 3dd4318
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed May 1 11:54:31 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:35:51 2013 +0000

----------------------------------------------------------------------
 .../forgetracker/tests/functional/test_root.py     |   37 +++++++++++++++
 ForgeTracker/forgetracker/tracker_main.py          |   13 +++++
 2 files changed, 50 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a770cdfa/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 e346482..da6544b 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -2352,6 +2352,43 @@ class TestBulkMove(TrackerTestController):
         assert_in(second_ticket_changes, admin_email.kwargs.text)
         assert_in(third_ticket_changes, admin_email.kwargs.text)
 
+    @td.with_tool('test2', 'Tickets', 'bugs2')
+    def test_monitoring_email(self):
+        self.app.post('/admin/bugs/set_options', params={
+            'TicketMonitoringEmail': 'monitoring@email.com',
+            'TicketMonitoringType': 'AllTicketChanges',
+        })
+        tickets = [
+            tm.Ticket.query.find({'summary': 'A New Hope'}).first(),
+            tm.Ticket.query.find({'summary': 'The Empire Strikes Back'}).first(),
+            tm.Ticket.query.find({'summary': 'Return Of The Jedi'}).first()]
+        p = M.Project.query.get(shortname='test2')
+        tracker = p.app_instance('bugs2')
+        M.MonQTask.query.remove()
+        r = self.app.post('/p/test/bugs/move_tickets', {
+                    'tracker': str(tracker.config._id),
+                    '__ticket_ids': [t._id for t in tickets],
+                    '__search': '',
+                })
+        M.MonQTask.run_ready()
+        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')
+        admin_email = M.MonQTask.query.find({
+            'task_name': 'allura.tasks.mail_tasks.sendmail',
+            'kwargs.destinations': str(M.User.by_username('test-admin')._id)
+        }).all()
+        monitoring_email = M.MonQTask.query.find({
+            'task_name': 'allura.tasks.mail_tasks.sendmail',
+            'kwargs.destinations': 'monitoring@email.com'
+        }).all()
+        assert_equal(len(admin_email), 1)
+        assert_equal(len(monitoring_email), 1)
+        admin_email_text = admin_email[0].kwargs.text
+        monitoring_email_text = monitoring_email[0].kwargs.text
+        assert_equal(admin_email_text, monitoring_email_text)
+
 
 def sidebar_contains(response, text):
     sidebar_menu = response.html.find('div', attrs={'id': 'sidebar'})

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a770cdfa/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index c41db5e..845d380 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -861,6 +861,19 @@ class RootController(BaseController, FeedController):
                 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)
+
         c.app.globals.invalidate_bin_counts()
         ThreadLocalORMSession.flush_all()
         count = len(tickets)


[03/15] git commit: [#5656] ticket:301 Bulk move tickets

Posted by br...@apache.org.
[#5656] ticket:301 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/ffb9e7f6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/ffb9e7f6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/ffb9e7f6

Branch: refs/heads/master
Commit: ffb9e7f685be99e9935e5315fc6fb02456b77f78
Parents: a087f64
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed May 1 08:48:35 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:35:51 2013 +0000

----------------------------------------------------------------------
 .../forgetracker/tests/functional/test_root.py     |   11 +++-
 ForgeTracker/forgetracker/tracker_main.py          |   35 ++++++++++++++-
 2 files changed, 42 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ffb9e7f6/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 7015cd4..2a0e3e9 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -2236,10 +2236,15 @@ class TestBulkMove(TrackerTestController):
 
     def test_access_restriction(self):
        self.app.get('/bugs/move/', status=200)
-       self.app.get('/bugs/move/', extra_environ={'username': 'test-user-0'},
+       self.app.get('/bugs/move/',
+                    extra_environ={'username': 'test-user-0'},
                     status=403)
-       self.app.get('/bugs/move/', extra_environ={'username': '*anonymous'},
+       self.app.get('/bugs/move/',
+                    extra_environ={'username': '*anonymous'},
                     status=302)
+       self.app.post('/bugs/move_tickets',
+                     extra_environ={'username': 'test-user-0'},
+                     status=403)
 
     def test_ticket_list(self):
         r = self.app.get('/bugs/move/?q=The')
@@ -2285,7 +2290,7 @@ class TestBulkMove(TrackerTestController):
             assert_equal(ticket.discussion_thread.app_config_id, ac_id)
             assert_equal(ticket.discussion_thread.discussion.app_config_id, ac_id)
             post = ticket.discussion_thread.last_post
-            assert_equal(post.text, 'Ticket moved from /p/test/bugs/1/')
+            assert_in('Ticket moved from /p/test/bugs/', post.text)
         for t in original_tickets:
             assert_equal(t.discussion_thread.app_config_id, original_ac_id)
             assert_equal(t.discussion_thread.discussion.app_config_id, original_ac_id)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ffb9e7f6/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index b2cc363..e5cf057 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -795,11 +795,44 @@ class RootController(BaseController, FeedController):
         result['cancel_href'] = url(c.app.url + 'search/', dict(q=q, limit=limit, sort=sort))
         c.mass_move = W.mass_edit
         trackers = _my_trackers(c.user, c.app.config)
-        c.mass_move_form = W.mass_move_form(trackers=trackers)
+        c.mass_move_form = W.mass_move_form(
+            trackers=trackers,
+            action=c.app.url + 'move_tickets')
         return result
 
     @expose()
     @require_post()
+    def move_tickets(self, **post_data):
+        require_access(c.app, 'admin')
+        ticket_ids = aslist(post_data.get('__ticket_ids', []))
+        search = post_data.get('__search', '')
+        try:
+            destination_tracker_id = ObjectId(post_data.get('tracker', ''))
+        except InvalidId:
+            destination_tracker_id = None
+        tracker = M.AppConfig.query.get(_id=destination_tracker_id)
+        if tracker is None:
+            flash('Select valid tracker', 'error')
+            redirect('move/' + search)
+        if tracker == c.app.config:
+            flash('Ticket already in a selected tracker', 'info')
+            redirect('move/' + search)
+        if not has_access(tracker, 'admin')():
+            flash('You should have admin access to destination tracker', 'error')
+            redirect('move/' + search)
+        tickets = TM.Ticket.query.find(dict(
+            _id={'$in': [ObjectId(id) for id in ticket_ids]},
+            app_config_id=c.app.config._id)).all()
+        for ticket in tickets:
+            ticket.move(tracker)
+        c.app.globals.invalidate_bin_counts()
+        ThreadLocalORMSession.flush_all()
+        count = len(tickets)
+        flash('Moved {} ticket{}'.format(count, 's' if count != 1 else ''), 'ok')
+        redirect('move/' + search)
+
+    @expose()
+    @require_post()
     def update_tickets(self, **post_data):
         tickets = TM.Ticket.query.find(dict(
                 _id={'$in':[ObjectId(id) for id in aslist(post_data['__ticket_ids'])]},


[09/15] git commit: [#5656] ticket:301 Fix missing semicolon in js

Posted by br...@apache.org.
[#5656] ticket:301 Fix missing semicolon in js


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

Branch: refs/heads/master
Commit: f7e873b5addccfaa4577d58400a1d97e92b760d5
Parents: a770cdf
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed May 1 12:05:25 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:35:52 2013 +0000

----------------------------------------------------------------------
 .../forgetracker/widgets/resources/js/mass-edit.js |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f7e873b5/ForgeTracker/forgetracker/widgets/resources/js/mass-edit.js
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/widgets/resources/js/mass-edit.js b/ForgeTracker/forgetracker/widgets/resources/js/mass-edit.js
index 83736c9..798473d 100644
--- a/ForgeTracker/forgetracker/widgets/resources/js/mass-edit.js
+++ b/ForgeTracker/forgetracker/widgets/resources/js/mass-edit.js
@@ -18,7 +18,7 @@
 */
 
 $(function(){
-    $form = $('#update-values')
+    $form = $('#update-values');
     if ($form.length == 0) {
         $form = $('.editbox > form');
     }


[12/15] git commit: [#5656] ticket:358 Respect new email monitoring types

Posted by br...@apache.org.
[#5656] ticket:358 Respect new email monitoring types


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

Branch: refs/heads/master
Commit: 82f675f705b860fe3806f28d530dbb139e8156da
Parents: ed74e25
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu May 23 14:45:33 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:42:27 2013 +0000

----------------------------------------------------------------------
 ForgeTracker/forgetracker/model/ticket.py          |   22 +++--
 .../forgetracker/tests/functional/test_root.py     |   87 +++++++++++++++
 2 files changed, 101 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/82f675f7/ForgeTracker/forgetracker/model/ticket.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 24a5d08..bc2d0c2 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -266,18 +266,24 @@ class Globals(MappedClass):
                 destinations = [str(user._id)]))
             mail_tasks.sendmail.post(**mail)
 
-        if c.app.config.options.get('TicketMonitoringType') == 'AllTicketChanges':
+        if c.app.config.options.get('TicketMonitoringType') in (
+                'AllTicketChanges', 'AllPublicTicketChanges'):
             monitoring_email = c.app.config.options.get('TicketMonitoringEmail')
-            tmpl_context['tickets'] = ({
+            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)
+                } for _id, t in moved_tickets.iteritems()
+                  if (not t.private or
+                      c.app.config.options.get('TicketMonitoringType') ==
+                      'AllTicketChanges')]
+            if len(tmpl_context['tickets']) > 0:
+                mail.update(dict(
+                    message_id = h.gen_message_id(),
+                    text = tmpl.render(tmpl_context),
+                    destinations = [monitoring_email]))
+                mail_tasks.sendmail.post(**mail)
+
         moved_from = '%s/%s' % (c.project.shortname, c.app.config.options.mount_point)
         moved_to = '%s/%s' % (tracker.project.shortname, tracker.options.mount_point)
         text = 'Tickets moved from %s to %s' % (moved_from, moved_to)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/82f675f7/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 1f4acf4..b7e7dd8 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -2396,6 +2396,93 @@ class TestBulkMove(TrackerTestController):
         monitoring_email_text = monitoring_email[0].kwargs.text
         assert_equal(admin_email_text, monitoring_email_text)
 
+    @td.with_tool('test2', 'Tickets', 'bugs2')
+    def test_monitoring_email_public_only(self):
+        """Test that private tickets are not included in bulk move
+        notifications if the "public only" option is selected.
+        """
+        self.app.post('/admin/bugs/set_options', params={
+            'TicketMonitoringEmail': 'monitoring@email.com',
+            'TicketMonitoringType': 'AllPublicTicketChanges',
+        })
+        self.new_ticket(summary='test first ticket', status='open')
+        self.new_ticket(summary='test second ticket', status='open', private=True)
+        ThreadLocalORMSession.flush_all()
+        M.MonQTask.run_ready()
+        ThreadLocalORMSession.flush_all()
+        tickets = [
+            tm.Ticket.query.find({'summary': 'test first ticket'}).first(),
+            tm.Ticket.query.find({'summary': 'test second ticket'}).first()]
+        M.MonQTask.query.remove()
+        p = M.Project.query.get(shortname='test2')
+        tracker = p.app_instance('bugs2')
+        self.app.post('/p/test/bugs/move_tickets', {
+                'tracker': str(tracker.config._id),
+                '__ticket_ids': [t._id for t in tickets],
+                '__search': '',
+            })
+        M.MonQTask.run_ready()
+        emails = M.MonQTask.query.find(dict(task_name='allura.tasks.mail_tasks.sendmail')).all()
+        assert_equal(len(emails), 2)  # one for admin and one for monitoring email
+        for email in emails:
+            assert_equal(email.kwargs.subject, '[test:bugs] Mass ticket moving by Test Admin')
+        admin = M.User.by_username('test-admin')
+        admin_email = M.MonQTask.query.find({
+            'task_name': 'allura.tasks.mail_tasks.sendmail',
+            'kwargs.destinations': str(admin._id)
+        }).all()
+        monitoring_email = M.MonQTask.query.find({
+            'task_name': 'allura.tasks.mail_tasks.sendmail',
+            'kwargs.destinations': 'monitoring@email.com'
+        }).all()
+        assert_equal(len(admin_email), 1)
+        assert_equal(len(monitoring_email), 1)
+        admin_email_text = admin_email[0].kwargs.text
+        monitoring_email_text = monitoring_email[0].kwargs.text
+        assert_in('second ticket', admin_email_text)
+        assert_not_in('second ticket', monitoring_email_text)
+
+    @td.with_tool('test2', 'Tickets', 'bugs2')
+    def test_monitoring_email_all_private_moved(self):
+        """Test that no monitoring email is sent if the "public only"
+        option is selected, and only private tickets were moved.
+        """
+        self.app.post('/admin/bugs/set_options', params={
+            'TicketMonitoringEmail': 'monitoring@email.com',
+            'TicketMonitoringType': 'AllPublicTicketChanges',
+        })
+        self.new_ticket(summary='test first ticket', status='open', private=True)
+        self.new_ticket(summary='test second ticket', status='open', private=True)
+        ThreadLocalORMSession.flush_all()
+        M.MonQTask.run_ready()
+        ThreadLocalORMSession.flush_all()
+        tickets = [
+            tm.Ticket.query.find({'summary': 'test first ticket'}).first(),
+            tm.Ticket.query.find({'summary': 'test second ticket'}).first()]
+        M.MonQTask.query.remove()
+        p = M.Project.query.get(shortname='test2')
+        tracker = p.app_instance('bugs2')
+        self.app.post('/p/test/bugs/move_tickets', {
+                'tracker': str(tracker.config._id),
+                '__ticket_ids': [t._id for t in tickets],
+                '__search': '',
+            })
+        M.MonQTask.run_ready()
+        emails = M.MonQTask.query.find(dict(task_name='allura.tasks.mail_tasks.sendmail')).all()
+        assert_equal(len(emails), 1)  # only admin email sent
+        for email in emails:
+            assert_equal(email.kwargs.subject, '[test:bugs] Mass ticket moving by Test Admin')
+        admin = M.User.by_username('test-admin')
+        admin_email = M.MonQTask.query.find({
+            'task_name': 'allura.tasks.mail_tasks.sendmail',
+            'kwargs.destinations': str(admin._id)
+        }).all()
+        monitoring_email = M.MonQTask.query.find({
+            'task_name': 'allura.tasks.mail_tasks.sendmail',
+            'kwargs.destinations': 'monitoring@email.com'
+        }).all()
+        assert_equal(len(admin_email), 1)
+        assert_equal(len(monitoring_email), 0)
 
 def sidebar_contains(response, text):
     sidebar_menu = response.html.find('div', attrs={'id': 'sidebar'})


[06/15] git commit: [#5656] ticket:301 Fix original ticket nums in the summary email

Posted by br...@apache.org.
[#5656] ticket:301 Fix original ticket nums in the summary email


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

Branch: refs/heads/master
Commit: 3dd431842e1106e727066fac1b6d33bfb47b7525
Parents: 36234bd
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed May 1 10:45:31 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:35:51 2013 +0000

----------------------------------------------------------------------
 ForgeTracker/forgetracker/tracker_main.py |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3dd43184/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 030d168..c41db5e 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -824,8 +824,8 @@ class RootController(BaseController, FeedController):
             _id={'$in': [ObjectId(id) for id in ticket_ids]},
             app_config_id=c.app.config._id)).all()
 
-        original_tickets = {t._id: t for t in tickets}
-        filtered = filtered_by_subscription(original_tickets)
+        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:
@@ -851,7 +851,7 @@ class RootController(BaseController, FeedController):
         }
         for user in users:
             tmpl_context['tickets'] = ({
-                    'original_num': original_tickets[_id].ticket_num,
+                    '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, []))


[04/15] git commit: [#5656] ticket:301 Refactor trackers collecting in helper function and use it in both 'moves'

Posted by br...@apache.org.
[#5656] ticket:301 Refactor trackers collecting in helper function and use it in both 'moves'


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

Branch: refs/heads/master
Commit: d1fc56e5dc000065d7f8926d709e4f69d45bcd4d
Parents: c0797ac
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Apr 30 15:04:22 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:35:51 2013 +0000

----------------------------------------------------------------------
 ForgeTracker/forgetracker/tracker_main.py |   34 +++++++++++++++--------
 1 files changed, 22 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d1fc56e5/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index b1bd941..b2cc363 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -139,6 +139,25 @@ def get_change_text(name, new_value, old_value):
         changelist=changes.get_changed())
 
 
+def _my_trackers(user, current_tracker_app_config):
+    '''Collect all 'Tickets' instances in all user's projects
+    for which user has admin permissions.
+
+    Returns list of 3-tuples (<tracker_id>, '<project>/<mount_point>', <is current tracker?>)
+    '''
+    trackers = []
+    projects = user.my_projects()
+    projects = ifilter(lambda p: has_access(p, 'admin')(), projects)
+    for p in projects:
+        for ac in p.app_configs:
+            if ac.tool_name.lower() == 'tickets':
+                trac = (str(ac._id),
+                        '%s/%s' % (p.shortname, ac.options['mount_point']),
+                        bool(current_tracker_app_config == ac))
+                trackers.append(trac)
+    return trackers
+
+
 class W:
     thread=w.Thread(
         page=None, limit=None, page_size=None, count=None,
@@ -775,7 +794,8 @@ class RootController(BaseController, FeedController):
         result['globals'] = c.app.globals
         result['cancel_href'] = url(c.app.url + 'search/', dict(q=q, limit=limit, sort=sort))
         c.mass_move = W.mass_edit
-        c.mass_move_form = W.mass_move_form(tracker=[])
+        trackers = _my_trackers(c.user, c.app.config)
+        c.mass_move_form = W.mass_move_form(trackers=trackers)
         return result
 
     @expose()
@@ -1475,17 +1495,7 @@ class TicketController(BaseController, FeedController):
             flash('Ticket successfully moved')
             redirect(new_ticket.url())
 
-        # collect all 'Tickets' instances in all user project for which his has admin perms
-        trackers = []
-        projects = c.user.my_projects()
-        projects = ifilter(lambda p: has_access(p, 'admin')(), projects)
-        for p in projects:
-            for ac in p.app_configs:
-                if ac.tool_name.lower() == 'tickets':
-                    trac = (str(ac._id),
-                            '%s/%s' % (p.shortname, ac.options['mount_point']),
-                            bool(self.ticket.app.config == ac))
-                    trackers.append(trac)
+        trackers = _my_trackers(c.user, self.ticket.app.config)
         return {
             'ticket': self.ticket,
             'form': W.move_ticket_form(trackers=trackers),


[07/15] git commit: [#5656] ticket:301 Summary email for bulk ticket move

Posted by br...@apache.org.
[#5656] ticket:301 Summary email for bulk ticket move


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

Branch: refs/heads/master
Commit: 36234bd7ff5f1c84fd33d869a2e0f2582f0bd1b5
Parents: 75adfcc
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed May 1 10:39:23 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:35:51 2013 +0000

----------------------------------------------------------------------
 .../forgetracker/data/mass_move_report.html        |    5 ++
 ForgeTracker/forgetracker/model/ticket.py          |    6 +-
 .../forgetracker/tests/functional/test_root.py     |   56 +++++++++++++++
 ForgeTracker/forgetracker/tracker_main.py          |   38 ++++++++++-
 4 files changed, 101 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/36234bd7/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
new file mode 100644
index 0000000..3ace7c6
--- /dev/null
+++ b/ForgeTracker/forgetracker/data/mass_move_report.html
@@ -0,0 +1,5 @@
+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']}}
+{% endfor %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/36234bd7/ForgeTracker/forgetracker/model/ticket.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index cf8249f..75c8bca 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -530,7 +530,7 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact):
                         o and o.username, n and n.username))
                 self.subscribe(user=n)
                 g.statsUpdater.ticketEvent("assigned", self, self.project, n)
-                if o: 
+                if o:
                     g.statsUpdater.ticketEvent("revoked", self, self.project, o)
             if old.description != self.description:
                 changes.append('Description updated:')
@@ -635,7 +635,7 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact):
                     attach_thumb.discussion_id = app_config.discussion_id
                 attach_thumb.app_config_id = app_config._id
 
-    def move(self, app_config):
+    def move(self, app_config, notify=True):
         '''Move ticket from current tickets app to tickets app with given app_config'''
         app = app_config.project.app_instance(app_config)
         prior_url = self.url()
@@ -724,7 +724,7 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact):
             message += '\n\nCan\'t be converted:\n\n'
         message += '\n'.join(messages)
         with h.push_context(ticket.project_id, app_config_id=app_config._id):
-            ticket.discussion_thread.add_post(text=message)
+            ticket.discussion_thread.add_post(text=message, notify=notify)
         return ticket
 
     def __json__(self):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/36234bd7/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 2a0e3e9..e346482 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -2296,6 +2296,62 @@ class TestBulkMove(TrackerTestController):
             assert_equal(t.discussion_thread.discussion.app_config_id, original_ac_id)
             assert t.discussion_thread.last_post is None
 
+    @td.with_tool('test2', 'Tickets', 'bugs2')
+    def test_notifications(self):
+        tickets = [
+            tm.Ticket.query.find({'summary': 'A New Hope'}).first(),
+            tm.Ticket.query.find({'summary': 'The Empire Strikes Back'}).first(),
+            tm.Ticket.query.find({'summary': 'Return Of The Jedi'}).first()]
+        p = M.Project.query.get(shortname='test2')
+        tracker = p.app_instance('bugs2')
+        first_user = M.User.by_username('test-user-0')
+        second_user = M.User.by_username('test-user-1')
+        admin = M.User.by_username('test-admin')
+        tickets[0].subscribe(user=first_user)
+        tickets[1].subscribe(user=second_user)
+        M.MonQTask.query.remove()
+        r = self.app.post('/p/test/bugs/move_tickets', {
+                    'tracker': str(tracker.config._id),
+                    '__ticket_ids': [t._id for t in tickets],
+                    '__search': '',
+                })
+        M.MonQTask.run_ready()
+        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')
+        first_user_email = M.MonQTask.query.find({
+            'task_name': 'allura.tasks.mail_tasks.sendmail',
+            'kwargs.destinations': str(first_user._id)
+        }).all()
+        assert_equal(len(first_user_email), 1)
+        first_user_email = first_user_email[0]
+        second_user_email = M.MonQTask.query.find({
+            'task_name': 'allura.tasks.mail_tasks.sendmail',
+            'kwargs.destinations': str(second_user._id)
+        }).all()
+        assert_equal(len(second_user_email), 1)
+        second_user_email = second_user_email[0]
+        admin_email = M.MonQTask.query.find({
+            'task_name': 'allura.tasks.mail_tasks.sendmail',
+            'kwargs.destinations': str(admin._id)
+        }).all()
+        assert_equal(len(admin_email), 1)
+        admin_email = admin_email[0]
+
+        email_header = 'Tickets were moved from [test:bugs] to [test2:bugs2]\n'
+        first_ticket_changes = 'A New Hope'
+        second_ticket_changes = 'The Empire Strikes Back'
+        third_ticket_changes = 'Return Of The Jedi'
+        assert_in(email_header, first_user_email.kwargs.text)
+        assert_in(first_ticket_changes, first_user_email.kwargs.text)
+        assert_in(email_header, second_user_email.kwargs.text)
+        assert_in(second_ticket_changes, second_user_email.kwargs.text)
+        assert_in(email_header, admin_email.kwargs.text)
+        assert_in(first_ticket_changes, admin_email.kwargs.text)
+        assert_in(second_ticket_changes, admin_email.kwargs.text)
+        assert_in(third_ticket_changes, admin_email.kwargs.text)
+
 
 def sidebar_contains(response, text):
     sidebar_menu = response.html.find('div', attrs={'id': 'sidebar'})

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/36234bd7/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index e5cf057..030d168 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -823,8 +823,44 @@ class RootController(BaseController, FeedController):
         tickets = TM.Ticket.query.find(dict(
             _id={'$in': [ObjectId(id) for id in ticket_ids]},
             app_config_id=c.app.config._id)).all()
+
+        original_tickets = {t._id: t for t in tickets}
+        filtered = filtered_by_subscription(original_tickets)
+        users = M.User.query.find({'_id': {'$in': filtered.keys()}}).all()
+        moved_tickets = {}
         for ticket in tickets:
-            ticket.move(tracker)
+            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_tickets[_id].ticket_num,
+                    '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)
+
         c.app.globals.invalidate_bin_counts()
         ThreadLocalORMSession.flush_all()
         count = len(tickets)


[05/15] git commit: [#5656] ticket:301 Tests for bulk move

Posted by br...@apache.org.
[#5656] ticket:301 Tests for bulk move


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

Branch: refs/heads/master
Commit: a087f64a3f786cbd092c8b6e1321f26e28ac7d04
Parents: d1fc56e
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed May 1 08:04:41 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:35:51 2013 +0000

----------------------------------------------------------------------
 .../forgetracker/tests/functional/test_root.py     |   67 +++++++++++++++
 1 files changed, 67 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a087f64a/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 84b63e5..7015cd4 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -2225,6 +2225,73 @@ class test_show_default_fields(TrackerTestController):
         assert '<td>Labels</td> <td><input type="checkbox" name="labels" ></td>' in r
 
 
+class TestBulkMove(TrackerTestController):
+
+    def setUp(self):
+        super(TestBulkMove, self).setUp()
+        self.new_ticket(summary='A New Hope')
+        self.new_ticket(summary='The Empire Strikes Back')
+        self.new_ticket(summary='Return Of The Jedi')
+        M.MonQTask.run_ready()
+
+    def test_access_restriction(self):
+       self.app.get('/bugs/move/', status=200)
+       self.app.get('/bugs/move/', extra_environ={'username': 'test-user-0'},
+                    status=403)
+       self.app.get('/bugs/move/', extra_environ={'username': '*anonymous'},
+                    status=302)
+
+    def test_ticket_list(self):
+        r = self.app.get('/bugs/move/?q=The')
+        tickets_table = r.html.find('tbody', attrs={'class': 'ticket-list'})
+        tickets = tickets_table.findAll('tr')
+        assert_equal(len(tickets), 2)
+        assert_in('The Empire Strikes Back', tickets_table.text)
+        assert_in('Return Of The Jedi', tickets_table.text)
+
+    @td.with_tool('test', 'Tickets', 'bugs2')
+    @td.with_tool('test2', 'Tickets', 'bugs')
+    @td.with_tool('test2', 'Tickets', 'bugs2')
+    def test_controls_present(self):
+        r = self.app.get('/bugs/move/')
+        trackers = r.html.find('select', {'name': 'tracker'}).findAll('option')
+        trackers = set([t.text for t in trackers])
+        expected = set(['test/bugs', 'test/bugs2', 'test2/bugs', 'test2/bugs2'])
+        assert_equal(trackers, expected)
+        move_btn = r.html.find('input', attrs={'type': 'submit', 'value': 'Move'})
+        assert move_btn is not None
+
+    @td.with_tool('test2', 'Tickets', 'bugs')
+    def test_move(self):
+        tickets = [
+            tm.Ticket.query.find({'summary': 'The Empire Strikes Back'}).first(),
+            tm.Ticket.query.find({'summary': 'Return Of The Jedi'}).first()]
+        p = M.Project.query.get(shortname='test2')
+        original_p = M.Project.query.get(shortname='test')
+        tracker = p.app_instance('bugs')
+        original_tracker = original_p.app_instance('bugs')
+        r = self.app.post('/p/test/bugs/move_tickets', {
+                    'tracker': str(tracker.config._id),
+                    '__ticket_ids': [t._id for t in tickets],
+                    '__search': '',
+                })
+        ac_id = tracker.config._id
+        original_ac_id = original_tracker.config._id
+        moved_tickets = tm.Ticket.query.find({'app_config_id': ac_id}).all()
+        original_tickets = tm.Ticket.query.find({'app_config_id': original_ac_id}).all()
+        assert_equal(len(moved_tickets), 2)
+        assert_equal(len(original_tickets), 1)
+        for ticket in moved_tickets:
+            assert_equal(ticket.discussion_thread.app_config_id, ac_id)
+            assert_equal(ticket.discussion_thread.discussion.app_config_id, ac_id)
+            post = ticket.discussion_thread.last_post
+            assert_equal(post.text, 'Ticket moved from /p/test/bugs/1/')
+        for t in original_tickets:
+            assert_equal(t.discussion_thread.app_config_id, original_ac_id)
+            assert_equal(t.discussion_thread.discussion.app_config_id, original_ac_id)
+            assert t.discussion_thread.last_post is None
+
+
 def sidebar_contains(response, text):
     sidebar_menu = response.html.find('div', attrs={'id': 'sidebar'})
     return text in str(sidebar_menu)


[08/15] git commit: [#5656] ticket:301 Change mass-edit.js to process move form also

Posted by br...@apache.org.
[#5656] ticket:301 Change mass-edit.js to process move form also


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

Branch: refs/heads/master
Commit: 75adfcc0785a592ce4ced6dba8c66c4421283e87
Parents: ffb9e7f
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed May 1 09:16:50 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:35:51 2013 +0000

----------------------------------------------------------------------
 .../forgetracker/templates/tracker/mass_move.html  |    1 +
 .../forgetracker/widgets/resources/js/mass-edit.js |   13 ++++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/75adfcc0/ForgeTracker/forgetracker/templates/tracker/mass_move.html
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/templates/tracker/mass_move.html b/ForgeTracker/forgetracker/templates/tracker/mass_move.html
index 1953801..ac5c515 100644
--- a/ForgeTracker/forgetracker/templates/tracker/mass_move.html
+++ b/ForgeTracker/forgetracker/templates/tracker/mass_move.html
@@ -25,6 +25,7 @@
 {% block edit_box %}
 <div class="editbox">
   {{c.mass_move_form.display()}}
+  <div id="result" style="clear:both;"></div>
 </div>
 {% endblock %}
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/75adfcc0/ForgeTracker/forgetracker/widgets/resources/js/mass-edit.js
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/widgets/resources/js/mass-edit.js b/ForgeTracker/forgetracker/widgets/resources/js/mass-edit.js
index 90a037e..83736c9 100644
--- a/ForgeTracker/forgetracker/widgets/resources/js/mass-edit.js
+++ b/ForgeTracker/forgetracker/widgets/resources/js/mass-edit.js
@@ -18,6 +18,13 @@
 */
 
 $(function(){
+    $form = $('#update-values')
+    if ($form.length == 0) {
+        $form = $('.editbox > form');
+    }
+    if ($('#id_search').length == 0) {
+        $form.append('<input type="hidden" name="__search" id="id_search">');
+    }
     $('#id_search').val(window.location.search);
     $('#assigned_to').val('');
     $('#select_all').click(function(){
@@ -28,16 +35,16 @@ $(function(){
             $('tbody.ticket-list input[type=checkbox]').removeAttr('checked');
         }
     });
-    $('#update-values').submit(function(){
+    $form.submit(function(){
         var $checked=$('tbody.ticket-list input:checked'), count=$checked.length;
 
         if ( !count ) {
-            $('#result').text('No tickets selected for update.');
+            $('#result').text('No tickets selected.');
             return false;
         }
 
         $checked.each(function() {
-            $('#update-values').append('<input type="hidden" name="__ticket_ids" value="'+$(this).val()+'"/>');
+            $form.append('<input type="hidden" name="__ticket_ids" value="'+$(this).val()+'"/>');
         });
     });
 });


[13/15] git commit: [#5656] ticket:358 Flash notification about move task completion

Posted by br...@apache.org.
[#5656] ticket:358 Flash notification about move task completion


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

Branch: refs/heads/master
Commit: ed74e25d1b4c89cdafbd90d23f97c7ac36592096
Parents: 5198a83
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu May 23 14:03:53 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:42:27 2013 +0000

----------------------------------------------------------------------
 ForgeTracker/forgetracker/model/ticket.py          |    4 ++++
 .../forgetracker/tests/functional/test_root.py     |   13 +++++++++----
 2 files changed, 13 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ed74e25d/ForgeTracker/forgetracker/model/ticket.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index b1144db..24a5d08 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -278,6 +278,10 @@ class Globals(MappedClass):
                 text = tmpl.render(tmpl_context),
                 destinations = [monitoring_email]))
             mail_tasks.sendmail.post(**mail)
+        moved_from = '%s/%s' % (c.project.shortname, c.app.config.options.mount_point)
+        moved_to = '%s/%s' % (tracker.project.shortname, tracker.options.mount_point)
+        text = 'Tickets moved from %s to %s' % (moved_from, moved_to)
+        Notification.post_user(c.user, None, 'flash', text=text)
 
     def filtered_by_subscription(self, tickets, project_id=None, app_config_id=None):
         p_id = project_id if project_id else c.project._id

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ed74e25d/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 0d129a3..1f4acf4 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -2235,14 +2235,14 @@ class TestBulkMove(TrackerTestController):
         M.MonQTask.run_ready()
 
     def test_access_restriction(self):
-       self.app.get('/bugs/move/', status=200)
-       self.app.get('/bugs/move/',
+        self.app.get('/bugs/move/', status=200)
+        self.app.get('/bugs/move/',
                     extra_environ={'username': 'test-user-0'},
                     status=403)
-       self.app.get('/bugs/move/',
+        self.app.get('/bugs/move/',
                     extra_environ={'username': '*anonymous'},
                     status=302)
-       self.app.post('/bugs/move_tickets',
+        self.app.post('/bugs/move_tickets',
                      extra_environ={'username': 'test-user-0'},
                      status=403)
 
@@ -2353,6 +2353,11 @@ class TestBulkMove(TrackerTestController):
         assert_in(first_ticket_changes, admin_email.kwargs.text)
         assert_in(second_ticket_changes, admin_email.kwargs.text)
         assert_in(third_ticket_changes, admin_email.kwargs.text)
+        # After tickets moved, user should see a flash
+        mbox = M.Mailbox.query.get(user_id=admin._id, is_flash=True)
+        notification_id = mbox.queue[-1]
+        notification = M.Notification.query.get(_id=notification_id)
+        assert_equal(notification.text, 'Tickets moved from test/bugs to test2/bugs2')
 
     @td.with_tool('test2', 'Tickets', 'bugs2')
     def test_monitoring_email(self):


[15/15] git commit: [#5656] ticket:358 Fix indentation

Posted by br...@apache.org.
[#5656] ticket:358 Fix indentation


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

Branch: refs/heads/master
Commit: 250337d2378b345a18aadbfe53c80322482c0a61
Parents: 6c1eecc
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu May 23 13:17:57 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:42:27 2013 +0000

----------------------------------------------------------------------
 ForgeTracker/forgetracker/model/ticket.py |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/250337d2/ForgeTracker/forgetracker/model/ticket.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 80a8eb2..b1144db 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -261,9 +261,9 @@ class Globals(MappedClass):
                     '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)]))
+                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':


[10/15] git commit: [#5656] ticket:358 Move move_tickets task to ForgeTracker

Posted by br...@apache.org.
[#5656] ticket:358 Move move_tickets task to ForgeTracker


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

Branch: refs/heads/master
Commit: 5198a838d7895d41b3422b2a3526ce103512dbe8
Parents: 250337d
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu May 23 13:29:17 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:42:27 2013 +0000

----------------------------------------------------------------------
 Allura/allura/tasks/tracker_task.py       |   25 ------------------------
 ForgeTracker/forgetracker/tasks.py        |    5 ++++
 ForgeTracker/forgetracker/tracker_main.py |    5 ++-
 3 files changed, 8 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5198a838/Allura/allura/tasks/tracker_task.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tasks/tracker_task.py b/Allura/allura/tasks/tracker_task.py
deleted file mode 100644
index 0a37850..0000000
--- a/Allura/allura/tasks/tracker_task.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.
-
-
-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/5198a838/ForgeTracker/forgetracker/tasks.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tasks.py b/ForgeTracker/forgetracker/tasks.py
index fa0b7bc..6cbd42d 100644
--- a/ForgeTracker/forgetracker/tasks.py
+++ b/ForgeTracker/forgetracker/tasks.py
@@ -32,3 +32,8 @@ def update_bin_counts(app_config_id):
     app = app_config.project.app_instance(app_config)
     with h.push_config(c, app=app):
         app.globals.update_bin_counts()
+
+
+@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/5198a838/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 1534f55..7fbbe9c 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -62,11 +62,12 @@ 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, tracker_task
+from allura.tasks import mail_tasks
 
 # Local imports
 from forgetracker import model as TM
 from forgetracker import version
+from forgetracker import tasks
 
 from forgetracker.widgets.admin import OptionsAdmin
 from forgetracker.widgets.ticket_form import TicketForm, TicketCustomField
@@ -824,7 +825,7 @@ class RootController(BaseController, FeedController):
             _id={'$in': [ObjectId(id) for id in ticket_ids]},
             app_config_id=c.app.config._id)).all()
 
-        tracker_task.move_tickets.post(ticket_ids, destination_tracker_id)
+        tasks.move_tickets.post(ticket_ids, destination_tracker_id)
 
         c.app.globals.invalidate_bin_counts()
         ThreadLocalORMSession.flush_all()


[14/15] git commit: [#5656] ticket:353 changed flash message and subject

Posted by br...@apache.org.
[#5656]  ticket:353 changed flash message and subject


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

Branch: refs/heads/master
Commit: 6c1eeccf177a521187cd060cf317e515eb86f732
Parents: 224499a
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Mon May 20 14:53:02 2013 +0400
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 24 18:42:27 2013 +0000

----------------------------------------------------------------------
 ForgeTracker/forgetracker/model/ticket.py          |    2 +-
 .../forgetracker/tests/functional/test_root.py     |    4 ++--
 ForgeTracker/forgetracker/tracker_main.py          |    2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6c1eeccf/ForgeTracker/forgetracker/model/ticket.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 3a6803d..80a8eb2 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -242,7 +242,7 @@ class Globals(MappedClass):
         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,
+            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')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6c1eeccf/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 37b3399..0d129a3 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -2321,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)
@@ -2376,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/6c1eeccf/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 62469a9..1534f55 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -829,7 +829,7 @@ class RootController(BaseController, FeedController):
         c.app.globals.invalidate_bin_counts()
         ThreadLocalORMSession.flush_all()
         count = len(tickets)
-        flash('Moved {} ticket{}'.format(count, 's' if count != 1 else ''), 'ok')
+        flash('Move scheduled ({} ticket{})'.format(count, 's' if count != 1 else ''), 'ok')
         redirect('move/' + search)
 
     @expose()


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

Posted by br...@apache.org.
[#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):