Skip to content

Commit b837bbb

Browse files
xuelichaoLichao Xue
andauthored
support to audit logs (#21377)
Signed-off-by: Lichao Xue <[email protected]> Co-authored-by: Lichao Xue <[email protected]>
1 parent 4565907 commit b837bbb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1650
-101
lines changed

src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.html

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@
141141
)
142142
}">
143143
<span class="font-style required flex-200"
144-
>{{ 'CLEARANCES.INCLUDED_OPERATIONS' | translate
144+
>{{ 'CLEARANCES.INCLUDED_EVENT_TYPES' | translate
145145
}}<clr-tooltip>
146146
<clr-icon
147147
clrTooltipTrigger
@@ -152,37 +152,35 @@
152152
clrSize="lg"
153153
*clrIfOpen>
154154
<span>{{
155-
'CLEARANCES.INCLUDED_OPERATION_TOOLTIP' | translate
155+
'CLEARANCES.INCLUDED_EVENT_TYPE_TOOLTIP' | translate
156156
}}</span>
157157
</clr-tooltip-content>
158158
</clr-tooltip></span
159159
>
160-
<div
161-
class="clr-control-container clr-control-inline"
162-
[class.clr-error]="!(selectedOperations?.length > 0)">
160+
<div class="clr-control-container">
163161
<div
164-
class="clr-checkbox-wrapper"
165-
*ngFor="let item of operations">
162+
class="clr-checkbox-wrapper float-left"
163+
*ngFor="let item of eventTypes">
166164
<input
167165
type="checkbox"
168-
id="{{ item }}"
169-
name="operations"
170-
value="{{ item }}"
166+
id="{{ item.id }}"
167+
name="eventTypes"
168+
value="{{ item.value }}"
171169
class="clr-checkbox"
172-
(change)="setOperation(item)"
173-
[checked]="hasOperation(item)" />
174-
<label for="{{ item }}" class="clr-control-label">{{
175-
operationsToText(item) | translate
170+
(change)="setEventType(item.value)"
171+
[checked]="hasEventType(item.value)" />
172+
<label for="{{ item.id }}" class="clr-control-label">{{
173+
item.label
176174
}}</label>
177175
</div>
178176
<div
179177
class="clr-subtext-wrapper"
180-
*ngIf="!(selectedOperations?.length > 0)">
178+
*ngIf="!(selectedEventTypes?.length > 0)">
181179
<clr-icon
182180
class="clr-validate-icon"
183181
shape="exclamation-circle"></clr-icon>
184182
<span class="clr-subtext">{{
185-
'CLEARANCES.INCLUDED_OPERATION_ERROR' | translate
183+
'CLEARANCES.INCLUDED_EVENT_TYPE_ERROR' | translate
186184
}}</span>
187185
</div>
188186
</div>
@@ -197,7 +195,7 @@
197195
[disabled]="
198196
disableGC ||
199197
purgeForm.invalid ||
200-
!(selectedOperations?.length > 0)
198+
!(selectedEventTypes?.length > 0)
201199
">
202200
{{ 'CLEARANCES.PURGE_NOW' | translate }}
203201
</button>
@@ -210,7 +208,7 @@
210208
[disabled]="
211209
dryRunOnGoing ||
212210
purgeForm.invalid ||
213-
!(selectedOperations?.length > 0)
211+
!(selectedEventTypes?.length > 0)
214212
">
215213
{{ 'TAG_RETENTION.WHAT_IF_RUN' | translate }}
216214
</button>

src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,8 @@
5151
padding-left: .6rem;
5252
padding-right: .6rem;
5353
}
54+
55+
.float-left {
56+
float:left;
57+
margin-right: 1rem;
58+
}

src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.spec.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
22
import { ErrorHandler } from '../../../../../shared/units/error-handler';
33
import { CronScheduleComponent } from '../../../../../shared/components/cron-schedule';
44
import { CronTooltipComponent } from '../../../../../shared/components/cron-schedule';
5-
import { of } from 'rxjs';
5+
import { delay, of } from 'rxjs';
66
import { SharedTestingModule } from '../../../../../shared/shared.module';
77
import { SetJobComponent } from './set-job.component';
88
import { PurgeService } from 'ng-swagger-gen/services/purge.service';
99
import { NO_ERRORS_SCHEMA } from '@angular/core';
10+
import { AuditlogService } from 'ng-swagger-gen/services';
11+
import { HttpHeaders, HttpResponse } from '@angular/common/http';
1012

1113
describe('GcComponent', () => {
1214
let component: SetJobComponent;
1315
let fixture: ComponentFixture<SetJobComponent>;
1416
let purgeService: PurgeService;
17+
let auditlogService: AuditlogService;
1518
let mockSchedule = [];
1619
const fakedErrorHandler = {
1720
error(error) {
@@ -23,6 +26,29 @@ describe('GcComponent', () => {
2326
};
2427
let spySchedule: jasmine.Spy;
2528
let spyGcNow: jasmine.Spy;
29+
const mockedAuditLogs = [
30+
{
31+
event_type: 'create_artifact',
32+
},
33+
{
34+
event_type: 'delete_artifact',
35+
},
36+
{
37+
event_type: 'pull_artifact',
38+
},
39+
];
40+
const fakedAuditlogService = {
41+
listAuditLogEventTypesResponse() {
42+
return of(
43+
new HttpResponse({
44+
body: mockedAuditLogs,
45+
headers: new HttpHeaders({
46+
'x-total-count': '18',
47+
}),
48+
})
49+
).pipe(delay(0));
50+
},
51+
};
2652
beforeEach(() => {
2753
TestBed.configureTestingModule({
2854
imports: [SharedTestingModule],
@@ -31,22 +57,26 @@ describe('GcComponent', () => {
3157
CronScheduleComponent,
3258
CronTooltipComponent,
3359
],
34-
providers: [{ provide: ErrorHandler, useValue: fakedErrorHandler }],
60+
providers: [
61+
{ provide: ErrorHandler, useValue: fakedErrorHandler },
62+
{ provide: AuditlogService, useValue: fakedAuditlogService },
63+
],
3564
schemas: [NO_ERRORS_SCHEMA],
3665
}).compileComponents();
3766
});
3867

3968
beforeEach(() => {
4069
fixture = TestBed.createComponent(SetJobComponent);
4170
component = fixture.componentInstance;
42-
71+
auditlogService = fixture.debugElement.injector.get(AuditlogService);
4372
purgeService = fixture.debugElement.injector.get(PurgeService);
4473
spySchedule = spyOn(purgeService, 'getPurgeSchedule').and.returnValues(
4574
of(mockSchedule as any)
4675
);
4776
spyGcNow = spyOn(purgeService, 'createPurgeSchedule').and.returnValues(
4877
of(null)
4978
);
79+
component.selectedEventTypes = ['create_artifact'];
5080
fixture.detectChanges();
5181
});
5282
it('should create', () => {

src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.ts

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ import { ExecHistory } from '../../../../../../../ng-swagger-gen/models/exec-his
1010
import {
1111
JOB_STATUS,
1212
REFRESH_STATUS_TIME_DIFFERENCE,
13-
RETENTION_OPERATIONS,
14-
RETENTION_OPERATIONS_I18N_MAP,
13+
RESOURCE_TYPES,
1514
RetentionTimeUnit,
1615
} from '../../clearing-job-interfact';
1716
import { clone } from '../../../../../shared/units/utils';
1817
import { PurgeHistoryComponent } from '../history/purge-history.component';
1918
import { NgForm } from '@angular/forms';
19+
import { AuditlogService } from 'ng-swagger-gen/services';
20+
import { AuditLogEventType } from 'ng-swagger-gen/models';
2021

2122
const ONE_MINUTE: number = 60000;
2223
const ONE_DAY: number = 24;
@@ -30,6 +31,7 @@ const MAX_RETENTION_DAYS: number = 10000;
3031
export class SetJobComponent implements OnInit, OnDestroy {
3132
originCron: OriginCron;
3233
disableGC: boolean = false;
34+
loading: boolean = false;
3335
getLabelCurrent = 'CLEARANCES.SCHEDULE_TO_PURGE';
3436
loadingGcStatus = false;
3537
@ViewChild(CronScheduleComponent)
@@ -43,27 +45,67 @@ export class SetJobComponent implements OnInit, OnDestroy {
4345

4446
retentionTime: number;
4547
retentionUnit: string = RetentionTimeUnit.DAYS;
46-
operations: string[] = clone(RETENTION_OPERATIONS);
47-
selectedOperations: string[] = clone(RETENTION_OPERATIONS);
48+
49+
eventTypes: Record<string, string>[] = [];
50+
selectedEventTypes: string[] = clone([]);
4851
@ViewChild(PurgeHistoryComponent)
4952
purgeHistoryComponent: PurgeHistoryComponent;
5053
@ViewChild('purgeForm')
5154
purgeForm: NgForm;
5255
constructor(
5356
private purgeService: PurgeService,
57+
private logService: AuditlogService,
5458
private errorHandler: ErrorHandler
5559
) {}
5660

5761
ngOnInit() {
5862
this.getCurrentSchedule(true);
5963
this.getStatus();
64+
this.initEventTypes();
6065
}
6166
ngOnDestroy() {
6267
if (this.statusTimeout) {
6368
clearTimeout(this.statusTimeout);
6469
this.statusTimeout = null;
6570
}
6671
}
72+
73+
initEventTypes() {
74+
this.loading = true;
75+
this.logService
76+
.listAuditLogEventTypesResponse()
77+
.pipe(finalize(() => (this.loading = false)))
78+
.subscribe(
79+
response => {
80+
const auditLogEventTypes =
81+
response.body as AuditLogEventType[];
82+
this.eventTypes = [
83+
...auditLogEventTypes
84+
.filter(item =>
85+
RESOURCE_TYPES.includes(item.event_type)
86+
)
87+
.map(event => ({
88+
label:
89+
event.event_type.charAt(0).toUpperCase() +
90+
event.event_type
91+
.slice(1)
92+
.replace(/_/g, ' '),
93+
value: event.event_type,
94+
id: event.event_type,
95+
})),
96+
{
97+
label: 'Other events',
98+
value: 'other',
99+
id: 'other_events',
100+
},
101+
];
102+
},
103+
error => {
104+
this.errorHandler.error(error);
105+
}
106+
);
107+
}
108+
67109
// get the latest non-dry-run execution to get the status
68110
getStatus() {
69111
this.loadingLastCompletedTime = true;
@@ -122,11 +164,11 @@ export class SetJobComponent implements OnInit, OnDestroy {
122164
};
123165
if (purgeHistory && purgeHistory.job_parameters) {
124166
const obj = JSON.parse(purgeHistory.job_parameters);
125-
if (obj?.include_operations) {
126-
this.selectedOperations =
127-
obj?.include_operations?.split(',');
167+
if (obj?.include_event_types) {
168+
this.selectedEventTypes =
169+
obj?.include_event_types?.split(',');
128170
} else {
129-
this.selectedOperations = [];
171+
this.selectedEventTypes = [];
130172
}
131173
if (
132174
obj?.audit_retention_hour > ONE_DAY &&
@@ -140,7 +182,7 @@ export class SetJobComponent implements OnInit, OnDestroy {
140182
}
141183
} else {
142184
this.retentionTime = null;
143-
this.selectedOperations = clone(RETENTION_OPERATIONS);
185+
this.selectedEventTypes = clone([]);
144186
this.retentionUnit = RetentionTimeUnit.DAYS;
145187
}
146188
} else {
@@ -165,7 +207,7 @@ export class SetJobComponent implements OnInit, OnDestroy {
165207
schedule: {
166208
parameters: {
167209
audit_retention_hour: +retentionTime,
168-
include_operations: this.selectedOperations.join(','),
210+
include_event_types: this.selectedEventTypes.join(','),
169211
dry_run: false,
170212
},
171213
schedule: {
@@ -195,7 +237,7 @@ export class SetJobComponent implements OnInit, OnDestroy {
195237
schedule: {
196238
parameters: {
197239
audit_retention_hour: +retentionTime,
198-
include_operations: this.selectedOperations.join(','),
240+
include_event_types: this.selectedEventTypes.join(','),
199241
dry_run: true,
200242
},
201243
schedule: {
@@ -231,8 +273,8 @@ export class SetJobComponent implements OnInit, OnDestroy {
231273
schedule: {
232274
parameters: {
233275
audit_retention_hour: +retentionTime,
234-
include_operations:
235-
this.selectedOperations.join(','),
276+
include_event_types:
277+
this.selectedEventTypes.join(','),
236278
dry_run: false,
237279
},
238280
schedule: {
@@ -259,8 +301,8 @@ export class SetJobComponent implements OnInit, OnDestroy {
259301
schedule: {
260302
parameters: {
261303
audit_retention_hour: +retentionTime,
262-
include_operations:
263-
this.selectedOperations.join(','),
304+
include_event_types:
305+
this.selectedEventTypes.join(','),
264306
dry_run: false,
265307
},
266308
schedule: {
@@ -283,21 +325,16 @@ export class SetJobComponent implements OnInit, OnDestroy {
283325
});
284326
}
285327
}
286-
hasOperation(operation: string): boolean {
287-
return this.selectedOperations?.indexOf(operation) !== -1;
328+
hasEventType(eventType: string): boolean {
329+
return this.selectedEventTypes?.indexOf(eventType) !== -1;
288330
}
289-
operationsToText(operation: string): string {
290-
if (RETENTION_OPERATIONS_I18N_MAP[operation]) {
291-
return RETENTION_OPERATIONS_I18N_MAP[operation];
292-
}
293-
return operation;
294-
}
295-
setOperation(operation: string) {
296-
if (this.selectedOperations.indexOf(operation) === -1) {
297-
this.selectedOperations.push(operation);
331+
332+
setEventType(eventType: string) {
333+
if (this.selectedEventTypes.indexOf(eventType) === -1) {
334+
this.selectedEventTypes.push(eventType);
298335
} else {
299-
this.selectedOperations.splice(
300-
this.selectedOperations.findIndex(item => item === operation),
336+
this.selectedEventTypes.splice(
337+
this.selectedEventTypes.findIndex(item => item === eventType),
301338
1
302339
);
303340
}
@@ -311,7 +348,7 @@ export class SetJobComponent implements OnInit, OnDestroy {
311348
return true;
312349
}
313350
return !(
314-
this.purgeForm?.invalid || !(this.selectedOperations?.length > 0)
351+
this.purgeForm?.invalid || !(this.selectedEventTypes?.length > 0)
315352
);
316353
}
317354
isRetentionTimeValid() {

src/portal/src/app/base/left-side-nav/clearing-job/clearing-job-interfact.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@ export enum RetentionTimeUnit {
33
DAYS = 'days',
44
}
55

6-
export const RETENTION_OPERATIONS = ['create', 'delete', 'pull'];
6+
export const RESOURCE_TYPES = [
7+
'create_artifact',
8+
'delete_artifact',
9+
'pull_artifact',
10+
];
711

8-
export const RETENTION_OPERATIONS_I18N_MAP = {
9-
pull: 'AUDIT_LOG.PULL',
10-
create: 'AUDIT_LOG.CREATE',
11-
delete: 'AUDIT_LOG.DELETE',
12+
export const RESOURCE_TYPES_I18N_MAP = {
13+
artifact: 'AUDIT_LOG.ARTIFACT',
14+
user_login_logout: 'AUDIT_LOG.USER_LOGIN_LOGOUT',
15+
user: 'AUDIT_LOG.USER',
16+
project: 'AUDIT_LOG.PROJECT',
17+
configuration: 'AUDIT_LOG.CONFIGURATION',
18+
project_member: 'AUDIT_LOG.PROJECT_MEMBER',
1219
};
1320

1421
export const JOB_STATUS = {

0 commit comments

Comments
 (0)