Skip to content

Commit 1e5942a

Browse files
committed
Merged dspace-cris-2023_02_x into task/dspace-cris-2023_02_x/DSC-1860_new
2 parents 68780d4 + a063cbe commit 1e5942a

45 files changed

Lines changed: 2114 additions & 43 deletions

Some content is hidden

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

src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
[attr.aria-labelledby]="'sidebarName-' + section.id"
66
[title]="('menu.section.icon.' + section.id) | translate"
77
[routerLink]="itemModel.link"
8+
[queryParams]="itemModel.queryParams"
89
(keyup.space)="navigate($event)"
910
(keyup.enter)="navigate($event)"
1011
href="javascript:void(0);"
@@ -21,3 +22,4 @@
2122
</div>
2223
</a>
2324
</div>
25+

src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ export class AdminSidebarSectionComponent extends MenuSectionComponent implement
4949
navigate(event: any): void {
5050
event.preventDefault();
5151
if (!this.isDisabled) {
52-
this.router.navigate(this.itemModel.link);
52+
const extras = {
53+
queryParams: this.itemModel.queryParams
54+
};
55+
this.router.navigate(this.itemModel.link, extras);
5356
}
5457
}
5558
}

src/app/item-page/item.resolver.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const ITEM_PAGE_LINKS_TO_FOLLOW: FollowLinkConfig<Item>[] = [
2020
),
2121
followLink('relationships'),
2222
followLink('version', {}, followLink('versionhistory')),
23+
followLink('bundles', {}, followLink('bitstreams')),
2324
followLink('thumbnail'),
2425
followLink('metrics')
2526
];
@@ -45,7 +46,7 @@ export class ItemResolver implements Resolve<RemoteData<Item>> {
4546
*/
4647
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<RemoteData<Item>> {
4748
const itemRD$ = this.itemService.findById(route.params.id,
48-
true,
49+
false,
4950
false,
5051
...ITEM_PAGE_LINKS_TO_FOLLOW
5152
).pipe(

src/app/menu.resolver.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { createSuccessfulRemoteDataObject$ } from './shared/remote-data.utils';
1919
import { createPaginatedList } from './shared/testing/utils.test';
2020
import { SectionDataService } from './core/layout/section-data.service';
2121
import createSpy = jasmine.createSpy;
22+
import { ConfigurationDataService } from './core/data/configuration-data.service';
2223

2324
const BOOLEAN = { t: true, f: false };
2425
const MENU_STATE = {
@@ -68,6 +69,7 @@ describe('MenuResolver', () => {
6869
let sectionsService;
6970
let authorizationService;
7071
let scriptService;
72+
let configService;
7173

7274
beforeEach(waitForAsync(() => {
7375
menuService = new MenuServiceStub();
@@ -83,6 +85,9 @@ describe('MenuResolver', () => {
8385
scriptService = jasmine.createSpyObj('scriptService', {
8486
scriptWithNameExistsAndCanExecute: observableOf(true)
8587
});
88+
configService = jasmine.createSpyObj('ConfigurationDataService', {
89+
findByPropertyName: observableOf({})
90+
});
8691

8792
TestBed.configureTestingModule({
8893
imports: [TranslateModule.forRoot(), NoopAnimationsModule, RouterTestingModule],
@@ -92,6 +97,7 @@ describe('MenuResolver', () => {
9297
{ provide: SectionDataService, useValue: sectionsService },
9398
{ provide: AuthorizationDataService, useValue: authorizationService },
9499
{ provide: ScriptDataService, useValue: scriptService },
100+
{ provide: ConfigurationDataService, useValue: configService },
95101
{
96102
provide: NgbModal, useValue: {
97103
open: () => {/*comment*/

src/app/menu.resolver.ts

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { RemoteData } from './core/data/remote-data';
1111
import { TextMenuItemModel } from './shared/menu/menu-item/models/text.model';
1212
import { MenuService } from './shared/menu/menu.service';
1313
import { filter, find, map, switchMap, take } from 'rxjs/operators';
14-
import { hasValue } from './shared/empty.util';
14+
import { hasValue, isNotEmpty } from './shared/empty.util';
1515
import { FeatureID } from './core/data/feature-authorization/feature-id';
1616
import {
1717
ThemedCreateCommunityParentSelectorComponent
@@ -52,6 +52,8 @@ import { environment } from '../environments/environment';
5252
import { SectionDataService } from './core/layout/section-data.service';
5353
import { Section } from './core/layout/models/section.model';
5454
import { NOTIFICATIONS_RECITER_SUGGESTION_PATH } from './admin/admin-notifications/admin-notifications-routing-paths';
55+
import { ConfigurationDataService } from './core/data/configuration-data.service';
56+
import { ConfigurationProperty } from './core/shared/configuration-property.model';
5557

5658
/**
5759
* Creates all of the app's menus
@@ -70,6 +72,7 @@ export class MenuResolver implements Resolve<boolean> {
7072
protected modalService: NgbModal,
7173
protected scriptDataService: ScriptDataService,
7274
protected sectionDataService: SectionDataService,
75+
protected configService: ConfigurationDataService,
7376
) {
7477
}
7578

@@ -254,6 +257,7 @@ export class MenuResolver implements Resolve<boolean> {
254257
this.createExportMenuSections();
255258
this.createImportMenuSections();
256259
this.createAccessControlMenuSections();
260+
this.createDLExporterMenuItem();
257261

258262
return this.waitForMenu$(MenuID.ADMIN);
259263
}
@@ -528,11 +532,11 @@ export class MenuResolver implements Resolve<boolean> {
528532
];
529533
menuList.forEach((menuSection) => this.menuService.addSection(MenuID.ADMIN, menuSection));
530534

531-
observableCombineLatest([
532-
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
533-
this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_EXPORT_SCRIPT_NAME)
534-
]).pipe(
535-
filter(([authorized, metadataExportScriptExists]: boolean[]) => authorized && metadataExportScriptExists),
535+
this.authorizationService.isAuthorized(FeatureID.AdministratorOf).pipe(
536+
filter((authorized: boolean) => authorized),
537+
take(1),
538+
switchMap(() => this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_EXPORT_SCRIPT_NAME)),
539+
filter((metadataExportScriptExists: boolean) => metadataExportScriptExists),
536540
take(1)
537541
).subscribe(() => {
538542
// Hides the export menu for unauthorised people
@@ -609,6 +613,44 @@ export class MenuResolver implements Resolve<boolean> {
609613
});
610614
}
611615

616+
/**
617+
* Add the DL Exporter menu item to the admin menu
618+
*/
619+
createDLExporterMenuItem() {
620+
this.authorizationService.isAuthorized(FeatureID.AdministratorOf).pipe(
621+
filter((authorized: boolean) => authorized),
622+
take(1),
623+
switchMap(() => observableCombineLatest([
624+
this.getDLExporterURL(),
625+
this.getDLExporterAccessToken()
626+
])),
627+
filter(([url, accesstoken]) => isNotEmpty(url) && isNotEmpty(accesstoken)),
628+
take(1)
629+
).subscribe(([url, accesstoken]) => {
630+
const urlSegments = url.split('?');
631+
const queryParamSegments = urlSegments[1].split('=');
632+
this.menuService.addSection(MenuID.ADMIN,
633+
{
634+
id: 'loginmiur_dlexporter_url',
635+
index: 15,
636+
active: false,
637+
visible: true,
638+
model: {
639+
type: MenuItemType.LINK,
640+
text: 'menu.section.loginmiur_dlexporter_url',
641+
disabled: false,
642+
link: urlSegments[0],
643+
queryParams: {
644+
[queryParamSegments[0]]: queryParamSegments[1]
645+
}
646+
} as LinkMenuItemModel,
647+
icon: 'fa-solid fa-arrows-spin',
648+
shouldPersistOnRouteChange: true
649+
}
650+
);
651+
});
652+
}
653+
612654
/**
613655
* Create menu sections dependent on whether or not the current user is a site administrator and on whether or not
614656
* the import scripts exist and the current user is allowed to execute them
@@ -617,11 +659,11 @@ export class MenuResolver implements Resolve<boolean> {
617659
const menuList = [];
618660
menuList.forEach((menuSection) => this.menuService.addSection(MenuID.ADMIN, menuSection));
619661

620-
observableCombineLatest([
621-
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
622-
this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_IMPORT_SCRIPT_NAME)
623-
]).pipe(
624-
filter(([authorized, metadataImportScriptExists]: boolean[]) => authorized && metadataImportScriptExists),
662+
this.authorizationService.isAuthorized(FeatureID.AdministratorOf).pipe(
663+
filter((authorized: boolean) => authorized),
664+
take(1),
665+
switchMap(() => this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_IMPORT_SCRIPT_NAME)),
666+
filter((metadataImportScriptExists: boolean) => metadataImportScriptExists),
625667
take(1)
626668
).subscribe(() => {
627669
// Hides the import menu for unauthorised people
@@ -974,4 +1016,25 @@ export class MenuResolver implements Resolve<boolean> {
9741016
const object = data.site ? data.site : data.dso?.payload;
9751017
return object?._links?.self?.href;
9761018
}
1019+
1020+
/**
1021+
* Get the DL Exporter URL from the configuration
1022+
*/
1023+
getDLExporterURL(): Observable<string> {
1024+
return this.configService.findByPropertyName('loginmiur.dlexporter.url').pipe(
1025+
getFirstCompletedRemoteData(),
1026+
map((res: RemoteData<ConfigurationProperty>) => {
1027+
return res?.payload?.values[0];
1028+
})
1029+
);
1030+
}
1031+
1032+
private getDLExporterAccessToken() {
1033+
return this.configService.findByPropertyName('loginmiur.dlexporter.accesstoken').pipe(
1034+
getFirstCompletedRemoteData(),
1035+
map((res: RemoteData<ConfigurationProperty>) => {
1036+
return res?.payload?.values[0];
1037+
})
1038+
);
1039+
}
9771040
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<ds-themed-search [renderOnServerSide]="false" [showCharts]="true" [showCsvExport]="false" [showExport]="true" [trackStatistics]="true"></ds-themed-search>
1+
<ds-themed-search [showCharts]="true" [showCsvExport]="false" [showExport]="true" [trackStatistics]="true"></ds-themed-search>

src/app/shared/browse-most-elements/abstract-browse-elements.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export abstract class AbstractBrowseElementsComponent implements OnInit, OnChang
5555
}
5656

5757
ngOnInit() {
58-
const followLinks = this.followThumbnailLink ? [followLink('thumbnail')] : [];
58+
const followLinks = this.followThumbnailLink ? [followLink('thumbnail'), followLink('metrics')] : [followLink('metrics')];
5959
this.paginatedSearchOptionsBS = new BehaviorSubject<PaginatedSearchOptions>(this.paginatedSearchOptions);
6060
this.searchResults$ = this.paginatedSearchOptionsBS.asObservable().pipe(
6161
mergeMap((paginatedSearchOptions) =>

src/app/shared/browse-most-elements/default-browse-elements/default-browse-elements.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ export class DefaultBrowseElementsComponent extends AbstractBrowseElementsCompon
2020

2121
@Input() showLabel: boolean;
2222

23-
protected followThumbnailLink = true;
23+
protected followThumbnailLink = this.appConfig.browseBy.showThumbnails;
2424
}

src/app/shared/cookies/browser-klaro.service.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { BehaviorSubject, combineLatest as observableCombineLatest, Observable,
33
import { AuthService } from '../../core/auth/auth.service';
44
import { TranslateService } from '@ngx-translate/core';
55
import { environment } from '../../../environments/environment';
6-
import { map, switchMap, take } from 'rxjs/operators';
6+
import { filter, map, switchMap, take } from 'rxjs/operators';
77
import { EPerson } from '../../core/eperson/models/eperson.model';
88
import { CookieConsents, KlaroService } from './klaro.service';
99
import { hasValue, isEmpty, isNotEmpty } from '../empty.util';
@@ -65,9 +65,6 @@ export class BrowserKlaroService extends KlaroService {
6565
private readonly REGISTRATION_VERIFICATION_ENABLED_KEY = 'registration.verification.enabled';
6666

6767
private readonly GOOGLE_ANALYTICS_SERVICE_NAME = 'google-analytics';
68-
69-
private lastCookiesConsents: CookieConsents;
70-
7168
/**
7269
* Initial Klaro configuration
7370
*/
@@ -77,8 +74,21 @@ export class BrowserKlaroService extends KlaroService {
7774
* Subject to emit updates in the consents
7875
*/
7976
consentsUpdates$: BehaviorSubject<CookieConsents> = new BehaviorSubject<CookieConsents>(null);
77+
/**
78+
* Subject to emit initialization
79+
*/
80+
initialized$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
8081

81-
82+
/**
83+
* Boolean to check if a new watch method from the manager needs to be fired
84+
* @private
85+
*/
86+
private isKlaroManagerWatching = false;
87+
/**
88+
* Boolean to check if service has been initialized
89+
* @private
90+
*/
91+
private initialized = false;
8292
constructor(
8393
private translateService: TranslateService,
8494
private authService: AuthService,
@@ -180,8 +190,16 @@ export class BrowserKlaroService extends KlaroService {
180190
this.translateConfiguration();
181191

182192
this.klaroConfig.services = this.filterConfigServices(servicesToHide);
183-
this.lazyKlaro.then(({ setup }) => setup(this.klaroConfig));
193+
this.lazyKlaro.then(({ setup }) => {
194+
setup(this.klaroConfig);
195+
this.initialized = true;
196+
this.initialized$.next(this.initialized);
197+
});
184198
});
199+
200+
this.consentsUpdates$.pipe(
201+
filter(() => this.initialized)
202+
).subscribe((consents) => this.isKlaroManagerWatching = hasValue(consents));
185203
}
186204

187205
/**
@@ -366,15 +384,18 @@ export class BrowserKlaroService extends KlaroService {
366384
}
367385

368386
watchConsentUpdates(): void {
387+
if (this.isKlaroManagerWatching || !this.initialized) {
388+
return;
389+
}
390+
369391
this.lazyKlaro.then(({getManager}) => {
370392
const manager = getManager(this.klaroConfig);
371393
const consentsSubject$ = this.consentsUpdates$;
372-
let lastCookiesConsents = this.lastCookiesConsents;
394+
let lastCookiesConsents;
373395

374396
consentsSubject$.next(manager.consents);
375397
manager.watch({
376398
update(_, eventName, consents) {
377-
378399
if (eventName === 'consents' && !isEqual(consents, lastCookiesConsents)) {
379400
lastCookiesConsents = deepClone(consents);
380401
consentsSubject$.next(consents);

src/app/shared/cookies/klaro.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,8 @@ export abstract class KlaroService {
3333
* Subject to emit updates in the consents
3434
*/
3535
abstract consentsUpdates$: BehaviorSubject<CookieConsents>;
36+
/**
37+
* Subject to emit initialization
38+
*/
39+
abstract initialized$: BehaviorSubject<boolean>;
3640
}

0 commit comments

Comments
 (0)