Merge lp:~gmb/launchpad/non-js-muting-bug-734732 into lp:launchpad

Proposed by Graham Binns
Status: Merged
Merged at revision: 12624
Proposed branch: lp:~gmb/launchpad/non-js-muting-bug-734732
Merge into: lp:launchpad
Diff against target: 170 lines (+110/-3)
5 files modified
lib/lp/bugs/browser/bug.py (+1/-3)
lib/lp/bugs/browser/bugsubscription.py (+34/-0)
lib/lp/bugs/browser/configure.zcml (+6/-0)
lib/lp/bugs/browser/tests/test_bugsubscription_views.py (+37/-0)
lib/lp/bugs/templates/bug-mute.pt (+32/-0)
To merge this branch: bzr merge lp:~gmb/launchpad/non-js-muting-bug-734732
Reviewer Review Type Date Requested Status
Brad Crittenden (community) code Approve
Review via email: mp+53981@code.launchpad.net

Commit message

[r=bac][bug=734732] There is now a non-JS process for muting mail from a bug.

Description of the change

This branch adds a BugTask:+mute view, so that stick-in-the muds who use
console-based browsers (RMS, I'm looking at you here) and people who use
browsers that don't play nice with YUI 3 (IE, now I'm looking at you)
can still use the mute / unmute functionality.

The +mute view presents a single button that allows the user to mute or
unmute bug mail for a bug. If the +mute page is visited by a user who
already holds a mute on the bug, they'll be redirected to the +subscribe
page, which handles the unmuting (and resubscribing if desired) story.

To post a comment you must log in.
Revision history for this message
Brad Crittenden (bac) wrote :

Looks good, Graham, nice and simple.

I have a few issues:

1) You are inconsistent in text presented to the user of "mail" vs. "email" but definitely not "e-mail".

2) The phrase "Bug mail for bug X" is wordy. s/Bug mail/Mail or Email.

3) In test_bug_mute_self_view_mutes_bug it would be nice to see the user is not muted before you exercise the form.

review: Approve (code)
Revision history for this message
Graham Binns (gmb) wrote :

