launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #07552
[Merge] lp:~stevenk/launchpad/bugs-information_type-mail into lp:launchpad
Steve Kowalik has proposed merging lp:~stevenk/launchpad/bugs-information_type-mail into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #933766 in Launchpad itself: "Update bug to use information_visibility_policy"
https://bugs.launchpad.net/launchpad/+bug/933766
For more details, see:
https://code.launchpad.net/~stevenk/launchpad/bugs-information_type-mail/+merge/104483
Add support for an 'information_type' mail command. I have not touched the existing private and security commands, or their tests. I have also not implemented warning of deprecation for either of them, since that requires a little more investigation.
As it stands, I accept the titles of the InformationType enum, plus 'Private' if the display_userdata_as_private feature flag is enabled. I have explicitly forbidden Proprietary for the moment, since the rules around when to allow it are still ... mushy.
--
https://code.launchpad.net/~stevenk/launchpad/bugs-information_type-mail/+merge/104483
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/bugs-information_type-mail into lp:launchpad.
=== modified file 'lib/lp/bugs/mail/commands.py'
--- lib/lp/bugs/mail/commands.py 2012-03-29 00:48:21 +0000
+++ lib/lp/bugs/mail/commands.py 2012-05-03 05:02:19 +0000
@@ -58,6 +58,7 @@
from lp.registry.interfaces.projectgroup import IProjectGroup
from lp.registry.interfaces.sourcepackage import ISourcePackage
from lp.registry.interfaces.sourcepackagename import ISourcePackageName
+from lp.services.features import getFeatureFlag
from lp.services.mail.commands import (
EditEmailCommand,
EmailCommand,
@@ -153,6 +154,66 @@
return bug, None
+class InformationTypeEmailCommand(EmailCommand):
+ """Changes the information type of a bug.
+
+ We do not subclass `EditEmailCommand` because we must call
+ `IBug.transitionToInformationType` to update it.
+ """
+
+ implements(IBugEditEmailCommand)
+
+ _numberOfArguments = 3
+ RANK = 3
+
+ def execute(self, context, current_event):
+ information_type_string = ' '.join(self.string_args)
+ userdata_as_private = bool(getFeatureFlag(
+ 'disclosure.display_userdata_as_private.enabled'))
+ if information_type_string == 'Private' and userdata_as_private:
+ information_type_string = 'User Data'
+ if information_type_string == 'Proprietary':
+ raise EmailProcessingError(
+ get_error_message(
+ 'information_type-proprietary-denied.txt',
+ error_templates=error_templates),
+ stop_processing=True)
+ try:
+ information_type = InformationType.getTermByToken(
+ information_type_string).value
+ except LookupError:
+ raise EmailProcessingError(
+ get_error_message(
+ 'information_type-parameter-mismatch.txt',
+ error_templates=error_templates),
+ stop_processing=True)
+
+ # Snapshot.
+ edited_fields = set()
+ if IObjectModifiedEvent.providedBy(current_event):
+ context_snapshot = current_event.object_before_modification
+ edited_fields.update(current_event.edited_fields)
+ else:
+ context_snapshot = Snapshot(
+ context, providing=providedBy(context))
+
+ # Apply requested changes.
+ if isinstance(context, CreateBugParams):
+ context.information_type = information_type
+ return context, current_event
+
+ edited = context.transitionToInformationType(
+ information_type, getUtility(ILaunchBag).user)
+
+ # Update the current event.
+ if edited and not IObjectCreatedEvent.providedBy(current_event):
+ edited_fields.add('private')
+ current_event = ObjectModifiedEvent(
+ context, context_snapshot, list(edited_fields))
+
+ return context, current_event
+
+
class PrivateEmailCommand(EmailCommand):
"""Marks a bug public or private.
@@ -901,6 +962,7 @@
_commands = {
'bug': BugEmailCommand,
+ 'information_type': InformationTypeEmailCommand,
'private': PrivateEmailCommand,
'security': SecurityEmailCommand,
'summary': SummaryEmailCommand,
=== added file 'lib/lp/bugs/mail/errortemplates/information_type-parameter-mismatch.txt'
--- lib/lp/bugs/mail/errortemplates/information_type-parameter-mismatch.txt 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/mail/errortemplates/information_type-parameter-mismatch.txt 2012-05-03 05:02:19 +0000
@@ -0,0 +1,6 @@
+The 'information_type' command expects one of 'Public', 'Unembargoed Security',
+'Embargoed Security', 'User Data'.
+
+For example:
+
+ information_type Unembargoed Security
=== added file 'lib/lp/bugs/mail/errortemplates/information_type-proprietary-denied.txt'
--- lib/lp/bugs/mail/errortemplates/information_type-proprietary-denied.txt 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/mail/errortemplates/information_type-proprietary-denied.txt 2012-05-03 05:02:19 +0000
@@ -0,0 +1,1 @@
+Proprietary bugs are forbidden to be filed via the mail interface.
=== modified file 'lib/lp/bugs/mail/tests/test_commands.py'
--- lib/lp/bugs/mail/tests/test_commands.py 2012-04-03 06:14:09 +0000
+++ lib/lp/bugs/mail/tests/test_commands.py 2012-05-03 05:02:19 +0000
@@ -12,6 +12,7 @@
BugEmailCommand,
CVEEmailCommand,
DuplicateEmailCommand,
+ InformationTypeEmailCommand,
PrivateEmailCommand,
SecurityEmailCommand,
SubscribeEmailCommand,
@@ -20,6 +21,7 @@
UnsubscribeEmailCommand,
)
from lp.registry.enums import InformationType
+from lp.services.features.testing import FeatureFixture
from lp.services.mail.interfaces import (
BugTargetNotFound,
EmailProcessingError,
@@ -412,6 +414,81 @@
self.assertEqual(dummy_event, event)
+class InformationTypeEmailCommandTestCase(TestCaseWithFactory):
+
+ layer = DatabaseFunctionalLayer
+
+ def test_execute_bug_params(self):
+ user = self.factory.makePerson()
+ login_person(user)
+ bug_params = CreateBugParams(title='bug title', owner=user)
+ command = InformationTypeEmailCommand(
+ 'information_type', ['Unembargoed', 'Security'])
+ dummy_event = object()
+ params, event = command.execute(bug_params, dummy_event)
+ self.assertEqual(bug_params, params)
+ self.assertEqual(
+ InformationType.UNEMBARGOEDSECURITY, bug_params.information_type)
+ self.assertEqual(dummy_event, event)
+
+ def test_private_without_feature_flag(self):
+ user = self.factory.makePerson()
+ login_person(user)
+ bug_params = CreateBugParams(title='bug title', owner=user)
+ command = InformationTypeEmailCommand(
+ 'information_type', ['Private'])
+ dummy_event = object()
+ self.assertRaises(
+ EmailProcessingError, command.execute, bug_params, dummy_event)
+
+ def test_private_with_feature_flag(self):
+ user = self.factory.makePerson()
+ login_person(user)
+ bug_params = CreateBugParams(title='bug title', owner=user)
+ command = InformationTypeEmailCommand(
+ 'information_type', ['Private'])
+ dummy_event = object()
+ feature_flag = {
+ 'disclosure.display_userdata_as_private.enabled': 'on'}
+ with FeatureFixture(feature_flag):
+ params, event = command.execute(bug_params, dummy_event)
+ self.assertEqual(bug_params, params)
+ self.assertEqual(
+ InformationType.USERDATA, bug_params.information_type)
+ self.assertEqual(dummy_event, event)
+
+ def test_execute_bug(self):
+ bug = self.factory.makeBug()
+ login_person(bug.owner)
+ command = InformationTypeEmailCommand(
+ 'information_type', ['Embargoed', 'Security'])
+ exec_bug, event = command.execute(bug, None)
+ self.assertEqual(bug, exec_bug)
+ self.assertEqual(
+ InformationType.EMBARGOEDSECURITY, bug.information_type)
+ self.assertTrue(IObjectModifiedEvent.providedBy(event))
+
+ def test_execute_bug_params_with_rubbish(self):
+ user = self.factory.makePerson()
+ login_person(user)
+ bug_params = CreateBugParams(title='bug title', owner=user)
+ command = InformationTypeEmailCommand(
+ 'information_type', ['Rubbish'])
+ dummy_event = object()
+ self.assertRaises(
+ EmailProcessingError, command.execute, bug_params, dummy_event)
+
+ def test_execute_bug_params_with_proprietary(self):
+ user = self.factory.makePerson()
+ login_person(user)
+ bug_params = CreateBugParams(title='bug title', owner=user)
+ command = InformationTypeEmailCommand(
+ 'information_type', ['Proprietary'])
+ dummy_event = object()
+ self.assertRaises(
+ EmailProcessingError, command.execute, bug_params, dummy_event)
+
+
class SubscribeEmailCommandTestCase(TestCaseWithFactory):
layer = DatabaseFunctionalLayer
=== modified file 'lib/lp/bugs/mail/tests/test_handler.py'
--- lib/lp/bugs/mail/tests/test_handler.py 2012-03-27 13:41:38 +0000
+++ lib/lp/bugs/mail/tests/test_handler.py 2012-05-03 05:02:19 +0000
@@ -28,6 +28,7 @@
MaloneHandler,
)
from lp.bugs.model.bugnotification import BugNotification
+from lp.registry.enums import InformationType
from lp.services.config import config
from lp.services.identity.interfaces.emailaddress import EmailAddressStatus
from lp.services.mail import stub
@@ -318,6 +319,23 @@
recipients.add(recipient.person)
self.assertContentEqual([maintainer], recipients)
+ def test_information_type(self):
+ project = self.factory.makeProduct(name='fnord')
+ transaction.commit()
+ handler = MaloneHandler()
+ with person_logged_in(project.owner):
+ msg = self.factory.makeSignedMessage(
+ body='unsecure\n information_type User Data\n affects fnord',
+ subject='unsecure code',
+ to_address='new@xxxxxxxxxxxxxxxxxx')
+ handler.process(msg, msg['To'])
+ notification = self.getLatestBugNotification()
+ bug = notification.bug
+ self.assertEqual('unsecure code', bug.title)
+ self.assertEqual(InformationType.USERDATA, bug.information_type)
+ self.assertEqual(1, len(bug.bugtasks))
+ self.assertEqual(project, bug.bugtasks[0].target)
+
class BugTaskCommandGroupTestCase(TestCase):
Follow ups