Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { of as observableOf } from 'rxjs';
import { getForbiddenRoute } from '../../app-routing-paths';
import { AuthService } from '../../core/auth/auth.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { ConfigurationDataService } from '../../core/data/configuration-data.service';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { SignpostingDataService } from '../../core/data/signposting-data.service';
import { HardRedirectService } from '../../core/services/hard-redirect.service';
Expand Down Expand Up @@ -112,7 +113,10 @@ describe('BitstreamDownloadPageComponent', () => {
signpostingDataService = jasmine.createSpyObj('SignpostingDataService', {
getLinks: observableOf([mocklink, mocklink2]),
});
matomoService = jasmine.createSpyObj('MatomoService', ['appendVisitorId']);
matomoService = jasmine.createSpyObj('MatomoService', {
appendVisitorId: observableOf(''),
isMatomoEnabled$: observableOf(true),
});
matomoService.appendVisitorId.and.callFake((link) => observableOf(link));
}

Expand All @@ -132,6 +136,7 @@ describe('BitstreamDownloadPageComponent', () => {
{ provide: PLATFORM_ID, useValue: 'server' },
{ provide: Location, useValue: location },
{ provide: DSONameService, useValue: dsoNameService },
{ provide: ConfigurationDataService, useValue: {} },
],
})
.compileComponents();
Expand Down Expand Up @@ -227,4 +232,42 @@ describe('BitstreamDownloadPageComponent', () => {
}));
});
});

describe('when Matomo is enabled', () => {
beforeEach(waitForAsync(() => {
init();
(matomoService.appendVisitorId as jasmine.Spy).and.callFake((link) => observableOf(link + '?visitorId=12345'));
initTestbed();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BitstreamDownloadPageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should append visitor ID to the file link', waitForAsync(() => {
fixture.whenStable().then(() => {
expect(matomoService.appendVisitorId).toHaveBeenCalledWith('content-url-with-headers');
expect(hardRedirectService.redirect).toHaveBeenCalledWith('content-url-with-headers?visitorId=12345');
});
}));
});

