Merge lp:~gmb/launchpad/rollback-13050 into lp:launchpad

Proposed by Graham Binns
Status: Merged
Merged at revision: 13065
Proposed branch: lp:~gmb/launchpad/rollback-13050
Merge into: lp:launchpad
Diff against target: 257 lines (+9/-149)
5 files modified
lib/lp/bugs/browser/bug.py (+3/-2)
lib/lp/bugs/browser/tests/test_bug_views.py (+0/-61)
lib/lp/bugs/doc/bugsubscription.txt (+1/-1)
lib/lp/bugs/model/bug.py (+5/-62)
lib/lp/bugs/tests/test_bugsubscription.py (+0/-23)
To merge this branch: bzr merge lp:~gmb/launchpad/rollback-13050
Reviewer Review Type Date Requested Status
Graham Binns (community) Approve
Review via email: mp+61265@code.launchpad.net

Commit message

[r=gmb][ui=none][bug=783948] [rollback=13050] Revert bad revision r13050, which may have caused bug 783948.

Description of the change

This branch reverts devel r13050, which may have resulted in bug 783948 manifesting.

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) wrote :

Self-approving after checking that rolling back fixed the problem.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/browser/bug.py'
--- lib/lp/bugs/browser/bug.py 2011-05-16 17:43:29 +0000
+++ lib/lp/bugs/browser/bug.py 2011-05-17 15:03:32 +0000
@@ -536,7 +536,6 @@
536 @cachedproperty536 @cachedproperty
537 def user_should_see_mute_link(self):537 def user_should_see_mute_link(self):
538 """Return True if the user should see the Mute link."""538 """Return True if the user should see the Mute link."""
539 user_is_subscribed = False
540 if features.getFeatureFlag('malone.advanced-subscriptions.enabled'):539 if features.getFeatureFlag('malone.advanced-subscriptions.enabled'):
541 user_is_subscribed = (540 user_is_subscribed = (
542 # Note that we don't have to check for isMuted(), since541 # Note that we don't have to check for isMuted(), since
@@ -545,7 +544,9 @@
545 self.context.isSubscribed(self.user) or544 self.context.isSubscribed(self.user) or
546 self.context.isSubscribedToDupes(self.user) or545 self.context.isSubscribedToDupes(self.user) or
547 self.context.personIsAlsoNotifiedSubscriber(self.user))546 self.context.personIsAlsoNotifiedSubscriber(self.user))
548 return user_is_subscribed547 return user_is_subscribed
548 else:
549 return False
549550
550 @cachedproperty551 @cachedproperty
551 def _bug_attachments(self):552 def _bug_attachments(self):
552553
=== modified file 'lib/lp/bugs/browser/tests/test_bug_views.py'
--- lib/lp/bugs/browser/tests/test_bug_views.py 2011-05-12 10:36:43 +0000
+++ lib/lp/bugs/browser/tests/test_bug_views.py 2011-05-17 15:03:32 +0000
@@ -177,64 +177,3 @@
177 self.assertTrue(177 self.assertTrue(
178 self._hasCSSClass(html, 'mute-link-container', 'hidden'),178 self._hasCSSClass(html, 'mute-link-container', 'hidden'),
179 'No "hidden" CSS class in mute-link-container.')179 'No "hidden" CSS class in mute-link-container.')
180
181 def test_mute_link_shown_for_team_subscription_to_duplicate(self):
182 # If the person belongs to a team with a structural subscription to a
183 # duplicate of this bug, then the mute link will be displayed to them.
184 person = self.factory.makePerson(name="a-person")
185 team_owner = self.factory.makePerson(name="team-owner")
186 team = self.factory.makeTeam(owner=team_owner, name="subscribed-team")
187 dupe = self.factory.makeBug()
188 with person_logged_in(self.bug.owner):
189 dupe.markAsDuplicate(self.bug)
190 with FeatureFixture({self.feature_flag_1: 'on'}):
191 with person_logged_in(team_owner):
192 team.addMember(person, team_owner)
193 dupe_target = dupe.default_bugtask.target
194 dupe_target.addBugSubscription(team, team_owner)
195 with person_logged_in(person):
196 self.assertFalse(self.bug.isMuted(person))
197 # This is a sanity check for the test.
198 self.assertFalse(self.bug.duplicates.is_empty())
199 self.assertEqual(self.bug, dupe.duplicateof)
200 self.assertTrue(
201 self.bug.personIsAlsoNotifiedSubscriber(
202 person), "Person should be a notified subscriber")
203 view = create_initialized_view(
204 self.bug, name="+portlet-subscribers")
205 self.assertTrue(view.user_should_see_mute_link,
206 "User should see mute link.")
207 contents = view.render()
208 self.assertTrue('mute_subscription' in contents,
209 "'mute_subscription' not in contents.")
210 create_initialized_view(
211 self.bug.default_bugtask, name="+mute",
212 form={'field.actions.mute': 'Mute bug mail'})
213 self.assertTrue(self.bug.isMuted(person))
214
215 def test_mute_subscription_link_shown_for_team_direct_subscription(self):
216 # If the person belongs to a team with a direct subscription,
217 # then the mute link will be displayed to them.
218 person = self.factory.makePerson(name="a-person")
219 team_owner = self.factory.makePerson(name="team-owner")
220 team = self.factory.makeTeam(owner=team_owner, name="subscribed-team")
221 with FeatureFixture({self.feature_flag_1: 'on'}):
222 with person_logged_in(team_owner):
223 team.addMember(person, team_owner)
224 self.bug.subscribe(team, team_owner)
225 with person_logged_in(person):
226 self.assertFalse(self.bug.isMuted(person))
227 self.assertTrue(
228 self.bug.personIsAlsoNotifiedSubscriber(person),
229 "Person should be a notified subscriber")
230 view = create_initialized_view(
231 self.bug, name="+portlet-subscribers")
232 self.assertTrue(view.user_should_see_mute_link,
233 "User should see mute link.")
234 contents = view.render()
235 self.assertTrue('mute_subscription' in contents,
236 "'mute_subscription' not in contents.")
237 create_initialized_view(
238 self.bug.default_bugtask, name="+mute",
239 form={'field.actions.mute': 'Mute bug mail'})
240 self.assertTrue(self.bug.isMuted(person))
241180
=== modified file 'lib/lp/bugs/doc/bugsubscription.txt'
--- lib/lp/bugs/doc/bugsubscription.txt 2011-05-16 17:40:00 +0000
+++ lib/lp/bugs/doc/bugsubscription.txt 2011-05-17 15:03:32 +0000
@@ -423,7 +423,7 @@
423 []423 []
424424
425 >>> linux_source_bug.getSubscribersFromDuplicates()425 >>> linux_source_bug.getSubscribersFromDuplicates()
426 []426 ()
427427
428Direct subscriptions always take precedence over indirect428Direct subscriptions always take precedence over indirect
429subscriptions. So, if we unmark the above bug as private,429subscriptions. So, if we unmark the above bug as private,
430430
=== modified file 'lib/lp/bugs/model/bug.py'
--- lib/lp/bugs/model/bug.py 2011-05-17 05:43:19 +0000
+++ lib/lp/bugs/model/bug.py 2011-05-17 15:03:32 +0000
@@ -953,30 +953,18 @@
953 See the comment in getDirectSubscribers for a description of the953 See the comment in getDirectSubscribers for a description of the
954 recipients argument.954 recipients argument.
955 """955 """
956 if self.private:
957 # We short-circuit for private bugs, since actually
958 # returning something non-empty here causes things to break
959 # in fun and interesting ways (see bug 780248).
960 return []
961
962 if level is None:956 if level is None:
963 level = BugNotificationLevel.NOTHING957 level = BugNotificationLevel.NOTHING
964 info = self.getSubscriptionInfo(level)958 info = self.getSubscriptionInfo(level)
965959
966 if recipients is not None:960 if recipients is not None:
967 # Pre-load duplicates961 # Pre-load duplicate bugs.
968 list(self.duplicates)962 list(self.duplicates)
969 for subscription in info.duplicate_only_subscriptions:963 for subscription in info.duplicate_only_subscriptions:
970 recipients.addDupeSubscriber(964 recipients.addDupeSubscriber(
971 subscription.person, subscription.bug)965 subscription.person, subscription.bug)
972 for subscription in info.structural_subscriptions_from_duplicates:
973 recipients.addDupeSubscriber(
974 subscription.subscriber)
975966
976 unified_subscribers = (967 return info.duplicate_only_subscriptions.subscribers.sorted
977 info.duplicate_only_subscriptions.subscribers.union(
978 info.structural_subscriptions_from_duplicates.subscribers))
979 return unified_subscribers.sorted
980968
981 def getSubscribersForPerson(self, person):969 def getSubscribersForPerson(self, person):
982 """See `IBug."""970 """See `IBug."""
@@ -1041,16 +1029,12 @@
1041 include_master_dupe_subscribers=False):1029 include_master_dupe_subscribers=False):
1042 """See `IBug`."""1030 """See `IBug`."""
1043 recipients = BugNotificationRecipients(duplicateof=duplicateof)1031 recipients = BugNotificationRecipients(duplicateof=duplicateof)
1044 # Call getDirectSubscribers to update the recipients list with direct
1045 # subscribers. The results of the method call are not used.
1046 self.getDirectSubscribers(recipients, level=level)1032 self.getDirectSubscribers(recipients, level=level)
1047 if self.private:1033 if self.private:
1048 assert self.getIndirectSubscribers() == [], (1034 assert self.getIndirectSubscribers() == [], (
1049 "Indirect subscribers found on private bug. "1035 "Indirect subscribers found on private bug. "
1050 "A private bug should never have implicit subscribers!")1036 "A private bug should never have implicit subscribers!")
1051 else:1037 else:
1052 # Call getIndirectSubscribers to update the recipients list with direct
1053 # subscribers. The results of the method call are not used.
1054 self.getIndirectSubscribers(recipients, level=level)1038 self.getIndirectSubscribers(recipients, level=level)
1055 if include_master_dupe_subscribers and self.duplicateof:1039 if include_master_dupe_subscribers and self.duplicateof:
1056 # This bug is a public duplicate of another bug, so include1040 # This bug is a public duplicate of another bug, so include
@@ -1917,22 +1901,6 @@
19171901
1918 def personIsAlsoNotifiedSubscriber(self, person):1902 def personIsAlsoNotifiedSubscriber(self, person):
1919 """See `IBug`."""1903 """See `IBug`."""
1920 # This is here to avoid circular imports.
1921 from lp.bugs.mail.bugnotificationrecipients import (
1922 BugNotificationRecipients,
1923 )
1924
1925 def check_person_in_team(person, list_of_people):
1926 """Is the person in one of the teams?
1927
1928 Given a person and a list of people/teams, see if the person
1929 belongs to one of the teams.
1930 """
1931 for subscriber in list_of_people:
1932 if subscriber.is_team and person.inTeam(subscriber):
1933 return True
1934 return False
1935
1936 # We have to use getAlsoNotifiedSubscribers() here and iterate1904 # We have to use getAlsoNotifiedSubscribers() here and iterate
1937 # over what it returns because "also notified subscribers" is1905 # over what it returns because "also notified subscribers" is
1938 # actually a composite of bug contacts, structural subscribers1906 # actually a composite of bug contacts, structural subscribers
@@ -1943,16 +1911,9 @@
1943 return True1911 return True
1944 # Otherwise check to see if the person is a member of any of the1912 # Otherwise check to see if the person is a member of any of the
1945 # subscribed teams.1913 # subscribed teams.
1946 if check_person_in_team(person, also_notified_subscribers):1914 for subscriber in also_notified_subscribers:
1947 return True1915 if subscriber.is_team and person.inTeam(subscriber):
19481916 return True
1949 direct_subscribers = self.getDirectSubscribers()
1950 if check_person_in_team(person, direct_subscribers):
1951 return True
1952 duplicate_subscribers = self.getSubscribersFromDuplicates(
1953 recipients=BugNotificationRecipients())
1954 if check_person_in_team(person, duplicate_subscribers):
1955 return True
1956 return False1917 return False
19571918
1958 def personIsSubscribedToDuplicate(self, person):1919 def personIsSubscribedToDuplicate(self, person):
@@ -2312,24 +2273,6 @@
2312 return get_structural_subscriptions_for_bug(self.bug)2273 return get_structural_subscriptions_for_bug(self.bug)
23132274
2314 @cachedproperty2275 @cachedproperty
2315 @freeze(StructuralSubscriptionSet)
2316 def structural_subscriptions_from_duplicates(self):
2317 """Structural subscriptions from the bug's duplicates."""
2318 self.duplicate_subscriptions.subscribers # Pre-load subscribers.
2319 higher_precedence = (
2320 self.direct_subscriptions.subscribers.union(
2321 self.also_notified_subscribers))
2322 all_duplicate_structural_subscriptions = list()
2323 for duplicate in self.bug.duplicates:
2324 duplicate_struct_subs = get_structural_subscriptions_for_bug(
2325 duplicate)
2326 all_duplicate_structural_subscriptions += duplicate_struct_subs
2327 return (
2328 subscription for subscription in
2329 all_duplicate_structural_subscriptions
2330 if subscription.subscriber not in higher_precedence)
2331
2332 @cachedproperty
2333 @freeze(BugSubscriberSet)2276 @freeze(BugSubscriberSet)
2334 def all_assignees(self):2277 def all_assignees(self):
2335 """Assignees of the bug's tasks."""2278 """Assignees of the bug's tasks."""
23362279
=== modified file 'lib/lp/bugs/tests/test_bugsubscription.py'
--- lib/lp/bugs/tests/test_bugsubscription.py 2011-05-10 14:13:24 +0000
+++ lib/lp/bugs/tests/test_bugsubscription.py 2011-05-17 15:03:32 +0000
@@ -146,26 +146,3 @@
146 self.bug.id, team_2.name, self.subscriber)146 self.bug.id, team_2.name, self.subscriber)
147 self.assertThat(147 self.assertThat(
148 collector, HasQueryCount(LessThan(25)))148 collector, HasQueryCount(LessThan(25)))
149
150
151class TestBugSubscriptionMethods(TestCaseWithFactory):
152 """A TestCase for the subscription-related methods of `Bug`."""
153
154 layer = DatabaseFunctionalLayer
155
156 def test_getSubscribersFromDuplicates_returns_empty_when_private(self):
157 # If a private bug has duplicates its
158 # getSubscribersFromDuplicates() method should return an empty
159 # set.
160 # This is a regression test for bug 780248.
161 bug = self.factory.makeBug()
162 duplicate = self.factory.makeBug()
163 team = self.factory.makeTeam()
164 with person_logged_in(team.teamowner):
165 duplicate.default_bugtask.product.addSubscription(
166 team, team.teamowner)
167 with person_logged_in(bug.owner):
168 bug.setPrivate(True, bug.owner)
169 duplicate.markAsDuplicate(bug)
170 duplicate_subscribers = bug.getSubscribersFromDuplicates()
171 self.assertEqual(0, len(duplicate_subscribers))