Skip to content

Commit

Permalink
Add view for auditevents enpoint
Browse files Browse the repository at this point in the history
closes #386
  • Loading branch information
joshiste committed Jan 15, 2017
1 parent 17d7699 commit 1dc3d9c
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 9 deletions.
@@ -0,0 +1,18 @@
<div class="container">
<div class="alert alert-error" ng-if="error">
<b>Error:</b> {{ error }}
</div>
<form class="form-search">
<input placeholder="Principal" class="input-large search-query" type="search" ng-model="filter.principal" />
<input placeholder="Type" class="input-large search-query" type="search" ng-model="filter.type" />
<div class="input-append input-append">
<input placeholder="After" class="input-large search-query" type="datetime-local" ng-model="filter.after" />
<button title="search" class="btn" ng-click="search()"><i class="fa fa-search"></i></button>
</div>
</form>
<ul class="timeline">
<li ng-repeat="event in auditevents">
<sba-auditevent value="event" filter-callback="setFilter"></sba-auditevent>
</li>
</ul>
</div>
@@ -0,0 +1,63 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';

module.exports = function ($scope, $http, application) {
'ngInject';
$scope.auditevents = [];
$scope.filter = { principal: null, type: null, after: null };

$scope.setFilter = function (key, value) {
$scope.filter[key] = value;
$scope.search();
};

var trimToNull = function (s) {
if (s !== null) {
s = s.trim();
if (s === '') {
s = null;
}
}
return s;
};

var convert = function (d) {
if (d === null) {
return d;
}
return d.toISOString().replace(/Z$/, '+0000').replace(/\.\d{3}\+/, '+');
};

$scope.search = function () {
$http({
url: 'api/applications/' + application.id + '/auditevents',
method: 'GET',
params: {
principal: trimToNull($scope.filter.principal),
type: trimToNull($scope.filter.type),
after: convert($scope.filter.after)
}
}).then(function (response) {
$scope.auditevents = response.data.events;
$scope.error = null;
}).catch(function (response) {
$scope.error = response.data;
});
};

$scope.search();
};
@@ -0,0 +1,70 @@
.auditevent {
position: relative;
width: 100%;
display: inline-block;
left: 15px;
padding-left: 5px;
}

.auditevent .header {
cursor: pointer;
}
.auditevent .time {
position: absolute;
left: -120px;
margin-left: -25px;
display: inline-block;
vertical-align: middle;
text-align: right;
width: 120px;
}

.auditevent .add-to-filter {
color: #5fa134;
position: absolute;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
cursor: pointer;
border: 0;
padding: 0;
box-shadow: none;
background: none;
opacity: 0;
}

.auditevent .title:hover .add-to-filter,
.auditevent .add-to-filter:hover {
opacity: 100;
}

.auditevent .header:before {
box-sizing: border-box;
content: ' ';
display: block;
width: 20px;
height: 20px;
background: #fff;
border-radius: 10px;
border: 4px solid #999999;
z-index: 10;
position: absolute;
left: -6px;
margin-left: -15px;
}

.auditevent .header:hover:before {
background: #ccc;
}

.auditevent.failure .header:before {
border-color: #b30000;
}

.auditevent.success .header:before {
border-color: #6db33f;
}

.auditevent.unknown .header:before {
border-color: #999999;
}
@@ -0,0 +1,50 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, softwareÍ
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';

require('./auditevent.css');

