Skip to content

Commit 9f9cd7c

Browse files
Merge remote-tracking branch 'gitHub/main' into task/main/DURACOM-347
2 parents 5a52763 + efaf437 commit 9f9cd7c

134 files changed

Lines changed: 6295 additions & 540 deletions

File tree

Some content is hidden

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

config/config.example.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ form:
164164
validatorMap:
165165
required: required
166166
regex: pattern
167+
# If true it enables the button "Duplicate" inside inline form groups.
168+
# The button will give the possibility to duplicate the whole form section copying the metadata values as well.
169+
showInlineGroupDuplicateButton: false
167170

168171
# Notification settings
169172
notifications:
@@ -202,6 +205,10 @@ submission:
202205
# default configuration
203206
- name: default
204207
style: ''
208+
# Icons that should remain visible even when no authority value is present for the metadata field.
209+
# This is useful for fields where you want to display an icon regardless of whether the value has an authority link.
210+
# Example: ['fas fa-user'] will show the user icon for author fields even without authority data.
211+
iconsVisibleWithNoAuthority: ['fas fa-user']
205212
authority:
206213
confidence:
207214
# NOTE: example of configuration
@@ -430,6 +437,8 @@ item:
430437
iconPosition: IdentifierSubtypesIconPositionEnum.LEFT
431438
link: https://ror.org
432439

440+
# Enable authority based relations in item page
441+
showAuthorityRelations: false
433442
# Community Page Config
434443
community:
435444
# Default tab to be shown when browsing a Community. Valid values are: comcols, search, or browse_<field>
@@ -706,6 +715,28 @@ layout:
706715
default:
707716
icon: fas fa-project-diagram
708717
style: text-success
718+
# If true the download link in item page will be rendered as an advanced attachment, the view can be then configured with the layout.advancedAttachmentRendering config
719+
showDownloadLinkAsAttachment: false
720+
# Configuration for advanced attachment rendering in item pages. This controls how files are displayed when showDownloadLinkAsAttachment is enabled.
721+
# Defines which metadata/attributes to display for bitstream attachments.
722+
advancedAttachmentRendering:
723+
# Metadata and attributes to display for each attachment
724+
metadata:
725+
- name: dc.title
726+
type: metadata
727+
truncatable: false
728+
- name: dc.type
729+
type: metadata
730+
truncatable: false
731+
- name: dc.description
732+
type: metadata
733+
truncatable: true
734+
- name: size
735+
type: attribute
736+
- name: format
737+
type: attribute
738+
- name: checksum
739+
type: attribute
709740

710741
# Configuration for customization of search results
711742
searchResults:
@@ -736,3 +767,22 @@ searchResults:
736767
followAuthorityMetadataValuesLimit: 5
737768

738769

770+
# Configuration of social links using AddToAny plugin
771+
addToAnyPlugin:
772+
# This is enabled flag
773+
socialNetworksEnabled: false
774+
# If you want to self-host check https://www.addtoany.com/buttons/customize/host_cache
775+
scriptUrl: "https://static.addtoany.com/menu/page.js"
776+
# Check available integrations, visit https://www.addtoany.com/buttons/for/website
777+
# 1. Click "Choose Services", select integrations, then click Done
778+
# 2. Get Button Code
779+
# 3. You will get a HTML e.g. <a class="a2a_button_facebook"></a> where "facebook" is part you want to include in list
780+
buttons:
781+
- facebook
782+
- twitter
783+
- linkedin
784+
- email
785+
- copy_link
786+
showPlusButton: true
787+
showCounters: true
788+
title: DSpace demo

src/app/app.component.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
<ds-root
22
[shouldShowFullscreenLoader]="(isAuthBlocking$ | async) || (isThemeLoading$ | async)"
33
[shouldShowRouteLoader]="isRouteLoading$ | async"></ds-root>
4+
5+
@if (browserPlatform) {
6+
<ds-social></ds-social>
7+
}

src/app/app.component.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ import { IdleModalComponent } from './shared/idle-modal/idle-modal.component';
5252
import { CSSVariableService } from './shared/sass-helper/css-variable.service';
5353
import { HostWindowState } from './shared/search/host-window.reducer';
5454
import { ThemeService } from './shared/theme-support/theme.service';
55+
import { SocialComponent } from './social/social.component';
56+
import { SocialService } from './social/social.service';
5557

