Add View Audit Logs to view/edit user. #330

This commit is contained in:
Korina Cordero 2020-03-10 04:30:19 +00:00
parent 5b167ef680
commit afeb06006d
6 changed files with 204 additions and 64 deletions

View file

@ -21,6 +21,8 @@ access_keys:
label: Super Admin Role
- id: user.profile
label: User Profile
- id: user.logs
label: User Logs
- id: role
label: Role Access
acls:

View file

@ -41,3 +41,13 @@ user_profile_submit:
path: /profile
controller: App\Controller\UserController::profileSubmit
methods: [POST]
user_view_logs_form:
path: /users/{id}/logs
controller: App\Controller\UserController::viewLogsForm
methods: [GET]
user_view_logs:
path: /user/{id}/logs
controller: App\Controller\UserController::getLogs
methods: [POST]

View file

@ -23,12 +23,10 @@ services:
# The best practice is to be explicit about your dependencies anyway.
# influxdb
influxdb_client:
class: InfluxDB\Client
InfluxDB\Client:
arguments: ['%env(INFLUXDB_HOST)%', '%env(INFLUXDB_PORT)%']
influxdb_database:
class: InfluxDB\Database
arguments: ['%env(INFLUXDB_DB)%', '@influxdb_client']
InfluxDB\Database:
arguments: ['%env(INFLUXDB_DB)%', "@InfluxDB\\Client"]
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
@ -270,7 +268,7 @@ services:
App\EventListener\EntityListener:
arguments:
$token_storage: "@security.token_storage"
$log_db: '@influxdb_database'
$log_db: "@InfluxDB\\Database"
$entities: ['App\Entity\User', 'App\Entity\Role', 'App\Entity\Partner']
tags:
- name: 'doctrine.event_listener'

View file

@ -15,6 +15,8 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Catalyst\MenuBundle\Annotation\Menu;
use InfluxDB\Client;
class UserController extends Controller
{
/**
@ -484,4 +486,49 @@ class UserController extends Controller
]);
}
}
/**
* @Menu(selected="user_list")
*/
public function viewLogsForm($id)
{
$this->denyAccessUnlessGranted('user.logs', null, 'No access.');
$params['id'] = $id;
// response
return $this->render('user/log.html.twig', $params);
}
public function getLogs(Client $client, $id)
{
error_log('in getLogs');
// fetch database
// TODO: find way to replace hardcoded db name
$database = $client->selectDB('logging_db');
// query will return a resultset object
$result = $database->query('SELECT * FROM entity_log');
// get the points from the resultset, which is an array
$points = $result->getPoints();
error_log('getLogs count points ' . count($points));
// array has format
/*
$rows = [];
foreach ($points as $point)
{
$row['time'] = $point['time'];
error_log($point['entity_type']);
error_log($point['action']);
} */
return $this->json([
'data' => $points,
]);
}
}

View file

