Merge lp:~intellectronica/launchpad/bug-544794 into lp:launchpad

Proposed by Eleanor Berger
Status: Merged
Approved by: Deryck Hodge
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~intellectronica/launchpad/bug-544794
Merge into: lp:launchpad
Diff against target: 391 lines (+106/-23)
16 files modified
database/schema/security.cfg (+1/-0)
lib/canonical/launchpad/doc/security-teams.txt (+2/-1)
lib/canonical/launchpad/mail/commands.py (+1/-1)
lib/lp/bugs/browser/bug.py (+18/-9)
lib/lp/bugs/browser/bugtarget.py (+10/-1)
lib/lp/bugs/configure.zcml (+1/-0)
lib/lp/bugs/doc/bug-heat.txt (+22/-0)
lib/lp/bugs/doc/bug.txt (+1/-1)
lib/lp/bugs/doc/bugnotification-email.txt (+3/-3)
lib/lp/bugs/doc/bugnotification-sending.txt (+2/-1)
lib/lp/bugs/interfaces/bug.py (+12/-1)
lib/lp/bugs/model/bug.py (+27/-0)
lib/lp/bugs/scripts/bugheat.py (+1/-0)
lib/lp/bugs/scripts/bugimport.py (+1/-1)
lib/lp/bugs/scripts/tests/test_bugheat.py (+2/-2)
lib/lp/bugs/tests/test_bugchanges.py (+2/-2)
To merge this branch: bzr merge lp:~intellectronica/launchpad/bug-544794
Reviewer Review Type Date Requested Status
Deryck Hodge (community) code Approve
Review via email: mp+23389@code.launchpad.net

Commit message

Adjust bug heat immediately when bug privacy and security are changed.

Description of the change

This branch makes changes to bug privacy and security reflect in the bug's heat immediately. The only complication is the addition of IBug.setSecurityRelated() as a mutator for IBug.security_related and changes to use the new setter method instead of setting the attribute directly. I've also added a test demonstrating the immediate effect of these changes.

