parent-form. WIP: User experience. Show controls depending on email state

parent 394f6e34
......@@ -34,3 +34,17 @@ function epal_theme() {
],
];
}
function epal_mail($key, &$message, $params) {
$options = array(
'langcode' => $message['langcode'],
);
switch ($key) {
case 'send_verification_code':
$message['from'] = \Drupal::config('system.site')->get('mail');
$message['subject'] = t('Email Confirmation Needed', $options);
$message['body'][] = $params['message'];
break;
}
}
user_data:
epal.user.send_verification_code:
path: '/epal/user/sendvercode'
options:
_auth: [ 'basic_auth' ]
defaults:
_controller: '\Drupal\epal\Controller\CurrentUser::sendVerificationCode'
requirements:
_user_is_logged_in: 'TRUE'
epal.user.verify_verification_code:
path: '/epal/user/verifyvercode'
options:
_auth: [ 'basic_auth' ]
defaults:
_controller: '\Drupal\epal\Controller\CurrentUser::verifyVerificationCode'
requirements:
_user_is_logged_in: 'TRUE'
epal.user.get_data:
path: '/epal/userdata'
options:
_auth: [ 'basic_auth' ]
......@@ -6,7 +22,7 @@ user_data:
_controller: '\Drupal\epal\Controller\CurrentUser::getEpalUserData'
requirements:
_user_is_logged_in: 'TRUE'
current_user:
epal.current_user:
path: '/epal/curuser'
options:
_auth: [ 'basic_auth' ]
......
......@@ -8,20 +8,32 @@ use Symfony\Component\HttpFoundation\JsonResponse;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Drupal\Core\Database\Connection;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
class CurrentUser extends ControllerBase
{
protected $entityTypeManager;
protected $logger;
protected $connection;
public function __construct(EntityTypeManagerInterface $entityTypeManager)
public function __construct(
EntityTypeManagerInterface $entityTypeManager,
Connection $connection,
LoggerChannelFactoryInterface $loggerChannel
)
{
$this->entityTypeManager = $entityTypeManager;
$this->connection = $connection;
$this->logger = $loggerChannel->get('epal');
}
public static function create(ContainerInterface $container)
{
return new static(
$container->get('entity_type.manager')
$container->get('entity_type.manager'),
$container->get('database'),
$container->get('logger.factory')
);
}
......@@ -62,6 +74,7 @@ class CurrentUser extends ControllerBase
'userFathername' => mb_substr($epalUser->fathername->value,0,4,'UTF-8') !== "####" ? $epalUser->fathername->value : '',
'userMothername' => mb_substr($epalUser->mothername->value,0,4,'UTF-8') !== "####" ? $epalUser->mothername->value : '',
'userEmail' => mb_substr($user->mail->value,0,4,'UTF-8') !== "####" ? $user->mail->value : '',
'verificationCodeVerified' => $epalUser->verificationcodeverified->value,
], Response::HTTP_OK);
} else {
return $this->respondWithStatus([
......@@ -76,6 +89,130 @@ class CurrentUser extends ControllerBase
}
}
public function sendVerificationCode(Request $request)
{
if (!$request->isMethod('POST')) {
return $this->respondWithStatus([
"message" => t("Method Not Allowed")
], Response::HTTP_METHOD_NOT_ALLOWED);
}
$authToken = $request->headers->get('PHP_AUTH_USER');
$trx = $this->connection->startTransaction();
try {
$epalUsers = $this->entityTypeManager->getStorage('epal_users')->loadByProperties(array('authtoken' => $authToken));
$epalUser = reset($epalUsers);
if ($epalUser) {
$user = $this->entityTypeManager->getStorage('user')->load($epalUser->user_id->target_id);
if ($user) {
$postData = null;
if ($content = $request->getContent()) {
$postData = json_decode($content);
$verificationCode = uniqid();
$epalUser->set('verificationcode', $verificationCode);
$epalUser->set('verificationcodeverified', FALSE);
$epalUser->save();
$user->set('mail', $postData->userEmail);
$user->save();
$this->sendEmailWithVerificationCode($postData->userEmail, $verificationCode, $user);
return $this->respondWithStatus([
'userEmail' => $postData->userEmail,
'verCode' => $verificationCode,
], Response::HTTP_OK);
}
else {
return $this->respondWithStatus([
'message' => t("post with no data"),
], Response::HTTP_BAD_REQUEST);
}
} else {
return $this->respondWithStatus([
'message' => t("user not found"),
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
} else {
return $this->respondWithStatus([
'message' => t("EPAL user not found"),
], Response::HTTP_FORBIDDEN);
}
} catch (\Exception $ee) {
$this->logger->warning($ee->getMessage());
$trx->rollback();
return false;
}
}
private function sendEmailWithVerificationCode($email, $vc, $user) {
$mailManager = \Drupal::service('plugin.manager.mail');
$module = 'epal';
$key = 'send_verification_code';
$to = $email;
$params['message'] = 'verification code=' . $vc;
$langcode = $user->getPreferredLangcode();
$send = true;
$mail_sent = $mailManager->mail($module, $key, $to, $langcode, $params, NULL, $send);
if ($mail_sent) {
$this->logger->info("Mail Sent successfully.");
}
else {
$this->logger->info("There is error in sending mail.");
}
return;
}
public function verifyVerificationCode(Request $request)
{
if (!$request->isMethod('POST')) {
return $this->respondWithStatus([
"message" => t("Method Not Allowed")
], Response::HTTP_METHOD_NOT_ALLOWED);
}
$authToken = $request->headers->get('PHP_AUTH_USER');
$epalUsers = $this->entityTypeManager->getStorage('epal_users')->loadByProperties(array('authtoken' => $authToken));
$epalUser = reset($epalUsers);
if ($epalUser) {
$user = $this->entityTypeManager->getStorage('user')->load($epalUser->user_id->target_id);
if ($user) {
$postData = null;
if ($content = $request->getContent()) {
$postData = json_decode($content);
if ($epalUser->verificationcode->value !== $postData->verificationCode) {
return $this->respondWithStatus([
'userEmail' => $user->mail->value,
'verificationCodeVerified' => false
], Response::HTTP_OK);
} else {
$epalUser->set('verificationcodeverified', true);
$epalUser->save();
return $this->respondWithStatus([
'userEmail' => $user->mail->value,
'verificationCodeVerified' => true
], Response::HTTP_OK);
}
}
} else {
return $this->respondWithStatus([
'message' => t("user not found"),
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
} else {
return $this->respondWithStatus([
'message' => t("EPAL user not found"),
], Response::HTTP_FORBIDDEN);
}
}
private function respondWithStatus($arr, $s) {
$res = new JsonResponse($arr);
......
......@@ -473,6 +473,31 @@ class EpalUsers extends ContentEntityBase implements EpalUsersInterface {
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['verificationcode'] = BaseFieldDefinition::create('string')
->setLabel(t('Email Verification Code'))
->setDescription(t('Generated email verification code'))
->setSettings(array(
'max_length' => 20,
'text_processing' => 0,
))
->setDefaultValue('')
->setDisplayOptions('view', array(
'label' => 'above',
'type' => 'string',
'weight' => -4,
))
->setDisplayOptions('form', array(
'type' => 'string_textfield',
'weight' => -4,
))
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['verificationcodeverified'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Email Verification Code Verified'))
->setDescription(t('A boolean indicating whether the email verification code was verified.'))
->setDefaultValue(FALSE);
$fields['accesstoken'] = BaseFieldDefinition::create('string')
->setLabel(t('Access-Token από taxis'))
->setDescription(t('Access-Token από taxis.'))
......
......@@ -216,7 +216,7 @@ class CBController extends ControllerBase
$this->logger->warning($e->getMessage());
$trx->rollback();
return false;
} catch (Exception $ee) {
} catch (\Exception $ee) {
$this->logger->warning($ee->getMessage());
$trx->rollback();
return false;
......
<div class = "loading" *ngIf="(epalUserData$ | async) === {}"></div>
<form [formGroup]="formGroup">
<div class="form-group">
<label for="userEmail">Email Επικοινωνίας</label><input #userEmail class="form-control" type="text" formControlName="userEmail" value="{{ (epalUserData$ | async).userEmail }}">
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('userEmail').touched && formGroup.get('userEmail').hasError('required') ">
Το πεδίο δεν μπορεί να αφεθεί κενό!
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('userEmail').hasError('pattern')">
Πληκτρολογήστε ένα σωστό συντακτικά email!
</div>
<div class="row" *ngIf="verificationCodeVerified | async">
<div class="col-md-12">
<div *ngIf="userEmailEnabled | async">
<button type="button" class="btn-primary btn-sm pull-right" (click)="disableUserEmail();">
Ακύρωση Αλλαγής Email
</button>
</div>
<div *ngIf="!(userEmailEnabled | async)">
<button type="button" class="btn-primary btn-sm pull-right" (click)="enableUserEmail();">
Αλλαγή Email
</button>
</div>
</div>
</div>
<div class="row" *ngIf="(showSendVerification | async) && !(verificationCodeSent | async) && !formGroup.get('userEmail').hasError('required') && !formGroup.get('userEmail').hasError('pattern')">
<div class="col-md-12">
<button type="button" class="btn-primary btn-sm pull-right" (click)="sendVerificationCode()">
Λήψη Κωδικού Επαλήθευσης
</button>
</div>
</div>
<div class="form-group" *ngIf="(verificationCodeSent | async) && !(verificationCodeVerified | async)">
<label for="verificationCode">Κωδικός επαλήθευσης</label><input class="form-control" type="text" formControlName="verificationCode">
</div>
<div class="row" *ngIf="(verificationCodeSent | async) && !(verificationCodeVerified | async)">
<div class="col-md-12">
<button type="button" class="btn-primary btn-sm pull-right" (click)="verifyVerificationCode()">
Αποστολή Κωδικού Επαλήθευσης
</button>
</div>
</div>
<div class="form-group" *ngIf="verificationCodeVerified | async">
<label for="userName">Όνομα</label><input class="form-control" type="text" formControlName="userName" value="{{ (epalUserData$ | async).userName }}">
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('userName').touched && formGroup.get('userName').hasError('required') ">
Το πεδίο δεν μπορεί να αφεθεί κενό!
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('userName').hasError('pattern')">
Πληκτρολογήστε το όνομά σας!
</div>
<div class="form-group" *ngIf="verificationCodeVerified | async">
<label for="userSurname">Επώνυμο</label><input class="form-control" type="text" formControlName="userSurname" value="{{ (epalUserData$ | async).userSurname }}">
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('userSurname').touched && formGroup.get('userSurname').hasError('required') ">
Το πεδίο δεν μπορεί να αφεθεί κενό!
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('userSurname').hasError('pattern')">
Πληκτρολογήστε το επώνυμό σας!
</div>
<div class="form-group" *ngIf="verificationCodeVerified | async">
<label for="userFathername">Πατρώνυμο</label><input class="form-control" type="text" formControlName="userFathername" value="{{ (epalUserData$ | async).userFathername }}">
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('userFathername').touched && formGroup.get('userFathername').hasError('required') ">
Το πεδίο δεν μπορεί να αφεθεί κενό!
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('userFathername').hasError('pattern')">
Πληκτρολογήστε το όνομα του πατέρα σας!
</div>
<div class="form-group" *ngIf="verificationCodeVerified | async">
<label for="userMothername">Μητρώνυμο</label><input class="form-control" type="text" formControlName="userMothername" value="{{ (epalUserData$ | async).userMothername }}">
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('userMothername').touched && formGroup.get('userMothername').hasError('required') ">
Το πεδίο δεν μπορεί να αφεθεί κενό!
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('userMothername').hasError('pattern')">
Πληκτρολογήστε το όνομα της μητέρας σας!
</div>
<div class="row" *ngIf="!(showSendVerification | async) && (verificationCodeVerified | async)">
<div class="col-md-12">
<button type="button" class="btn-primary btn-lg pull-right" (click)="verifyCodeAndContinue()">
Αποθήκευση - Συνέχεια
<i class="fa fa-forward"></i> </button>
</div>
</div>
</form>
import { Component, OnInit, OnDestroy, Injectable } from '@angular/core';
import { Component, OnInit, OnDestroy, Injectable, ViewChild, ElementRef, Renderer } from '@angular/core';
import { Router } from '@angular/router';
import { BehaviorSubject, Subscription } from 'rxjs/Rx';
import { VALID_EMAIL_PATTERN } from '../../constants';
import { VALID_EMAIL_PATTERN, VALID_NAMES_PATTERN } from '../../constants';
import { HelperDataService } from '../../services/helper-data-service';
import {
......@@ -15,60 +15,100 @@ import {AppSettings} from '../../app.settings';
@Component({
selector: 'parent-form',
template: `
<div class = "loading" *ngIf="(epalUserData$ | async) === {}"></div>
<form [formGroup]="formGroup">
<div class="form-group">
<label for="email">Email Επικοινωνίας</label><input class="form-control" type="text" formControlName="email">
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('email').touched && formGroup.get('email').hasError('required') ">
Το πεδίο δεν μπορεί να αφεθεί κενό!
</div>
<div class="alert alert-danger" *ngIf="formGroup.get('email').dirty && formGroup.get('email').hasError('pattern')">
Πληκτρολογήστε ένα σωστό συντακτικά email!
</div>
<div class="row">
<div class="col-md-12">
<button type="button" class="btn-primary btn-lg pull-right" (click)="sendVerificationCode()">
Αποστολή Κωδικού Επαλήθευσης </button>
</div>
</div>
<div class="form-group">
<label for="verification_code">Κωδικός επαλήθευσης</label><input class="form-control" type="text" formControlName="verification_code">
</div>
<div class="row">
<div class="col-md-12">
<button type="button" class="btn-primary btn-lg pull-right" (click)="verifyCodeAndContinue()">
<i class="fa fa-forward"></i> </button>
</div>
</div>
</form>
`
templateUrl: 'parent.form.html'
})
@Injectable() export default class ParentForm implements OnInit {
@Injectable() export default class ParentForm implements OnInit, OnDestroy {
public formGroup: FormGroup;
private respond: any;
private epalUserData$: BehaviorSubject<any>;
private epalUserDataSub: Subscription;
private userEmailSub: Subscription;
private showSendVerification: BehaviorSubject<boolean>;
private verificationCodeSent: BehaviorSubject<boolean>;
private verificationCodeVerified: BehaviorSubject<boolean>;
private userEmailEnabled: BehaviorSubject<boolean>;
@ViewChild('userEmail') userEmail: ElementRef;
constructor(private fb: FormBuilder,
private router: Router,
private hds: HelperDataService) {
this.epalUserData$ = new BehaviorSubject({});
this.formGroup = this.fb.group({
name: ['', [Validators.pattern(VALID_EMAIL_PATTERN),Validators.required]],
});
};
private hds: HelperDataService,
private rd: Renderer) {
this.showSendVerification = new BehaviorSubject(false);
this.verificationCodeSent = new BehaviorSubject(false);
this.verificationCodeVerified = new BehaviorSubject(false);
this.userEmailEnabled = new BehaviorSubject(false);
this.formGroup = this.fb.group({
userName: ['', [Validators.pattern(VALID_NAMES_PATTERN),Validators.required]],
userSurname: ['', [Validators.pattern(VALID_NAMES_PATTERN),Validators.required]],
userFathername: ['', [Validators.pattern(VALID_NAMES_PATTERN),Validators.required]],
userMothername: ['', [Validators.pattern(VALID_NAMES_PATTERN),Validators.required]],
userEmail: [{value: '', disabled: true}, [Validators.pattern(VALID_EMAIL_PATTERN),Validators.required]],
verificationCode: ['', [Validators.required]]
});
this.epalUserData$ = new BehaviorSubject({});
}
ngOnInit() {
this.epalUserDataSub = this.hds.getEpalUserData().subscribe(this.epalUserData$);
// this.epalUserDataSub = this.hds.getEpalUserData().subscribe(this.epalUserData$);
this.epalUserDataSub = this.hds.getEpalUserData().subscribe(
x => {
this.epalUserData$.next(x);
if (typeof(x.verificationCodeVerified) !== 'undefined' && x.verificationCodeVerified === "1") {
this.verificationCodeVerified.next(true);
}
if (typeof(x.userEmail) !== 'undefined' && x.userEmail.length > 0)
this.userEmailEnabled.next(false);
else
this.userEmailEnabled.next(true);
}
);
this.userEmailSub = this.formGroup.controls['userEmail'].valueChanges.subscribe(
x => {
if (this.formGroup.controls['userEmail'].value === '') {
this.enableUserEmail();
}
}
);
}
ngOnDestroy() {
if (this.epalUserDataSub) this.epalUserDataSub.unsubscribe();
if (this.userEmailSub) this.epalUserDataSub.unsubscribe();
}
sendVerificationCode() {
this.hds.sendVerificationCode(this.formGroup.value.userEmail)
.then(res => {this.verificationCodeSent.next(true); this.showSendVerification.next(false);})
.catch(err => {console.log(err)});
}
verifyVerificationCode() {
this.hds.verifyVerificationCode(this.formGroup.value.verificationCode)
.then(res => {this.verificationCodeSent.next(true); this.showSendVerification.next(false); this.verificationCodeVerified.next((<any>res).verificationCodeVerified === "1" ? true : false); this.formGroup.value.userEmail=(<any>res).userEmail;})
.catch(err => {console.log(err)});
}
verifyCodeAndContinue() {
this.router.navigate(['/epal-class-select']);
}
enableUserEmail() {
this.userEmailEnabled.next(true);
this.formGroup.controls["userEmail"].enable({emitEvent: false});
this.rd.invokeElementMethod(this.userEmail.nativeElement,'focus');
}
disableUserEmail() {
this.userEmailEnabled.next(false);
this.formGroup.controls["userEmail"].setValue(this.epalUserData$.getValue().userEmail);
this.formGroup.controls["userEmail"].disable({emitEvent: false});
}
}
......@@ -50,7 +50,7 @@ import {AppSettings} from '../../app.settings';
`
})
@Injectable() export default class SectorFieldsSelect implements OnInit {
@Injectable() export default class SectorFieldsSelect implements OnInit, OnDestroy {
private sectorFields$: BehaviorSubject<ISectorFields>;
private sectorFieldsSub: Subscription;
public formGroup: FormGroup;
......
......@@ -36,4 +36,4 @@ export const VALID_NAMES_PATTERN = '[A-Za-zΑ-ΩΆΈΉΊΎΌΏα-ωάέήίύό
export const VALID_ADDRESS_PATTERN = '[0-9A-Za-zΑ-ΩΆΈΉΊΎΌΏα-ωάέήίύόώ ]*$';
export const VALID_ADDRESSTK_PATTERN = '[0-9 ]*$';
export const VALID_DIGITS_PATTERN = '[0-9]*$';
export const VALID_EMAIL_PATTERN = "/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i";
export const VALID_EMAIL_PATTERN = '[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}';
......@@ -53,6 +53,59 @@ export class HelperDataService {
.map(response => response.json());
};
sendVerificationCode(email) {
this.loginInfo$.forEach(loginInfoToken => {
this.authToken = loginInfoToken.get(0).auth_token;
});
let headers = new Headers({
"Content-Type": "application/json",
// "Accept": "*/*",
// "Access-Control-Allow-Credentials": "true",
});
this.createAuthorizationHeader(headers);
// let options = new RequestOptions({ headers: headers, withCredentials: true });
let options = new RequestOptions({ headers: headers });
return new Promise((resolve, reject) => {
this.http.post(`${AppSettings.API_ENDPOINT}/epal/user/sendvercode`, {userEmail: email}, options)
.map(response => response.json())
.subscribe(data => {
resolve(data);
}, // put the data returned from the server in our variable
error => {
console.log("Error Sending Verification Code"); // in case of failure show this message
reject("Error Sending Verification Code");
},
() => console.log("Sending Verification Code"));//run this code in all cases); */
});
}
verifyVerificationCode(verificationCode) {
this.loginInfo$.forEach(loginInfoToken => {
this.authToken = loginInfoToken.get(0).auth_token;
});
let headers = new Headers({
"Content-Type": "application/json",
// "Accept": "*/*",
// "Access-Control-Allow-Credentials": "true",
});
this.createAuthorizationHeader(headers);
// let options = new RequestOptions({ headers: headers, withCredentials: true });
let options = new RequestOptions({ headers: headers });
return new Promise((resolve, reject) => {
console.log("verificationCode=" + verificationCode);
this.http.post(`${AppSettings.API_ENDPOINT}/epal/user/verifyvercode`, {verificationCode: verificationCode}, options)
.map(response => response.json())
.subscribe(data => {
resolve(<any>data);
}, // put the data returned from the server in our variable
error => {
console.log("Error Verifying Verification Code"); // in case of failure show this message
reject("Error Verifying Verification Code");
},
() => console.log("Verifying Verification Code"));//run this code in all cases); */
});
}
getCourseFields() {
this.loginInfo$.forEach(loginInfoToken => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment