Skip to content

Commit 761b0c2

Browse files
authored
Merge pull request #2751 from 4Science/coar-notify-7-part-two
Coar Notify Integration - Administer/Log
2 parents 76f5d34 + 0f7965e commit 761b0c2

File tree

80 files changed

+3666
-70
lines changed

Some content is hidden

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

80 files changed

+3666
-70
lines changed

config/config.example.yml

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,9 +431,67 @@ comcolSelectionSort:
431431

432432

433433
# Search settings
434-
search:
434+
search:
435435
# Settings to enable/disable or configure advanced search filters.
436436
advancedFilters:
437437
enabled: false
438438
# List of filters to enable in "Advanced Search" dropdown
439439
filter: [ 'title', 'author', 'subject', 'entityType' ]
440+
441+
442+
# Notify metrics
443+
# Configuration for Notify Admin Dashboard for metrics visualization
444+
notifyMetrics:
445+
# Configuration for received messages
446+
- title: 'admin-notify-dashboard.received-ldn'
447+
boxes:
448+
- color: '#B8DAFF'
449+
title: 'admin-notify-dashboard.NOTIFY.incoming.accepted'
450+
config: 'NOTIFY.incoming.accepted'
451+
description: 'admin-notify-dashboard.NOTIFY.incoming.accepted.description'
452+
- color: '#D4EDDA'
453+
title: 'admin-notify-dashboard.NOTIFY.incoming.processed'
454+
config: 'NOTIFY.incoming.processed'
455+
description: 'admin-notify-dashboard.NOTIFY.incoming.processed.description'
456+
- color: '#FDBBC7'
457+
title: 'admin-notify-dashboard.NOTIFY.incoming.failure'
458+
config: 'NOTIFY.incoming.failure'
459+
description: 'admin-notify-dashboard.NOTIFY.incoming.failure.description'
460+
- color: '#FDBBC7'
461+
title: 'admin-notify-dashboard.NOTIFY.incoming.untrusted'
462+
config: 'NOTIFY.incoming.untrusted'
463+
description: 'admin-notify-dashboard.NOTIFY.incoming.untrusted.description'
464+
- color: '#43515F'
465+
title: 'admin-notify-dashboard.NOTIFY.incoming.involvedItems'
466+
textColor: '#fff'
467+
config: 'NOTIFY.incoming.involvedItems'
468+
description: 'admin-notify-dashboard.NOTIFY.incoming.involvedItems.description'
469+
# Configuration for outgoing messages
470+
- title: 'admin-notify-dashboard.generated-ldn'
471+
boxes:
472+
- color: '#B8DAFF'
473+
title: 'admin-notify-dashboard.NOTIFY.outgoing.queued'
474+
config: 'NOTIFY.outgoing.queued'
475+
description: 'admin-notify-dashboard.NOTIFY.outgoing.queued.description'
476+
- color: '#FDEEBB'
477+
title: 'admin-notify-dashboard.NOTIFY.outgoing.queued_for_retry'
478+
config: 'NOTIFY.outgoing.queued_for_retry'
479+
description: 'admin-notify-dashboard.NOTIFY.outgoing.queued_for_retry.description'
480+
- color: '#FDBBC7'
481+
title: 'admin-notify-dashboard.NOTIFY.outgoing.failure'
482+
config: 'NOTIFY.outgoing.failure'
483+
description: 'admin-notify-dashboard.NOTIFY.outgoing.failure.description'
484+
- color: '#43515F'
485+
title: 'admin-notify-dashboard.NOTIFY.outgoing.involvedItems'
486+
textColor: '#fff'
487+
config: 'NOTIFY.outgoing.involvedItems'
488+
description: 'admin-notify-dashboard.NOTIFY.outgoing.involvedItems.description'
489+
- color: '#D4EDDA'
490+
title: 'admin-notify-dashboard.NOTIFY.outgoing.delivered'
491+
config: 'NOTIFY.outgoing.delivered'
492+
description: 'admin-notify-dashboard.NOTIFY.outgoing.delivered.description'
493+
494+
495+
496+
497+

