From ecc5f8fba712aa61cb8d6e84b5c4d4847666eda7 Mon Sep 17 00:00:00 2001 From: yackob03 Date: Fri, 15 Nov 2013 17:45:37 -0500 Subject: [PATCH] Wire up webhooks to the UI. --- data/database.py | 2 +- data/model.py | 5 ++++ endpoints/api.py | 20 +++++++++++++--- static/css/quay.css | 6 +++-- static/js/controllers.js | 27 ++++++++++++++++++++- static/partials/repo-admin.html | 41 ++++++++++++++++++++++++++++++++ test/data/test.db | Bin 97280 -> 100352 bytes 7 files changed, 94 insertions(+), 7 deletions(-) diff --git a/data/database.py b/data/database.py index 674aeebe8..1a8291d5a 100644 --- a/data/database.py +++ b/data/database.py @@ -212,4 +212,4 @@ class QueueItem(BaseModel): all_models = [User, Repository, Image, AccessToken, Role, RepositoryPermission, Visibility, RepositoryTag, EmailConfirmation, FederatedLogin, LoginService, QueueItem, - RepositoryBuild, Team, TeamMember, TeamRole] + RepositoryBuild, Team, TeamMember, TeamRole, Webhook] diff --git a/data/model.py b/data/model.py index 9d10b19b3..28c910d28 100644 --- a/data/model.py +++ b/data/model.py @@ -973,3 +973,8 @@ def list_webhooks(namespace_name, repository_name): joined = Webhook.select().join(Repository) return joined.where(Repository.namespace == namespace_name, Repository.name == repository_name) + + +def delete_webhook(namespace_name, repository_name, public_id): + webhook = get_webhook(namespace_name, repository_name, public_id) + webhook.delete_instance() diff --git a/endpoints/api.py b/endpoints/api.py index 1d95bacc4..bab7ee9f0 100644 --- a/endpoints/api.py +++ b/endpoints/api.py @@ -841,7 +841,7 @@ def webhook_view(webhook): @api_login_required @parse_repository_name def create_webhook(namespace, repository): - permission = ModifyRepositoryPermission(namespace, repository) + permission = AdministerRepositoryPermission(namespace, repository) if permission.can(): repo = model.get_repository(namespace, repository) webhook = model.create_webhook(repo, request.get_json()) @@ -849,6 +849,7 @@ def create_webhook(namespace, repository): repo_string = '%s/%s' % (namespace, repository) resp.headers['Location'] = url_for('get_webhook', repository=repo_string, public_id=webhook.public_id) + return resp abort(403) # Permissions denied @@ -858,7 +859,7 @@ def create_webhook(namespace, repository): @api_login_required @parse_repository_name def get_webhook(namespace, repository, public_id): - permission = ModifyRepositoryPermission(namespace, repository) + permission = AdministerRepositoryPermission(namespace, repository) if permission.can(): webhook = model.get_webhook(namespace, repository, public_id) return jsonify(webhook_view(webhook)) @@ -870,7 +871,7 @@ def get_webhook(namespace, repository, public_id): @api_login_required @parse_repository_name def list_webhooks(namespace, repository): - permission = ModifyRepositoryPermission(namespace, repository) + permission = AdministerRepositoryPermission(namespace, repository) if permission.can(): webhooks = model.list_webhooks(namespace, repository) return jsonify({ @@ -880,6 +881,19 @@ def list_webhooks(namespace, repository): abort(403) # Permission denied +@app.route('/api/repository//webhook/', + methods=['DELETE']) +@api_login_required +@parse_repository_name +def delete_webhook(namespace, repository, public_id): + permission = AdministerRepositoryPermission(namespace, repository) + if permission.can(): + model.delete_webhook(namespace, repository, public_id) + return make_response('No Content', 204) + + abort(403) # Permission denied + + @app.route('/api/filedrop/', methods=['POST']) @api_login_required def get_filedrop_url(): diff --git a/static/css/quay.css b/static/css/quay.css index e466e43d6..d2ba879f9 100644 --- a/static/css/quay.css +++ b/static/css/quay.css @@ -524,11 +524,13 @@ font-size: .4em; } -form input.ng-invalid.ng-dirty { +form input.ng-invalid.ng-dirty, +*[ng-form] input.ng-invalid.ng-dirty { background-color: #FDD7D9; } -form input.ng-valid.ng-dirty { +form input.ng-valid.ng-dirty, +*[ng-form] input.ng-valid.ng-dirty { background-color: #DDFFEE; } diff --git a/static/js/controllers.js b/static/js/controllers.js index e4e3d5d4f..696b2b4e9 100644 --- a/static/js/controllers.js +++ b/static/js/controllers.js @@ -559,7 +559,7 @@ function RepoAdminCtrl($scope, Restangular, $routeParams, $rootScope) { }); }; - $scope.roles = [ + $scope.roles = [ { 'id': 'read', 'title': 'Read', 'kind': 'success' }, { 'id': 'write', 'title': 'Write', 'kind': 'success' }, { 'id': 'admin', 'title': 'Admin', 'kind': 'primary' } @@ -700,6 +700,31 @@ function RepoAdminCtrl($scope, Restangular, $routeParams, $rootScope) { $scope.loading = false; }); + $scope.webhooksLoading = true; + $scope.loadWebhooks = function() { + $scope.webhooksLoading = true; + var fetchWebhooks = Restangular.one('repository/' + namespace + '/' + name + '/webhook/'); + fetchWebhooks.get().then(function(resp) { + $scope.webhooks = resp.webhooks; + $scope.webhooksLoading = false; + }); + }; + + $scope.createWebhook = function() { + var newWebhook = Restangular.one('repository/' + namespace + '/' + name + '/webhook/'); + newWebhook.customPOST($scope.newWebhook).then(function(resp) { + $scope.webhooks.push(resp); + $scope.newWebhook.url = ''; + $scope.newWebhookForm.$setPristine(); + }); + }; + + $scope.deleteWebhook = function(webhook) { + var deleteWebhookReq = Restangular.one('repository/' + namespace + '/' + name + '/webhook/' + webhook.public_id); + deleteWebhookReq.customDELETE().then(function(resp) { + $scope.webhooks.splice($scope.webhooks.indexOf(webhook), 1); + }); + }; } function UserAdminCtrl($scope, $timeout, $location, Restangular, PlanService, UserService, KeyService, $routeParams) { diff --git a/static/partials/repo-admin.html b/static/partials/repo-admin.html index ada422d74..e0846a6a5 100644 --- a/static/partials/repo-admin.html +++ b/static/partials/repo-admin.html @@ -23,6 +23,7 @@
@@ -148,6 +149,46 @@
+ +
+
+ Loading webhooks: +
+ +
+
+ + + + + + + + + + + + + + + + + + +
Webhook URL
{{ webhook.parameters.url }} + + + + +
+ + + +
+
+
+
+
diff --git a/test/data/test.db b/test/data/test.db index d35f34afe8ac55fb1ec13452d0b6cf95d409ba99..6a2cb0c869049a5802a332d49c5cb6c7124f7aea 100644 GIT binary patch delta 963 zcmbu+O>YuG7zc0$u&6cB#+s@`vyy17u?q`3ER?7Py1>FNurENNYRkeFwk)s(wzl?HGhGBcU~Gs)cfcHqu~kq6GP zg2iHy(fl*6J-qA#g%?Y^L0I&6`BW*IW4N~0;P`g0v8vNb!OKSRQZO;^^{nM#`5aGkUKh1R_d6NQj9*rQ7p2y+Wg^d3+VTh_4oxr8-&k72+)pUx|m^(XvsGDikcN z@{P@=ITgA9@gSSkm{LWrZfMDP3395T&_+$vy>qQ5F4U-c+P&6P!|OG^yHQW*ftuSV zn(s0v&Bq}pOtqA5mTOjw7_%Y=3@IhmDW5_6jV@HHtwNkt4Xx+Sb2(}*&vdKHd`yn1 zgD;_1j}|gSF(JX22L_|LKrrTEgmeT(B%YZIL`jm)Q#_pr^I=BJv!!GV@???Dksg-g zQZVWDQ_P6hL-?i%Vw!*$LCuiljEBN07$k$#VDIA_$L#+$*#10v5|kh6;{)v56C1xY zi~f2sgt$Q=u6q#+(}==*3`=1w4^zE?!?lce*32` zER){Pc3~G?e@~{i@>d)aPA9l)>y>3q8QvWhX81ZO9AWAG1oJ&MIr2Ng41Yaie&3Cp o*2|r8Q|T$4t_zdsc?nBr(9E&y)Q)@>JOj_|<41Pv82GX96a5As2LJ#7 delta 685 zcmbu+Pfycu7zglm1ynFm5)K%mnFlo(*xGKtw%a_=c4hs?`gdD9)Une2DU<@68w@TS zJwkTaLB046bTQ+IS1(>n3^!kZFMxvy{y6vwe3Iw$y?vj+v9v>y2VbO?$mvjM9h>?~ziQ=V;NXwR&7v(4Fp^ z1Ah=^o`Jn1pHlTWlkfp+9I3KOiuJ>K3)^P$@h%H&+u*x_?$_9Ype8Ynb4ZaR2H!Hz z0p-X7pEHw34T`Y4iN09e1?_HYRZr)|!*tjp`eg;