Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: add UI to delete alerts #1119

Merged
merged 2 commits into from
Jun 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions rd_ui/app/scripts/controllers/alerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@

if ($scope.alertId === "new") {
$scope.alert = new Alert({options: {}});
$scope.canEdit = true;
} else {
$scope.alert = Alert.get({id: $scope.alertId}, function(alert) {
$scope.onQuerySelected(new Query($scope.alert.query));
});
$scope.canEdit = currentUser.canEdit($scope.alert);
}

$scope.ops = ['greater than', 'less than', 'equals'];
Expand Down Expand Up @@ -110,6 +112,15 @@
});
};

$scope.delete = function() {
$scope.alert.$delete(function() {
$location.path('/alerts');
growl.addSuccessMessage("Alert deleted.");
}, function() {
growl.addErrorMessage("Failed deleting alert.");
});
}

};

angular.module('redash.directives').directive('alertSubscriptions', ['$q', '$sce', 'AlertSubscription', 'Destination', 'growl', function ($q, $sce, AlertSubscription, Destination, growl) {
Expand Down
19 changes: 10 additions & 9 deletions rd_ui/app/views/alerts/edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
<div class="container">
<div class="row bg-white p-10">
<div class="col-md-8">
<form name="alertForm" ng-submit="saveChanges()" class="form">
<form name="alertForm" class="form">
<div class="form-group">
<label>Query</label>
<ui-select ng-model="alert.query" reset-search-input="false" on-select="onQuerySelected($item)">
<ui-select ng-model="alert.query" reset-search-input="false" on-select="onQuerySelected($item)" ng-disabled="!canEdit">
<ui-select-match placeholder="Search a query by name">{{$select.selected.name}}</ui-select-match>
<ui-select-choices repeat="q in queries"
refresh="searchQueries($select.search)"
Expand All @@ -22,15 +22,15 @@

<div class="form-group" ng-show="selectedQuery">
<label>Name</label>
<input type="string" placeholder="{{getDefaultName()}}" class="form-control" ng-model="alert.name">
<input type="string" placeholder="{{getDefaultName()}}" class="form-control" ng-model="alert.name" ng-disabled="!canEdit">
</div>

<div ng-show="queryResult" class="form-horizontal">
<div class="form-group">
<label class="control-label col-md-2">Value column</label>
<div class="col-md-4">
<select ng-options="name for name in queryResult.getColumnNames()" ng-model="alert.options.column"
class="form-control"></select>
class="form-control" ng-disabled="!canEdit"></select>
</div>
<label class="control-label col-md-2">Value</label>
<div class="col-md-4">
Expand All @@ -40,24 +40,25 @@
<div class="form-group">
<label class="control-label col-md-2">Op</label>
<div class="col-md-4">
<select ng-options="name for name in ops" ng-model="alert.options.op" class="form-control"></select>
<select ng-options="name for name in ops" ng-model="alert.options.op" class="form-control" ng-disabled="!canEdit"></select>
</div>
<label class="control-label col-md-2">Reference</label>
<div class="col-md-4">
<input type="number" step="any" class="form-control" ng-model="alert.options.value" placeholder="reference value"
<input type="number" step="any" class="form-control" ng-model="alert.options.value" placeholder="reference value" ng-disabled="!canEdit"
required/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2">Rearm seconds</label>
<div class="col-md-4">
<input type="number" class="form-control" ng-model="alert.rearm"/>
<input type="number" class="form-control" ng-model="alert.rearm" ng-disabled="!canEdit"/>
</div>
</div>
</div>

<div class="form-group">
<button class="btn btn-primary" ng-disabled="!alertForm.$valid">Save</button>
<div class="form-group" ng-if="canEdit">
<button class="btn btn-primary" ng-disabled="!alertForm.$valid" ng-click="saveChanges()">Save</button>
<button class="btn btn-danger" ng-if="alert.id" ng-click="delete()">Delete</button>
</div>
</form>
</div>
Expand Down
5 changes: 5 additions & 0 deletions redash/handlers/alerts.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ def post(self, alert_id):

return alert.to_dict()

def delete(self, alert_id):
alert = get_object_or_404(models.Alert.get_by_id_and_org, alert_id, self.current_org)
require_admin_or_owner(alert.user.id)
alert.delete_instance(recursive=True)


class AlertListResource(BaseResource):
def post(self):
Expand Down
3 changes: 2 additions & 1 deletion tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ def create_alert(self, **kwargs):

def create_alert_subscription(self, **kwargs):
args = {
'user': self.user
'user': self.user,
'alert': self.create_alert()
}

args.update(**kwargs)
Expand Down
35 changes: 31 additions & 4 deletions tests/handlers/test_alerts.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
from tests import BaseTestCase
from tests.factories import org_factory
from tests.handlers import authenticated_user, json_request
from redash.wsgi import app
from redash.models import AlertSubscription
from redash.models import AlertSubscription, Alert


class TestAlertResourceGet(BaseTestCase):
Expand Down Expand Up @@ -30,6 +27,36 @@ def test_returns_404_if_admin_from_another_org(self):
self.assertEqual(rv.status_code, 404)


class TestAlertResourceDelete(BaseTestCase):
def test_removes_alert_and_subscriptions(self):
subscription = self.factory.create_alert_subscription()
alert = subscription.alert

rv = self.make_request('delete', "/api/alerts/{}".format(alert.id))
self.assertEqual(rv.status_code, 200)

self.assertRaises(Alert.DoesNotExist, Alert.get_by_id, subscription.alert.id)
self.assertRaises(AlertSubscription.DoesNotExist, AlertSubscription.get_by_id, subscription.id)

def test_returns_403_if_not_allowed(self):
alert = self.factory.create_alert()

user = self.factory.create_user()
rv = self.make_request('delete', "/api/alerts/{}".format(alert.id), user=user)
self.assertEqual(rv.status_code, 403)

rv = self.make_request('delete', "/api/alerts/{}".format(alert.id), user=self.factory.create_admin())
self.assertEqual(rv.status_code, 200)

def test_returns_404_for_unauthorized_users(self):
alert = self.factory.create_alert()

second_org = self.factory.create_org()
second_org_admin = self.factory.create_admin(org=second_org)
rv = self.make_request('delete', "/api/alerts/{}".format(alert.id), user=second_org_admin)
self.assertEqual(rv.status_code, 404)


class TestAlertListPost(BaseTestCase):
def test_returns_200_if_has_access_to_query(self):
query = self.factory.create_query()
Expand Down