module.exports = {
bindings: {
auditevent: '<value',
filterCallback: '&filterCallback'
},
controller: function () {
var ctrl = this;
ctrl.show = false;
ctrl.toggle = function () {
ctrl.show = !ctrl.show;
};
ctrl.filterPrincipal = function (event) {
ctrl.filterCallback()('principal', ctrl.auditevent.principal);
event.stopPropagation();
};
ctrl.filterType = function (event) {
ctrl.filterCallback()('type', ctrl.auditevent.type);
event.stopPropagation();
};
ctrl.getStatusClass = function () {
if (/success/i.test(ctrl.auditevent.type)) {
return 'success';
} if (/failure/i.test(ctrl.auditevent.type) || /denied/i.test(ctrl.auditevent.type)) {
return 'failure';
} else {
return 'unknown';
}
};
},
template: require('./auditevent.tpl.html')
};
@@ -0,0 +1,10 @@
<div class="auditevent" ng-class="$ctrl.getStatusClass()">
<div class="header" ng-click="$ctrl.toggle()">
<div class="time">{{$ctrl.auditevent.timestamp | date:'HH:mm:ss.sss'}}<br>
<small class="muted" ng-bind="$ctrl.event.timestamp | date:'dd.MM.yyyy'"></small>
</div>
<span class="title">{{$ctrl.auditevent.principal}}<button class="add-to-filter" ng-click="$ctrl.filterPrincipal($event)"><i class="fa fa-search-plus"></i></button></span>
<span class="title muted"> - {{$ctrl.auditevent.type}}<button class="add-to-filter" ng-click="$ctrl.filterType($event)"><i class="fa fa-search-plus"></i></button></span>
</div>
<pre ng-show="$ctrl.show" ng-bind="$ctrl.auditevent | json"></pre>
</div>
@@ -0,0 +1,47 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';

var angular = require('angular');

var module = angular.module('sba-applications-auditevents', ['sba-applications']);
global.sbaModules.push(module.name);

module.controller('auditeventsCtrl', require('./auditeventsCtrl.js'));
module.component('sbaAuditevent', require('./components/auditevent.js'));

module.config(function ($stateProvider) {
$stateProvider.state('applications.auditevents', {
url: '/auditevents',
templateUrl: 'applications-auditevents/auditevents.html',
controller: 'auditeventsCtrl'
});
});

module.run(function (ApplicationViews, $sce, $http) {
ApplicationViews.register({
order: 55,
title: $sce.trustAsHtml('<i class="fa fa-user-circle-o fa-fw"></i>Audit'),
state: 'applications.auditevents',
show: function (application) {
return $http.head('api/applications/' + application.id + '/auditevents').then(function () {
return true;
}).catch(function () {
return false;
});
}
});
});
Expand Up @@ -4,8 +4,12 @@
display: inline-block;
left: 15px;
padding-left: 5px;
}

.trace-event .header {
cursor: pointer;
}

.trace-event .time {
position: absolute;
left: -120px;
Expand Down
@@ -1,9 +1,11 @@
<div class="trace-event" ng-class="$ctrl.getStatusClass()" ng-click="$ctrl.toggle()">
<div class="time">{{$ctrl.trace.timestamp | date:'HH:mm:ss.sss'}}
<br/><small class="muted">{{$ctrl.trace.timestamp | date:'dd.MM.yyyy'}}</small></div>
<div class="title">
<span class="status">{{$ctrl.trace.info.headers.response.status || '???' }}</span>
<span class="muted"> - {{$ctrl.trace.info.method}}</span> {{$ctrl.trace.info.path}}
<div class="trace-event" ng-class="$ctrl.getStatusClass()">
<div class="header" ng-click="$ctrl.toggle()">
<div class="time">{{$ctrl.trace.timestamp | date:'HH:mm:ss.sss'}}
<br/><small class="muted">{{$ctrl.trace.timestamp | date:'dd.MM.yyyy'}}</small></div>
<div class="title">
<span class="status">{{$ctrl.trace.info.headers.response.status || '???' }}</span>
<span class="muted"> - {{$ctrl.trace.info.method}}</span> {{$ctrl.trace.info.path}}
</div>
</div>
<pre ng-show="$ctrl.show">{{$ctrl.trace.info | json}}</pre>
</div>
<pre ng-show="$ctrl.show">{{$ctrl.trace.info | json }}</pre>
</div>
Expand Up @@ -71,7 +71,7 @@ public static class RoutesProperties {
* Endpoints to be proxified by spring boot admin.
*/
private String[] endpoints = { "env", "metrics", "trace", "dump", "jolokia", "info",
"trace", "logfile", "refresh", "flyway", "liquibase", "heapdump", "loggers" };
"trace", "logfile", "refresh", "flyway", "liquibase", "heapdump", "loggers", "auditevents" };

public String[] getEndpoints() {
return endpoints;
Expand Down

0 comments on commit 1dc3d9c

Please sign in to comment.