changeset 435:8424a8afd1a1

Started implementing platform editing via admin interface.
author cmlenz
date Thu, 16 Aug 2007 22:53:35 +0000
parents ca0fded18882
children cfbc9ee622d5
files bitten/admin.py bitten/templates/bitten_admin_configs.cs bitten/tests/admin.py
diffstat 3 files changed, 215 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/bitten/admin.py
+++ b/bitten/admin.py
@@ -93,27 +93,50 @@
         data = {}
 
         if config_name:
-            config = BuildConfig.fetch(self.env, config_name)
-            platforms = list(TargetPlatform.select(self.env, config=config.name))
-
-            if req.method == 'POST':
-                if 'save' in req.args:
-                    self._update_config(req, config)
-                req.redirect(req.abs_href.admin(cat, page))
+            if '/' in config_name:
+                config_name, platform_id = config_name.split('/', 1)
+                platform_id = int(platform_id)
 
-            data['config'] = {
-                'name': config.name, 'label': config.label or config.name,
-                'active': config.active, 'path': config.path,
-                'min_rev': config.min_rev, 'max_rev': config.max_rev,
-                'description': config.description,
-                'recipe': config.recipe,
-                'platforms': [{
-                    'name': platform.name,
-                    'id': platform.id,
-                    'href': req.href.admin('bitten', 'configs', config.name,
-                                           platform.id)
-                } for platform in platforms]
-            }
+                platform = TargetPlatform.fetch(self.env, platform_id)
+
+                if req.method == 'POST':
+                    if 'cancel' in req.args:
+                        req.redirect(req.abs_href.admin(cat, page, config_name))
+                    elif self._process_platform(req, platform):
+                        req.redirect(req.abs_href.admin(cat, page, config_name))
+
+                data['platform'] = {
+                    'id': platform.id, 'name': platform.name,
+                    'exists': platform.exists,
+                    'rules': [
+                        {'property': propname, 'pattern': pattern}
+                        for propname, pattern in platform.rules
+                    ] or [('', '')]
+                }
+
+            else:
+                config = BuildConfig.fetch(self.env, config_name)
+                platforms = list(TargetPlatform.select(self.env,
+                                                       config=config.name))
+
+                if req.method == 'POST':
+                    if 'save' in req.args:
+                        self._update_config(req, config)
+                    req.redirect(req.abs_href.admin(cat, page))
+
+                data['config'] = {
+                    'name': config.name, 'label': config.label or config.name,
+                    'active': config.active, 'path': config.path,
+                    'min_rev': config.min_rev, 'max_rev': config.max_rev,
+                    'description': config.description,
+                    'recipe': config.recipe,
+                    'platforms': [{
+                        'name': platform.name,
+                        'id': platform.id,
+                        'href': req.href.admin('bitten', 'configs', config.name,
+                                               platform.id)
+                    } for platform in platforms]
+                }
 
         else:
             if req.method == 'POST':
@@ -175,10 +198,12 @@
 
     def _remove_configs(self, req):
         req.perm.assert_permission('BUILD_DELETE')
+
         sel = req.args.get('sel')
         if not sel:
             raise TracError('No configuration selected')
         sel = isinstance(sel, list) and sel or [sel]
+
         db = self.env.get_db_cnx()
         for name in sel:
             config = BuildConfig.fetch(self.env, name, db=db)
@@ -226,6 +251,33 @@
         config.recipe = recipe_xml
         config.min_rev = req.args.get('min_rev')
         config.max_rev = req.args.get('max_rev')
-        config.label = req.args.get('label', '')
+        config.label = req.args.get('label', config.name)
         config.description = req.args.get('description', '')
         config.update()
