Source

trac-rpc-mq / t10738 / t10738_r13203_ticket_create_validate.diff

Full commit
# HG changeset patch
# Parent 862c4e51bd555fbfec474921060ee297c37e150a
TracRpc #10738 : Invoke ticket manipulators validations on ticket.create

diff -r 862c4e51bd55 trunk/setup.py
--- a/trunk/setup.py	Fri Feb 21 09:57:47 2014 +0100
+++ b/trunk/setup.py	Thu Mar 06 13:44:39 2014 -0500
@@ -19,7 +19,7 @@
 
 setup(
     name='TracXMLRPC',
-    version='1.1.2',
+    version='1.2.0',
     license='BSD',
     author='Alec Thomas',
     author_email='alec@swapoff.org',
diff -r 862c4e51bd55 trunk/tracrpc/tests/ticket.py
--- a/trunk/tracrpc/tests/ticket.py	Fri Feb 21 09:57:47 2014 +0100
+++ b/trunk/tracrpc/tests/ticket.py	Thu Mar 06 13:44:39 2014 -0500
@@ -153,19 +153,19 @@
         t2 = self.admin.ticket.create("2", "", {'type': 'task', 'owner': 'B'})
         t3 = self.admin.ticket.create("3", "", {'type': 'defect', 'owner': 'A'})
         # order
-        self.assertEquals([3,1,2], self.admin.ticket.query("order=type"))
-        self.assertEquals([1,3,2], self.admin.ticket.query("order=owner"))
-        self.assertEquals([2,1,3],
+        self.assertEquals([t3,t1,t2], self.admin.ticket.query("order=type"))
+        self.assertEquals([t1,t3,t2], self.admin.ticket.query("order=owner"))
+        self.assertEquals([t2,t1,t3],
                         self.admin.ticket.query("order=owner&desc=1"))
         # group
-        self.assertEquals([1,3,2], self.admin.ticket.query("group=owner"))
-        self.assertEquals([2,1,3],
+        self.assertEquals([t1,t3,t2], self.admin.ticket.query("group=owner"))
+        self.assertEquals([t2,t1,t3],
                         self.admin.ticket.query("group=owner&groupdesc=1"))
         # group + order
-        self.assertEquals([2,3,1],
+        self.assertEquals([t2,t3,t1],
                 self.admin.ticket.query("group=owner&groupdesc=1&order=type"))
         # col should just be ignored
-        self.assertEquals([3,1,2],
+        self.assertEquals([t3,t1,t2],
                 self.admin.ticket.query("order=type&col=status&col=reporter"))
         # clean
         self.assertEquals(0, self.admin.ticket.delete(t1))
@@ -374,6 +374,60 @@
         self.admin.ticket.delete(1)
 
 
+    def test_create_ticket_validate(self):
+        # Enable ticket manipulator
+        plugin = os.path.join(rpc_testenv.tracdir, 'plugins', 'TicketManipulator.py')
+        open(plugin, 'w').write(
+        "from trac.core import *\n"
+        "from trac.ticket.api import ITicketManipulator\n"
+        "class TicketManipulator(Component):\n"
+        "    implements(ITicketManipulator)\n"
+        "    def prepare_ticket(self, req, ticket, fields, actions):\n"
+        "        pass\n"
+        "    def validate_ticket(self, req, ticket):\n"
+        "        if 'BOOM' in ticket['description']:\n"
+        "            return [('summary', 'Detected BOOM in ticket description')]\n"
+        "        ticket['summary'] += ' [VALID]'\n"
+        "        return []\n")
+        rpc_testenv.restart()
+
+        tickets = []
+
+        # Valid ticket submissions
+        tid = self.user.ticket.create('Valid user submission', 
+                                      'Expected success')
+        tickets.append(tid)
+        t = self.user.ticket.get(tid)
+        self.assertTrue(t[3]['summary'].endswith('[VALID]'))
+
+        tid = self.admin.ticket.create('Let admin bypass verifications', 
+                                       'Expected success. No BOOM',
+                                       {}, False, 0, False)
+        tickets.append(tid)
+        t = self.admin.ticket.get(tid)
+        self.assertFalse(t[3]['summary'].endswith('[VALID]'))
+
+        # Invalid ticket submissions
+        e = self.assertRaises(xmlrpclib.Fault, self.user.ticket.create, 
+                          'Invalid user submission', 'Expected BOOM')
+        self.assertTrue('Detected BOOM in ticket description' in str(e))
+        e = self.assertRaises(xmlrpclib.Fault, self.user.ticket.create, 
+                          'Ignore validate arg in user submission',
+                          'Expected BOOM', {}, False, 0, False)
+        self.assertTrue('Detected BOOM in ticket description' in str(e))
+        e = self.assertRaises(xmlrpclib.Fault, self.admin.ticket.create, 
+                          'Invalid admin submission', 'Expected BOOM')
+        self.assertTrue('Detected BOOM in ticket description' in str(e))
+
+        # clean
+        for tid in tickets:
+            self.assertEquals(0, self.admin.ticket.delete(tid))
+
+        # Remove plugin and restart
+        os.unlink(plugin)
+        rpc_testenv.restart()
+
+
 class RpcTicketVersionTestCase(TracRpcTestCase):
     
     def setUp(self):
diff -r 862c4e51bd55 trunk/tracrpc/ticket.py
--- a/trunk/tracrpc/ticket.py	Fri Feb 21 09:57:47 2014 +0100
+++ b/trunk/tracrpc/ticket.py	Thu Mar 06 13:44:39 2014 -0500
@@ -46,7 +46,8 @@
         yield ('TICKET_CREATE', ((int, str, str),
                                  (int, str, str, dict),
                                  (int, str, str, dict, bool),
-                                 (int, str, str, dict, bool, datetime)),
+                                 (int, str, str, dict, bool, datetime),
+                                 (int, str, str, dict, bool, datetime, bool)),
                       self.create)
         yield (None, ((list, int, str),
                       (list, int, str, dict),
@@ -151,9 +152,11 @@
         t['_ts'] = str(to_utimestamp(t.time_changed))
         return (t.id, t.time_created, t.time_changed, t.values)
 
-    def create(self, req, summary, description, attributes={}, notify=False, when=None):
+    def create(self, req, summary, description, attributes={}, notify=False, 
+               when=None, validate=True):
         """ Create a new ticket, returning the ticket ID.
-        Overriding 'when' requires admin permission. """
+        Overriding 'when' as well as setting 'validate' to `True`
+        requires admin permission."""
         t = model.Ticket(self.env)
         t['summary'] = summary
         t['description'] = description
@@ -163,10 +166,24 @@
         t['status'] = 'new'
         t['resolution'] = ''
         # custom create timestamp?
+        when = when or None
         if when and not 'TICKET_ADMIN' in req.perm:
             self.log.warn("RPC ticket.create: %r not allowed to create with "
                     "non-current timestamp (%r)", req.authname, when)
             when = None
+        # skip ticket manipulators?
+        if not validate and not 'TICKET_ADMIN' in req.perm:
+            self.log.warn("RPC ticket.create: %s not allowed to "
+                    "bypass ticket manipulator validations", req.authname)
+            validate = True
+        msg = None
+        if validate:
+            tm = TicketModule(self.env)
+            valid = tm._validate_ticket(req, t)
+            if not valid:
+                msg = '\n\n'.join(req.chrome.get('warnings', 
+                                                 ['RPC : Validation failed']))
+                raise TracError('Invalid ticket submission : %s' % msg)
         t.insert(when=when)
         if notify:
             try: