234
235
self.updateContextFromData(data)
237
class FileBugViewBase(LaunchpadFormView):
238
class FileBugReportingGuidelines(LaunchpadFormView):
239
"""Provides access to common bug reporting attributes.
241
Attributes provided are: security_related and bug_reporting_guidelines.
243
This view is a superclass of `FileBugViewBase` so that non-ajax browsers
244
can load the file bug form, and it is also invoked directly via an XHR
245
request to provide an HTML snippet for Javascript enabled browsers.
251
def field_names(self):
252
"""Return the list of field names to display."""
253
return ['security_related']
255
def setUpFields(self):
256
"""Set up the form fields. See `LaunchpadFormView`."""
257
super(FileBugReportingGuidelines, self).setUpFields()
259
security_related_field = Bool(
260
__name__='security_related',
261
title=_("This bug is a security vulnerability"),
262
required=False, default=False)
264
self.form_fields = self.form_fields.omit('security_related')
265
self.form_fields += formlib.form.Fields(security_related_field)
268
def bug_reporting_guidelines(self):
269
"""Guidelines for filing bugs in the current context.
271
Returns a list of dicts, with each dict containing values for
272
"preamble" and "content".
275
def target_name(target):
276
# IProjectGroup can be considered the target of a bug during
277
# the bug filing process, but does not extend IBugTarget
278
# and ultimately cannot actually be the target of a
279
# bug. Hence this function to determine a suitable
280
# name/title to display. Hurrumph.
281
if IBugTarget.providedBy(target):
282
return target.bugtargetdisplayname
284
return target.displayname
287
bugtarget = self.context
288
if bugtarget is not None:
289
content = bugtarget.bug_reporting_guidelines
290
if content is not None and len(content) > 0:
292
"source": target_name(bugtarget),
295
# Distribution source packages are shown with both their
296
# own reporting guidelines and those of their
298
if IDistributionSourcePackage.providedBy(bugtarget):
299
distribution = bugtarget.distribution
300
content = distribution.bug_reporting_guidelines
301
if content is not None and len(content) > 0:
303
"source": target_name(distribution),
308
def getMainContext(self):
309
if IDistributionSourcePackage.providedBy(self.context):
310
return self.context.distribution
315
class FileBugViewBase(FileBugReportingGuidelines, LaunchpadFormView):
238
316
"""Base class for views related to filing a bug."""
240
318
implements(IBrowserPublisher)
307
385
elif not IProduct.providedBy(context):
308
386
raise AssertionError('Unknown context: %r' % context)
310
if IHasBugSupervisor.providedBy(context):
311
if self.user.inTeam(context.bug_supervisor):
313
['assignee', 'importance', 'milestone', 'status'])
388
# If the context is a project group we want to render the optional
389
# fields since they will initially be hidden and later exposed if the
390
# selected project supports them.
391
include_extra_fields = IProjectGroup.providedBy(context)
392
if not include_extra_fields and IHasBugSupervisor.providedBy(context):
393
include_extra_fields = self.user.inTeam(context.bug_supervisor)
395
if include_extra_fields:
397
['assignee', 'importance', 'milestone', 'status'])
315
399
return field_names
438
522
self.form_fields = self.form_fields.omit('subscribe_to_existing_bug')
439
523
self.form_fields += formlib.form.Fields(subscribe_field)
441
security_related_field = Bool(
442
__name__='security_related',
443
title=_("This bug is a security vulnerability"),
444
required=False, default=False)
446
self.form_fields = self.form_fields.omit('security_related')
447
self.form_fields += formlib.form.Fields(security_related_field)
449
525
def contextUsesMalone(self):
450
526
"""Does the context use Malone as its official bugtracker?"""
451
527
if IProjectGroup.providedBy(self.context):
457
533
bug_tracking_usage = self.getMainContext().bug_tracking_usage
458
534
return bug_tracking_usage == ServiceUsage.LAUNCHPAD
460
def getMainContext(self):
461
if IDistributionSourcePackage.providedBy(self.context):
462
return self.context.distribution
466
def getSecurityContext(self):
467
"""Return the context used for security bugs."""
468
return self.getMainContext()
471
def can_decide_security_contact(self):
472
"""Will we be able to discern a security contact for this?"""
473
return (self.getSecurityContext() is not None)
475
536
def shouldSelectPackageName(self):
476
537
"""Should the radio button to select a package be selected?"""
557
618
if extra_data.private:
558
619
params.private = extra_data.private
560
params.status = data['status']
561
if 'assignee' in data:
562
params.assignee = data['assignee']
564
params.status = data['status']
565
if 'importance' in data:
566
params.importance = data['importance']
567
if 'milestone' in data:
568
params.milestone = data['milestone']
621
# Apply any extra options given by a bug supervisor.
622
if IHasBugSupervisor.providedBy(context):
623
if self.user.inTeam(context.bug_supervisor):
624
if 'assignee' in data:
625
params.assignee = data['assignee']
627
params.status = data['status']
628
if 'importance' in data:
629
params.importance = data['importance']
630
if 'milestone' in data:
631
params.milestone = data['milestone']
570
633
self.added_bug = bug = context.createBug(params)
572
# Apply any extra options given by a bug supervisor.
573
635
for comment in extra_data.comments:
574
636
bug.newMessage(self.user, bug.followup_subject(), comment)
575
637
notifications.append(
810
872
return self.context
813
def bug_reporting_guidelines(self):
814
"""Guidelines for filing bugs in the current context.
816
Returns a list of dicts, with each dict containing values for
817
"preamble" and "content".
820
def target_name(target):
821
# IProjectGroup can be considered the target of a bug during
822
# the bug filing process, but does not extend IBugTarget
823
# and ultimately cannot actually be the target of a
824
# bug. Hence this function to determine a suitable
825
# name/title to display. Hurrumph.
826
if IBugTarget.providedBy(target):
827
return target.bugtargetdisplayname
832
context = self.bugtarget
833
if context is not None:
834
content = context.bug_reporting_guidelines
835
if content is not None and len(content) > 0:
837
"source": target_name(context),
840
# Distribution source packages are shown with both their
841
# own reporting guidelines and those of their
843
if IDistributionSourcePackage.providedBy(context):
844
distribution = context.distribution
845
content = distribution.bug_reporting_guidelines
846
if content is not None and len(content) > 0:
848
"source": target_name(distribution),
853
874
default_bug_reported_acknowledgement = "Thank you for your bug report."
855
876
def getAcknowledgementMessage(self, context):
1042
1065
config.malone.ubuntu_bug_filing_url)
1068
@action("Continue", name="projectgroupsearch", validator="validate_search")
1069
def projectgroup_search_action(self, action, data):
1070
"""Search for similar bug reports."""
1071
# Don't give focus to any widget, to ensure that the browser
1072
# won't scroll past the "possible duplicates" list.
1073
self.initial_focus_widget = None
1074
return self._PROJECTGROUP_SEARCH_FOR_DUPES()
1045
1077
@action("Continue", name="search", validator="validate_search")
1046
1078
def search_action(self, action, data):
1047
1079
"""Search for similar bug reports."""
1154
1186
url = urlappend(url, self.extra_data_token)
1157
def _getSelectedProduct(self):
1158
"""Return the product that's selected."""
1159
assert self.widgets['product'].hasValidInput(), (
1160
"This method should be called only when we know which"
1161
" product the user selected.")
1162
return self.widgets['product'].getInputValue()
1164
def getSecurityContext(self):
1165
"""See FileBugViewBase."""
1166
return self._getSelectedProduct()
1169
1190
class BugTargetBugListingView:
1170
1191
"""Helper methods for rendering bug listings."""