+
+    def _process_platform(self, req, platform):
+        platform.name = req.args.get('name')
+
+        properties = [int(key[9:]) for key in req.args.keys()
+                      if key.startswith('property_')]
+        properties.sort()
+        patterns = [int(key[8:]) for key in req.args.keys()
+                    if key.startswith('pattern_')]
+        patterns.sort()
+        platform.rules = [(req.args.get('property_%d' % property),
+                           req.args.get('pattern_%d' % pattern))
+                          for property, pattern in zip(properties, patterns)
+                          if req.args.get('property_%d' % property)]
+
+        add_rules = [int(key[9:]) for key in req.args.keys()
+                     if key.startswith('add_rule_')]
+        if add_rules:
+            platform.rules.insert(add_rules[0] + 1, ('', ''))
+            return False
+        rm_rules = [int(key[8:]) for key in req.args.keys()
+                    if key.startswith('rm_rule_')]
+        if rm_rules:
+            del platform.rules[rm_rules[0]]
+            return False
+
+        return True
--- a/bitten/templates/bitten_admin_configs.cs
+++ b/bitten/templates/bitten_admin_configs.cs
@@ -50,6 +50,10 @@
       </li><?cs
      /each ?></ul><?cs
     /if ?>
+    <div class="buttons">
+     <input type="submit" name="new" value="Add target platform" />
+     <input type="submit" name="delete" value="Delete selected platforms" />
+    </div>
   </fieldset>
   <div class="buttons">
    <input type="submit" name="cancel" value="Cancel" />
@@ -57,6 +61,42 @@
   </div>
  </form><?cs
 
+elif admin.platform.name ?>
+ <form class="mod" id="modplatform" method="post">
+    <div class="field"><label>Target Platform:
+     <input type="text" name="name" value="<?cs var:admin.platform.name ?>" />
+    </label></div>
+    <fieldset>
+     <legend>Rules</legend>
+     <table><thead><tr>
+      <th>Property name</th><th>Match pattern</th>
+     </tr></thead><tbody><?cs
+      each:rule = admin.platform.rules ?><tr>
+       <td><input type="text" name="property_<?cs var:name(rule) ?>" value="<?cs
+        var:rule.property ?>" /></td>
+       <td><input type="text" name="pattern_<?cs var:name(rule) ?>" value="<?cs
+        var:rule.pattern ?>" /></td>
+       <td><input type="submit" name="add_rule_<?cs
+         var:name(rule) ?>" value="+" /><input type="submit" name="rm_rule_<?cs
+         var:name(rule) ?>" value="-" />
+       </td>
+      </tr><?cs /each ?>
+     </tbody></table>
+    </fieldset>
+    <div class="buttons">
+     <form method="get" action=""><div>
+      <input type="hidden" name="action" value="<?cs
+       if:admin.platform.exists ?>edit<?cs else ?>new<?cs /if ?>" />
+      <input type="hidden" name="platform" value="<?cs
+       var:admin.platform.id ?>" />
+      <input type="submit" name="cancel" value="Cancel" />
+      <input type="submit" name="save" value="<?cs
+       if:admin.platform.exists ?>Save<?cs else ?>Add<?cs
+       /if ?>" />
+     </div></form>
+    </div>
+ </form><?cs
+
 else ?>
  <form class="addnew" id="addcomp" method="post">
   <fieldset>
--- a/bitten/tests/admin.py
+++ b/bitten/tests/admin.py
@@ -247,9 +247,29 @@
             config = BuildConfig.fetch(self.env, name='bar')
             self.assertEqual('Bar', config.label)
 
+    def test_process_add_config_cancel(self):
+        redirected_to = []
+        def redirect(url):
+            redirected_to.append(url)
+            raise RequestDone
+        req = Mock(method='POST', perm=PermissionCache(self.env, 'joe'),
+                   abs_href=Href('http://example.org/'), redirect=redirect,
+                   args={'cancel': '', 'name': 'bar', 'label': 'Bar'})
+
+        provider = BuildConfigurationsAdminPageProvider(self.env)
+        try:
+            provider.process_admin_request(req, 'bitten', 'configs', '')
+            self.fail('Expected RequestDone')
+
+        except RequestDone:
+            self.assertEqual('http://example.org/admin/bitten/configs',
+                             redirected_to[0])
+            configs = list(BuildConfig.select(self.env, include_inactive=True))
+            self.assertEqual(0, len(configs))
+
     def test_process_add_config_no_name(self):
         req = Mock(method='POST', perm=PermissionCache(self.env, 'joe'),
-                   args={'add': '', 'name': ''})
+                   args={'add': ''})
 
         provider = BuildConfigurationsAdminPageProvider(self.env)
         try:
