From 421bd3fd8275f60131c738a1f69c512b8e4a3e8e Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Fri, 8 Dec 2023 14:37:38 +0530 Subject: [PATCH 01/12] Add Captcha TEST --- ...tstream-request-a-copy-page.component.html | 12 +- ...ream-request-a-copy-page.component.spec.ts | 22 +++- ...bitstream-request-a-copy-page.component.ts | 123 +++++++++++++++++- 3 files changed, 150 insertions(+), 7 deletions(-) diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html index 2d4ac89fcc3..74ca6df9941 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html @@ -67,6 +67,13 @@

{{'bitstream-request-a-copy.header' | translate}}

id="message" formControlName="message"> +
+
+ +
+
@@ -77,11 +84,10 @@

{{'bitstream-request-a-copy.header' | translate}}

{{'bitstream-request-a-copy.return' | translate}} - + (click)="register()">{{'bitstream-request-a-copy.submit' | translate}} diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts index cbfbdf361f4..de54872f499 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { AuthService } from '../../../core/auth/auth.service'; -import { of as observableOf } from 'rxjs'; +import { of as observableOf, of } from 'rxjs'; import { Bitstream } from '../../../core/shared/bitstream.model'; import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; import { @@ -25,6 +25,9 @@ import { EPerson } from '../../../core/eperson/models/eperson.model'; import { ItemRequest } from '../../../core/shared/item-request.model'; import { Location } from '@angular/common'; import { BitstreamDataService } from '../../../core/data/bitstream-data.service'; +import { CookieService } from 'src/app/core/services/cookie.service'; +import { CookieServiceMock } from 'src/app/shared/mocks/cookie.service.mock'; +import { GoogleRecaptchaService } from 'src/app/core/google-recaptcha/google-recaptcha.service'; describe('BitstreamRequestACopyPageComponent', () => { @@ -44,6 +47,19 @@ describe('BitstreamRequestACopyPageComponent', () => { let bitstream: Bitstream; let eperson; + const captchaVersion$ = of('v3'); + const captchaMode$ = of('invisible'); + const confResponse$ = createSuccessfulRemoteDataObject$({ values: ['true'] }); + const confResponseDisabled$ = createSuccessfulRemoteDataObject$({ values: ['false'] }); + + const googleRecaptchaService = jasmine.createSpyObj('googleRecaptchaService', { + getRecaptchaToken: Promise.resolve('googleRecaptchaToken'), + executeRecaptcha: Promise.resolve('googleRecaptchaToken'), + getRecaptchaTokenResponse: Promise.resolve('googleRecaptchaToken'), + captchaVersion: captchaVersion$, + captchaMode: captchaMode$, + }); + function init() { eperson = Object.assign(new EPerson(), { email: 'test@mail.org', @@ -112,6 +128,8 @@ describe('BitstreamRequestACopyPageComponent', () => { {provide: NotificationsService, useValue: notificationsService}, {provide: DSONameService, useValue: new DSONameServiceMock()}, {provide: BitstreamDataService, useValue: bitstreamDataService}, + {provide: CookieService, useValue: new CookieServiceMock()}, + {provide: GoogleRecaptchaService, useValue: googleRecaptchaService}, ] }) .compileComponents(); @@ -125,6 +143,8 @@ describe('BitstreamRequestACopyPageComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(BitstreamRequestACopyPageComponent); component = fixture.componentInstance; + googleRecaptchaService.captchaVersion$ = captchaVersion$; + googleRecaptchaService.captchaMode$ = captchaMode$; fixture.detectChanges(); }); it('should init the comp', () => { diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts index 77e1049d87f..bdf29d865da 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts @@ -1,5 +1,5 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { filter, map, switchMap, take } from 'rxjs/operators'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { filter, map, startWith, switchMap, take } from 'rxjs/operators'; import { ActivatedRoute, Router } from '@angular/router'; import { hasValue, isNotEmpty } from '../../../shared/empty.util'; import { getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators'; @@ -7,7 +7,7 @@ import { Bitstream } from '../../../core/shared/bitstream.model'; import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; import { FeatureID } from '../../../core/data/feature-authorization/feature-id'; import { AuthService } from '../../../core/auth/auth.service'; -import { combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription } from 'rxjs'; +import { combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription, combineLatest, of, BehaviorSubject } from 'rxjs'; import { getBitstreamDownloadRoute, getForbiddenRoute } from '../../../app-routing-paths'; import { TranslateService } from '@ngx-translate/core'; import { EPerson } from '../../../core/eperson/models/eperson.model'; @@ -20,6 +20,9 @@ import { DSONameService } from '../../../core/breadcrumbs/dso-name.service'; import { Location } from '@angular/common'; import { BitstreamDataService } from '../../../core/data/bitstream-data.service'; import { getItemPageRoute } from '../../item-page-routing-paths'; +import { CookieService } from 'src/app/core/services/cookie.service'; +import { CAPTCHA_NAME, GoogleRecaptchaService } from 'src/app/core/google-recaptcha/google-recaptcha.service'; + @Component({ selector: 'ds-bitstream-request-a-copy-page', @@ -42,6 +45,29 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { bitstream$: Observable; bitstream: Bitstream; bitstreamName: string; + form: UntypedFormGroup; + /** + * registration verification configuration + */ + registrationVerification = false; + subscriptions: Subscription[] = []; + /** + * The message prefix + */ + @Input() + MESSAGE_PREFIX: string; + /** + * Return true if the user completed the reCaptcha verification (checkbox mode) + */ + checkboxCheckedSubject$ = new BehaviorSubject(false); + + captchaVersion(): Observable { + return this.googleRecaptchaService.captchaVersion(); + } + + captchaMode(): Observable { + return this.googleRecaptchaService.captchaMode(); + } constructor(private location: Location, private translateService: TranslateService, @@ -54,6 +80,8 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { private notificationsService: NotificationsService, private dsoNameService: DSONameService, private bitstreamService: BitstreamDataService, + public cookieService: CookieService, + public googleRecaptchaService: GoogleRecaptchaService, ) { } @@ -209,4 +237,93 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { getBitstreamLink() { return [getBitstreamDownloadRoute(this.bitstream)]; } + + /** + * execute the captcha function for v2 invisible + */ + executeRecaptcha() { + this.googleRecaptchaService.executeRecaptcha(); + } + + /** + * Register an email address + */ + register(tokenV2?) { + if (!this.requestCopyForm.invalid) { + if (this.registrationVerification) { + this.subscriptions.push(combineLatest([this.captchaVersion(), this.captchaMode()]).pipe( + switchMap(([captchaVersion, captchaMode]) => { + if (captchaVersion === 'v3') { + return this.googleRecaptchaService.getRecaptchaToken('register_email'); + } else if (captchaVersion === 'v2' && captchaMode === 'checkbox') { + return of(this.googleRecaptchaService.getRecaptchaTokenResponse()); + } else if (captchaVersion === 'v2' && captchaMode === 'invisible') { + return of(tokenV2); + } else { + console.error(`Invalid reCaptcha configuration: version = ${captchaVersion}, mode = ${captchaMode}`); + this.showNotification('error'); + } + }), + take(1), + ).subscribe((token) => { + if (isNotEmpty(token)) { + // this.onSubmit(); + this.registrationVerification = true; + } else { + console.error('reCaptcha error'); + this.showNotification('error'); + } + } + )); + } else { + // this.onSubmit(); + this.registrationVerification = true; + } + } + } + + /** + * Return true if the user has accepted the required cookies for reCaptcha + */ + isRecaptchaCookieAccepted(): boolean { + const klaroAnonymousCookie = this.cookieService.get('klaro-anonymous'); + return isNotEmpty(klaroAnonymousCookie) ? klaroAnonymousCookie[CAPTCHA_NAME] : false; + } + + /** + * Return true if the user has not completed the reCaptcha verification (checkbox mode) + */ + disableUntilCheckedFcn(): Observable { + const checked$ = this.checkboxCheckedSubject$.asObservable(); + return combineLatest([this.captchaVersion(), this.captchaMode(), checked$]).pipe( + // disable if checkbox is not checked or if reCaptcha is not in v2 checkbox mode + switchMap(([captchaVersion, captchaMode, checked]) => captchaVersion === 'v2' && captchaMode === 'checkbox' ? of(!checked) : of(false)), + startWith(true), + ); + } + + onCheckboxChecked(checked: boolean) { + this.checkboxCheckedSubject$.next(checked); + } + + /** + * Show a notification to the user + * @param key + */ + showNotification(key) { + const notificationTitle = this.translateService.get(this.MESSAGE_PREFIX + '.google-recaptcha.notification.title'); + const notificationErrorMsg = this.translateService.get(this.MESSAGE_PREFIX + '.google-recaptcha.notification.message.error'); + const notificationExpiredMsg = this.translateService.get(this.MESSAGE_PREFIX + '.google-recaptcha.notification.message.expired'); + switch (key) { + case 'expired': + this.notificationsService.warning(notificationTitle, notificationExpiredMsg); + break; + case 'error': + this.notificationsService.error(notificationTitle, notificationErrorMsg); + break; + default: + console.warn(`Unimplemented notification '${key}' from reCaptcha service`); + } + } + } From 424b176420ebea599d816c2daa6e3112554c1873 Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:48:12 +0530 Subject: [PATCH 02/12] OFr test For Test added consoles --- .../bitstream-request-a-copy-page.component.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts index bdf29d865da..384b6986fa6 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts @@ -249,15 +249,21 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { * Register an email address */ register(tokenV2?) { + console.log('1',this.registrationVerification) if (!this.requestCopyForm.invalid) { - if (this.registrationVerification) { + if (!this.registrationVerification) { + console.log('2',this.registrationVerification) this.subscriptions.push(combineLatest([this.captchaVersion(), this.captchaMode()]).pipe( switchMap(([captchaVersion, captchaMode]) => { + console.log('3',this.registrationVerification) if (captchaVersion === 'v3') { + console.log('4',this.registrationVerification) return this.googleRecaptchaService.getRecaptchaToken('register_email'); } else if (captchaVersion === 'v2' && captchaMode === 'checkbox') { + console.log('5',this.registrationVerification) return of(this.googleRecaptchaService.getRecaptchaTokenResponse()); } else if (captchaVersion === 'v2' && captchaMode === 'invisible') { + console.log('6',this.registrationVerification) return of(tokenV2); } else { console.error(`Invalid reCaptcha configuration: version = ${captchaVersion}, mode = ${captchaMode}`); @@ -268,16 +274,21 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { ).subscribe((token) => { if (isNotEmpty(token)) { // this.onSubmit(); + this.registrationVerification = true; + console.log('7',this.registrationVerification) } else { + console.log('8',this.registrationVerification) console.error('reCaptcha error'); this.showNotification('error'); } } )); } else { + // this.onSubmit(); this.registrationVerification = true; + console.log('3',this.registrationVerification) } } } From 025910571b86af46ac5cfd5ebb65a6c49ccc7107 Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:57:14 +0530 Subject: [PATCH 03/12] Enable Button Button error resolved --- ...tstream-request-a-copy-page.component.html | 24 ++++++------- ...bitstream-request-a-copy-page.component.ts | 35 ++++++++++++++++++- .../register-email-form.component.ts | 2 ++ 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html index 74ca6df9941..95563bb7093 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html @@ -16,7 +16,7 @@

{{'bitstream-request-a-copy.header' | translate}}

+ type="text" id="name" formControlName="name" (input)="changeCatch()"/>
@@ -31,7 +31,7 @@

{{'bitstream-request-a-copy.header' | translate}}

for="email">{{'bitstream-request-a-copy.email.label' | translate}} + id="email" formControlName="email" (input)="changeCatch()">
@@ -64,19 +64,19 @@

{{'bitstream-request-a-copy.header' | translate}}

for="message">{{'bitstream-request-a-copy.message.label' | translate}} + id="message" formControlName="message" (input)="changeCatch()">
-
-
- -
-
+
- +
+
+ +
+

@@ -85,7 +85,7 @@

{{'bitstream-request-a-copy.header' | translate}}

{{'bitstream-request-a-copy.return' | translate}}
diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts index 384b6986fa6..bd627e1274c 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { filter, map, startWith, switchMap, take } from 'rxjs/operators'; import { ActivatedRoute, Router } from '@angular/router'; import { hasValue, isNotEmpty } from '../../../shared/empty.util'; @@ -60,12 +60,18 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { * Return true if the user completed the reCaptcha verification (checkbox mode) */ checkboxCheckedSubject$ = new BehaviorSubject(false); + disableUntilChecked = true; captchaVersion(): Observable { + this.cdRef.detectChanges(); + console.log(this.googleRecaptchaService.captchaVersion()) return this.googleRecaptchaService.captchaVersion(); + } captchaMode(): Observable { + this.cdRef.detectChanges(); + console.log(this.googleRecaptchaService.captchaMode()) return this.googleRecaptchaService.captchaMode(); } @@ -82,6 +88,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { private bitstreamService: BitstreamDataService, public cookieService: CookieService, public googleRecaptchaService: GoogleRecaptchaService, + private cdRef:ChangeDetectorRef ) { } @@ -133,6 +140,11 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { } })); this.initValues(); + + this.subscriptions.push(this.disableUntilCheckedFcn().subscribe((res) => { + this.disableUntilChecked = res; + this.cdRef.detectChanges(); + })); } get name() { @@ -224,6 +236,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { * Navigates back to the user's previous location */ navigateBack() { + this.resetForm(); this.location.back(); } @@ -249,6 +262,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { * Register an email address */ register(tokenV2?) { + debugger; console.log('1',this.registrationVerification) if (!this.requestCopyForm.invalid) { if (!this.registrationVerification) { @@ -276,6 +290,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { // this.onSubmit(); this.registrationVerification = true; + console.log('7',this.registrationVerification) } else { console.log('8',this.registrationVerification) @@ -315,6 +330,13 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { onCheckboxChecked(checked: boolean) { this.checkboxCheckedSubject$.next(checked); + if(!!checked) { + console.log(this.requestCopyForm.invalid); + if (!this.requestCopyForm.invalid) { + this.registrationVerification = true; + this.cdRef.detectChanges(); + } + } } /** @@ -336,5 +358,16 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { console.warn(`Unimplemented notification '${key}' from reCaptcha service`); } } + + resetForm() { + this.requestCopyForm.reset(); + } + + changeCatch() { + if (!this.requestCopyForm.invalid) { + this.registrationVerification = true; + this.cdRef.detectChanges(); + } + } } diff --git a/src/app/register-email-form/register-email-form.component.ts b/src/app/register-email-form/register-email-form.component.ts index df7e9bea5ef..bbda00035d9 100644 --- a/src/app/register-email-form/register-email-form.component.ts +++ b/src/app/register-email-form/register-email-form.component.ts @@ -148,6 +148,7 @@ export class RegisterEmailFormComponent implements OnDestroy, OnInit { * Register an email address */ register(tokenV2?) { + debugger; if (!this.form.invalid) { if (this.registrationVerification) { this.subscriptions.push(combineLatest([this.captchaVersion(), this.captchaMode()]).pipe( @@ -225,6 +226,7 @@ export class RegisterEmailFormComponent implements OnDestroy, OnInit { } onCheckboxChecked(checked: boolean) { + debugger; this.checkboxCheckedSubject$.next(checked); } From 5e08706386c7f9e90b6048e06f5b525049b0ae1b Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Mon, 11 Dec 2023 14:20:18 +0530 Subject: [PATCH 04/12] with some changes with some changes --- .../bitstream-request-a-copy-page.component.ts | 4 +--- .../register-email-form/register-email-form.component.ts | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts index bd627e1274c..c9980628e05 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts @@ -64,14 +64,12 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { captchaVersion(): Observable { this.cdRef.detectChanges(); - console.log(this.googleRecaptchaService.captchaVersion()) return this.googleRecaptchaService.captchaVersion(); } captchaMode(): Observable { this.cdRef.detectChanges(); - console.log(this.googleRecaptchaService.captchaMode()) return this.googleRecaptchaService.captchaMode(); } @@ -88,7 +86,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { private bitstreamService: BitstreamDataService, public cookieService: CookieService, public googleRecaptchaService: GoogleRecaptchaService, - private cdRef:ChangeDetectorRef + private cdRef: ChangeDetectorRef ) { } diff --git a/src/app/register-email-form/register-email-form.component.ts b/src/app/register-email-form/register-email-form.component.ts index bbda00035d9..dbebe678d90 100644 --- a/src/app/register-email-form/register-email-form.component.ts +++ b/src/app/register-email-form/register-email-form.component.ts @@ -66,11 +66,11 @@ export class RegisterEmailFormComponent implements OnDestroy, OnInit { subscriptions: Subscription[] = []; - captchaVersion(): Observable { +captchaVersion(): Observable { return this.googleRecaptchaService.captchaVersion(); } - captchaMode(): Observable { +captchaMode(): Observable { return this.googleRecaptchaService.captchaMode(); } @@ -148,7 +148,6 @@ export class RegisterEmailFormComponent implements OnDestroy, OnInit { * Register an email address */ register(tokenV2?) { - debugger; if (!this.form.invalid) { if (this.registrationVerification) { this.subscriptions.push(combineLatest([this.captchaVersion(), this.captchaMode()]).pipe( @@ -226,7 +225,6 @@ export class RegisterEmailFormComponent implements OnDestroy, OnInit { } onCheckboxChecked(checked: boolean) { - debugger; this.checkboxCheckedSubject$.next(checked); } From a5c7eb240f21d6796ca0434cba4a7a9b22baf465 Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Mon, 11 Dec 2023 14:44:01 +0530 Subject: [PATCH 05/12] with chnages with changes --- ...bitstream-request-a-copy-page.component.ts | 138 ++++++++---------- 1 file changed, 63 insertions(+), 75 deletions(-) diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts index c9980628e05..53c364389ba 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts @@ -51,21 +51,21 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { */ registrationVerification = false; subscriptions: Subscription[] = []; - /** - * The message prefix - */ - @Input() - MESSAGE_PREFIX: string; - /** - * Return true if the user completed the reCaptcha verification (checkbox mode) - */ + /** + * The message prefix + */ + @Input() + MESSAGE_PREFIX: string; + /** + * Return true if the user completed the reCaptcha verification (checkbox mode) + */ checkboxCheckedSubject$ = new BehaviorSubject(false); disableUntilChecked = true; captchaVersion(): Observable { this.cdRef.detectChanges(); return this.googleRecaptchaService.captchaVersion(); - + } captchaMode(): Observable { @@ -74,19 +74,19 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { } constructor(private location: Location, - private translateService: TranslateService, - private route: ActivatedRoute, - protected router: Router, - private authorizationService: AuthorizationDataService, - private auth: AuthService, - private formBuilder: UntypedFormBuilder, - private itemRequestDataService: ItemRequestDataService, - private notificationsService: NotificationsService, - private dsoNameService: DSONameService, - private bitstreamService: BitstreamDataService, - public cookieService: CookieService, - public googleRecaptchaService: GoogleRecaptchaService, - private cdRef: ChangeDetectorRef + private translateService: TranslateService, + private route: ActivatedRoute, + protected router: Router, + private authorizationService: AuthorizationDataService, + private auth: AuthService, + private formBuilder: UntypedFormBuilder, + private itemRequestDataService: ItemRequestDataService, + private notificationsService: NotificationsService, + private dsoNameService: DSONameService, + private bitstreamService: BitstreamDataService, + public cookieService: CookieService, + public googleRecaptchaService: GoogleRecaptchaService, + private cdRef: ChangeDetectorRef ) { } @@ -134,7 +134,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { this.subs.push(observableCombineLatest([this.canDownload$, canRequestCopy$]).subscribe(([canDownload, canRequestCopy]) => { if (!canDownload && !canRequestCopy) { - this.router.navigateByUrl(getForbiddenRoute(), {skipLocationChange: true}); + this.router.navigateByUrl(getForbiddenRoute(), { skipLocationChange: true }); } })); this.initValues(); @@ -166,13 +166,13 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { */ private initValues() { this.getCurrentUser().pipe(take(1)).subscribe((user) => { - this.requestCopyForm.patchValue({allfiles: 'true'}); + this.requestCopyForm.patchValue({ allfiles: 'true' }); if (hasValue(user)) { - this.requestCopyForm.patchValue({name: user.name, email: user.email}); + this.requestCopyForm.patchValue({ name: user.name, email: user.email }); } }); this.bitstream$.pipe(take(1)).subscribe((bitstream) => { - this.requestCopyForm.patchValue({allfiles: 'false'}); + this.requestCopyForm.patchValue({ allfiles: 'false' }); }); } @@ -260,22 +260,15 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { * Register an email address */ register(tokenV2?) { - debugger; - console.log('1',this.registrationVerification) if (!this.requestCopyForm.invalid) { if (!this.registrationVerification) { - console.log('2',this.registrationVerification) this.subscriptions.push(combineLatest([this.captchaVersion(), this.captchaMode()]).pipe( - switchMap(([captchaVersion, captchaMode]) => { - console.log('3',this.registrationVerification) + switchMap(([captchaVersion, captchaMode]) => { if (captchaVersion === 'v3') { - console.log('4',this.registrationVerification) return this.googleRecaptchaService.getRecaptchaToken('register_email'); } else if (captchaVersion === 'v2' && captchaMode === 'checkbox') { - console.log('5',this.registrationVerification) return of(this.googleRecaptchaService.getRecaptchaTokenResponse()); } else if (captchaVersion === 'v2' && captchaMode === 'invisible') { - console.log('6',this.registrationVerification) return of(tokenV2); } else { console.error(`Invalid reCaptcha configuration: version = ${captchaVersion}, mode = ${captchaMode}`); @@ -284,24 +277,20 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { }), take(1), ).subscribe((token) => { - if (isNotEmpty(token)) { - // this.onSubmit(); - - this.registrationVerification = true; + if (isNotEmpty(token)) { + // this.onSubmit(); - console.log('7',this.registrationVerification) - } else { - console.log('8',this.registrationVerification) - console.error('reCaptcha error'); - this.showNotification('error'); - } + this.registrationVerification = true; + + } else { + this.showNotification('error'); } + } )); } else { - + // this.onSubmit(); this.registrationVerification = true; - console.log('3',this.registrationVerification) } } } @@ -321,14 +310,14 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { const checked$ = this.checkboxCheckedSubject$.asObservable(); return combineLatest([this.captchaVersion(), this.captchaMode(), checked$]).pipe( // disable if checkbox is not checked or if reCaptcha is not in v2 checkbox mode - switchMap(([captchaVersion, captchaMode, checked]) => captchaVersion === 'v2' && captchaMode === 'checkbox' ? of(!checked) : of(false)), + switchMap(([captchaVersion, captchaMode, checked]) => captchaVersion === 'v2' && captchaMode === 'checkbox' ? of(!checked) : of(false)), startWith(true), ); } onCheckboxChecked(checked: boolean) { this.checkboxCheckedSubject$.next(checked); - if(!!checked) { + if (!!checked) { console.log(this.requestCopyForm.invalid); if (!this.requestCopyForm.invalid) { this.registrationVerification = true; @@ -337,35 +326,34 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { } } - /** - * Show a notification to the user - * @param key - */ - showNotification(key) { - const notificationTitle = this.translateService.get(this.MESSAGE_PREFIX + '.google-recaptcha.notification.title'); - const notificationErrorMsg = this.translateService.get(this.MESSAGE_PREFIX + '.google-recaptcha.notification.message.error'); - const notificationExpiredMsg = this.translateService.get(this.MESSAGE_PREFIX + '.google-recaptcha.notification.message.expired'); - switch (key) { - case 'expired': - this.notificationsService.warning(notificationTitle, notificationExpiredMsg); - break; - case 'error': - this.notificationsService.error(notificationTitle, notificationErrorMsg); - break; - default: - console.warn(`Unimplemented notification '${key}' from reCaptcha service`); - } + /** + * Show a notification to the user + * @param key + */ + showNotification(key) { + const notificationTitle = this.translateService.get(this.MESSAGE_PREFIX + '.google-recaptcha.notification.title'); + const notificationErrorMsg = this.translateService.get(this.MESSAGE_PREFIX + '.google-recaptcha.notification.message.error'); + const notificationExpiredMsg = this.translateService.get(this.MESSAGE_PREFIX + '.google-recaptcha.notification.message.expired'); + switch (key) { + case 'expired': + this.notificationsService.warning(notificationTitle, notificationExpiredMsg); + break; + case 'error': + this.notificationsService.error(notificationTitle, notificationErrorMsg); + break; + default: + console.warn(`Unimplemented notification '${key}' from reCaptcha service`); } + } - resetForm() { - this.requestCopyForm.reset(); - } + resetForm() { + this.requestCopyForm.reset(); + } - changeCatch() { - if (!this.requestCopyForm.invalid) { - this.registrationVerification = true; - this.cdRef.detectChanges(); - } + changeCatch() { + if (!this.requestCopyForm.invalid) { + this.registrationVerification = true; + this.cdRef.detectChanges(); } - + } } From e69918ab4bafd7877644506710596a7f268e7560 Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Wed, 13 Dec 2023 10:54:48 +0530 Subject: [PATCH 06/12] with somechanges --- .../request-a-copy/bitstream-request-a-copy-page.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html index 95563bb7093..bc968b6ee2a 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html @@ -87,7 +87,7 @@

{{'bitstream-request-a-copy.header' | translate}}

+ (click)="onSubmit()">{{'bitstream-request-a-copy.submit' | translate}}
From 262975b2e5fd0f8e6b3cb060eb5f2beb47fc0445 Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Mon, 18 Dec 2023 17:55:10 +0530 Subject: [PATCH 07/12] Addea TOken TO header --- src/app/core/data/item-request-data.service.ts | 11 +++++++++-- .../bitstream-request-a-copy-page.component.ts | 6 +++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/app/core/data/item-request-data.service.ts b/src/app/core/data/item-request-data.service.ts index ff6025f7ac8..b14921a66e8 100644 --- a/src/app/core/data/item-request-data.service.ts +++ b/src/app/core/data/item-request-data.service.ts @@ -50,15 +50,22 @@ export class ItemRequestDataService extends IdentifiableDataService * Request a copy of an item * @param itemRequest */ - requestACopy(itemRequest: ItemRequest): Observable> { + requestACopy(itemRequest: ItemRequest, captchaToken: string = null): Observable> { const requestId = this.requestService.generateRequestId(); const href$ = this.getItemRequestEndpoint(); + + const options: HttpOptions = Object.create({}); + let headers = new HttpHeaders(); + if (captchaToken) { + headers = headers.append('x-recaptcha-token', captchaToken); + } + options.headers = headers; href$.pipe( find((href: string) => hasValue(href)), map((href: string) => { - const request = new PostRequest(requestId, href, itemRequest); + const request = new PostRequest(requestId, href, itemRequest,options); this.requestService.send(request); }) ).subscribe(); diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts index 53c364389ba..d55fa64f812 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts @@ -61,7 +61,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { */ checkboxCheckedSubject$ = new BehaviorSubject(false); disableUntilChecked = true; - + captchaToken:string; captchaVersion(): Observable { this.cdRef.detectChanges(); return this.googleRecaptchaService.captchaVersion(); @@ -208,7 +208,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { itemRequest.requestName = this.name.value; itemRequest.requestMessage = this.message.value; - this.itemRequestDataService.requestACopy(itemRequest).pipe( + this.itemRequestDataService.requestACopy(itemRequest,this.captchaToken).pipe( getFirstCompletedRemoteData() ).subscribe((rd) => { if (rd.hasSucceeded) { @@ -279,7 +279,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { ).subscribe((token) => { if (isNotEmpty(token)) { // this.onSubmit(); - + this.captchaToken = token; this.registrationVerification = true; } else { From b9cc9e10b8ed5e13913b77898527420dfb65c523 Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Tue, 19 Dec 2023 11:55:53 +0530 Subject: [PATCH 08/12] Trailing spaces remove and space add --- src/app/core/data/item-request-data.service.ts | 4 ---- .../request-a-copy/bitstream-request-a-copy-page.component.ts | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/app/core/data/item-request-data.service.ts b/src/app/core/data/item-request-data.service.ts index b14921a66e8..0bc219462df 100644 --- a/src/app/core/data/item-request-data.service.ts +++ b/src/app/core/data/item-request-data.service.ts @@ -52,16 +52,13 @@ export class ItemRequestDataService extends IdentifiableDataService */ requestACopy(itemRequest: ItemRequest, captchaToken: string = null): Observable> { const requestId = this.requestService.generateRequestId(); - const href$ = this.getItemRequestEndpoint(); - const options: HttpOptions = Object.create({}); let headers = new HttpHeaders(); if (captchaToken) { headers = headers.append('x-recaptcha-token', captchaToken); } options.headers = headers; - href$.pipe( find((href: string) => hasValue(href)), map((href: string) => { @@ -69,7 +66,6 @@ export class ItemRequestDataService extends IdentifiableDataService this.requestService.send(request); }) ).subscribe(); - return this.rdbService.buildFromRequestUUID(requestId).pipe( getFirstCompletedRemoteData() ); diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts index d55fa64f812..1fcac687528 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts @@ -61,7 +61,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { */ checkboxCheckedSubject$ = new BehaviorSubject(false); disableUntilChecked = true; - captchaToken:string; + captchaToken: string; captchaVersion(): Observable { this.cdRef.detectChanges(); return this.googleRecaptchaService.captchaVersion(); From 40fb040d9b6a339978bd8dcef7811944bc94c47b Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Wed, 20 Dec 2023 11:14:26 +0530 Subject: [PATCH 09/12] Added TEST cases Updated test cases which are previously fail due to added captcha to request a copy --- src/app/core/data/item-request-data.service.spec.ts | 7 ++++++- .../bitstream-request-a-copy-page.component.spec.ts | 7 ++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/app/core/data/item-request-data.service.spec.ts b/src/app/core/data/item-request-data.service.spec.ts index a5d18725109..0e0d9a1063a 100644 --- a/src/app/core/data/item-request-data.service.spec.ts +++ b/src/app/core/data/item-request-data.service.spec.ts @@ -8,6 +8,8 @@ import { ItemRequest } from '../shared/item-request.model'; import { PostRequest } from './request.models'; import { RequestCopyEmail } from '../../request-copy/email-request-copy/request-copy-email.model'; import { RestRequestMethod } from './rest-request-method'; +import { HttpHeaders } from '@angular/common/http'; +import { HttpOptions } from '../dspace-rest/dspace-rest.service'; describe('ItemRequestDataService', () => { let service: ItemRequestDataService; @@ -40,8 +42,11 @@ describe('ItemRequestDataService', () => { describe('requestACopy', () => { it('should send a POST request containing the provided item request', (done) => { + let headers = new HttpHeaders(); + const options: HttpOptions = Object.create({}); + options.headers = headers; service.requestACopy(itemRequest).subscribe(() => { - expect(requestService.send).toHaveBeenCalledWith(new PostRequest(requestId, restApiEndpoint, itemRequest)); + expect(requestService.send).toHaveBeenCalledWith(new PostRequest(requestId, restApiEndpoint, itemRequest,options)); done(); }); }); diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts index de54872f499..069860ec0f2 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts @@ -254,7 +254,7 @@ describe('BitstreamRequestACopyPageComponent', () => { component.email.patchValue('user@name.org'); component.allfiles.patchValue('false'); component.message.patchValue('I would like to request a copy'); - + component.captchaToken = 'googleRecaptchaToken'; component.onSubmit(); const itemRequest = Object.assign(new ItemRequest(), { @@ -266,7 +266,7 @@ describe('BitstreamRequestACopyPageComponent', () => { requestMessage: 'I would like to request a copy' }); - expect(itemRequestDataService.requestACopy).toHaveBeenCalledWith(itemRequest); + expect(itemRequestDataService.requestACopy).toHaveBeenCalledWith(itemRequest,component.captchaToken); expect(notificationsService.success).toHaveBeenCalled(); expect(location.back).toHaveBeenCalled(); }); @@ -288,6 +288,7 @@ describe('BitstreamRequestACopyPageComponent', () => { component.email.patchValue('user@name.org'); component.allfiles.patchValue('false'); component.message.patchValue('I would like to request a copy'); + component.captchaToken = 'googleRecaptchaToken'; component.onSubmit(); const itemRequest = Object.assign(new ItemRequest(), @@ -300,7 +301,7 @@ describe('BitstreamRequestACopyPageComponent', () => { requestMessage: 'I would like to request a copy' }); - expect(itemRequestDataService.requestACopy).toHaveBeenCalledWith(itemRequest); + expect(itemRequestDataService.requestACopy).toHaveBeenCalledWith(itemRequest,component.captchaToken); expect(notificationsService.error).toHaveBeenCalled(); expect(location.back).not.toHaveBeenCalled(); }); From 39f68cf6900dc94e301858530466eeeef5770894 Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Fri, 1 Mar 2024 13:50:02 +0530 Subject: [PATCH 10/12] Update register-email-form.component.ts revert file --- src/app/register-email-form/register-email-form.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/register-email-form/register-email-form.component.ts b/src/app/register-email-form/register-email-form.component.ts index dbebe678d90..df7e9bea5ef 100644 --- a/src/app/register-email-form/register-email-form.component.ts +++ b/src/app/register-email-form/register-email-form.component.ts @@ -66,11 +66,11 @@ export class RegisterEmailFormComponent implements OnDestroy, OnInit { subscriptions: Subscription[] = []; -captchaVersion(): Observable { + captchaVersion(): Observable { return this.googleRecaptchaService.captchaVersion(); } -captchaMode(): Observable { + captchaMode(): Observable { return this.googleRecaptchaService.captchaMode(); } From 872d239d5fad4ba2a4cba88fdc4119abbe40f706 Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Sat, 2 Mar 2024 10:35:43 +0530 Subject: [PATCH 11/12] commented out code and rename label --- ...tstream-request-a-copy-page.component.html | 75 ++++++----- ...ream-request-a-copy-page.component.spec.ts | 127 +++++++++++++++--- ...bitstream-request-a-copy-page.component.ts | 49 +++---- 3 files changed, 171 insertions(+), 80 deletions(-) diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html index bc968b6ee2a..f7b5433cb7b 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html @@ -6,7 +6,8 @@

{{'bitstream-request-a-copy.header' | translate}}

{{'bitstream-request-a-copy.intro' | translate}} {{itemName}}

-

{{'bitstream-request-a-copy.intro.bitstream.one' | translate}} {{bitstreamName}}

+

{{'bitstream-request-a-copy.intro.bitstream.one' + | translate}} {{bitstreamName}}

{{'bitstream-request-a-copy.intro.bitstream.all' | translate}}

@@ -16,27 +17,24 @@

{{'bitstream-request-a-copy.header' | translate}}

-
- - {{ 'bitstream-request-a-copy.name.error' | translate }} - + type="text" id="name" formControlName="name" /> +
+ + {{ 'bitstream-request-a-copy.name.error' | translate }} +
- + -
- - {{ 'bitstream-request-a-copy.email.error' | translate }} - + [className]="(email.invalid) && (email.dirty || email.touched) ? 'form-control is-invalid' :'form-control'" + id="email" formControlName="email" /> +
+ + {{ 'bitstream-request-a-copy.email.error' | translate }} +
{{'bitstream-request-a-copy.email.hint' |translate}}
@@ -45,38 +43,41 @@

{{'bitstream-request-a-copy.header' | translate}}

{{'bitstream-request-a-copy.allfiles.label' |translate}}
- + + for="allfiles-true">{{'bitstream-request-a-copy.files-all-true.label' | translate}}
- + + for="allfiles-false">{{'bitstream-request-a-copy.files-all-false.label' | + translate}}
- - + +
- +
-
- -
-
+ +

+

{{ MESSAGE_PREFIX + + '.google-recaptcha.open-cookie-settings' | translate }}

+
+
+ +
+
@@ -85,9 +86,9 @@

{{'bitstream-request-a-copy.header' | translate}}

{{'bitstream-request-a-copy.return' | translate}} + [disabled]="!requestCopyVerification ? requestCopyForm.invalid : requestCopyForm.invalid || requestCopyVerification && !isRecaptchaCookieAccepted() || disableUntilChecked" + class="btn btn-default btn-primary" (click)="onSubmit()">{{'bitstream-request-a-copy.submit' | + translate}}
diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts index 069860ec0f2..d0adeb04172 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.spec.ts @@ -28,6 +28,7 @@ import { BitstreamDataService } from '../../../core/data/bitstream-data.service' import { CookieService } from 'src/app/core/services/cookie.service'; import { CookieServiceMock } from 'src/app/shared/mocks/cookie.service.mock'; import { GoogleRecaptchaService } from 'src/app/core/google-recaptcha/google-recaptcha.service'; +import { ConfigurationDataService } from 'src/app/core/data/configuration-data.service'; describe('BitstreamRequestACopyPageComponent', () => { @@ -47,6 +48,7 @@ describe('BitstreamRequestACopyPageComponent', () => { let bitstream: Bitstream; let eperson; + const captchaVersion$ = of('v3'); const captchaMode$ = of('invisible'); const confResponse$ = createSuccessfulRemoteDataObject$({ values: ['true'] }); @@ -59,13 +61,16 @@ describe('BitstreamRequestACopyPageComponent', () => { captchaVersion: captchaVersion$, captchaMode: captchaMode$, }); + let configurationDataService = jasmine.createSpyObj('configurationDataService', { + findByPropertyName: jasmine.createSpy('findByPropertyName') + }); function init() { eperson = Object.assign(new EPerson(), { email: 'test@mail.org', metadata: { - 'eperson.firstname': [{value: 'Test'}], - 'eperson.lastname': [{value: 'User'}], + 'eperson.firstname': [{ value: 'Test' }], + 'eperson.lastname': [{ value: 'User' }], } }); authService = jasmine.createSpyObj('authService', { @@ -86,13 +91,13 @@ describe('BitstreamRequestACopyPageComponent', () => { notificationsService = new NotificationsServiceStub(); - item = Object.assign(new Item(), {uuid: 'item-uuid'}); + item = Object.assign(new Item(), { uuid: 'item-uuid' }); bitstream = Object.assign(new Bitstream(), { uuid: 'bitstreamUuid', _links: { - content: {href: 'bitstream-content-link'}, - self: {href: 'bitstream-self-link'}, + content: { href: 'bitstream-content-link' }, + self: { href: 'bitstream-self-link' }, } }); @@ -103,7 +108,7 @@ describe('BitstreamRequestACopyPageComponent', () => { ) }), queryParams: observableOf({ - bitstream : bitstream.uuid + bitstream: bitstream.uuid }) }; @@ -112,6 +117,9 @@ describe('BitstreamRequestACopyPageComponent', () => { }); router = new RouterStub(); + configurationDataService = jasmine.createSpyObj('configurationDataService', { + findByPropertyName: jasmine.createSpy('findByPropertyName') + }); } function initTestbed() { @@ -119,17 +127,19 @@ describe('BitstreamRequestACopyPageComponent', () => { imports: [CommonModule, TranslateModule.forRoot(), FormsModule, ReactiveFormsModule], declarations: [BitstreamRequestACopyPageComponent], providers: [ - {provide: Location, useValue: location}, - {provide: ActivatedRoute, useValue: activatedRoute}, - {provide: Router, useValue: router}, - {provide: AuthorizationDataService, useValue: authorizationService}, - {provide: AuthService, useValue: authService}, - {provide: ItemRequestDataService, useValue: itemRequestDataService}, - {provide: NotificationsService, useValue: notificationsService}, - {provide: DSONameService, useValue: new DSONameServiceMock()}, - {provide: BitstreamDataService, useValue: bitstreamDataService}, - {provide: CookieService, useValue: new CookieServiceMock()}, - {provide: GoogleRecaptchaService, useValue: googleRecaptchaService}, + { provide: Location, useValue: location }, + { provide: ActivatedRoute, useValue: activatedRoute }, + { provide: Router, useValue: router }, + { provide: AuthorizationDataService, useValue: authorizationService }, + { provide: AuthService, useValue: authService }, + { provide: ItemRequestDataService, useValue: itemRequestDataService }, + { provide: NotificationsService, useValue: notificationsService }, + { provide: DSONameService, useValue: new DSONameServiceMock() }, + { provide: BitstreamDataService, useValue: bitstreamDataService }, + { provide: CookieService, useValue: new CookieServiceMock() }, + { provide: GoogleRecaptchaService, useValue: googleRecaptchaService }, + { provide: ConfigurationDataService, useValue: configurationDataService }, + ] }) .compileComponents(); @@ -138,6 +148,7 @@ describe('BitstreamRequestACopyPageComponent', () => { describe('init', () => { beforeEach(waitForAsync(() => { init(); + (configurationDataService.findByPropertyName as jasmine.Spy).and.returnValue(confResponse$); initTestbed(); })); beforeEach(() => { @@ -156,6 +167,7 @@ describe('BitstreamRequestACopyPageComponent', () => { describe('when the user is not logged in', () => { beforeEach(waitForAsync(() => { init(); + (configurationDataService.findByPropertyName as jasmine.Spy).and.returnValue(confResponse$); initTestbed(); })); beforeEach(() => { @@ -175,6 +187,7 @@ describe('BitstreamRequestACopyPageComponent', () => { beforeEach(waitForAsync(() => { init(); (authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(true)); + (configurationDataService.findByPropertyName as jasmine.Spy).and.returnValue(confResponse$); initTestbed(); })); beforeEach(() => { @@ -193,6 +206,7 @@ describe('BitstreamRequestACopyPageComponent', () => { describe('when no bitstream was provided', () => { beforeEach(waitForAsync(() => { init(); + (configurationDataService.findByPropertyName as jasmine.Spy).and.returnValue(confResponse$); activatedRoute = { data: observableOf({ dso: createSuccessfulRemoteDataObject( @@ -224,6 +238,7 @@ describe('BitstreamRequestACopyPageComponent', () => { beforeEach(waitForAsync(() => { init(); (authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(true)); + (configurationDataService.findByPropertyName as jasmine.Spy).and.returnValue(confResponse$); initTestbed(); })); beforeEach(() => { @@ -242,6 +257,7 @@ describe('BitstreamRequestACopyPageComponent', () => { describe('onSuccess', () => { beforeEach(waitForAsync(() => { init(); + (configurationDataService.findByPropertyName as jasmine.Spy).and.returnValue(confResponse$); initTestbed(); })); beforeEach(() => { @@ -254,7 +270,7 @@ describe('BitstreamRequestACopyPageComponent', () => { component.email.patchValue('user@name.org'); component.allfiles.patchValue('false'); component.message.patchValue('I would like to request a copy'); - component.captchaToken = 'googleRecaptchaToken'; + component.captchaToken = ''; component.onSubmit(); const itemRequest = Object.assign(new ItemRequest(), { @@ -266,7 +282,7 @@ describe('BitstreamRequestACopyPageComponent', () => { requestMessage: 'I would like to request a copy' }); - expect(itemRequestDataService.requestACopy).toHaveBeenCalledWith(itemRequest,component.captchaToken); + expect(itemRequestDataService.requestACopy).toHaveBeenCalledWith(itemRequest, component.captchaToken); expect(notificationsService.success).toHaveBeenCalled(); expect(location.back).toHaveBeenCalled(); }); @@ -275,6 +291,7 @@ describe('BitstreamRequestACopyPageComponent', () => { describe('onFail', () => { beforeEach(waitForAsync(() => { init(); + (configurationDataService.findByPropertyName as jasmine.Spy).and.returnValue(confResponse$); (itemRequestDataService.requestACopy as jasmine.Spy).and.returnValue(createFailedRemoteDataObject$()); initTestbed(); })); @@ -284,12 +301,82 @@ describe('BitstreamRequestACopyPageComponent', () => { fixture.detectChanges(); }); it('should take the current form information and submit it', () => { + component.name.patchValue('User Name'); + component.email.patchValue('user@name.org'); + component.allfiles.patchValue('false'); + component.message.patchValue('I would like to request a copy'); + component.captchaToken = ''; + component.onSubmit(); + const itemRequest = Object.assign(new ItemRequest(), + { + itemId: item.uuid, + bitstreamId: bitstream.uuid, + allfiles: 'false', + requestEmail: 'user@name.org', + requestName: 'User Name', + requestMessage: 'I would like to request a copy' + }); + + expect(itemRequestDataService.requestACopy).toHaveBeenCalledWith(itemRequest, component.captchaToken); + expect(notificationsService.error).toHaveBeenCalled(); + expect(location.back).not.toHaveBeenCalled(); + }); + }); + }); + + describe('register with google recaptcha', () => { + describe('onSuccess', () => { + beforeEach(waitForAsync(() => { + init(); + (configurationDataService.findByPropertyName as jasmine.Spy).and.returnValue(confResponse$); + initTestbed(); + })); + beforeEach(() => { + fixture = TestBed.createComponent(BitstreamRequestACopyPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + it('should send a registration to the service and on success display a message and return to home', () => { component.name.patchValue('User Name'); component.email.patchValue('user@name.org'); component.allfiles.patchValue('false'); component.message.patchValue('I would like to request a copy'); component.captchaToken = 'googleRecaptchaToken'; + component.onSubmit(); + const itemRequest = Object.assign(new ItemRequest(), + { + itemId: item.uuid, + bitstreamId: bitstream.uuid, + allfiles: 'false', + requestEmail: 'user@name.org', + requestName: 'User Name', + requestMessage: 'I would like to request a copy' + }); + expect(itemRequestDataService.requestACopy).toHaveBeenCalledWith(itemRequest, component.captchaToken); + expect(notificationsService.success).toHaveBeenCalled(); + expect(location.back).toHaveBeenCalled(); + }); + }); + + describe('onFail', () => { + beforeEach(waitForAsync(() => { + init(); + (configurationDataService.findByPropertyName as jasmine.Spy).and.returnValue(confResponse$); + (itemRequestDataService.requestACopy as jasmine.Spy).and.returnValue(createFailedRemoteDataObject$()); + initTestbed(); + })); + beforeEach(() => { + fixture = TestBed.createComponent(BitstreamRequestACopyPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + it('should send a registration to the service and on error display a message', () => { + component.name.patchValue('User Name'); + component.email.patchValue('user@name.org'); + component.allfiles.patchValue('false'); + component.message.patchValue('I would like to request a copy'); + component.captchaToken = ''; component.onSubmit(); const itemRequest = Object.assign(new ItemRequest(), { @@ -301,7 +388,7 @@ describe('BitstreamRequestACopyPageComponent', () => { requestMessage: 'I would like to request a copy' }); - expect(itemRequestDataService.requestACopy).toHaveBeenCalledWith(itemRequest,component.captchaToken); + expect(itemRequestDataService.requestACopy).toHaveBeenCalledWith(itemRequest, component.captchaToken); expect(notificationsService.error).toHaveBeenCalled(); expect(location.back).not.toHaveBeenCalled(); }); diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts index 1fcac687528..1f6ece5fd0b 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit, Optional } from '@angular/core'; import { filter, map, startWith, switchMap, take } from 'rxjs/operators'; import { ActivatedRoute, Router } from '@angular/router'; import { hasValue, isNotEmpty } from '../../../shared/empty.util'; @@ -22,6 +22,10 @@ import { BitstreamDataService } from '../../../core/data/bitstream-data.service' import { getItemPageRoute } from '../../item-page-routing-paths'; import { CookieService } from 'src/app/core/services/cookie.service'; import { CAPTCHA_NAME, GoogleRecaptchaService } from 'src/app/core/google-recaptcha/google-recaptcha.service'; +import { ConfigurationDataService } from 'src/app/core/data/configuration-data.service'; +import { ConfigurationProperty } from 'src/app/core/shared/configuration-property.model'; +import { KlaroService } from 'src/app/shared/cookies/klaro.service'; +import { AlertType } from 'src/app/shared/alert/alert-type'; @Component({ @@ -47,21 +51,22 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { bitstreamName: string; form: UntypedFormGroup; /** - * registration verification configuration + * request verification configuration */ - registrationVerification = false; + requestCopyVerification = false; subscriptions: Subscription[] = []; /** * The message prefix */ @Input() - MESSAGE_PREFIX: string; + MESSAGE_PREFIX = 'request-copy-page.registration'; /** * Return true if the user completed the reCaptcha verification (checkbox mode) */ checkboxCheckedSubject$ = new BehaviorSubject(false); disableUntilChecked = true; captchaToken: string; + public AlertTypeEnum = AlertType; captchaVersion(): Observable { this.cdRef.detectChanges(); return this.googleRecaptchaService.captchaVersion(); @@ -86,7 +91,9 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { private bitstreamService: BitstreamDataService, public cookieService: CookieService, public googleRecaptchaService: GoogleRecaptchaService, - private cdRef: ChangeDetectorRef + private cdRef: ChangeDetectorRef, + private configService: ConfigurationDataService, + @Optional() public klaroService: KlaroService ) { } @@ -138,7 +145,12 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { } })); this.initValues(); - + this.subscriptions.push(this.configService.findByPropertyName('requestcopy.verification.enabled').pipe( + getFirstSucceededRemoteDataPayload(), + map((res: ConfigurationProperty) => res?.values[0].toLowerCase() === 'true') + ).subscribe((res: boolean) => { + this.requestCopyVerification = res; + })); this.subscriptions.push(this.disableUntilCheckedFcn().subscribe((res) => { this.disableUntilChecked = res; this.cdRef.detectChanges(); @@ -207,8 +219,8 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { itemRequest.requestEmail = this.email.value; itemRequest.requestName = this.name.value; itemRequest.requestMessage = this.message.value; - - this.itemRequestDataService.requestACopy(itemRequest,this.captchaToken).pipe( + console.log(this.captchaToken); + this.itemRequestDataService.requestACopy(itemRequest, this.captchaToken).pipe( getFirstCompletedRemoteData() ).subscribe((rd) => { if (rd.hasSucceeded) { @@ -257,11 +269,11 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { } /** - * Register an email address + * Request Copy */ - register(tokenV2?) { + requestCopy(tokenV2?) { if (!this.requestCopyForm.invalid) { - if (!this.registrationVerification) { + if (!this.requestCopyVerification) { this.subscriptions.push(combineLatest([this.captchaVersion(), this.captchaMode()]).pipe( switchMap(([captchaVersion, captchaMode]) => { if (captchaVersion === 'v3') { @@ -278,9 +290,8 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { take(1), ).subscribe((token) => { if (isNotEmpty(token)) { - // this.onSubmit(); this.captchaToken = token; - this.registrationVerification = true; + this.requestCopyVerification = true; } else { this.showNotification('error'); @@ -289,8 +300,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { )); } else { - // this.onSubmit(); - this.registrationVerification = true; + this.requestCopyVerification = true; } } } @@ -320,7 +330,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { if (!!checked) { console.log(this.requestCopyForm.invalid); if (!this.requestCopyForm.invalid) { - this.registrationVerification = true; + this.requestCopyVerification = true; this.cdRef.detectChanges(); } } @@ -349,11 +359,4 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy { resetForm() { this.requestCopyForm.reset(); } - - changeCatch() { - if (!this.requestCopyForm.invalid) { - this.registrationVerification = true; - this.cdRef.detectChanges(); - } - } } From d20eb13fd56b3f9eaa9aeaa493cdbf8e3d1cfbad Mon Sep 17 00:00:00 2001 From: gaurav patel <100828173+GauravD2t@users.noreply.github.com> Date: Mon, 4 Mar 2024 10:18:34 +0530 Subject: [PATCH 12/12] cookies message properties --- src/assets/i18n/en.json5 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 58adaf9663b..94f90e46d17 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -6316,4 +6316,8 @@ "advancesearch.form.submit": "Add", "ldn.no-filter.label": "None", + + "request-copy-page.registration.google-recaptcha.must-accept-cookies": "In order to request copy you must accept the Request a copy of the file (Google reCaptcha) cookies.", + + "request-copy-page.registration.google-recaptcha.open-cookie-settings": "Open cookie settings", }