← Back to team overview

launchpad-reviewers team mailing list archive

[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