← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~gmb/launchpad/launchpadformify-subscribe-view-bug-651240 into lp:launchpad/devel

 

Graham Binns has proposed merging lp:~gmb/launchpad/launchpadformify-subscribe-view-bug-651240 into lp:launchpad/devel with lp:~gmb/launchpad/extract-subscription-view-bug-651240 as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers): code
Related bugs:
  #653122 Make the new Bug +subscribe view into a LaunchpadFormView
  https://bugs.launchpad.net/bugs/653122


This branch fixes bug 651240 by turning BugSubscriptionSubscribeSelfView from a LaunchpadView into a LaunchpadFormView. The work here is pretty straightforward - converting everything to use FormFields instead of custom widget attributes on the view - and will be used in subsequent branches to add new features to BugSubscriptions.
-- 
https://code.launchpad.net/~gmb/launchpad/launchpadformify-subscribe-view-bug-651240/+merge/37850
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~gmb/launchpad/launchpadformify-subscribe-view-bug-651240 into lp:launchpad/devel.
=== modified file 'lib/lp/bugs/browser/bugsubscription.py'
--- lib/lp/bugs/browser/bugsubscription.py	2010-10-07 13:43:57 +0000
+++ lib/lp/bugs/browser/bugsubscription.py	2010-10-07 13:43:58 +0000
@@ -15,6 +15,7 @@
 from lazr.delegates import delegates
 from simplejson import dumps
 
+from zope import formlib
 from zope.app.form import CustomWidgetFactory
 from zope.app.form.browser.itemswidgets import RadioWidget
 from zope.app.form.interfaces import IInputWidget
@@ -25,9 +26,11 @@
     SimpleVocabulary,
     )
 
+from canonical.launchpad import _
 from canonical.launchpad.webapp import (
     action,
     canonical_url,
+    custom_widget,
     LaunchpadFormView,
     LaunchpadView,
     )
@@ -36,6 +39,9 @@
 from canonical.launchpad.webapp.menu import structured
 from lp.bugs.browser.bug import BugViewMixin
 from lp.bugs.interfaces.bugsubscription import IBugSubscription
+from lp.registry.enum import BugNotificationLevel
+from lp.services import features
+from lp.services.propertycache import cachedproperty
 
 
 class BugSubscriptionAddView(LaunchpadFormView):
@@ -74,10 +80,11 @@
     page_title = label
 
 
-class BugSubscriptionSubscribeSelfView(LaunchpadView,
-                                       ReturnToReferrerMixin):
+class BugSubscriptionSubscribeSelfView(LaunchpadFormView):
     """A view to handle the +subscribe page for a bug."""
 
+    schema = IBugSubscription
+
     @property
     def next_url(self):
         """Provided so returning to the page they came from works."""
@@ -85,7 +92,7 @@
 
         # XXX bdmurray 2010-09-30 bug=98437: work around zope's test
         # browser setting referer to localhost.
-        if referer and referer != 'localhost':
+        if referer and referer not in ('localhost', self.request.getURL()):
             next_url = referer
         else:
             next_url = canonical_url(self.context)
@@ -93,20 +100,30 @@
 
     cancel_url = next_url
 
-    def initialize(self):
-        """Set up the needed widgets."""
-        bug = self.context.bug
-
-        # See render() for how this flag is used.
-        self._redirecting_to_bug_list = False
-
+    @cachedproperty
+    def _subscribers_for_current_user(self):
+        """Return a dict of the subscribers for the current user."""
+        persons_for_user = {}
+        person_count = 0
+        bug = self.context.bug
+        for person in bug.getSubscribersForPerson(self.user):
+            if person.id not in persons_for_user:
+                persons_for_user[person.id] = person
+                person_count += 1
+
+        self._subscriber_count_for_current_user = person_count
+        return persons_for_user.values()
+
+    def setUpFields(self):
+        """See `LaunchpadFormView`."""
+        super(BugSubscriptionSubscribeSelfView, self).setUpFields()
+        bug = self.context.bug
         if self.user is None:
             return
 
-        # Set up widgets in order to handle subscription requests.
         subscription_terms = []
         self_subscribed = False