@@ -259,6 +279,19 @@
         except TracError, e:
             self.assertEqual('Missing required field "name"', e.message)
 
+    def test_process_add_config_no_name(self):
+        req = Mock(method='POST', perm=PermissionCache(self.env, 'joe'),
+                   args={'add': '', 'name': 'no spaces allowed'})
+
+        provider = BuildConfigurationsAdminPageProvider(self.env)
+        try:
+            provider.process_admin_request(req, 'bitten', 'configs', '')
+            self.fail('Expected TracError')
+
+        except TracError, e:
+            self.assertEqual('The field "name" may only contain letters, '
+                             'digits, periods, or dashes.', e.message)
+
     def test_process_add_config_no_perms(self):
         BuildConfig(self.env, name='foo', label='Foo', path='branches/foo',
                     active=True).insert()
@@ -296,6 +329,31 @@
                              redirected_to[0])
             assert not BuildConfig.fetch(self.env, name='bar')
 
+    def test_process_remove_config_cancel(self):
+        BuildConfig(self.env, name='foo', label='Foo', path='branches/foo',
+                    active=True).insert()
+        BuildConfig(self.env, name='bar', label='Bar', path='branches/bar',
+                    min_rev='123', max_rev='456').insert()
+
+        redirected_to = []
+        def redirect(url):
+            redirected_to.append(url)
+            raise RequestDone
+        req = Mock(method='POST', perm=PermissionCache(self.env, 'joe'),
+                   abs_href=Href('http://example.org/'), redirect=redirect,
+                   args={'cancel': '', 'sel': 'bar'})
+
+        provider = BuildConfigurationsAdminPageProvider(self.env)
+        try:
+            provider.process_admin_request(req, 'bitten', 'configs', '')
+            self.fail('Expected RequestDone')
+
+        except RequestDone:
+            self.assertEqual('http://example.org/admin/bitten/configs',
+                             redirected_to[0])
+            configs = list(BuildConfig.select(self.env, include_inactive=True))
+            self.assertEqual(2, len(configs))
+
     def test_process_remove_config_no_selection(self):
         BuildConfig(self.env, name='foo', label='Foo', path='branches/foo',
                     active=True).insert()
@@ -354,6 +412,49 @@
         except TracError, e:
             self.assertEqual('Missing required field "name"', e.message)
 
+    def test_process_update_config_invalid_name(self):
+        BuildConfig(self.env, name='foo', label='Foo', path='branches/foo',
+                    active=True).insert()
+
+        req = Mock(method='POST', perm=PermissionCache(self.env, 'joe'),
+                   args={'save': '', 'name': 'no spaces allowed'})
+
+        provider = BuildConfigurationsAdminPageProvider(self.env)
+        try:
+            provider.process_admin_request(req, 'bitten', 'configs', 'foo')
+            self.fail('Expected TracError')
+
+        except TracError, e:
+            self.assertEqual('The field "name" may only contain letters, '
+                             'digits, periods, or dashes.', e.message)
+
+    def test_process_update_config_valid(self):
+        BuildConfig(self.env, name='foo', label='Foo', path='branches/foo',
+                    active=True).insert()
+
+        redirected_to = []
+        def redirect(url):
+            redirected_to.append(url)
+            raise RequestDone
+        req = Mock(method='POST', perm=PermissionCache(self.env, 'joe'),
+                   abs_href=Href('http://example.org/'), redirect=redirect,
+                   authname='joe', args={
+            'save': '', 'name': 'foo', 'label': 'Foobar',
+            'description': 'Thanks for all the fish!'
+        })
+
+        provider = BuildConfigurationsAdminPageProvider(self.env)
+        try:
+            provider.process_admin_request(req, 'bitten', 'configs', 'foo')
+            self.fail('Expected RequestDone')
+
+        except RequestDone:
+            self.assertEqual('http://example.org/admin/bitten/configs',
+                             redirected_to[0])
+            config = BuildConfig.fetch(self.env, name='foo')
+            self.assertEqual('Foobar', config.label)
+            self.assertEqual('Thanks for all the fish!', config.description)
+
 
 def suite():
     suite = unittest.TestSuite()
Copyright (C) 2012-2017 Edgewall Software