Skip to content

Commit

Permalink
gh-886 Add audit-trail support for Streams
Browse files Browse the repository at this point in the history
  • Loading branch information
ghillert authored and oodamien committed Sep 13, 2018
1 parent 6c267de commit 394af23
Show file tree
Hide file tree
Showing 24 changed files with 1,601 additions and 0 deletions.
5 changes: 5 additions & 0 deletions ui/proxy.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
"secure": false,
"logLevel": "debug"
},
"/audit-records" : {
"target": "http://localhost:9393/",
"secure": false,
"logLevel": "debug"
},
"/authenticate" : {
"target": "http://localhost:9393/",
"secure": false,
Expand Down
2 changes: 2 additions & 0 deletions ui/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { SharedAboutService } from './shared/services/shared-about.service';
import { LayoutModule } from './layout/layout.module';
import { LogoComponent } from './layout/logo/logo.component';
import { AuditRecordModule } from './audit/audit-record.module';

/**
* Executed when the app starts up. Will load the security
Expand Down Expand Up @@ -48,6 +49,7 @@ export function init(authService: AuthService, sharedAboutService: SharedAboutSe
AboutModule,
AnalyticsModule,
AppsModule,
AuditRecordModule,
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<app-page id="audit-record-details-list">

<app-page-head>
<app-page-head-back [defaultUrl]="'/audit-records'" [isNotRegex]="'^(\/audit-records\/)'"></app-page-head-back>
<app-page-head-title>Audit Records Details (<strong>{{ auditRecord.auditRecordId }}</strong>)</app-page-head-title>
</app-page-head>


<div dataflowLayoutType type="large">

<div class="row audit-summary-row">
<div class="col-md-3">
<strong>Id:</strong>
</div>
<div class="col-md-21">
{{ auditRecord.auditRecordId }}
</div>
</div>
<div class="row audit-summary-row">
<div class="col-md-3">
<strong>Created On:</strong>
</div>
<div class="col-md-21">
{{ auditRecord.createdOn | dataflowDateTime }}
</div>
</div>
<div class="row audit-summary-row">
<div class="col-md-3">
<strong>Operation:</strong>
</div>
<div class="col-md-21">
<app-audit-record-operation [auditRecord]="auditRecord"></app-audit-record-operation>
</div>
</div>
<div class="row audit-summary-row">
<div class="col-md-3">
<strong>Action:</strong>
</div>
<div class="col-md-21">
<app-audit-record-action [auditRecord]="auditRecord"></app-audit-record-action>
</div>
</div>
<div class="row audit-summary-row">
<div class="col-md-3">
<strong>Correlation Id:</strong>
</div>
<div class="col-md-21">
<strong>{{ auditRecord.correlationId }}</strong>
</div>
</div>
<div class="row audit-summary-row">
<div class="col-md-3">
<strong>Created By:</strong>
</div>
<div class="col-md-21">
{{ auditRecord.createdBy ? auditRecord.createdBy : 'N/A' }}
</div>
</div>
<div class="row audit-summary-row">
<div class="col-md-3">
<strong>Server Host:</strong>
</div>
<div class="col-md-21">
{{ auditRecord.serverHost }}
</div>
</div>
<div class="row audit-summary-row">
<div class="col-md-3">
<strong>Data:</strong>
</div>
<div class="col-md-21">
<pre class="audit-pre">{{ auditRecord.auditData | json }}</pre>
</div>
</div>

</div>

</app-page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { BsDropdownModule, BsModalService, ModalModule, PopoverModule, TooltipModule } from 'ngx-bootstrap';
import { AuditRecordService } from '../audit-record.service';
import { MockNotificationService } from '../../tests/mocks/notification';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { AuditRecordDetailsComponent } from './audit-record-details.component';
import { RolesDirective } from '../../auth/directives/roles.directive';
import { ActivatedRoute, Params } from '@angular/router';
import { MockAuthService } from '../../tests/mocks/auth';
import { AuthService } from '../../auth/auth.service';
import { SortComponent } from '../../shared/components/sort/sort.component';
import { OrderByPipe } from '../../shared/pipes/orderby.pipe';
import { BusyService } from '../../shared/services/busy.service';
import { RoutingStateService } from '../../shared/services/routing-state.service';
import { MockRoutingStateService } from '../../tests/mocks/routing-state';
import { NotificationService } from '../../shared/services/notification.service';
import { LoggerService } from '../../shared/services/logger.service';
import { DATAFLOW_PAGE } from 'src/app/shared/components/page/page.component';
import { DATAFLOW_LIST } from 'src/app/shared/components/list/list.component';
import { PagerComponent } from '../../shared/components/pager/pager.component';
import { NgxPaginationModule } from 'ngx-pagination/dist/ngx-pagination';
import { MockAuditRecordService } from '../../tests/mocks/audit';
import { Observable } from 'rxjs';
import { AuditRecordActionComponent } from '../components/audit-record-action/audit-record-action.component';
import { AuditRecordOperationComponent } from '../components/audit-record-operation/audit-record-operation.component';
import { DataflowDateTimePipe } from '../../shared/pipes/dataflow-date-time.pipe';

/**
* Test {@link AuditRecordDetailsComponent}.
*
* @author Gunnar Hillert
*/
describe('AuditRecordDetailsComponent', () => {
let component: AuditRecordDetailsComponent;
let fixture: ComponentFixture<AuditRecordDetailsComponent>;
const notificationService = new MockNotificationService();
const auditRecordService = new MockAuditRecordService();
const authService = new MockAuthService();

const routingStateService = new MockRoutingStateService();
const loggerService = new LoggerService();

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AuditRecordDetailsComponent,
SortComponent,
OrderByPipe,
RolesDirective,
DATAFLOW_PAGE,
DATAFLOW_LIST,
PagerComponent,
AuditRecordActionComponent,
AuditRecordOperationComponent,
DataflowDateTimePipe
],
imports: [
ModalModule.forRoot(),
PopoverModule.forRoot(),
TooltipModule.forRoot(),
BsDropdownModule.forRoot(),
NgxPaginationModule,
ReactiveFormsModule,
FormsModule,
RouterTestingModule.withRoutes([])
],
providers: [
{ provide: AuditRecordService, useValue: auditRecordService },
{ provide: AuthService, useValue: authService },
{ provide: ActivatedRoute, useValue: {
params: Observable.of({ auditRecordId: 12347 })
} },
BsModalService,
{ provide: BusyService, useValue: new BusyService() },
{ provide: RoutingStateService, useValue: routingStateService },
{ provide: NotificationService, useValue: notificationService },
{ provide: LoggerService, useValue: loggerService }
]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(AuditRecordDetailsComponent);
component = fixture.componentInstance;
notificationService.clearAll();
});

