You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by je...@apache.org on 2015/02/16 12:44:48 UTC

[17/37] allura git commit: [#4542] ticket:714 Handle DuplicateKeyError

[#4542] ticket:714 Handle DuplicateKeyError


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/ba555ec4
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/ba555ec4
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/ba555ec4

Branch: refs/heads/ib/4542
Commit: ba555ec4743d46dad2bd1c70121d6e437ff202dd
Parents: ad60782
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Jan 29 14:34:19 2015 +0000
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Mon Feb 16 10:16:48 2015 +0000

----------------------------------------------------------------------
 .../allura/templates/webhooks/create_form.html  |  1 +
 Allura/allura/webhooks.py                       | 76 ++++++++++++++------
 2 files changed, 55 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/ba555ec4/Allura/allura/templates/webhooks/create_form.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/webhooks/create_form.html b/Allura/allura/templates/webhooks/create_form.html
index c5ccdfb..6653985 100644
--- a/Allura/allura/templates/webhooks/create_form.html
+++ b/Allura/allura/templates/webhooks/create_form.html
@@ -64,6 +64,7 @@
 {%- endmacro %}
 
 {% block content %}
+{{ error('_the_form') }}
 <form action="{{action}}" method="post" enctype="multipart/form-data">
   <div>
     <label for="url">url</label>

http://git-wip-us.apache.org/repos/asf/allura/blob/ba555ec4/Allura/allura/webhooks.py
----------------------------------------------------------------------
diff --git a/Allura/allura/webhooks.py b/Allura/allura/webhooks.py
index c4c6ca6..8495786 100644
--- a/Allura/allura/webhooks.py
+++ b/Allura/allura/webhooks.py
@@ -21,12 +21,14 @@ import hmac
 import hashlib
 
 import requests
+from bson import ObjectId
 from tg import expose, validate, redirect, flash
 from tg.decorators import with_trailing_slash, without_trailing_slash
 from pylons import tmpl_context as c
 from formencode import validators as fev, schema, Invalid
 from ming.odm import session
 from webob import exc
+from pymongo.errors import DuplicateKeyError
 
 from allura.controllers import BaseController
 from allura.lib import helpers as h
@@ -53,14 +55,23 @@ class MingOneOf(av.Ming):
             value, state)
 
 
-class WebhookValidator(av.Ming):
+class WebhookValidator(fev.FancyValidator):
     def __init__(self, sender, ac_ids, **kw):
         self.ac_ids = ac_ids
         self.sender = sender
-        super(WebhookValidator, self).__init__(cls=M.Webhook, **kw)
+        super(WebhookValidator, self).__init__(**kw)
 
     def _to_python(self, value, state):
-        wh = super(WebhookValidator, self)._to_python(value, state)
+        wh = None
+        if isinstance(value, M.Webhook):
+            wh = value
+        elif isinstance(value, ObjectId):
+            wh = M.Webhook.query.get(_id=value)
+        else:
+            try:
+                wh = M.Webhook.query.get(_id=ObjectId(value))
+            except:
+                pass
         if wh and wh.type == self.sender.type and wh.app_config_id in self.ac_ids:
             return wh
         raise Invalid(u'Invalid webhook', value, state)
@@ -72,7 +83,9 @@ class WebhookCreateForm(schema.Schema):
         self.triggered_by = [ac for ac in c.project.app_configs
                              if ac.tool_name.lower() in sender.triggered_by]
         self.add_field('app', MingOneOf(
-            cls=M.AppConfig, ids=[ac._id for ac in self.triggered_by]))
+            cls=M.AppConfig,
+            ids=[ac._id for ac in self.triggered_by],
+            not_empty=True))
 
     url = fev.URL(not_empty=True)
     secret = fev.UnicodeString()
@@ -82,7 +95,9 @@ class WebhookEditForm(WebhookCreateForm):
     def __init__(self, sender):
         super(WebhookEditForm, self).__init__(sender)
         self.add_field('webhook', WebhookValidator(
-            sender=sender, ac_ids=[ac._id for ac in self.triggered_by]))
+            sender=sender,
+            ac_ids=[ac._id for ac in self.triggered_by],
+            not_empty=True))
 
 
 class WebhookControllerMeta(type):
@@ -115,9 +130,38 @@ class WebhookController(BaseController):
     def gen_secret(self):
         return h.cryptographic_nonce(20)
 
+    def update_webhook(self, wh, url, ac, secret=None):
+        if not secret:
+            secret = self.gen_secret()
+        wh.hook_url = url
+        wh.app_config_id = ac._id
+        wh.secret = secret
+        try:
+            session(wh).flush(wh)
+        except DuplicateKeyError:
+            session(wh).expunge(wh)
+            msg = u'_the_form: "{}" webhook already exists for {} {}'.format(
+                wh.type, ac.options.mount_label, url)
+            raise Invalid(msg, None, None)
+
+    def form_app_id(self, app):
+        if app and isinstance(app, M.AppConfig):
+            _app = unicode(app._id)
+        elif app:
+            _app = unicode(app)
+        else:
+            _app = None
+        return _app
+
     @with_trailing_slash
     @expose('jinja:allura:templates/webhooks/create_form.html')
     def index(self, **kw):
+        if not c.form_values and kw:
+            # Executes if update_webhook raises an error
+            _app = self.form_app_id(kw.get('app'))
+            c.form_values = {'url': kw.get('url'),
+                             'app': _app,
+                             'secret': kw.get('secret')}
         return {'sender': self.sender,
                 'action': 'create',
                 'form': self.create_form(self.sender)}
@@ -125,15 +169,8 @@ class WebhookController(BaseController):
     @expose()
     @require_post()
     def create(self, url, app, secret):
-        if not secret:
-            secret = self.gen_secret()
-        # TODO: catch DuplicateKeyError
-        wh = M.Webhook(
-            hook_url=url,
-            secret=secret,
-            app_config_id=app._id,
-            type=self.sender.type)
-        session(wh).flush(wh)
+        wh = M.Webhook(type=self.sender.type)
+        self.update_webhook(wh, url, app, secret)
         M.AuditLog.log('add webhook %s %s %s',
                        wh.type, wh.hook_url, wh.app_config.url())
         flash('Created successfully', 'ok')
@@ -142,16 +179,10 @@ class WebhookController(BaseController):
     @expose()
     @require_post()
     def edit(self, webhook, url, app, secret):
-        if not secret:
-            secret = self.gen_secret()
         old_url = webhook.hook_url
         old_app = webhook.app_config.url()
         old_secret = webhook.secret
-        webhook.hook_url = url
-        webhook.app_config_id = app._id
-        webhook.secret = secret
-        # TODO: duplicate
-        session(webhook).flush(webhook)
+        self.update_webhook(webhook, url, app, secret)
         M.AuditLog.log('edit webhook %s\n%s => %s\n%s => %s\n%s',
             webhook.type, old_url, url, old_app, app.url(),
             'secret changed' if old_secret != secret else '')
@@ -179,8 +210,9 @@ class WebhookController(BaseController):
             wh = form.fields['webhook'].to_python(webhook)
         except Invalid:
             raise exc.HTTPNotFound()
+        _app = self.form_app_id(kw.get('app')) or unicode(wh.app_config._id)
         c.form_values = {'url': kw.get('url') or wh.hook_url,
-                         'app': kw.get('app') or unicode(wh.app_config_id),
+                         'app': _app,
                          'secret': kw.get('secret') or wh.secret,
                          'webhook': unicode(wh._id)}
         return {'sender': self.sender,