src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.html

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,13 @@ <h1 class="flex-grow-1">{{ isNewService ? ('ldn-create-service.title' | translat
102102
id="ldnUrl"
103103
name="ldnUrl"
104104
type="text">
105-
<div *ngIf="formModel.get('ldnUrl').invalid && formModel.get('ldnUrl').touched" class="error-text">
106-
{{ 'ldn-new-service.form.error.ldnurl' | translate }}
105+
<div *ngIf="formModel.get('ldnUrl').invalid && formModel.get('ldnUrl').touched" >
106+
<div *ngIf="formModel.get('ldnUrl').errors['required']" class="error-text">
107+
{{ 'ldn-new-service.form.error.ldnurl' | translate }}
108+
</div>
109+
<div *ngIf="formModel.get('ldnUrl').errors['ldnUrlAlreadyAssociated']" class="error-text">
110+
{{ 'ldn-new-service.form.error.ldnurl.ldnUrlAlreadyAssociated' | translate }}
111+
</div>
107112
</div>
108113
</div>
109114

src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ import {
66
TemplateRef,
77
ViewChild
88
} from '@angular/core';
9-
import {FormArray, FormBuilder, FormGroup, Validators} from '@angular/forms';
9+
import {
10+
FormArray,
11+
FormBuilder,
12+
FormGroup,
13+
Validators
14+
} from '@angular/forms';
1015
import {LDN_SERVICE} from '../ldn-services-model/ldn-service.resource-type';
1116
import {ActivatedRoute, Router} from '@angular/router';
1217
import {LdnServicesService} from '../ldn-services-data/ldn-services-data.service';
@@ -167,6 +172,9 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
167172
this.closeModal();
168173
this.sendBack();
169174
} else {
175+
if (!this.formModel.errors) {
176+
this.setLdnUrlError();
177+
}
170178
this.notificationService.error(this.translateService.get('ldn-service-notification.created.failure.title'),
171179
this.translateService.get('ldn-service-notification.created.failure.body'));
172180
this.closeModal();
@@ -405,6 +413,9 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
405413
this.notificationService.success(this.translateService.get('admin.registries.services-formats.modify.success.head'),
406414
this.translateService.get('admin.registries.services-formats.modify.success.content'));
407415
} else {
416+
if (!this.formModel.errors) {
417+
this.setLdnUrlError();
418+
}
408419
this.notificationService.error(this.translateService.get('admin.registries.services-formats.modify.failure.head'),
409420
this.translateService.get('admin.registries.services-formats.modify.failure.content'));
410421
this.closeModal();
@@ -554,4 +565,14 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
554565
automatic: '',
555566
});
556567
}
568+
569+
570+
/**
571+
* set ldnUrl error in case of unprocessable entity and provided value
572+
*/
573+
private setLdnUrlError(): void {
574+
const control = this.formModel.controls.ldnUrl;
575+
const controlErrors = control.errors || {};
576+
control.setErrors({...controlErrors, ldnUrlAlreadyAssociated: true });
577+
}
557578
}

src/app/admin/admin-ldn-services/ldn-services-data/ldn-services-data.service.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ describe('LdnServicesService test', () => {
7878

7979
rdbService = jasmine.createSpyObj('rdbService', {
8080
buildSingle: createSuccessfulRemoteDataObject$({}, 500),
81+
buildFromRequestUUID: createSuccessfulRemoteDataObject$({}, 500),
8182
buildList: cold('a', { a: remoteDataMocks.Success })
8283
});
8384

@@ -111,6 +112,20 @@ describe('LdnServicesService test', () => {
111112
done();
112113
});
113114
});
115+
116+
it('should invoke service', (done) => {
117+
const constraints = [{void: true}];
118+
const files = [new File([],'fileName')];
119+
spyOn(service as any, 'getInvocationFormData');
120+
spyOn(service, 'getBrowseEndpoint').and.returnValue(observableOf('testEndpoint'));
121+
service.invoke('serviceName', 'serviceId', constraints, files).subscribe(result => {
122+
expect((service as any).getInvocationFormData).toHaveBeenCalledWith(constraints, files);
123+
expect(service.getBrowseEndpoint).toHaveBeenCalled();
124+
expect(result).toBeInstanceOf(RemoteData);
125+
done();
126+
});
127+
128+
});
114129
});
115130

116131
});