-        for person in bug.getSubscribersForPerson(self.user):
+        for person in self._subscribers_for_current_user:
             if person.id == self.user.id:
                 subscription_terms.append(
                     SimpleTerm(
@@ -125,16 +142,18 @@
                 SimpleTerm(
                     self.user, self.user.name, 'Subscribe me to this bug'))
         subscription_vocabulary = SimpleVocabulary(subscription_terms)
-        person_field = Choice(
-            __name__='subscription',
-            vocabulary=subscription_vocabulary, required=True)
-        self.subscription_widget = CustomWidgetFactory(RadioWidget)
-        setUpWidget(
-            self, 'subscription', person_field, IInputWidget, value=self.user)
-
-        self.handleSubscriptionRequest()
-
-    def userIsSubscribed(self):
+        default_subscription_value = subscription_vocabulary.getTermByToken(
+            self.user.name).value
+        subscription_field = Choice(
+            __name__='subscription', title=_("Subscription options"),
+            vocabulary=subscription_vocabulary, required=True,
+            default=default_subscription_value)
+        self.form_fields += formlib.form.Fields(subscription_field)
+        self.form_fields['subscription'].custom_widget = CustomWidgetFactory(
+            RadioWidget)
+
+    @cachedproperty
+    def user_is_subscribed(self):
         """Is the user subscribed to this bug?"""
         return (
             self.context.bug.isSubscribed(self.user) or
@@ -146,7 +165,7 @@
         The warning should tell the user that, when unsubscribing, they
         will also be unsubscribed from dupes of this bug.
         """
-        if self.userIsSubscribed():
+        if self.user_is_subscribed:
             return True
 
         bug = self.context.bug
@@ -156,37 +175,16 @@
 
         return False
 
-    def render(self):
-        """Render the bug list if the user has permission to see the bug."""
-        # Prevent normal rendering when redirecting to the bug list
-        # after unsubscribing from a private bug, because rendering the
-        # bug page would raise Unauthorized errors!
-        if self._redirecting_to_bug_list:
-            return u''
-        elif self._isSubscriptionRequest() and self.request.get('next_url'):
-            self.request.response.redirect(self.request.get('next_url'))
-            return u''
-        else:
-            return LaunchpadView.render(self)
-
-    def handleSubscriptionRequest(self):
-        """Subscribe or unsubscribe the user from the bug, if requested."""
-        if not self._isSubscriptionRequest():
-            return
-
-        subscription_person = self.subscription_widget.getInputValue()
-
-        # 'subscribe' appears in the request whether the request is to
-        # subscribe or unsubscribe. Since "subscribe someone else" is
-        # handled by a different view we can assume that 'subscribe' +
-        # current user as a parameter means "subscribe the current
-        # user", and any other kind of 'subscribe' request actually
-        # means "unsubscribe". (Yes, this *is* very confusing!)
-        if ('subscribe' in self.request.form and
+    @action('Continue', name='continue')
+    def subscribe_action(self, action, data):
+        """Handle subscription requests."""
+        subscription_person = self.widgets['subscription'].getInputValue()
+        if (not self.user_is_subscribed and
             (subscription_person == self.user)):
             self._handleSubscribe()
         else:
             self._handleUnsubscribe(subscription_person)
+        self.request.response.redirect(self.next_url)
 
     def _isSubscriptionRequest(self):
         """Return True if the form contains subscribe/unsubscribe input."""
@@ -194,7 +192,7 @@
             self.user and
             self.request.method == 'POST' and
             'cancel' not in self.request.form and
-            self.subscription_widget.hasValidInput())
+            self.widgets['subscription'].hasValidInput())
 
     def _handleSubscribe(self):
         """Handle a subscribe request."""

=== modified file 'lib/lp/bugs/stories/bugs/xx-bug-personal-subscriptions.txt'
--- lib/lp/bugs/stories/bugs/xx-bug-personal-subscriptions.txt	2010-10-07 13:43:57 +0000
+++ lib/lp/bugs/stories/bugs/xx-bug-personal-subscriptions.txt	2010-10-07 13:43:58 +0000
@@ -68,7 +68,7 @@
   >>> submit.click()
 
   >>> browser.url
-  'http://bugs.launchpad.dev/firefox/+bug/1/'
+  'http://bugs.launchpad.dev/firefox/+bug/1'
 
   >>> for tag in find_tags_by_class(browser.contents, 'informational message'):
   ...   print tag.renderContents()

=== modified file 'lib/lp/bugs/templates/bug-subscription.pt'
--- lib/lp/bugs/templates/bug-subscription.pt	2010-10-07 13:43:57 +0000
+++ lib/lp/bugs/templates/bug-subscription.pt	2010-10-07 13:43:58 +0000
@@ -15,13 +15,13 @@
 
     <div id="maincontent">
       <div id="nonportlets" class="readable">
-        <h1 tal:define="subscribed view/userIsSubscribed">
+        <h1 tal:define="subscribed view/user_is_subscribed">
           <tal:action condition="subscribed">Unsubscribe from</tal:action>
           <tal:action condition="not:subscribed">Subscribe to</tal:action>
           bug #<span tal:replace="context/bug/id" />
         </h1>
 
-        <p tal:condition="not: view/userIsSubscribed">
+        <p tal:condition="not: view/user_is_subscribed">
           If you subscribe to a bug it shows up on your
           personal pages, you receive copies of all comments by email,
           and notification of any changes to the status of the bug upstream
@@ -34,33 +34,8 @@
           duplicates.
         </p>
 
-        <form action="" method="POST">
-
-          <div class="field">
-            <div>
-              <div tal:content="structure view/subscription_widget">
-                <input type="radio" />
-              </div>
-            </div>
-
-          </div>
-
-          <div class="actions">
-            <input type="hidden" name="next_url"
-                   tal:condition="view/next_url | nothing"
-                   tal:attributes="value view/next_url" />
-            <input tal:condition="not: view/userIsSubscribed"
-                   type="submit"
-                   name="subscribe"
-                   value="Continue" />
-            <input tal:condition="view/userIsSubscribed"
-                   type="submit"
-                   name="unsubscribe"
-                   value="Continue" />
-                   or <a tal:condition="view/cancel_url | nothing"
-                         tal:attributes="href view/cancel_url">Cancel</a>
-          </div>
-        </form>
+        <div metal:use-macro="context/@@launchpad_form/form">
+        </div>
 
       </div>
     </div>