@ -57,6 +57,9 @@
<div class="form-control-feedback hide" data-field="username"></div>
<span class="m-form__help">Unique alias for this user</span>
</div>
<div class="col-lg-6">
<a href="{{ url('user_view_logs_form', {'id':obj.getID()}) }}" class="btn btn-success">View Audit Logs</a>
</div>
</div>
<div class="form-group m-form__group row">
<div class="col-lg-6">
@ -182,72 +185,73 @@
{% endblock %}
{% block scripts %}
<script>
$(function() {
$("#row-form").submit(function(e) {
var form = $(this);
<script>
$(function() {
$("#row-form").submit(function(e) {
var form = $(this);
e.preventDefault();
e.preventDefault();
$.ajax({
method: "POST",
url: form.prop('action'),
data: form.serialize()
}).done(function(response) {
// remove all error classes
removeErrors();
swal({
title: 'Done!',
text: 'Your changes have been saved!',
type: 'success',
onClose: function() {
window.location.href = "{{ url(mode == 'profile' ? 'home' : 'user_list') }}";
}
});
}).fail(function(response) {
if (response.status == 422) {
var errors = response.responseJSON.errors;
var firstfield = false;
$.ajax({
method: "POST",
url: form.prop('action'),
data: form.serialize()
}).done(function(response) {
// remove all error classes
removeErrors();
swal({
title: 'Done!',
text: 'Your changes have been saved!',
type: 'success',
onClose: function() {
window.location.href = "{{ url(mode == 'profile' ? 'home' : 'user_list') }}";
}
});
}).fail(function(response) {
if (response.status == 422) {
var errors = response.responseJSON.errors;
var firstfield = false;
// remove all error classes first
removeErrors();
// remove all error classes first
removeErrors();
// display errors contextually
$.each(errors, function(field, msg) {
var formfield = $("[name='" + field + "']");
var label = $("label[data-field='" + field + "']");
var msgbox = $(".form-control-feedback[data-field='" + field + "']");
// display errors contextually
$.each(errors, function(field, msg) {
var formfield = $("[name='" + field + "']");
var label = $("label[data-field='" + field + "']");
var msgbox = $(".form-control-feedback[data-field='" + field + "']");
// add error classes to bad fields
formfield.addClass('form-control-danger');
label.addClass('has-danger');
msgbox.html(msg).addClass('has-danger').removeClass('hide');
// add error classes to bad fields
formfield.addClass('form-control-danger');
label.addClass('has-danger');
msgbox.html(msg).addClass('has-danger').removeClass('hide');
// check if this field comes first in DOM
var domfield = formfield.get(0);
// check if this field comes first in DOM
var domfield = formfield.get(0);
if (!firstfield || (firstfield && firstfield.compareDocumentPosition(domfield) === 2)) {
firstfield = domfield;
}
});
if (!firstfield || (firstfield && firstfield.compareDocumentPosition(domfield) === 2)) {
firstfield = domfield;
}
});
// focus on first bad field
firstfield.focus();
// focus on first bad field
firstfield.focus();
// scroll to above that field to make it visible
$('html, body').animate({
scrollTop: $(firstfield).offset().top - 200
}, 100);
}
});
});
// scroll to above that field to make it visible
$('html, body').animate({
scrollTop: $(firstfield).offset().top - 200
}, 100);
}
});
});
// remove all error classes
function removeErrors() {
$(".form-control-danger").removeClass('form-control-danger');
$("[data-field]").removeClass('has-danger');
$(".form-control-feedback[data-field]").addClass('hide');
}
});
</script>
// remove all error classes
function removeErrors() {
$(".form-control-danger").removeClass('form-control-danger');
$("[data-field]").removeClass('has-danger');
$(".form-control-feedback[data-field]").addClass('hide');
}
});
</script>
{% endblock %}

View file

@ -0,0 +1,79 @@
{% extends 'base.html.twig' %}
{% block body %}
<!-- BEGIN: Subheader -->
<div class="m-subheader">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title">Audit Logs</h3>
</div>
</div>
</div>
<!-- END: Subheader -->
<div class="m-content">
<!--Begin::Section-->
<div class="row">
<div class="col-xl-12">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__body">
<!--begin: Datatable -->
<div id="data-rows"></div>
<!--end: Datatable -->
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
$(function() {
console.log( {{ id }} );
var options = {
data: {
type: 'remote',
source: {
read: {
url: '{{ url('user_view_logs', {'id': id}) }}',
method: 'POST'
}
},
saveState: {
cookie: false,
webstorage: false
},
},
columns: [
{
field: 'time',
title: 'Time'
},
{
field: 'action',
title: 'Action'
},
{
field: 'content',
title: 'Content'
},
{
field: 'entity_id',
title: 'Entity ID'
},
{
field: 'entity_type',
title: 'Entity Type'
},
{
field: 'user',
title: 'User'
},
],
};
var table = $("#data-rows").mDatatable(options);
});
</script>
{% endblock %}