mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
72635: Cookie preferences first committ
This commit is contained in:
@@ -97,6 +97,7 @@
|
|||||||
"json5": "^2.1.0",
|
"json5": "^2.1.0",
|
||||||
"jsonschema": "1.2.2",
|
"jsonschema": "1.2.2",
|
||||||
"jwt-decode": "^2.2.0",
|
"jwt-decode": "^2.2.0",
|
||||||
|
"klaro": "^0.5.34",
|
||||||
"moment": "^2.22.1",
|
"moment": "^2.22.1",
|
||||||
"morgan": "^1.9.1",
|
"morgan": "^1.9.1",
|
||||||
"ng-mocks": "^8.1.0",
|
"ng-mocks": "^8.1.0",
|
||||||
|
@@ -5,7 +5,7 @@ import {
|
|||||||
Component,
|
Component,
|
||||||
HostListener,
|
HostListener,
|
||||||
Inject,
|
Inject,
|
||||||
OnInit,
|
OnInit, Optional,
|
||||||
ViewEncapsulation
|
ViewEncapsulation
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { NavigationCancel, NavigationEnd, NavigationStart, Router } from '@angular/router';
|
import { NavigationCancel, NavigationEnd, NavigationStart, Router } from '@angular/router';
|
||||||
@@ -31,8 +31,7 @@ import { Angulartics2DSpace } from './statistics/angulartics/dspace-provider';
|
|||||||
import { environment } from '../environments/environment';
|
import { environment } from '../environments/environment';
|
||||||
import { models } from './core/core.module';
|
import { models } from './core/core.module';
|
||||||
import { LocaleService } from './core/locale/locale.service';
|
import { LocaleService } from './core/locale/locale.service';
|
||||||
|
import { CookiesService } from './shared/cookies/cookies.service';
|
||||||
export const LANG_COOKIE = 'language_cookie';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-app',
|
selector: 'ds-app',
|
||||||
@@ -69,7 +68,8 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||||||
private cssService: CSSVariableService,
|
private cssService: CSSVariableService,
|
||||||
private menuService: MenuService,
|
private menuService: MenuService,
|
||||||
private windowService: HostWindowService,
|
private windowService: HostWindowService,
|
||||||
private localeService: LocaleService
|
private localeService: LocaleService,
|
||||||
|
@Optional() private cookiesService: CookiesService
|
||||||
) {
|
) {
|
||||||
/* Use models object so all decorators are actually called */
|
/* Use models object so all decorators are actually called */
|
||||||
this.models = models;
|
this.models = models;
|
||||||
@@ -91,6 +91,8 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||||||
console.info(environment);
|
console.info(environment);
|
||||||
}
|
}
|
||||||
this.storeCSSVariables();
|
this.storeCSSVariables();
|
||||||
|
|
||||||
|
this.cookiesService.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
12
src/app/shared/cookies/cookies.service.spec.ts
Normal file
12
src/app/shared/cookies/cookies.service.spec.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CookiesService } from './cookies.service';
|
||||||
|
|
||||||
|
describe('CookiesService', () => {
|
||||||
|
beforeEach(() => TestBed.configureTestingModule({}));
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
const service: CookiesService = TestBed.get(CookiesService);
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
192
src/app/shared/cookies/cookies.service.ts
Normal file
192
src/app/shared/cookies/cookies.service.ts
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import * as Klaro from 'klaro'
|
||||||
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
import { TOKENITEM } from '../../core/auth/models/auth-token-info.model';
|
||||||
|
import { IMPERSONATING_COOKIE, REDIRECT_COOKIE } from '../../core/auth/auth.service';
|
||||||
|
import { LANG_COOKIE } from '../../core/locale/locale.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
export const HAS_AGREED_END_USER = 'hasAgreedEndUser';
|
||||||
|
export const KLARO = 'klaro';
|
||||||
|
|
||||||
|
const cookieNameMessagePrefix = 'cookies.consent.app.title.';
|
||||||
|
const cookieDescriptionMessagePrefix = 'cookies.consent.app.description.';
|
||||||
|
const cookiePurposeMessagePrefix = 'cookies.consent.purpose.';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
|
||||||
|
export class CookiesService {
|
||||||
|
|
||||||
|
message$: BehaviorSubject<string> = new BehaviorSubject<string>('');
|
||||||
|
|
||||||
|
klaroConfig = {
|
||||||
|
/*
|
||||||
|
Setting 'hideLearnMore' to 'true' will hide the "learn more / customize" link in
|
||||||
|
the consent notice. We strongly advise against using this under most
|
||||||
|
circumstances, as it keeps the user from customizing his/her consent choices.
|
||||||
|
*/
|
||||||
|
hideLearnMore: false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
Setting 'acceptAll' to 'true' will show an "accept all" button in the notice and
|
||||||
|
modal, which will enable all third-party apps if the user clicks on it. If set
|
||||||
|
to 'false', there will be an "accept" button that will only enable the apps that
|
||||||
|
are enabled in the consent modal.
|
||||||
|
*/
|
||||||
|
acceptAll: true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
You can also set a custom expiration time for the Klaro cookie. By default, it
|
||||||
|
will expire after 30 days. Only relevant if 'storageMethod' is set to 'cookie'.
|
||||||
|
*/
|
||||||
|
cookieExpiresAfterDays: 365,
|
||||||
|
|
||||||
|
htmlText: true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
You can overwrite existing translations and add translations for your app
|
||||||
|
descriptions and purposes. See `src/translations/` for a full list of
|
||||||
|
translations that can be overwritten:
|
||||||
|
https://github.com/KIProtect/klaro/tree/master/src/translations
|
||||||
|
*/
|
||||||
|
translations: {
|
||||||
|
en: {
|
||||||
|
consentNotice: {
|
||||||
|
description: 'We collect and process your personal information for the following purposes: {purposes}.<br>To learn more, please read our {privacyPolicy}'
|
||||||
|
},
|
||||||
|
purposes: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: 'token_item',
|
||||||
|
purposes: ['authentication'],
|
||||||
|
required: true,
|
||||||
|
cookies: [
|
||||||
|
TOKENITEM
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'impersonation',
|
||||||
|
purposes: ['authentication'],
|
||||||
|
required: true,
|
||||||
|
cookies: [
|
||||||
|
IMPERSONATING_COOKIE
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'redirect',
|
||||||
|
purposes: ['authentication'],
|
||||||
|
required: true,
|
||||||
|
cookies: [
|
||||||
|
REDIRECT_COOKIE
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'language',
|
||||||
|
purposes: ['preferences'],
|
||||||
|
required: true,
|
||||||
|
cookies: [
|
||||||
|
LANG_COOKIE
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'klaro',
|
||||||
|
purposes: ['acknowledgement'],
|
||||||
|
required: true,
|
||||||
|
cookies: [
|
||||||
|
KLARO
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'has_agreed_end_user',
|
||||||
|
purposes: ['acknowledgement'],
|
||||||
|
required: true,
|
||||||
|
cookies: [
|
||||||
|
HAS_AGREED_END_USER
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'google-analytics',
|
||||||
|
purposes: ['statistics'],
|
||||||
|
required: false,
|
||||||
|
cookies: [
|
||||||
|
// /*
|
||||||
|
// you an either only provide a cookie name or regular expression (regex) or a list
|
||||||
|
// consisting of a name or regex, a path and a cookie domain. Providing a path and
|
||||||
|
// domain is necessary if you have apps that set cookies for a path that is not
|
||||||
|
// "/", or a domain that is not the current domain. If you do not set these values
|
||||||
|
// properly, the cookie can't be deleted by Klaro, as there is no way to access the
|
||||||
|
// path or domain of a cookie in JS. Notice that it is not possible to delete
|
||||||
|
// cookies that were set on a third-party domain, or cookies that have the HTTPOnly
|
||||||
|
// attribute: https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#new-
|
||||||
|
// cookie_domain
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
// /*
|
||||||
|
// This rule will match cookies that contain the string '_pk_' and that are set on
|
||||||
|
// the path '/' and the domain 'klaro.kiprotect.com'
|
||||||
|
// */
|
||||||
|
[/^_ga.?$/],
|
||||||
|
[/^_gid$/],
|
||||||
|
//
|
||||||
|
// /*
|
||||||
|
// Same as above, only for the 'localhost' domain
|
||||||
|
// */
|
||||||
|
// [/^_pk_.*$/, '/', 'localhost'],
|
||||||
|
//
|
||||||
|
// /*
|
||||||
|
// This rule will match all cookies named 'piwik_ignore' that are set on the path
|
||||||
|
// '/' on the current domain
|
||||||
|
// */
|
||||||
|
// 'piwik_ignore',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
You can define an optional callback function that will be called each time the
|
||||||
|
consent state for the given app changes. The consent value will be passed as the
|
||||||
|
first parameter to the function (true=consented). The `app` config will be
|
||||||
|
passed as the second parameter.
|
||||||
|
*/
|
||||||
|
callback: (consent, app) => {
|
||||||
|
this.message$.next('User consent for app ' + app.name + ': consent=' + consent);
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
If 'onlyOnce' is set to 'true', the app will only be executed once regardless
|
||||||
|
how often the user toggles it on and off. This is relevant e.g. for tracking
|
||||||
|
scripts that would generate new page view events every time Klaro disables and
|
||||||
|
re-enables them due to a consent change by the user.
|
||||||
|
*/
|
||||||
|
onlyOnce: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(private translateService: TranslateService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
this.klaroConfig.apps.forEach((app) => {
|
||||||
|
this.klaroConfig.translations.en[app.name] = { title: this.getTitleTranslation(app.name), description: this.getDescriptionTranslation(app.name) };
|
||||||
|
app.purposes.forEach((purpose) => {
|
||||||
|
this.klaroConfig.translations.en.purposes[purpose] = this.getPurposeTranslation(purpose);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
Klaro.show(this.klaroConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTitleTranslation(title: string) {
|
||||||
|
return this.translateService.instant(cookieNameMessagePrefix + title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getDescriptionTranslation(description: string) {
|
||||||
|
return this.translateService.instant(cookieDescriptionMessagePrefix + description);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getPurposeTranslation(purpose: string) {
|
||||||
|
return this.translateService.instant(cookiePurposeMessagePrefix + purpose);
|
||||||
|
}
|
||||||
|
}
|
@@ -937,6 +937,41 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"cookies.consent.app.title.token_item": "User Token",
|
||||||
|
|
||||||
|
"cookies.consent.app.description.token_item": "User login identification",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"cookies.consent.app.title.impersonation": "Impersonation",
|
||||||
|
|
||||||
|
"cookies.consent.app.description.impersonation": "Switching users",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"cookies.consent.app.title.klaro": "Klaro",
|
||||||
|
|
||||||
|
"cookies.consent.app.description.klaro": "Cookie consent preferences",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"cookies.consent.app.title.has_agreed_end_user": "Has agreed end user",
|
||||||
|
|
||||||
|
"cookies.consent.app.description.has_agreed_end_user": "",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"cookies.consent.purpose.authentication": "Authentication",
|
||||||
|
|
||||||
|
"cookies.consent.purpose.statistics": "Statistics",
|
||||||
|
|
||||||
|
"cookies.consent.purpose.preferences": "Preferences",
|
||||||
|
|
||||||
|
"cookies.consent.purpose.acknowledgement": "Acknowledgement",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"curation-task.task.checklinks.label": "Check Links in Metadata",
|
"curation-task.task.checklinks.label": "Check Links in Metadata",
|
||||||
|
|
||||||
"curation-task.task.noop.label": "NOOP",
|
"curation-task.task.noop.label": "NOOP",
|
||||||
|
@@ -23,6 +23,7 @@ import { SubmissionService } from '../../app/submission/submission.service';
|
|||||||
import { StatisticsModule } from '../../app/statistics/statistics.module';
|
import { StatisticsModule } from '../../app/statistics/statistics.module';
|
||||||
import { HardRedirectService } from '../../app/core/services/hard-redirect.service';
|
import { HardRedirectService } from '../../app/core/services/hard-redirect.service';
|
||||||
import { BrowserHardRedirectService } from '../../app/core/services/browser-hard-redirect.service';
|
import { BrowserHardRedirectService } from '../../app/core/services/browser-hard-redirect.service';
|
||||||
|
import { CookiesService } from '../../app/shared/cookies/cookies.service';
|
||||||
|
|
||||||
export const REQ_KEY = makeStateKey<string>('req');
|
export const REQ_KEY = makeStateKey<string>('req');
|
||||||
|
|
||||||
@@ -83,6 +84,10 @@ export function locationProvider(): Location {
|
|||||||
provide: CookieService,
|
provide: CookieService,
|
||||||
useClass: ClientCookieService
|
useClass: ClientCookieService
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: CookiesService,
|
||||||
|
useClass: CookiesService
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: SubmissionService,
|
provide: SubmissionService,
|
||||||
useClass: SubmissionService
|
useClass: SubmissionService
|
||||||
|
@@ -6165,6 +6165,11 @@ kind-of@^6.0.0, kind-of@^6.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
|
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
|
||||||
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
||||||
|
|
||||||
|
klaro@^0.5.34:
|
||||||
|
version "0.5.34"
|
||||||
|
resolved "https://registry.yarnpkg.com/klaro/-/klaro-0.5.34.tgz#0b524be96a1bb177fe88ff2603e1be75f494fc98"
|
||||||
|
integrity sha512-M6KHqlBWpMyYoxOK1icoJMeYsaPT7YhzJIAQ3wdxZWGgBc0sV7xQsf0PsgMUVnuTD0AeC58QegCGEv0qYeq4gw==
|
||||||
|
|
||||||
last-call-webpack-plugin@^3.0.0:
|
last-call-webpack-plugin@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555"
|
resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555"
|
||||||
|
Reference in New Issue
Block a user