5658
@Component({
5759
selector: 'ds-app',
@@ -60,6 +62,7 @@ import { ThemeService } from './shared/theme-support/theme.service';
6062
changeDetection: ChangeDetectionStrategy.OnPush,
6163
imports: [
6264
AsyncPipe,
65+
SocialComponent,
6366
ThemedRootComponent,
6467
],
6568
})
@@ -87,6 +90,11 @@ export class AppComponent implements OnInit, AfterViewInit {
8790
*/
8891
idleModalOpen: boolean;
8992

93+
/**
94+
* In order to show sharing component only in csr
95+
*/
96+
browserPlatform = false;
97+
9098
constructor(
9199
@Inject(NativeWindowService) private _window: NativeWindowRef,
92100
@Inject(DOCUMENT) private document: any,
@@ -99,16 +107,20 @@ export class AppComponent implements OnInit, AfterViewInit {
99107
private cssService: CSSVariableService,
100108
private modalService: NgbModal,
101109
private modalConfig: NgbModalConfig,
110+
private socialService: SocialService,
102111
) {
103112
this.notificationOptions = environment.notifications;
113+
this.browserPlatform = isPlatformBrowser(this.platformId);
104114

105-
if (isPlatformBrowser(this.platformId)) {
115+
if (this.browserPlatform) {
106116
this.trackIdleModal();
107117
}
108118

109119
this.isThemeLoading$ = this.themeService.isThemeLoading$;
110120

111121
this.storeCSSVariables();
122+
123+
this.socialService.initialize();
112124
}
113125

114126
ngOnInit() {
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import { PLATFORM_ID } from '@angular/core';
2+
import {
3+
TestBed,
4+
waitForAsync,
5+
} from '@angular/core/testing';
6+
import { Router } from '@angular/router';
7+
import { NotificationsService } from '@dspace/core/notification-system/notifications.service';
8+
import { getForbiddenRoute } from '@dspace/core/router/core-routing-paths';
9+
import { createSuccessfulRemoteDataObject$ } from '@dspace/core/utilities/remote-data.utils';
10+
import { Store } from '@ngrx/store';
11+
import { of } from 'rxjs';
12+
13+
import { AuthService } from '../core/auth/auth.service';
14+
import { RemoteDataBuildService } from '../core/cache/builders/remote-data-build.service';
15+
import { ObjectCacheService } from '../core/cache/object-cache.service';
16+
import { BitstreamDataService } from '../core/data/bitstream-data.service';
17+
import { BitstreamFormatDataService } from '../core/data/bitstream-format-data.service';
18+
import { DSOChangeAnalyzer } from '../core/data/dso-change-analyzer.service';
19+
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
20+
import { SignpostingDataService } from '../core/data/signposting-data.service';
21+
import { HardRedirectService } from '../core/services/hard-redirect.service';
22+
import { ServerResponseService } from '../core/services/server-response.service';
23+
import {
24+
NativeWindowRef,
25+
NativeWindowService,
26+
} from '../core/services/window.service';
27+
import { Bitstream } from '../core/shared/bitstream.model';
28+
import { FileService } from '../core/shared/file.service';
29+
import { HALEndpointService } from '../core/shared/hal-endpoint.service';
30+
import { UUIDService } from '../core/shared/uuid.service';
31+
import { bitstreamDownloadRedirectGuard } from './bitstream-download-redirect.guard';
32+
33+
describe('BitstreamDownloadRedirectGuard', () => {
34+
let resolver: any;
35+
36+
let authService: AuthService;
37+
let authorizationService: AuthorizationDataService;
38+
let bitstreamDataService: BitstreamDataService;
39+
let fileService: FileService;
40+
let halEndpointService: HALEndpointService;
41+
let hardRedirectService: HardRedirectService;
42+
let remoteDataBuildService: RemoteDataBuildService;
43+
let uuidService: UUIDService;
44+
let objectCacheService: ObjectCacheService;
45+
let router: Router;
46+
let store: Store;
47+
let bitstream: Bitstream;
48+
let serverResponseService: jasmine.SpyObj<ServerResponseService>;
49+
let signpostingDataService: jasmine.SpyObj<SignpostingDataService>;
50+
51+
let route = {
52+
params: {},
53+
queryParams: {},
54+
};
55+
let state = {};
56+
57+
const mocklink = {
58+
href: 'http://test.org',
59+
rel: 'test',
60+
type: 'test',
61+
};
62+
63+
const mocklink2 = {
64+
href: 'http://test2.org',
65+
rel: 'test',
66+
type: 'test',
67+
};
68+
69+
function init() {
70+
authService = jasmine.createSpyObj('authService', {
71+
isAuthenticated: of(true),
72+
setRedirectUrl: {},
73+
});
74+
authorizationService = jasmine.createSpyObj('authorizationSerivice', {
75+
isAuthorized: of(true),
76+
});
77+
78+
fileService = jasmine.createSpyObj('fileService', {
79+
retrieveFileDownloadLink: of('content-url-with-headers'),
80+
});
81+
82+
hardRedirectService = jasmine.createSpyObj('fileService', {
83+
redirect: {},
84+
});
85+
86+
halEndpointService = jasmine.createSpyObj('halEndpointService', {
87+
getEndpoint: of('https://rest.api/core'),
88+
});
89+
90+
remoteDataBuildService = jasmine.createSpyObj('remoteDataBuildService', {
91+
buildSingle: of(new Bitstream()),
92+
});
93+
94+
uuidService = jasmine.createSpyObj('uuidService', {
95+
generate: 'test-id',
96+
});
97+
98+
bitstream = Object.assign(new Bitstream(), {
99+
uuid: 'bitstreamUuid',
100+
_links: {
101+
content: { href: 'bitstream-content-link' },
102+
self: { href: 'bitstream-self-link' },
103+
},
104+
});
105+
106+
router = jasmine.createSpyObj('router', ['navigateByUrl', 'createUrlTree']);
107+
108+
store = jasmine.createSpyObj('store', {
109+
dispatch: {},
110+
pipe: of(true),
111+
});
112+
113+
serverResponseService = jasmine.createSpyObj('ServerResponseService', {
114+
setHeader: jasmine.createSpy('setHeader'),
115+
});
116+
117+
signpostingDataService = jasmine.createSpyObj('SignpostingDataService', {
118+
getLinks: of([mocklink, mocklink2]),
119+
});
120+
121+
objectCacheService = jasmine.createSpyObj('objectCacheService', {
122+
getByHref: of(null),
123+
});
124+
125+
bitstreamDataService = jasmine.createSpyObj('bitstreamDataService', {
126+
findById: createSuccessfulRemoteDataObject$(Object.assign(new Bitstream(), {
127+
_links: {
128+
content: { href: 'bitstream-content-link' },
129+
self: { href: 'bitstream-self-link' },
130+
},
131+
})),
132+
});
133+
134+
resolver = bitstreamDownloadRedirectGuard;
135+
}
136+
137+
function initTestbed() {
138+
TestBed.configureTestingModule({
139+
providers: [
140+
{ provide: NativeWindowService, useValue: new NativeWindowRef() },
141+
{ provide: Router, useValue: router },
142+
{ provide: AuthorizationDataService, useValue: authorizationService },
143+
{ provide: AuthService, useValue: authService },
144+
{ provide: FileService, useValue: fileService },
145+
{ provide: HardRedirectService, useValue: hardRedirectService },
146+
{ provide: ServerResponseService, useValue: serverResponseService },
147+
{ provide: SignpostingDataService, useValue: signpostingDataService },
148+
{ provide: ObjectCacheService, useValue: objectCacheService },
149+
{ provide: PLATFORM_ID, useValue: 'server' },
150+
{ provide: UUIDService, useValue: uuidService },
151+
{ provide: Store, useValue: store },
152+
{ provide: RemoteDataBuildService, useValue: remoteDataBuildService },
153+
{ provide: HALEndpointService, useValue: halEndpointService },
154+
{ provide: DSOChangeAnalyzer, useValue: {} },
155+
{ provide: BitstreamFormatDataService, useValue: {} },
156+
{ provide: NotificationsService, useValue: {} },
157+
{ provide: BitstreamDataService, useValue: bitstreamDataService },
158+
],
159+
});
160+
}
161+
162+
describe('bitstream retrieval', () => {
163+
describe('when the user is authorized and not logged in', () => {
164+
beforeEach(() => {
165+
init();
166+
(authService.isAuthenticated as jasmine.Spy).and.returnValue(of(false));
167+
initTestbed();
168+
});
169+
it('should redirect to the content link', waitForAsync(() => {
170+
TestBed.runInInjectionContext(() => {
171+
resolver(route, state).subscribe(() => {
172+
expect(hardRedirectService.redirect).toHaveBeenCalledWith('bitstream-content-link', null, true);
173+
},
174+
);
175+
});
176+
}));
177+
});
178+
describe('when the user is authorized and logged in', () => {
179+
beforeEach(() => {
180+
init();
181+
initTestbed();
182+
});
183+
it('should redirect to an updated content link', waitForAsync(() => {
184+
TestBed.runInInjectionContext(() => {
185+
resolver(route, state).subscribe(() => {
186+
expect(hardRedirectService.redirect).toHaveBeenCalledWith('content-url-with-headers', null, true);
187+
});
188+
});
189+
}));
190+
});
191+
describe('when the user is not authorized and logged in', () => {
192+
beforeEach(() => {
193+
init();
194+
(authorizationService.isAuthorized as jasmine.Spy).and.returnValue(of(false));
195+
initTestbed();
196+
});
197+
it('should navigate to the forbidden route', waitForAsync(() => {
198+
TestBed.runInInjectionContext(() => {
199+
resolver(route, state).subscribe(() => {
200+
expect(router.createUrlTree).toHaveBeenCalledWith([getForbiddenRoute()]);
201+
});
202+
});
203+
}));
204+
});
205+
describe('when the user is not authorized and not logged in', () => {
206+
beforeEach(() => {
207+
init();
208+
(authService.isAuthenticated as jasmine.Spy).and.returnValue(of(false));
209+
(authorizationService.isAuthorized as jasmine.Spy).and.returnValue(of(false));
210+
initTestbed();
211+
});
212+
it('should navigate to the login page', waitForAsync(() => {
213+
214+
TestBed.runInInjectionContext(() => {
215+
resolver(route, state).subscribe(() => {
216+
expect(authService.setRedirectUrl).toHaveBeenCalled();
217+
expect(router.createUrlTree).toHaveBeenCalledWith(['login']);
218+
});
219+
});
220+
}));
221+
});
222+
});
223+
});

0 commit comments

Comments
 (0)