describe('when Matomo is not enabled', () => {
beforeEach(waitForAsync(() => {
init();
(matomoService.isMatomoEnabled$ as jasmine.Spy).and.returnValue(observableOf(false));
initTestbed();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BitstreamDownloadPageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should not append visitor ID to the file link', waitForAsync(() => {
fixture.whenStable().then(() => {
expect(matomoService.appendVisitorId).not.toHaveBeenCalled();
expect(hardRedirectService.redirect).toHaveBeenCalledWith('content-url-with-headers');
});
}));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import {
Component,
Inject,
inject,
OnInit,
PLATFORM_ID,
} from '@angular/core';
Expand All @@ -30,6 +31,7 @@
import { getForbiddenRoute } from '../../app-routing-paths';
import { AuthService } from '../../core/auth/auth.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { ConfigurationDataService } from '../../core/data/configuration-data.service';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { RemoteData } from '../../core/data/remote-data';
Expand Down Expand Up @@ -64,6 +66,8 @@
bitstream$: Observable<Bitstream>;
bitstreamRD$: Observable<RemoteData<Bitstream>>;

configService = inject(ConfigurationDataService);

constructor(
private route: ActivatedRoute,
protected router: Router,
Expand Down Expand Up @@ -103,30 +107,33 @@
switchMap((bitstream: Bitstream) => {
const isAuthorized$ = this.authorizationService.isAuthorized(FeatureID.CanDownload, isNotEmpty(bitstream) ? bitstream.self : undefined);
const isLoggedIn$ = this.auth.isAuthenticated();
return observableCombineLatest([isAuthorized$, isLoggedIn$, accessToken$, observableOf(bitstream)]);
const isMatomoEnabled$ = this.matomoService.isMatomoEnabled$();
return observableCombineLatest([isAuthorized$, isLoggedIn$, isMatomoEnabled$, accessToken$, observableOf(bitstream)]);
}),
filter(([isAuthorized, isLoggedIn, accessToken, bitstream]: [boolean, boolean, string, Bitstream]) => (hasValue(isAuthorized) && hasValue(isLoggedIn)) || hasValue(accessToken)),
filter(([isAuthorized, isLoggedIn, isMatomoEnabled, accessToken, bitstream]: [boolean, boolean, boolean, string, Bitstream]) => (hasValue(isAuthorized) && hasValue(isLoggedIn)) || hasValue(accessToken)),
take(1),
switchMap(([isAuthorized, isLoggedIn, accessToken, bitstream]: [boolean, boolean, string, Bitstream]) => {
switchMap(([isAuthorized, isLoggedIn, isMatomoEnabled, accessToken, bitstream]: [boolean, boolean, boolean, string, Bitstream]) => {
if (isAuthorized && isLoggedIn) {
return this.fileService.retrieveFileDownloadLink(bitstream._links.content.href).pipe(
filter((fileLink) => hasValue(fileLink)),
take(1),
map((fileLink) => {
return [isAuthorized, isLoggedIn, bitstream, fileLink];
return [isAuthorized, isLoggedIn, isMatomoEnabled, bitstream, fileLink];
}));
} else if (hasValue(accessToken)) {
return [[isAuthorized, !isLoggedIn, bitstream, '', accessToken]];
return [[isAuthorized, !isLoggedIn, isMatomoEnabled, bitstream, '', accessToken]];

Check warning on line 124 in src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.ts

View check run for this annotation

Codecov / codecov/patch

src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.ts#L124

Added line #L124 was not covered by tests
} else {
return [[isAuthorized, isLoggedIn, bitstream, bitstream._links.content.href]];
return [[isAuthorized, isLoggedIn, isMatomoEnabled, bitstream, bitstream._links.content.href]];
}
}),
switchMap(([isAuthorized, isLoggedIn, bitstream, fileLink, accessToken]: [boolean, boolean, Bitstream, string, string]) =>
this.matomoService.appendVisitorId(fileLink)
.pipe(
switchMap(([isAuthorized, isLoggedIn, isMatomoEnabled, bitstream, fileLink, accessToken]: [boolean, boolean, boolean, Bitstream, string, string]) => {
if (isMatomoEnabled) {
return this.matomoService.appendVisitorId(fileLink).pipe(
map((fileLinkWithVisitorId) => [isAuthorized, isLoggedIn, bitstream, fileLinkWithVisitorId, accessToken]),
),
),
);
}
return observableOf([isAuthorized, isLoggedIn, bitstream, fileLink, accessToken]);
}),
).subscribe(([isAuthorized, isLoggedIn, bitstream, fileLink, accessToken]: [boolean, boolean, Bitstream, string, string]) => {
if (isAuthorized && isLoggedIn && isNotEmpty(fileLink)) {
this.hardRedirectService.redirect(fileLink);
Expand Down
3 changes: 2 additions & 1 deletion src/app/shared/cookies/browser-orejime.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
NativeWindowService,
} from '../../core/services/window.service';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { MATOMO_ENABLED } from '../../statistics/matomo.service';
import {
hasValue,
isEmpty,
Expand Down Expand Up @@ -90,7 +91,7 @@ export class BrowserOrejimeService extends OrejimeService {

private readonly GOOGLE_ANALYTICS_SERVICE_NAME = 'google-analytics';

private readonly MATOMO_ENABLED = 'matomo.enabled';
private readonly MATOMO_ENABLED = MATOMO_ENABLED;

/**
* Initial Orejime configuration
Expand Down
17 changes: 17 additions & 0 deletions src/app/statistics/matomo.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
export const MATOMO_TRACKER_URL = 'matomo.tracker.url';
export const MATOMO_SITE_ID = 'matomo.request.siteid';

export const MATOMO_ENABLED = 'matomo.enabled';

/**
* Service to manage Matomo analytics integration.
* Handles initialization and consent management for Matomo tracking.
Expand Down Expand Up @@ -143,6 +145,21 @@
);
}

/**
* Checks if Matomo tracking is enabled by retrieving the configuration property.
* @returns An Observable that emits a boolean indicating whether Matomo tracking is enabled.
*/
isMatomoEnabled$(): Observable<boolean> {
return this.configService.findByPropertyName(MATOMO_ENABLED)

Check warning on line 153 in src/app/statistics/matomo.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/statistics/matomo.service.ts#L153

Added line #L153 was not covered by tests
.pipe(
getFirstCompletedRemoteData(),
map((res: RemoteData<ConfigurationProperty>) => {
return res.hasSucceeded && res.payload && isNotEmpty(res.payload.values) &&
res.payload.values[0]?.toLowerCase() === 'true';
}),
);
}

/**
* Appends the visitor ID as a query parameter to the given URL.
* @param url - The original URL to modify
Expand Down
Loading