To post a comment you must log in.
Revision history for this message
Deryck Hodge (deryck) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'database/schema/security.cfg'
2--- database/schema/security.cfg 2010-04-12 09:41:01 +0000
3+++ database/schema/security.cfg 2010-04-15 11:01:09 +0000
4@@ -1337,6 +1337,7 @@
5 public.question = SELECT
6 public.questionbug = SELECT
7 public.distribution = SELECT
8+public.distributionsourcepackage = SELECT, INSERT, UPDATE
9 public.distroseries = SELECT
10 public.sourcepackagename = SELECT
11 public.sourcepackagerelease = SELECT
12
13=== modified file 'lib/canonical/launchpad/doc/security-teams.txt'
14--- lib/canonical/launchpad/doc/security-teams.txt 2009-08-14 12:59:56 +0000
15+++ lib/canonical/launchpad/doc/security-teams.txt 2010-04-15 11:01:09 +0000
16@@ -268,7 +268,8 @@
17 >>> bug.addTask(owner=reporter, target=distribution)
18 <BugTask at ...>
19 >>> old_state = Snapshot(bug, providing=IBug)
20- >>> bug.security_related = True
21+ >>> bug.setSecurityRelated(True)
22+ True
23 >>> notify(ObjectModifiedEvent(bug, old_state, ['security_related']))
24 >>> for subscriber_name in sorted(
25 ... s.displayname for s in bug.getDirectSubscribers()):
26
27=== modified file 'lib/canonical/launchpad/mail/commands.py'
28--- lib/canonical/launchpad/mail/commands.py 2010-02-17 11:13:06 +0000
29+++ lib/canonical/launchpad/mail/commands.py 2010-04-15 11:01:09 +0000
30@@ -279,7 +279,7 @@
31 edited = True
32 edited_fields.add('private')
33 if context.security_related != security_related:
34- context.security_related = security_related
35+ context.setSecurityRelated(security_related)
36 edited = True
37 edited_fields.add('security_related')
38
39
40=== modified file 'lib/lp/bugs/browser/bug.py'
41--- lib/lp/bugs/browser/bug.py 2010-04-07 11:28:32 +0000
42+++ lib/lp/bugs/browser/bug.py 2010-04-15 11:01:09 +0000
43@@ -673,7 +673,7 @@
44 page_title = label
45
46 def setUpFields(self):
47- """Make the read-only version of `private` writable."""
48+ """Make the read-only version of the form fields writable."""
49 private_field = Bool(
50 __name__='private',
51 title=_("This bug report should be private"),
52@@ -681,10 +681,17 @@
53 description=_("Private bug reports are visible only to "
54 "their subscribers."),
55 default=False)
56+ security_related_field = Bool(
57+ __name__='security_related',
58+ title=_("This bug is a security vulnerability"),
59+ required=False, default=False)
60+
61 super(BugSecrecyEditView, self).setUpFields()
62 self.form_fields = self.form_fields.omit('private')
63+ self.form_fields = self.form_fields.omit('security_related')
64 self.form_fields = (
65- formlib.form.Fields(private_field) + self.form_fields)
66+ formlib.form.Fields(private_field) +
67+ formlib.form.Fields(security_related_field))
68
69 @property
70 def initial_values(self):
71@@ -705,16 +712,18 @@
72 bug_before_modification = Snapshot(
73 bug, providing=providedBy(bug))
74 private = data.pop('private')
75+ security_related = data.pop('security_related')
76 private_changed = bug.setPrivate(
77 private, getUtility(ILaunchBag).user)
78- if private_changed:
79- # Although the call to updateBugFromData later on will
80- # send notification of changes, it will only do so if it
81- # makes the change. We have applied the 'private' change
82- # already, so updateBugFromData will only send an event if
83- # 'security_related' is changed, and we can't have that.
84+ security_related_changed = bug.setSecurityRelated(security_related)
85+ if private_changed or security_related_changed:
86+ changed_fields = []
87+ if private_changed:
88+ changed_fields.append('private')
89+ if security_related_changed:
90+ changed_fields.append('security_related')
91 notify(ObjectModifiedEvent(
92- bug, bug_before_modification, ['private']))
93+ bug, bug_before_modification, changed_fields))
94
95 # Apply other changes.
96 self.updateBugFromData(data)
97
98=== modified file 'lib/lp/bugs/browser/bugtarget.py'
99--- lib/lp/bugs/browser/bugtarget.py 2010-03-16 16:23:50 +0000
100+++ lib/lp/bugs/browser/bugtarget.py 2010-04-15 11:01:09 +0000
101@@ -36,7 +36,7 @@
102 from zope.interface import implements
103 from zope.publisher.interfaces import NotFound
104 from zope.publisher.interfaces.browser import IBrowserPublisher
105-from zope.schema import Choice
106+from zope.schema import Bool, Choice
107 from zope.schema.vocabulary import SimpleVocabulary
108
109 from canonical.cachedproperty import cachedproperty
110@@ -45,6 +45,7 @@
111 from lp.bugs.interfaces.apportjob import IProcessApportBlobJobSource
112 from lp.bugs.interfaces.bug import IBug
113 from lp.bugs.interfaces.bugtask import BugTaskSearchParams
114+from canonical.launchpad import _
115 from canonical.launchpad.browser.feeds import (
116 BugFeedLink, BugTargetLatestBugsFeedLink, FeedsMixin)
117 from lp.bugs.interfaces.bugsupervisor import IHasBugSupervisor
118@@ -297,6 +298,14 @@
119 self.form_fields = self.form_fields.omit('subscribe_to_existing_bug')
120 self.form_fields += formlib.form.Fields(subscribe_field)
121
122+ security_related_field = Bool(
123+ __name__='security_related',
124+ title=_("This bug is a security vulnerability"),
125+ required=False, default=False)
126+
127+ self.form_fields = self.form_fields.omit('security_related')
128+ self.form_fields += formlib.form.Fields(security_related_field)
129+
130 def contextUsesMalone(self):
131 """Does the context use Malone as its official bugtracker?"""
132 if IProjectGroup.providedBy(self.context):
133
134=== modified file 'lib/lp/bugs/configure.zcml'
135--- lib/lp/bugs/configure.zcml 2010-04-08 08:55:10 +0000
136+++ lib/lp/bugs/configure.zcml 2010-04-15 11:01:09 +0000
137@@ -681,6 +681,7 @@
138 expireNotifications
139 setStatus
140 setPrivate
141+ setSecurityRelated
142 convertToQuestion
143 markUserAffected
144 addTask
145
146=== modified file 'lib/lp/bugs/doc/bug-heat.txt'
147--- lib/lp/bugs/doc/bug-heat.txt 2010-04-12 07:11:47 +0000
148+++ lib/lp/bugs/doc/bug-heat.txt 2010-04-15 11:01:09 +0000
149@@ -29,6 +29,28 @@
150 datetime.datetime(..., tzinfo=<UTC>)
151
152
153+Adjusting bug heat in transaction
154+---------------------------------
155+
156+Sometimes, when a bug changes, we want to see the changes reflected in the bug's
157+heat value immidiately, without waiting for heat to be recalculated. Currently
158+we adjust heat immidiately for bug privacy and security.
159+
160+ >>> bug_owner = factory.makePerson()
161+ >>> bug = factory.makeBug(owner=bug_owner)
162+ >>> bug.heat
163+ 0
164+ >>> changed = bug.setPrivate(True, bug_owner)
165+ >>> bug.heat
166+ 150
167+ >>> changed = bug.setSecurityRelated(True)
168+ >>> bug.heat
169+ 400
170+ >>> changed = bug.setPrivate(False, bug_owner)
171+ >>> bug.heat
172+ 250
173+
174+
175 Getting bugs whose heat is outdated
176 -----------------------------------
177
178
179=== modified file 'lib/lp/bugs/doc/bug.txt'
180--- lib/lp/bugs/doc/bug.txt 2010-02-11 05:08:47 +0000
181+++ lib/lp/bugs/doc/bug.txt 2010-04-15 11:01:09 +0000
182@@ -747,7 +747,7 @@
183
184 >>> firefox_bug.security_related
185 False
186- >>> firefox_bug.security_related = True
187+ >>> changed = firefox_bug.setSecurityRelated(True)
188
189 >>> bug_security_changed = ObjectModifiedEvent(
190 ... firefox_bug, bug_before_modification, ["security_related"])
191
192=== modified file 'lib/lp/bugs/doc/bugnotification-email.txt'
193--- lib/lp/bugs/doc/bugnotification-email.txt 2010-01-20 17:09:40 +0000
194+++ lib/lp/bugs/doc/bugnotification-email.txt 2010-04-15 11:01:09 +0000
195@@ -85,7 +85,7 @@
196
197 New security related bugs are sent with a prominent warning:
198
199- >>> bug_four.security_related = True
200+ >>> changed = bug_four.setSecurityRelated(True)
201
202 >>> subject, body = generate_bug_add_email(bug_four)
203 >>> subject
204@@ -202,7 +202,7 @@
205
206 >>> edited_bug.setPrivate(True, getUtility(ILaunchBag).user)
207 True
208- >>> edited_bug.security_related = True
209+ >>> changed = edited_bug.setSecurityRelated(True)
210 >>> bug_delta = BugDelta(
211 ... bug=edited_bug,
212 ... bugurl="http://www.example.com/bugs/2",
213@@ -225,7 +225,7 @@
214
215 >>> edited_bug.setPrivate(False, getUtility(ILaunchBag).user)
216 True
217- >>> edited_bug.security_related = False
218+ >>> changed = edited_bug.setSecurityRelated(False)
219 >>> bug_delta = BugDelta(
220 ... bug=edited_bug,
221 ... bugurl="http://www.example.com/bugs/2",
222
223=== modified file 'lib/lp/bugs/doc/bugnotification-sending.txt'
224--- lib/lp/bugs/doc/bugnotification-sending.txt 2009-12-24 01:41:54 +0000
225+++ lib/lp/bugs/doc/bugnotification-sending.txt 2010-04-15 11:01:09 +0000
226@@ -1199,7 +1199,8 @@
227 The presence of the security flag on a bug is, surprise, denoted by a
228 simple "yes":
229
230- >>> bug_three.security_related = True
231+ >>> bug_three.setSecurityRelated(True)
232+ True
233 >>> bug_three.security_related
234 True
235
236
237=== modified file 'lib/lp/bugs/interfaces/bug.py'
238--- lib/lp/bugs/interfaces/bug.py 2010-04-12 14:48:34 +0000
239+++ lib/lp/bugs/interfaces/bug.py 2010-04-15 11:01:09 +0000
240@@ -207,7 +207,7 @@
241 readonly=True))
242 security_related = exported(
243 Bool(title=_("This bug is a security vulnerability"),
244- required=False, default=False))
245+ required=False, default=False, readonly=True))
246 displayname = TextLine(title=_("Text of the form 'Bug #X"),
247 readonly=True)
248 activity = Attribute('SQLObject.Multijoin of IBugActivity')
249@@ -705,6 +705,17 @@
250 Return True if a change is made, False otherwise.
251 """
252
253+ @mutator_for(security_related)
254+ @operation_parameters(security_related=copy_field(security_related))
255+ @export_write_operation()
256+ def setSecurityRelated(security_related):
257+ """Set bug security.
258+
259+ :security_related: True/False.
260+
261+ Return True if a change is made, False otherwise.
262+ """
263+
264 def getBugTask(target):
265 """Return the bugtask with the specified target.
266
267
268=== modified file 'lib/lp/bugs/model/bug.py'
269--- lib/lp/bugs/model/bug.py 2010-04-12 14:48:34 +0000
270+++ lib/lp/bugs/model/bug.py 2010-04-15 11:01:09 +0000
271@@ -83,6 +83,7 @@
272 from lp.bugs.interfaces.bugtracker import BugTrackerType
273 from lp.bugs.interfaces.bugwatch import IBugWatchSet
274 from lp.bugs.interfaces.cve import ICveSet
275+from lp.bugs.scripts.bugheat import BugHeatConstants
276 from lp.bugs.model.bugattachment import BugAttachment
277 from lp.bugs.model.bugbranch import BugBranch
278 from lp.bugs.model.bugcve import BugCve
279@@ -1351,10 +1352,33 @@
280 self.who_made_private = None
281 self.date_made_private = None
282
283+ # Correct the heat for the bug immediately, so that we don't have
284+ # to wait for the next calculation job for the adjusted heat.
285+ if private:
286+ self.setHeat(self.heat + BugHeatConstants.PRIVACY)
287+ else:
288+ self.setHeat(self.heat - BugHeatConstants.PRIVACY)
289+
290 return True # Changed.
291 else:
292 return False # Not changed.
293
294+ def setSecurityRelated(self, security_related):
295+ """Setter for the `security_related` property."""
296+ if self.security_related != security_related:
297+ self.security_related = security_related
298+
299+ # Correct the heat for the bug immediately, so that we don't have
300+ # to wait for the next calculation job for the adjusted heat.
301+ if security_related:
302+ self.setHeat(self.heat + BugHeatConstants.SECURITY)
303+ else:
304+ self.setHeat(self.heat - BugHeatConstants.SECURITY)
305+
306+ return True # Changed
307+ else:
308+ return False # Unchanged
309+
310 def getBugTask(self, target):
311 """See `IBug`."""
312 for bugtask in self.bugtasks:
313@@ -1540,6 +1564,9 @@
314 if timestamp is None:
315 timestamp = UTC_NOW
316
317+ if heat < 0:
318+ heat = 0
319+
320 self.heat = heat
321 self.heat_last_updated = timestamp
322 for task in self.bugtasks:
323
324=== modified file 'lib/lp/bugs/scripts/bugheat.py'
325--- lib/lp/bugs/scripts/bugheat.py 2010-03-04 19:49:08 +0000
326+++ lib/lp/bugs/scripts/bugheat.py 2010-04-15 11:01:09 +0000
327@@ -6,6 +6,7 @@
328 __metaclass__ = type
329 __all__ = [
330 'BugHeatCalculator',
331+ 'BugHeatConstants',
332 ]
333
334 from datetime import datetime
335
336=== modified file 'lib/lp/bugs/scripts/bugimport.py'
337--- lib/lp/bugs/scripts/bugimport.py 2009-09-11 14:59:08 +0000
338+++ lib/lp/bugs/scripts/bugimport.py 2010-04-15 11:01:09 +0000
339@@ -328,7 +328,7 @@
340
341 # set up bug
342 bug.setPrivate(get_value(bugnode, 'private') == 'True', owner)
343- bug.security_related = (
344+ bug.setSecurityRelated(
345 get_value(bugnode, 'security_related') == 'True')
346 bug.name = get_value(bugnode, 'nickname')
347 description = get_value(bugnode, 'description')
348
349=== modified file 'lib/lp/bugs/scripts/tests/test_bugheat.py'
350--- lib/lp/bugs/scripts/tests/test_bugheat.py 2010-03-03 16:05:57 +0000
351+++ lib/lp/bugs/scripts/tests/test_bugheat.py 2010-04-15 11:01:09 +0000
352@@ -155,7 +155,7 @@
353
354 # If, on the other hand, the bug is security_related,
355 # _getHeatFromSecurity() will return BugHeatConstants.SECURITY
356- self.bug.security_related = True
357+ self.bug.setSecurityRelated(True)
358 self.assertEqual(
359 BugHeatConstants.SECURITY, self.calculator._getHeatFromSecurity())
360
361@@ -179,7 +179,7 @@
362 dupe = self.factory.makeBug()
363 dupe.duplicateof = self.bug
364 self.bug.setPrivate(True, self.bug.owner)
365- self.bug.security_related = True
366+ self.bug.setSecurityRelated(True)
367
368 expected_heat += (
369 BugHeatConstants.DUPLICATE +
370
371=== modified file 'lib/lp/bugs/tests/test_bugchanges.py'
372--- lib/lp/bugs/tests/test_bugchanges.py 2009-12-05 18:37:28 +0000
373+++ lib/lp/bugs/tests/test_bugchanges.py 2010-04-15 11:01:09 +0000
374@@ -562,7 +562,7 @@
375 def test_mark_as_security_vulnerability(self):
376 # Marking a bug as a security vulnerability adds to the bug's
377 # activity log and sends a notification.
378- self.bug.security_related = False
379+ self.bug.setSecurityRelated(False)
380 self.changeAttribute(self.bug, 'security_related', True)
381
382 security_change_activity = {
383@@ -586,7 +586,7 @@
384 def test_unmark_as_security_vulnerability(self):
385 # Unmarking a bug as a security vulnerability adds to the
386 # bug's activity log and sends a notification.
387- self.bug.security_related = True
388+ self.bug.setSecurityRelated(True)
389 self.changeAttribute(self.bug, 'security_related', False)
390
391 security_change_activity = {