Thanks Brad, I've updated the code as you've suggested.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/browser/bug.py'
2--- lib/lp/bugs/browser/bug.py 2011-03-10 12:42:35 +0000
3+++ lib/lp/bugs/browser/bug.py 2011-03-18 13:42:19 +0000
4@@ -281,10 +281,8 @@
5 else:
6 text = "Mute bug mail"
7
8- # We link to '#' here because we don't yet have a view to handle
9- # this link.
10 return Link(
11- '#', text, icon='remove', summary=(
12+ '+mute', text, icon='remove', summary=(
13 "Mute this bug so that you will never receive emails "
14 "about it."))
15
16
17=== modified file 'lib/lp/bugs/browser/bugsubscription.py'
18--- lib/lp/bugs/browser/bugsubscription.py 2011-03-16 13:26:30 +0000
19+++ lib/lp/bugs/browser/bugsubscription.py 2011-03-18 13:42:19 +0000
20@@ -6,6 +6,7 @@
21 __metaclass__ = type
22 __all__ = [
23 'AdvancedSubscriptionMixin',
24+ 'BugMuteSelfView',
25 'BugPortletDuplicateSubcribersContents',
26 'BugPortletSubcribersContents',
27 'BugSubscriptionAddView',
28@@ -584,3 +585,36 @@
29 @property
30 def structural_subscriptions(self):
31 return self.context.bug.getStructuralSubscriptionsForPerson(self.user)
32+
33+
34+class BugMuteSelfView(LaunchpadFormView):
35+ """A view to mute a user's bug mail for a given bug."""
36+
37+ schema = IBugSubscription
38+ field_names = []
39+
40+ @property
41+ def label(self):
42+ return "Mute bug mail for bug %s" % self.context.bug.id
43+
44+ page_title = label
45+
46+ @property
47+ def next_url(self):
48+ return canonical_url(self.context)
49+
50+ cancel_url = next_url
51+
52+ def initialize(self):
53+ super(BugMuteSelfView, self).initialize()
54+ # If the user is already muted, redirect them to the +subscribe
55+ # page, since there's no point doing its work twice.
56+ if self.context.bug.isMuted(self.user):
57+ self.request.response.redirect(
58+ canonical_url(self.context, view_name="+subscribe"))
59+
60+ @action('Mute bug mail', name='mute')
61+ def mute_action(self, action, data):
62+ self.context.bug.mute(self.user, self.user)
63+ self.request.response.addInfoNotification(
64+ "Mail for bug #%s has been muted." % self.context.bug.id)
65
66=== modified file 'lib/lp/bugs/browser/configure.zcml'
67--- lib/lp/bugs/browser/configure.zcml 2011-03-15 02:17:01 +0000
68+++ lib/lp/bugs/browser/configure.zcml 2011-03-18 13:42:19 +0000
69@@ -713,6 +713,12 @@
70 permission="launchpad.AnyPerson"
71 template="../templates/bug-subscription.pt"/>
72 <browser:page
73+ for="lp.bugs.interfaces.bugtask.IBugTask"
74+ name="+mute"
75+ class="lp.bugs.browser.bugsubscription.BugMuteSelfView"
76+ permission="launchpad.AnyPerson"
77+ template="../templates/bug-mute.pt"/>
78+ <browser:page
79 name="+linkcve"
80 for="lp.bugs.interfaces.bugtask.IBugTask"
81 class="lp.bugs.browser.cve.CveLinkView"
82
83=== modified file 'lib/lp/bugs/browser/tests/test_bugsubscription_views.py'
84--- lib/lp/bugs/browser/tests/test_bugsubscription_views.py 2011-03-16 13:26:30 +0000
85+++ lib/lp/bugs/browser/tests/test_bugsubscription_views.py 2011-03-18 13:42:19 +0000
86@@ -6,6 +6,7 @@
87 __metaclass__ = type
88
89 from canonical.launchpad.ftests import LaunchpadFormHarness
90+from canonical.launchpad.webapp import canonical_url
91 from canonical.testing.layers import LaunchpadFunctionalLayer
92
93 from lp.bugs.browser.bugsubscription import (
94@@ -444,3 +445,39 @@
95 decorator.subscription for decorator in
96 view.sorted_direct_subscriptions]
97 self.assertFalse(subscription in sorted_subscriptions)
98+
99+
100+class BugMuteSelfViewTestCase(TestCaseWithFactory):
101+ """Tests for the BugMuteSelfView."""
102+
103+ layer = LaunchpadFunctionalLayer
104+
105+ def setUp(self):
106+ super(BugMuteSelfViewTestCase, self).setUp()
107+ self.bug = self.factory.makeBug()
108+ self.person = self.factory.makePerson()
109+
110+ def test_bug_mute_self_view_mutes_bug(self):
111+ # The BugMuteSelfView mutes bug mail for the current user when
112+ # its form is submitted.
113+ with person_logged_in(self.person):
114+ self.assertFalse(self.bug.isMuted(self.person))
115+ mute_view = create_initialized_view(
116+ self.bug.default_bugtask, name="+mute",
117+ form={'field.actions.mute': 'Mute bug mail'})
118+ self.assertTrue(self.bug.isMuted(self.person))
119+
120+ def test_bug_mute_self_view_redirects_muted_users(self):
121+ # The BugMuteSelfView redirects muted users to the +subscribe
122+ # page, where they can remove their muted subscription or change
123+ # their BugNotificationLevel.
124+ with person_logged_in(self.person):
125+ self.bug.mute(self.person, self.person)
126+ mute_view = create_initialized_view(
127+ self.bug.default_bugtask, name="+mute")
128+ response = mute_view.request.response
129+ self.assertEqual(302, response.getStatus())
130+ self.assertEqual(
131+ canonical_url(self.bug.default_bugtask,
132+ view_name="+subscribe"),
133+ response.getHeader('Location'))
134
135=== added file 'lib/lp/bugs/templates/bug-mute.pt'
136--- lib/lp/bugs/templates/bug-mute.pt 1970-01-01 00:00:00 +0000
137+++ lib/lp/bugs/templates/bug-mute.pt 2011-03-18 13:42:19 +0000
138@@ -0,0 +1,32 @@
139+<html
140+ xmlns="http://www.w3.org/1999/xhtml"
141+ xmlns:tal="http://xml.zope.org/namespaces/tal"
142+ xmlns:metal="http://xml.zope.org/namespaces/metal"
143+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
144+ xml:lang="en"
145+ lang="en"
146+ dir="ltr"
147+ metal:use-macro="view/macro:page/main_only"
148+ i18n:domain="malone"
149+>
150+
151+<body>
152+ <div metal:fill-slot="main">
153+
154+ <div id="maincontent">
155+ <div id="nonportlets" class="readable">
156+ <p>
157+ If you mute a bug you will receive no mail about the the bug
158+ at all until you unmute it again.
159+ </p>
160+
161+ <div metal:use-macro="context/@@launchpad_form/form">
162+ </div>
163+
164+ </div>
165+ </div>
166+
167+ </div>
168+
169+</body>
170+</html>