Skip to content
This repository was archived by the owner on May 14, 2025. It is now read-only.

Commit 394af23

Browse files
ghillertoodamien
authored andcommitted
gh-886 Add audit-trail support for Streams
1 parent 6c267de commit 394af23

24 files changed

+1601
-0
lines changed

ui/proxy.conf.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
"secure": false,
55
"logLevel": "debug"
66
},
7+
"/audit-records" : {
8+
"target": "http://localhost:9393/",
9+
"secure": false,
10+
"logLevel": "debug"
11+
},
712
"/authenticate" : {
813
"target": "http://localhost:9393/",
914
"secure": false,

ui/src/app/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
2121
import { SharedAboutService } from './shared/services/shared-about.service';
2222
import { LayoutModule } from './layout/layout.module';
2323
import { LogoComponent } from './layout/logo/logo.component';
24+
import { AuditRecordModule } from './audit/audit-record.module';
2425

2526
/**
2627
* Executed when the app starts up. Will load the security
@@ -48,6 +49,7 @@ export function init(authService: AuthService, sharedAboutService: SharedAboutSe
4849
AboutModule,
4950
AnalyticsModule,
5051
AppsModule,
52+
AuditRecordModule,
5153
BrowserModule,
5254
AppRoutingModule,
5355
BrowserAnimationsModule,
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<app-page id="audit-record-details-list">
2+
3+
<app-page-head>
4+
<app-page-head-back [defaultUrl]="'/audit-records'" [isNotRegex]="'^(\/audit-records\/)'"></app-page-head-back>
5+
<app-page-head-title>Audit Records Details (<strong>{{ auditRecord.auditRecordId }}</strong>)</app-page-head-title>
6+
</app-page-head>
7+
8+
9+
<div dataflowLayoutType type="large">
10+
11+
<div class="row audit-summary-row">
12+
<div class="col-md-3">
13+
<strong>Id:</strong>
14+
</div>
15+
<div class="col-md-21">
16+
{{ auditRecord.auditRecordId }}
17+
</div>
18+
</div>
19+
<div class="row audit-summary-row">
20+
<div class="col-md-3">
21+
<strong>Created On:</strong>
22+
</div>
23+
<div class="col-md-21">
24+
{{ auditRecord.createdOn | dataflowDateTime }}
25+
</div>
26+
</div>
27+
<div class="row audit-summary-row">
28+
<div class="col-md-3">
29+
<strong>Operation:</strong>
30+
</div>
31+
<div class="col-md-21">
32+
<app-audit-record-operation [auditRecord]="auditRecord"></app-audit-record-operation>
33+
</div>
34+
</div>
35+
<div class="row audit-summary-row">
36+
<div class="col-md-3">
37+
<strong>Action:</strong>
38+
</div>
39+
<div class="col-md-21">
40+
<app-audit-record-action [auditRecord]="auditRecord"></app-audit-record-action>
41+
</div>
42+
</div>
43+
<div class="row audit-summary-row">
44+
<div class="col-md-3">
45+
<strong>Correlation Id:</strong>
46+
</div>
47+
<div class="col-md-21">
48+
<strong>{{ auditRecord.correlationId }}</strong>
49+
</div>
50+
</div>
51+
<div class="row audit-summary-row">
52+
<div class="col-md-3">
53+
<strong>Created By:</strong>
54+
</div>
55+
<div class="col-md-21">
56+
{{ auditRecord.createdBy ? auditRecord.createdBy : 'N/A' }}
57+
</div>
58+
</div>
59+
<div class="row audit-summary-row">
60+
<div class="col-md-3">
61+
<strong>Server Host:</strong>
62+
</div>
63+
<div class="col-md-21">
64+
{{ auditRecord.serverHost }}
65+
</div>
66+
</div>
67+
<div class="row audit-summary-row">
68+
<div class="col-md-3">
69+
<strong>Data:</strong>
70+
</div>
71+
<div class="col-md-21">
72+
<pre class="audit-pre">{{ auditRecord.auditData | json }}</pre>
73+
</div>
74+
</div>
75+
76+
</div>
77+
78+
</app-page>
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { RouterTestingModule } from '@angular/router/testing';
3+
import { BsDropdownModule, BsModalService, ModalModule, PopoverModule, TooltipModule } from 'ngx-bootstrap';
4+
import { AuditRecordService } from '../audit-record.service';
5+
import { MockNotificationService } from '../../tests/mocks/notification';
6+
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
7+
import { AuditRecordDetailsComponent } from './audit-record-details.component';
8+
import { RolesDirective } from '../../auth/directives/roles.directive';
9+
import { ActivatedRoute, Params } from '@angular/router';
10+
import { MockAuthService } from '../../tests/mocks/auth';
11+
import { AuthService } from '../../auth/auth.service';
12+
import { SortComponent } from '../../shared/components/sort/sort.component';
13+
import { OrderByPipe } from '../../shared/pipes/orderby.pipe';
14+
import { BusyService } from '../../shared/services/busy.service';
15+
import { RoutingStateService } from '../../shared/services/routing-state.service';
16+
import { MockRoutingStateService } from '../../tests/mocks/routing-state';
17+
import { NotificationService } from '../../shared/services/notification.service';
18+
import { LoggerService } from '../../shared/services/logger.service';
19+
import { DATAFLOW_PAGE } from 'src/app/shared/components/page/page.component';
20+
import { DATAFLOW_LIST } from 'src/app/shared/components/list/list.component';
21+
import { PagerComponent } from '../../shared/components/pager/pager.component';
22+
import { NgxPaginationModule } from 'ngx-pagination/dist/ngx-pagination';
23+
import { MockAuditRecordService } from '../../tests/mocks/audit';
24+
import { Observable } from 'rxjs';
25+
import { AuditRecordActionComponent } from '../components/audit-record-action/audit-record-action.component';
26+
import { AuditRecordOperationComponent } from '../components/audit-record-operation/audit-record-operation.component';
27+
import { DataflowDateTimePipe } from '../../shared/pipes/dataflow-date-time.pipe';
28+
29+
/**
30+
* Test {@link AuditRecordDetailsComponent}.
31+
*
32+
* @author Gunnar Hillert
33+
*/
34+
describe('AuditRecordDetailsComponent', () => {
35+
let component: AuditRecordDetailsComponent;
36+
let fixture: ComponentFixture<AuditRecordDetailsComponent>;
37+
const notificationService = new MockNotificationService();
38+
const auditRecordService = new MockAuditRecordService();
39+
const authService = new MockAuthService();
40+
41+
const routingStateService = new MockRoutingStateService();
42+
const loggerService = new LoggerService();
43+
44+
beforeEach(async(() => {
45+
TestBed.configureTestingModule({
46+
declarations: [
47+
AuditRecordDetailsComponent,
48+
SortComponent,
49+
OrderByPipe,
50+
RolesDirective,
51+
DATAFLOW_PAGE,
52+
DATAFLOW_LIST,
53+
PagerComponent,
54+
AuditRecordActionComponent,
55+
AuditRecordOperationComponent,
56+
DataflowDateTimePipe
57+
],
58+
imports: [
59+
ModalModule.forRoot(),
60+
PopoverModule.forRoot(),
61+
TooltipModule.forRoot(),
62+
BsDropdownModule.forRoot(),
63+
NgxPaginationModule,
64+
ReactiveFormsModule,
65+
FormsModule,
66+
RouterTestingModule.withRoutes([])
67+
],
68+
providers: [
69+
{ provide: AuditRecordService, useValue: auditRecordService },
70+
{ provide: AuthService, useValue: authService },
71+
{ provide: ActivatedRoute, useValue: {
72+
params: Observable.of({ auditRecordId: 12347 })
73+
} },
74+
BsModalService,
75+
{ provide: BusyService, useValue: new BusyService() },
76+
{ provide: RoutingStateService, useValue: routingStateService },
77+
{ provide: NotificationService, useValue: notificationService },
78+
{ provide: LoggerService, useValue: loggerService }
79+
]
80+
})
81+
.compileComponents();
82+
}));
83+
84+
beforeEach(() => {
85+
fixture = TestBed.createComponent(AuditRecordDetailsComponent);
86+
component = fixture.componentInstance;
87+
notificationService.clearAll();
88+
});
89+
90+
it('should be created', () => {
91+
fixture.detectChanges();
92+
expect(component).toBeTruthy();
93+
});
94+
});
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { Component, OnInit, OnDestroy } from '@angular/core';
2+
import { ActivatedRoute } from '@angular/router';
3+
import { AuditRecordService } from '../audit-record.service';
4+
import { Subject } from 'rxjs/Subject';
5+
import { takeUntil } from 'rxjs/operators';
6+
import { BusyService } from '../../shared/services/busy.service';
7+
import { RoutingStateService } from '../../shared/services/routing-state.service';
8+
import { NotificationService } from '../../shared/services/notification.service';
9+
import { LoggerService } from '../../shared/services/logger.service';
10+
import { HttpAppError, AppError } from '../../shared/model/error.model';
11+
import { AuditRecord } from '../../shared/model/audit-record.model';
12+
13+
/**
14+
* Provides details for an AuditRecord.
15+
*
16+
* @author Gunnar Hillert
17+
*/
18+
@Component({
19+
selector: 'app-details',
20+
styleUrls: ['./styles.scss'],
21+
templateUrl: './audit-record-details.component.html'
22+
})
23+
export class AuditRecordDetailsComponent implements OnInit, OnDestroy {
24+
25+
/**
26+
* Busy Subscriptions
27+
*/
28+
private ngUnsubscribe$: Subject<any> = new Subject();
29+
30+
/**
31+
* AuditRecord
32+
*/
33+
auditRecord: AuditRecord;
34+
35+
/**
36+
* Constructor
37+
*
38+
* @param {AuditRecordService} auditRecordService
39+
* @param {NotificationService} notificationService
40+
* @param {ActivatedRoute} route
41+
* @param {RoutingStateService} routingStateService
42+
* @param {BusyService} busyService
43+
* @param {LoggerService} loggerService
44+
*/
45+
constructor(private auditRecordService: AuditRecordService,
46+
private notificationService: NotificationService,
47+
private route: ActivatedRoute,
48+
private routingStateService: RoutingStateService,
49+
private busyService: BusyService,
50+
private loggerService: LoggerService) {
51+
}
52+
53+
/**
54+
* Init
55+
*/
56+
ngOnInit() {
57+
this.loggerService.log('Audit Record Details');
58+
59+
this.route.params
60+
.subscribe(params => {
61+
this.auditRecord = new AuditRecord();
62+
this.auditRecord.auditRecordId = params.auditRecordId as number;
63+
this.refresh();
64+
});
65+
}
66+
67+
/**
68+
* Will cleanup any {@link Subscription}s to prevent
69+
* memory leaks.
70+
*/
71+
ngOnDestroy() {
72+
this.ngUnsubscribe$.next();
73+
this.ngUnsubscribe$.complete();
74+
}
75+
76+
/**
77+
* Refresh page, load the current version informations
78+
*/
79+
refresh() {
80+
this.loadAuditRecordDetails();
81+
}
82+
83+
/**
84+
* Used to load properties
85+
*/
86+
loadAuditRecordDetails() {
87+
this.loggerService.log('Retrieving Audit Record details for id ' + this.auditRecord.auditRecordId + '.');
88+
const busy = this.auditRecordService.getAuditRecordDetails(this.auditRecord.auditRecordId)
89+
.pipe(takeUntil(this.ngUnsubscribe$))
90+
.subscribe((auditRecord: AuditRecord) => {
91+
this.auditRecord = auditRecord;
92+
},
93+
error => {
94+
if (HttpAppError.is404(error)) {
95+
this.cancel();
96+
}
97+
this.notificationService.error(AppError.is(error) ? error.getMessage() : error);
98+
});
99+
100+
this.busyService.addSubscription(busy);
101+
}
102+
103+
/**
104+
* Back action
105+
* Navigate to the previous URL or /audit-records
106+
*/
107+
cancel() {
108+
this.routingStateService.back('/audit-records', /^(\/audit-records\/)/);
109+
}
110+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
.audit-summary-row {
3+
padding-top: 1rem;
4+
padding-bottom: 0.3rem;
5+
}
6+
7+
pre.audit-pre {
8+
font-size: 12px;
9+
border: 1px solid #dfe5e8;
10+
background: #F5F6F7;
11+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { NgModule } from '@angular/core';
2+
import { Routes, RouterModule } from '@angular/router';
3+
import { AuditRecordComponent } from './audit-record/audit-record.component';
4+
import { AuditRecordDetailsComponent } from './audit-record-details/audit-record-details.component';
5+
import { AuthGuard } from '../auth/support/auth.guard';
6+
7+
const appsRoutes: Routes = [
8+
{
9+
path: 'audit-records',
10+
canActivate: [AuthGuard],
11+
data: {
12+
authenticate: true,
13+
roles: ['ROLE_VIEW']
14+
},
15+
children: [
16+
{
17+
path: '',
18+
component: AuditRecordComponent,
19+
},
20+
{
21+
path: ':auditRecordId',
22+
component: AuditRecordDetailsComponent
23+
}
24+
]
25+
}
26+
];
27+
28+
@NgModule({
29+
imports: [RouterModule.forChild(appsRoutes)],
30+
exports: [RouterModule]
31+
})
32+
export class AuditRecordRoutingModule {
33+
}

0 commit comments

Comments
 (0)