src/app/admin/admin-ldn-services/ldn-services-directory/ldn-services-directory.component.spec.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
2-
import {ChangeDetectorRef, EventEmitter} from '@angular/core';
2+
import { ChangeDetectorRef, EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core';
33
import {NotificationsService} from '../../../shared/notifications/notifications.service';
44
import {NotificationsServiceStub} from '../../../shared/testing/notifications-service.stub';
55
import {TranslateModule, TranslateService} from '@ngx-translate/core';
@@ -21,8 +21,6 @@ describe('LdnServicesOverviewComponent', () => {
2121
let ldnServicesService;
2222
let paginationService;
2323
let modalService: NgbModal;
24-
let notificationsService: NotificationsService;
25-
let translateService: TranslateService;
2624

2725
const translateServiceStub = {
2826
get: () => of('translated-text'),
@@ -33,7 +31,11 @@ describe('LdnServicesOverviewComponent', () => {
3331

3432
beforeEach(async () => {
3533
paginationService = new PaginationServiceStub();
36-
ldnServicesService = jasmine.createSpyObj('LdnServicesService', ['findAll', 'delete', 'patch']);
34+
ldnServicesService = jasmine.createSpyObj('ldnServicesService', {
35+
'findAll': createSuccessfulRemoteDataObject$({}),
36+
'delete': createSuccessfulRemoteDataObject$({}),
37+
'patch': createSuccessfulRemoteDataObject$({}),
38+
});
3739
await TestBed.configureTestingModule({
3840
imports: [TranslateModule.forRoot()],
3941
declarations: [LdnServicesOverviewComponent],
@@ -50,9 +52,10 @@ describe('LdnServicesOverviewComponent', () => {
5052
}
5153
},
5254
{provide: ChangeDetectorRef, useValue: {}},
53-
{provide: NotificationsService, useValue: NotificationsServiceStub},
55+
{provide: NotificationsService, useValue: new NotificationsServiceStub()},
5456
{provide: TranslateService, useValue: translateServiceStub},
55-
]
57+
],
58+
schemas: [NO_ERRORS_SCHEMA]
5659
}).compileComponents();
5760
});
5861

@@ -62,8 +65,6 @@ describe('LdnServicesOverviewComponent', () => {
6265
ldnServicesService = TestBed.inject(LdnServicesService);
6366
paginationService = TestBed.inject(PaginationService);
6467
modalService = TestBed.inject(NgbModal);
65-
notificationsService = TestBed.inject(NotificationsService);
66-
translateService = TestBed.inject(TranslateService);
6768
component.modalRef = jasmine.createSpyObj({close: null});
6869
component.isProcessingSub = jasmine.createSpyObj({unsubscribe: null});
6970
component.ldnServicesRD$ = of({} as RemoteData<PaginatedList<LdnService>>);
@@ -141,4 +142,22 @@ describe('LdnServicesOverviewComponent', () => {
141142
expect(deleteSpy).toHaveBeenCalledWith(serviceId);
142143
}));
143144
});
145+
146+
describe('selectServiceToDelete', () => {
147+
it('should set service to delete', fakeAsync(() => {
148+
spyOn(component, 'openDeleteModal');
149+
const serviceId = 123;
150+
component.selectServiceToDelete(serviceId);
151+
expect(component.selectedServiceId).toEqual(serviceId);
152+
expect(component.openDeleteModal).toHaveBeenCalled();
153+
}));
154+
});
155+
156+
describe('toggleStatus', () => {
157+
it('should toggle status', (() => {
158+
component.toggleStatus({enabled: false}, ldnServicesService);
159+
expect(ldnServicesService.patch).toHaveBeenCalled();
160+
}));
161+
});
162+
144163
});
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { NgModule } from '@angular/core';
2+
import { RouterModule } from '@angular/router';
3+
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
4+
import { AdminNotifyDashboardComponent } from './admin-notify-dashboard.component';
5+
import {
6+
SiteAdministratorGuard
7+
} from '../../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
8+
import {
9+
AdminNotifyIncomingComponent
10+
} from './admin-notify-logs/admin-notify-incoming/admin-notify-incoming.component';
11+
import {
12+
AdminNotifyOutgoingComponent
13+
} from './admin-notify-logs/admin-notify-outgoing/admin-notify-outgoing.component';
14+
import { NotifyInfoGuard } from '../../core/coar-notify/notify-info/notify-info.guard';
15+
16+
@NgModule({
17+
imports: [
18+
RouterModule.forChild([
19+
{
20+
canActivate: [SiteAdministratorGuard, NotifyInfoGuard],
21+
path: '',
22+
resolve: {
23+
breadcrumb: I18nBreadcrumbResolver,
24+
},
25+
component: AdminNotifyDashboardComponent,
26+
pathMatch: 'full',
27+
data: {
28+
title: 'admin.notify.dashboard.page.title',
29+
breadcrumbKey: 'admin.notify.dashboard',
30+
},
31+
},
32+
{
33+
path: 'inbound',
34+
resolve: {
35+
breadcrumb: I18nBreadcrumbResolver,
36+
},
37+
component: AdminNotifyIncomingComponent,
38+
canActivate: [SiteAdministratorGuard, NotifyInfoGuard],
39+
data: {
40+
title: 'admin.notify.dashboard.page.title',
41+
breadcrumbKey: 'admin.notify.dashboard',
42+
},
43+
},
44+
{
45+
path: 'outbound',
46+
resolve: {
47+
breadcrumb: I18nBreadcrumbResolver,
48+
},
49+
component: AdminNotifyOutgoingComponent,
50+
canActivate: [SiteAdministratorGuard, NotifyInfoGuard],
51+
data: {
52+
title: 'admin.notify.dashboard.page.title',
53+
breadcrumbKey: 'admin.notify.dashboard',
54+
},
55+
}
56+
])
57+
],
58+
})
59+
/**
60+
* Routing module for the Notifications section of the admin sidebar
61+
*/
62+
export class AdminNotifyDashboardRoutingModule {
63+
64+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<div class="container">
2+
<div class="row">
3+
<div class="col-12">
4+
<h1 class="border-bottom pb-2">{{'admin-notify-dashboard.title'| translate}}</h1>
5+
<div class="my-4">{{'admin-notify-dashboard.description' | translate}}</div>
6+
<div>
7+
<ul class="nav nav-tabs">
8+
<li class="nav-item">
9+
<a class="nav-link active">{{'admin-notify-dashboard.metrics' | translate}}</a>
10+
</li>
11+
<li class="nav-item">
12+
<a class="nav-link" [routerLink]="'inbound'" [queryParams]="{view: 'table'}">{{'admin.notify.dashboard.inbound-logs' | translate}}</a>
13+
</li>
14+
<li class="nav-item">
15+
<a class="nav-link" [routerLink]="'outbound'" [queryParams]="{view: 'table'}">{{'admin.notify.dashboard.outbound-logs' | translate}}</a>
16+
</ul>
17+
<div class="mt-2">
18+
<ds-admin-notify-metrics *ngIf="(notifyMetricsRows$ | async)?.length" [boxesConfig]="notifyMetricsRows$ | async"></ds-admin-notify-metrics>
19+
</div>
20+
</div>
21+
</div>
22+
</div>
23+
</div>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { AdminNotifyDashboardComponent } from './admin-notify-dashboard.component';
4+
import { TranslateModule } from '@ngx-translate/core';
5+
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
6+
import { SearchService } from '../../core/shared/search/search.service';
7+
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
8+
import { buildPaginatedList } from '../../core/data/paginated-list.model';
9+
import { AdminNotifySearchResult } from './models/admin-notify-message-search-result.model';
10+
import { AdminNotifyMessage } from './models/admin-notify-message.model';
11+
12+
describe('AdminNotifyDashboardComponent', () => {
13+
let component: AdminNotifyDashboardComponent;
14+
let fixture: ComponentFixture<AdminNotifyDashboardComponent>;
15+
16+
let item1;
17+
let item2;
18+
let item3;
19+
let searchResult1;
20+
let searchResult2;
21+
let searchResult3;
22+
let results;
23+
24+
const mockBoxes = [
25+
{ title: 'admin-notify-dashboard.received-ldn', boxes: [ undefined, undefined, undefined, undefined, undefined ] },
26+
{ title: 'admin-notify-dashboard.generated-ldn', boxes: [ undefined, undefined, undefined, undefined, undefined ] }
27+
];
28+
29+
beforeEach(async () => {
30+
item1 = Object.assign(new AdminNotifyMessage(), { uuid: 'e1c51c69-896d-42dc-8221-1d5f2ad5516e' });
31+
item2 = Object.assign(new AdminNotifyMessage(), { uuid: 'c8279647-1acc-41ae-b036-951d5f65649b' });
32+
item3 = Object.assign(new AdminNotifyMessage(), { uuid: 'c3bcbff5-ec0c-4831-8e4c-94b9c933ccac' });
33+
searchResult1 = Object.assign(new AdminNotifySearchResult(), { indexableObject: item1 });
34+
searchResult2 = Object.assign(new AdminNotifySearchResult(), { indexableObject: item2 });
35+
searchResult3 = Object.assign(new AdminNotifySearchResult(), { indexableObject: item3 });
36+
results = buildPaginatedList(undefined, [searchResult1, searchResult2, searchResult3]);
37+
38+
await TestBed.configureTestingModule({
39+
imports: [TranslateModule.forRoot(), NgbNavModule],
40+
declarations: [ AdminNotifyDashboardComponent ],
41+
providers: [{ provide: SearchService, useValue: { search: () => createSuccessfulRemoteDataObject$(results)}}]
42+
})
43+
.compileComponents();
44+
45+
fixture = TestBed.createComponent(AdminNotifyDashboardComponent);
46+
component = fixture.componentInstance;
47+
fixture.detectChanges();
48+
});
49+
50+
it('should create', (done) => {
51+
component.notifyMetricsRows$.subscribe(boxes => {
52+
expect(boxes).toEqual(mockBoxes);
53+
done();
54+
});
55+
expect(component).toBeTruthy();
56+
});
57+
});

0 commit comments

Comments
 (0)