[UXP-10] reCAPTCHA angular component

This commit is contained in:
Sufiyan Shaikh
2022-06-10 20:48:35 +05:30
committed by Sufiyan Shaikh
parent 342a712513
commit 50e849dd44
12 changed files with 105 additions and 14 deletions

View File

@@ -110,6 +110,7 @@
"moment": "^2.29.4",
"morgan": "^1.10.0",
"ng-mocks": "^13.1.1",
"ng-recaptcha": "^9.0.0",
"ng2-file-upload": "1.4.0",
"ng2-nouislider": "^1.8.3",
"ngx-infinite-scroll": "^10.0.1",

View File

@@ -491,7 +491,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
*/
resetPassword() {
if (hasValue(this.epersonInitial.email)) {
this.epersonRegistrationService.registerEmail(this.epersonInitial.email).pipe(getFirstCompletedRemoteData())
this.epersonRegistrationService.registerEmail(this.epersonInitial.email, null).pipe(getFirstCompletedRemoteData())
.subscribe((response: RemoteData<Registration>) => {
if (response.hasSucceeded) {
this.notificationsService.success(this.translateService.get('admin.access-control.epeople.actions.reset'),

View File

@@ -178,6 +178,8 @@ import { OrcidHistoryDataService } from './orcid/orcid-history-data.service';
import { OrcidQueue } from './orcid/model/orcid-queue.model';
import { OrcidHistory } from './orcid/model/orcid-history.model';
import { OrcidAuthService } from './orcid/orcid-auth.service';
import { GoogleRecaptchaService } from './data/google-recaptcha.service';
import { RecaptchaV3Module, RECAPTCHA_V3_SITE_KEY } from 'ng-recaptcha';
/**
* When not in production, endpoint responses can be mocked for testing purposes
@@ -193,6 +195,7 @@ export const restServiceFactory = (mocks: ResponseMapMock, http: HttpClient) =>
const IMPORTS = [
CommonModule,
RecaptchaV3Module,
StoreModule.forFeature('core', coreReducers, storeModuleConfig as StoreConfig<CoreState, Action>),
EffectsModule.forFeature(coreEffects)
];
@@ -309,6 +312,8 @@ const PROVIDERS = [
OrcidAuthService,
OrcidQueueService,
OrcidHistoryDataService,
GoogleRecaptchaService,
{ provide: RECAPTCHA_V3_SITE_KEY, useValue: environment.recaptchaSiteKey }
];
/**

View File

@@ -54,9 +54,12 @@ export class EpersonRegistrationService {
* Register a new email address
* @param email
*/
registerEmail(email: string): Observable<RemoteData<Registration>> {
registerEmail(email: string, captchaToken: string): Observable<RemoteData<Registration>> {
const registration = new Registration();
registration.email = email;
if (captchaToken) {
registration.captchaToken = captchaToken;
}
const requestId = this.requestService.generateRequestId();

View File

@@ -0,0 +1,15 @@
import { Injectable } from '@angular/core';
import { ReCaptchaV3Service } from 'ng-recaptcha';
@Injectable()
export class GoogleRecaptchaService {
constructor(
private recaptchaV3Service: ReCaptchaV3Service
) {}
public getRecaptchaToken (action) {
return this.recaptchaV3Service.execute(action);
}
}

View File

@@ -25,5 +25,17 @@ export class Registration implements UnCacheableObject {
* The token linked to the registration
*/
token: string;
/**
* The token linked to the registration
*/
groupNames: string[];
/**
* The token linked to the registration
*/
groups: string[];
/**
* The captcha token linked to the registration
*/
captchaToken: string;
}

View File

@@ -6,6 +6,12 @@ import { Router } from '@angular/router';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { Registration } from '../core/shared/registration.model';
import { RemoteData } from '../core/data/remote-data';
import { GoogleRecaptchaService } from '../core/data/google-recaptcha.service';
import { ConfigurationDataService } from '../core/data/configuration-data.service';
import { getFirstCompletedRemoteData } from '../core/shared/operators';
import { ConfigurationProperty } from '../core/shared/configuration-property.model';
import { isNotEmpty } from '../shared/empty.util';
import { map } from 'rxjs/operators';
@Component({
selector: 'ds-register-email-form',
@@ -27,12 +33,19 @@ export class RegisterEmailFormComponent implements OnInit {
@Input()
MESSAGE_PREFIX: string;
/**
* registration verification configuration
*/
registrationVerification = false;
constructor(
private epersonRegistrationService: EpersonRegistrationService,
private notificationService: NotificationsService,
private translateService: TranslateService,
private router: Router,
private formBuilder: FormBuilder
private formBuilder: FormBuilder,
private configService: ConfigurationDataService,
private googleRecaptchaService: GoogleRecaptchaService
) {
}
@@ -45,7 +58,14 @@ export class RegisterEmailFormComponent implements OnInit {
],
})
});
this.configService.findByPropertyName('registration.verification.enabled').pipe(
getFirstCompletedRemoteData(),
map((res: RemoteData<ConfigurationProperty>) => {
return res.hasSucceeded && res.payload && isNotEmpty(res.payload.values) && res.payload.values[0].toLowerCase() === 'true';
})
).subscribe((res: boolean) => {
this.registrationVerification = res;
});
}
/**
@@ -53,20 +73,37 @@ export class RegisterEmailFormComponent implements OnInit {
*/
register() {
if (!this.form.invalid) {
this.epersonRegistrationService.registerEmail(this.email.value).subscribe((response: RemoteData<Registration>) => {
if (response.hasSucceeded) {
this.notificationService.success(this.translateService.get(`${this.MESSAGE_PREFIX}.success.head`),
this.translateService.get(`${this.MESSAGE_PREFIX}.success.content`, {email: this.email.value}));
this.router.navigate(['/home']);
if (this.registrationVerification) {
this.googleRecaptchaService.getRecaptchaToken('register_email').subscribe(res => {
if (isNotEmpty(res)) {
this.registeration(res);
} else {
this.notificationService.error(this.translateService.get(`${this.MESSAGE_PREFIX}.error.head`),
this.translateService.get(`${this.MESSAGE_PREFIX}.error.content`, {email: this.email.value}));
this.translateService.get(`${this.MESSAGE_PREFIX}.error.recaptcha`, {email: this.email.value}));
}
}
);
});
} else {
this.registeration(null);
}
}
}
/**
* Register an email address
*/
registeration(captchaToken) {
this.epersonRegistrationService.registerEmail(this.email.value, captchaToken).subscribe((response: RemoteData<Registration>) => {
if (response.hasSucceeded) {
this.notificationService.success(this.translateService.get(`${this.MESSAGE_PREFIX}.success.head`),
this.translateService.get(`${this.MESSAGE_PREFIX}.success.content`, {email: this.email.value}));
this.router.navigate(['/home']);
} else {
this.notificationService.error(this.translateService.get(`${this.MESSAGE_PREFIX}.error.head`),
this.translateService.get(`${this.MESSAGE_PREFIX}.error.content`, {email: this.email.value}));
}
});
}
get email() {
return this.form.get('email');
}

View File

@@ -3187,6 +3187,8 @@
"register-page.registration.error.content": "An error occured when registering the following email address: {{ email }}",
"register-page.registration.error.recaptcha": "Error when trying to authenticate with recaptcha",
"relationships.add.error.relationship-type.content": "No suitable match could be found for relationship type {{ type }} between the two items",

View File

@@ -3,4 +3,5 @@ import { UniversalConfig } from './universal-config.interface';
export interface BuildConfig extends AppConfig {
universal: UniversalConfig;
recaptchaSiteKey: string;
}

View File

@@ -8,5 +8,6 @@ export const environment: Partial<BuildConfig> = {
preboot: true,
async: true,
time: false
}
},
recaptchaSiteKey: '6LfmfEsgAAAAACNqQ0aHqJa0HOHcUsvv2OCiEbV4'
};

View File

@@ -13,7 +13,8 @@ export const environment: Partial<BuildConfig> = {
preboot: false,
async: true,
time: false
}
},
recaptchaSiteKey: '6LfmfEsgAAAAACNqQ0aHqJa0HOHcUsvv2OCiEbV4'
};
/*

View File

@@ -2247,6 +2247,11 @@
resolved "https://registry.yarnpkg.com/@types/file-saver/-/file-saver-2.0.5.tgz#9ee342a5d1314bb0928375424a2f162f97c310c7"
integrity sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==
"@types/grecaptcha@^3.0.3":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@types/grecaptcha/-/grecaptcha-3.0.4.tgz#3de601f3b0cd0298faf052dd5bd62aff64c2be2e"
integrity sha512-7l1Y8DTGXkx/r4pwU1nMVAR+yD/QC+MCHKXAyEX/7JZhwcN1IED09aZ9vCjjkcGdhSQiu/eJqcXInpl6eEEEwg==
"@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
@@ -8858,6 +8863,14 @@ ng-mocks@^13.1.1:
resolved "https://registry.yarnpkg.com/ng-mocks/-/ng-mocks-13.1.1.tgz#e967dacc420c2ecec71826c5f24e0120186fad0b"
integrity sha512-LYi/1ccDwHKLwi4/hvUsmxBDeQ+n8BTdg5f1ujCDCO7OM9OVnqkQcRlBHHK+5iFtEn/aqa2QG3xU/qwIhnaL4w==
ng-recaptcha@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/ng-recaptcha/-/ng-recaptcha-9.0.0.tgz#11b88f820cfca366d363fffd0f451490f2db2b04"
integrity sha512-39YfJh1+p6gvfsGUhC8cmjhFZ1TtQ1OJES5SUgnanPL2aQuwrSX4WyTFh2liFn1dQqtGUVd5O4EhbcexB7AECQ==
dependencies:
"@types/grecaptcha" "^3.0.3"
tslib "^2.2.0"
ng2-file-upload@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ng2-file-upload/-/ng2-file-upload-1.4.0.tgz#8dea28d573234c52af474ad2a4001b335271e5c4"