it('should be created', () => {
fixture.detectChanges();
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { AuditRecordService } from '../audit-record.service';
import { Subject } from 'rxjs/Subject';
import { takeUntil } from 'rxjs/operators';
import { BusyService } from '../../shared/services/busy.service';
import { RoutingStateService } from '../../shared/services/routing-state.service';
import { NotificationService } from '../../shared/services/notification.service';
import { LoggerService } from '../../shared/services/logger.service';
import { HttpAppError, AppError } from '../../shared/model/error.model';
import { AuditRecord } from '../../shared/model/audit-record.model';

/**
* Provides details for an AuditRecord.
*
* @author Gunnar Hillert
*/
@Component({
selector: 'app-details',
styleUrls: ['./styles.scss'],
templateUrl: './audit-record-details.component.html'
})
export class AuditRecordDetailsComponent implements OnInit, OnDestroy {

/**
* Busy Subscriptions
*/
private ngUnsubscribe$: Subject<any> = new Subject();

/**
* AuditRecord
*/
auditRecord: AuditRecord;

/**
* Constructor
*
* @param {AuditRecordService} auditRecordService
* @param {NotificationService} notificationService
* @param {ActivatedRoute} route
* @param {RoutingStateService} routingStateService
* @param {BusyService} busyService
* @param {LoggerService} loggerService
*/
constructor(private auditRecordService: AuditRecordService,
private notificationService: NotificationService,
private route: ActivatedRoute,
private routingStateService: RoutingStateService,
private busyService: BusyService,
private loggerService: LoggerService) {
}

/**
* Init
*/
ngOnInit() {
this.loggerService.log('Audit Record Details');

this.route.params
.subscribe(params => {
this.auditRecord = new AuditRecord();
this.auditRecord.auditRecordId = params.auditRecordId as number;
this.refresh();
});
}

/**
* Will cleanup any {@link Subscription}s to prevent
* memory leaks.
*/
ngOnDestroy() {
this.ngUnsubscribe$.next();
this.ngUnsubscribe$.complete();
}

/**
* Refresh page, load the current version informations
*/
refresh() {
this.loadAuditRecordDetails();
}

/**
* Used to load properties
*/
loadAuditRecordDetails() {
this.loggerService.log('Retrieving Audit Record details for id ' + this.auditRecord.auditRecordId + '.');
const busy = this.auditRecordService.getAuditRecordDetails(this.auditRecord.auditRecordId)
.pipe(takeUntil(this.ngUnsubscribe$))
.subscribe((auditRecord: AuditRecord) => {
this.auditRecord = auditRecord;
},
error => {
if (HttpAppError.is404(error)) {
this.cancel();
}
this.notificationService.error(AppError.is(error) ? error.getMessage() : error);
});

this.busyService.addSubscription(busy);
}

/**
* Back action
* Navigate to the previous URL or /audit-records
*/
cancel() {
this.routingStateService.back('/audit-records', /^(\/audit-records\/)/);
}
}
11 changes: 11 additions & 0 deletions ui/src/app/audit/audit-record-details/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

.audit-summary-row {
padding-top: 1rem;
padding-bottom: 0.3rem;
}

pre.audit-pre {
font-size: 12px;
border: 1px solid #dfe5e8;
background: #F5F6F7;
}
33 changes: 33 additions & 0 deletions ui/src/app/audit/audit-record-routing.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuditRecordComponent } from './audit-record/audit-record.component';
import { AuditRecordDetailsComponent } from './audit-record-details/audit-record-details.component';
import { AuthGuard } from '../auth/support/auth.guard';

const appsRoutes: Routes = [
{
path: 'audit-records',
canActivate: [AuthGuard],
data: {
authenticate: true,
roles: ['ROLE_VIEW']
},
children: [
{
path: '',
component: AuditRecordComponent,
},
{
path: ':auditRecordId',
component: AuditRecordDetailsComponent
}
]
}
];

@NgModule({
imports: [RouterModule.forChild(appsRoutes)],
exports: [RouterModule]
})
export class AuditRecordRoutingModule {
}
Loading

0 comments on commit 394af23

Please sign in to comment.