Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add CAPTCHA to request-a-copy form #2712

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 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
7 changes: 6 additions & 1 deletion src/app/core/data/item-request-data.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
});
});
Expand Down
13 changes: 8 additions & 5 deletions src/app/core/data/item-request-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,22 @@
* Request a copy of an item
* @param itemRequest
*/
requestACopy(itemRequest: ItemRequest): Observable<RemoteData<ItemRequest>> {
requestACopy(itemRequest: ItemRequest, captchaToken: string = null): Observable<RemoteData<ItemRequest>> {
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);

Check warning on line 59 in src/app/core/data/item-request-data.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/core/data/item-request-data.service.ts#L59

Added line #L59 was not covered by tests
}
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();

return this.rdbService.buildFromRequestUUID<ItemRequest>(requestId).pipe(
getFirstCompletedRemoteData()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ <h1 class="mb-4">{{'bitstream-request-a-copy.header' | translate}}</h1>
<div class="col-12">
<label for="name">{{'bitstream-request-a-copy.name.label' | translate}}</label>
<input [className]="(name.invalid) && (name.dirty || name.touched) ? 'form-control is-invalid' :'form-control'"
type="text" id="name" formControlName="name"/>
type="text" id="name" formControlName="name" (input)="changeCatch()"/>
<div *ngIf="name.invalid && (name.dirty || name.touched)"
class="invalid-feedback show-feedback">
<span *ngIf="name.errors && name.errors.required">
Expand All @@ -31,7 +31,7 @@ <h1 class="mb-4">{{'bitstream-request-a-copy.header' | translate}}</h1>
for="email">{{'bitstream-request-a-copy.email.label' | translate}}</label>
<input
[className]="(email.invalid) && (email.dirty || email.touched) ? 'form-control is-invalid' :'form-control'"
id="email" formControlName="email">
id="email" formControlName="email" (input)="changeCatch()">
<div *ngIf="email.invalid && (email.dirty || email.touched)"
class="invalid-feedback show-feedback">
<span *ngIf="email.errors">
Expand Down Expand Up @@ -64,22 +64,28 @@ <h1 class="mb-4">{{'bitstream-request-a-copy.header' | translate}}</h1>
for="message">{{'bitstream-request-a-copy.message.label' | translate}}</label>
<textarea rows="5"
[className]="'form-control'"
id="message" formControlName="message"></textarea>
id="message" formControlName="message" (input)="changeCatch()"></textarea>
</div>
</div>

</div>
</form>

<div class="row mb-4">
GauravD2t marked this conversation as resolved.
Show resolved Hide resolved
<div class="col-12" *ngIf="isRecaptchaCookieAccepted() && (googleRecaptchaService.captchaVersion() | async) === 'v2'">
<ds-google-recaptcha [captchaMode]="(googleRecaptchaService.captchaMode() | async)"
(executeRecaptcha)="register($event)" (checkboxChecked)="onCheckboxChecked($event)"
(showNotification)="showNotification($event)"></ds-google-recaptcha>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 text-right">

<a (click)="navigateBack()" role="button" class="btn btn-outline-secondary mr-1">
<i class="fas fa-arrow-left"></i> {{'bitstream-request-a-copy.return' | translate}}
</a>

<button
[disabled]="requestCopyForm.invalid"
[disabled]="!registrationVerification || registrationVerification && !isRecaptchaCookieAccepted() || disableUntilChecked"
class="btn btn-default btn-primary"
(click)="onSubmit()">{{'bitstream-request-a-copy.submit' | translate}}</button>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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', () => {
Expand All @@ -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: '[email protected]',
Expand Down Expand Up @@ -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();
Expand All @@ -125,6 +143,8 @@ describe('BitstreamRequestACopyPageComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(BitstreamRequestACopyPageComponent);
component = fixture.componentInstance;
googleRecaptchaService.captchaVersion$ = captchaVersion$;
googleRecaptchaService.captchaMode$ = captchaMode$;
GauravD2t marked this conversation as resolved.
Show resolved Hide resolved
fixture.detectChanges();
});
it('should init the comp', () => {
Expand Down Expand Up @@ -234,7 +254,7 @@ describe('BitstreamRequestACopyPageComponent', () => {
component.email.patchValue('[email protected]');
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(),
{
Expand All @@ -246,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();
});
Expand All @@ -268,6 +288,7 @@ describe('BitstreamRequestACopyPageComponent', () => {
component.email.patchValue('[email protected]');
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(),
Expand All @@ -280,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();
});
Expand Down
Loading
Loading