Merge branch 'dev' into feature/US-04

This commit is contained in:
Mariela Bonilla 2021-07-16 16:05:19 -06:00
commit c4d48183ec
14 changed files with 246 additions and 76 deletions

2
package-lock.json generated
View File

@ -21199,7 +21199,7 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
"deprecated": "The",
"deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.",
"dev": true,
"engines": {
"node": ">=0.4.x"

View File

@ -1,16 +1,55 @@
<div>
<div class="row justify-content-center">
<div class="col-md-8">
<h1 jhiTranslate="activate.title">Activation</h1>
<div class="account-pages pt-2 pt-sm-5 pb-4 pb-sm-5" style="height: 100vh; background-color: #f1f5f9">
<div class="container">
<div class="row justify-content-center">
<div class="col-xxl-4 col-lg-5">
<div class="card mt-5">
<!-- Logo -->
<div class="pl-4 pt-4 pr-4 pb-1 text-center">
<img src="../../content/img_datasurvey/datasurvey-logo-text-black.svg" alt="" />
</div>
<div class="alert alert-success" *ngIf="success">
<span jhiTranslate="activate.messages.success"><strong>Your user account has been activated.</strong> Please </span>
<a class="alert-link" routerLink="/login" jhiTranslate="global.messages.info.authenticated.link">sign in</a>.
</div>
<div class="card-body p-4">
<div class="text-center w-75 m-auto">
<h4
class="text-dark-50 text-center pb-0 fw-bold p-0 m-0"
style="color: #727070; font-weight: 700; font-size: 1.3rem"
jhiTranslate="activate.title"
>
Activación de Cuenta
</h4>
</div>
<div *ngIf="success">
<div class="alert alert-success text-center my-2">
<span jhiTranslate="activate.messages.success"><strong>Your user account has been activated.</strong></span>
<span jhiTranslate="global.messages.info.authenticated.link">sign in</span>
</div>
<div class="d-flex justify-content-center">
<button class="ds-btn ds-btn--primary" routerLink="/login" jhiTranslate="global.messages.info.authenticated.link">
sign in</button
>.
</div>
</div>
<div *ngIf="error">
<div class="alert alert-danger text-center my-2" jhiTranslate="activate.messages.error">
<strong>Your user could not be activated.</strong> Please use the registration form to sign up.
</div>
<div class="d-flex justify-content-center">
<button class="ds-btn ds-btn--primary" routerLink="/account/register" jhiTranslate="global.registerLink">
create account</button
>.
</div>
</div>
</div>
<!-- end card-body -->
</div>
<!-- end card -->
<div class="alert alert-danger" *ngIf="error" jhiTranslate="activate.messages.error">
<strong>Your user could not be activated.</strong> Please use the registration form to sign up.
<!-- end row -->
</div>
<!-- end col -->
</div>
<!-- end row -->
</div>
<!-- end container -->
</div>
<!-- end page -->

View File

@ -1,4 +1,4 @@
<div class="account-pages pt-2 pt-sm-5 pb-4 pb-sm-5" style="height: 100vh; background-color: #f1f5f9">
<div class="account-pages pt-2 pt-sm-5 pb-4 pb-sm-5" style="/*height: 100vh;*/ height: 100%; background-color: #f1f5f9">
<div class="container">
<div class="row justify-content-center">
<div class="col-xxl-4 col-lg-5">

View File

@ -180,7 +180,7 @@
</div>
</div>
<!-- Form -->
<!-- Form de info usuario -->
<form
autocomplete="off"
class="ds-form col-lg ml-lg-5 mr-lg-5 pr-lg-5"
@ -191,6 +191,20 @@
[formGroup]="editForm"
>
<div class="row mb-2">
<div
class="alert alert-danger"
*ngIf="error"
jhiTranslate="global.messages.info.authenticated.updateForm"
data-cy="loginError"
></div>
<div *ngIf="success" class="alert alert-success alert-dismissible fade show" role="alert">
Sus datos fueron actualizados de manera exitosa
<!--<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>-->
</div>
<div class="form-group w-100">
<label class="form-control-label" for="field_email">Correo electrónico</label>
<input type="text" class="form-control" name="email" id="field_email" data-cy="email" formControlName="email" [readonly]="true" />
@ -221,7 +235,7 @@
<input
id="field_fechaNacimiento"
data-cy="fechaNacimiento"
type="datetime-local"
type="date"
class="form-control"
name="fechaNacimiento"
formControlName="fechaNacimiento"
@ -273,33 +287,59 @@
Utilice una contraseña segura al realizar el cambio, este dato debe ser secreto ya que provee acceso a su cuenta.
</p>
</div>
<div class="alert alert-danger" *ngIf="isGoogle" jhiTranslate="login.messages.error.isGoogle" data-cy="loginError"></div>
</div>
</div>
<!-- Form -->
<!-- Form de password-->
<form
autocomplete="off"
class="ds-form col-lg ml-lg-5 mr-lg-5 pr-lg-5"
name="passwordForm"
role="form"
novalidate
(ngSubmit)="save()"
(ngSubmit)="savePassword()"
[formGroup]="passwordForm"
>
<div class="row mb-3 pb-3" style="border-bottom: 1px solid #e7ebf3">
<div
class="alert alert-danger"
*ngIf="errorPassword && !doNotMatch && !successPassword"
jhiTranslate="global.messages.info.authenticated.passwordForm"
data-cy="loginError"
></div>
<div *ngIf="successPassword" class="alert alert-success alert-dismissible fade show" role="alert">
Sus contraseña fue actualizada de manera exitosa
<!-- <button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>-->
</div>
<div class="alert alert-danger" *ngIf="doNotMatch && !successPassword" jhiTranslate="global.messages.error.dontmatch">
The password and its confirmation do not match!
</div>
<div class="form-group w-100">
<label class="form-control-label" for="field_password">Contraseña actual</label>
<input
type="text"
type="password"
class="form-control"
name="password"
id="field_password"
data-cy="password"
formControlName="password"
placeholder="Su contraseña actual"
[readOnly]="isGoogle"
/>
<div
*ngIf="passwordForm.get('password')!.invalid && (passwordForm.get('password')!.dirty || passwordForm.get('password')!.touched)"
*ngIf="
passwordForm.get('password')!.invalid &&
(passwordForm.get('password')!.dirty || passwordForm.get('password')!.touched) &&
!isGoogle
"
>
<small
class="form-text text-danger"
@ -308,6 +348,22 @@
>
This field is required.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('password')?.errors?.minlength"
jhiTranslate="global.messages.validate.newpassword.minlength"
>
Your password is required to be at least 4 characters.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('password')?.errors?.maxlength"
jhiTranslate="global.messages.validate.newpassword.maxlength"
>
Your password cannot be longer than 50 characters.
</small>
</div>
</div>
</div>
@ -315,18 +371,20 @@
<div class="form-group w-100">
<label class="form-control-label" for="field_passwordNew">Contraseña nueva</label>
<input
type="text"
type="password"
class="form-control"
name="passwordNew"
id="field_passwordNew"
data-cy="passwordNew"
formControlName="passwordNew"
placeholder="Contraseña nueva"
[readOnly]="isGoogle"
/>
<div
*ngIf="
passwordForm.get('passwordNew')!.invalid &&
(passwordForm.get('passwordNew')!.dirty || passwordForm.get('passwordNew')!.touched)
(passwordForm.get('passwordNew')!.dirty || passwordForm.get('passwordNew')!.touched) &&
!isGoogle
"
>
<small
@ -336,6 +394,22 @@
>
This field is required.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('passwordNew')?.errors?.minlength"
jhiTranslate="global.messages.validate.newpassword.minlength"
>
Your password is required to be at least 4 characters.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('passwordNew')?.errors?.maxlength"
jhiTranslate="global.messages.validate.newpassword.maxlength"
>
Your password cannot be longer than 50 characters.
</small>
</div>
</div>
</div>
@ -344,18 +418,20 @@
<div class="form-group w-100">
<label class="form-control-label" for="field_passwordNewConfirm">Confirmar contraseña nueva</label>
<input
type="text"
type="password"
class="form-control"
name="passwordNewConfirm"
id="field_passwordNewConfirm"
data-cy="passwordNewConfirm"
formControlName="passwordNewConfirm"
placeholder="Contraseña nueva"
[readOnly]="isGoogle"
/>
<div
*ngIf="
passwordForm.get('passwordNewConfirm')!.invalid &&
(passwordForm.get('passwordNewConfirm')!.dirty || passwordForm.get('passwordNewConfirm')!.touched)
(passwordForm.get('passwordNewConfirm')!.dirty || passwordForm.get('passwordNewConfirm')!.touched) &&
!isGoogle
"
>
<small
@ -365,12 +441,28 @@
>
This field is required.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('passwordNewConfirm')?.errors?.minlength"
jhiTranslate="global.messages.validate.newpassword.minlength"
>
Your password is required to be at least 4 characters.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('passwordNewConfirm')?.errors?.maxlength"
jhiTranslate="global.messages.validate.newpassword.maxlength"
>
Your password cannot be longer than 50 characters.
</small>
</div>
</div>
</div>
<div class="row">
<button
*ngIf="!isGoogle"
type="button"
id="cancel-save"
data-cy="entityCreateCancelButton"
@ -381,10 +473,11 @@
</button>
<button
*ngIf="!isGoogle"
type="submit"
id="save-entity"
data-cy="entityCreateSaveButton"
[disabled]="passwordForm.invalid || isSaving"
[disabled]="isSaving"
class="ds-btn ds-btn--primary"
>
<span jhiTranslate="entity.action.save">Save</span>

View File

@ -1,3 +1,5 @@
import { LocalStorageService } from 'ngx-webstorage';
jest.mock('@ngx-translate/core');
jest.mock('app/core/auth/account.service');
@ -19,6 +21,7 @@ describe('Component Tests', () => {
let comp: SettingsComponent;
let fixture: ComponentFixture<SettingsComponent>;
let mockAccountService: AccountService;
let localStorage: LocalStorageService;
const account: Account = {
id: 0,
firstName: 'John',
@ -36,17 +39,23 @@ describe('Component Tests', () => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, HttpClientTestingModule],
declarations: [SettingsComponent],
providers: [FormBuilder, TranslateService, AccountService],
providers: [FormBuilder, TranslateService, AccountService, LocalStorageService],
})
.overrideTemplate(SettingsComponent, '')
.compileComponents();
localStorage = TestBed.inject(LocalStorageService);
})
);
it('should be created', () => {
expect(localStorage).toBeTruthy();
});
beforeEach(() => {
fixture = TestBed.createComponent(SettingsComponent);
comp = fixture.componentInstance;
mockAccountService = TestBed.inject(AccountService);
localStorage = TestBed.inject(LocalStorageService);
mockAccountService.identity = jest.fn(() => of(account));
mockAccountService.getAuthenticationState = jest.fn(() => of(account));
});
@ -63,6 +72,10 @@ describe('Component Tests', () => {
// expect(comp.success).toBe(true);
});
it('should be created', () => {
expect(localStorage).toBeTruthy();
});
it('should notify of error upon failed save', () => {
// GIVEN
mockAccountService.save = jest.fn(() => throwError('ERROR'));

View File

@ -1,12 +1,11 @@
import { Component, OnInit } from '@angular/core';
import { HttpResponse } from '@angular/common/http';
import { Component, ContentChild, OnInit } from '@angular/core';
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { FormBuilder, Validators } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs';
import { finalize, map } from 'rxjs/operators';
import * as dayjs from 'dayjs';
import { DATE_TIME_FORMAT } from 'app/config/input.constants';
import { DATE_FORMAT, DATE_TIME_FORMAT } from 'app/config/input.constants';
import { IUser } from 'app/entities/user/user.model';
import { UserService } from 'app/entities/user/user.service';
import { IPlantilla } from 'app/entities/plantilla/plantilla.model';
@ -14,17 +13,29 @@ import { PlantillaService } from 'app/entities/plantilla/service/plantilla.servi
import { IUsuarioExtra, UsuarioExtra } from 'app/entities/usuario-extra/usuario-extra.model';
import { UsuarioExtraService } from 'app/entities/usuario-extra/service/usuario-extra.service';
import { AccountService } from 'app/core/auth/account.service';
import { LocalStorageService } from 'ngx-webstorage';
import { EMAIL_ALREADY_USED_TYPE, LOGIN_ALREADY_USED_TYPE } from '../../config/error.constants';
import { PasswordService } from '../password/password.service';
@Component({
selector: 'jhi-settings',
templateUrl: './settings.component.html',
})
export class SettingsComponent implements OnInit {
currentUrl = this.router.url;
isSaving = false;
success = false;
successPassword = false;
error = false;
errorPassword = false;
doNotMatch = false;
usersSharedCollection: IUser[] = [];
plantillasSharedCollection: IPlantilla[] = [];
showPassword = false;
isGoogle = this.localStorageService.retrieve('IsGoogle');
//Form info del usuario
editForm = this.fb.group({
email: [null, [Validators.required]],
id: [],
@ -36,10 +47,11 @@ export class SettingsComponent implements OnInit {
plantillas: [],
});
//form de la contraseña
passwordForm = this.fb.group({
password: [null, [Validators.required]],
passwordNew: [null, [Validators.required]],
passwordNewConfirm: [null, [Validators.required]],
password: [null, [Validators.required], Validators.minLength(8), Validators.maxLength(50)],
passwordNew: [null, [Validators.required], Validators.minLength(8), Validators.maxLength(50)],
passwordNewConfirm: [null, [Validators.required, Validators.minLength(8), Validators.maxLength(50)]],
});
usuarioExtra: UsuarioExtra | null = null;
@ -75,13 +87,18 @@ export class SettingsComponent implements OnInit {
{ name: 'C28' },
];
/* @ContentChild(IonInput) input: IonInput;*/
constructor(
protected usuarioExtraService: UsuarioExtraService,
protected userService: UserService,
protected plantillaService: PlantillaService,
protected activatedRoute: ActivatedRoute,
protected fb: FormBuilder,
protected accountService: AccountService
protected accountService: AccountService,
private localStorageService: LocalStorageService,
protected passwordService: PasswordService,
private router: Router
) {}
ngOnInit(): void {
@ -103,6 +120,8 @@ export class SettingsComponent implements OnInit {
}
});
console.log(this.isGoogle);
// this.activatedRoute.data.subscribe(({ usuarioExtra }) => {
// });
@ -112,13 +131,26 @@ export class SettingsComponent implements OnInit {
window.history.back();
}
//Se manda la info a guardar
save(): void {
this.isSaving = true;
const usuarioExtra = this.createFromForm();
if (usuarioExtra.id !== undefined) {
this.subscribeToSaveResponse(this.usuarioExtraService.update(usuarioExtra));
console.log(usuarioExtra.iconoPerfil);
console.log(usuarioExtra.fechaNacimiento);
this.subscribeToSaveResponse(this.usuarioExtraService.update(usuarioExtra));
}
savePassword(): void {
const passwordNew = this.passwordForm.get(['passwordNew'])!.value;
if (passwordNew !== this.passwordForm.get(['passwordNewConfirm'])!.value) {
this.doNotMatch = true;
} else {
this.subscribeToSaveResponse(this.usuarioExtraService.create(usuarioExtra));
this.passwordService.save(this.passwordForm.get(['passwordNew'])!.value, this.passwordForm.get(['password'])!.value).subscribe(
() => (this.successPassword = true),
() => (this.errorPassword = true)
);
}
}
@ -143,10 +175,20 @@ export class SettingsComponent implements OnInit {
protected subscribeToSaveResponse(result: Observable<HttpResponse<IUsuarioExtra>>): void {
result.pipe(finalize(() => this.onSaveFinalize())).subscribe(
() => this.onSaveSuccess(),
() => this.onSaveError()
() => (
(this.success = true),
this.router.navigate(['account/settings']).then(() => {
window.location.reload();
})
),
response => this.processError(response)
);
}
processError(response: HttpErrorResponse): void {
if (response.status === 400) {
this.error = true;
}
}
protected onSaveSuccess(): void {
this.previousState();
@ -160,20 +202,21 @@ export class SettingsComponent implements OnInit {
this.isSaving = false;
}
//Llena el formulario para que se vea en pantalla
protected updateForm(usuarioExtra: IUsuarioExtra): void {
this.editForm.patchValue({
email: usuarioExtra.user?.login,
id: usuarioExtra.id,
nombre: usuarioExtra.nombre,
iconoPerfil: usuarioExtra.iconoPerfil,
fechaNacimiento: usuarioExtra.fechaNacimiento ? usuarioExtra.fechaNacimiento.format(DATE_TIME_FORMAT) : null,
fechaNacimiento: usuarioExtra.fechaNacimiento ? usuarioExtra.fechaNacimiento.format(DATE_FORMAT) : null,
estado: usuarioExtra.estado,
user: usuarioExtra.user,
plantillas: usuarioExtra.plantillas,
});
// Update swiper
this.profileIcon = parseInt(usuarioExtra.iconoPerfil!);
this.profileIcon = usuarioExtra.iconoPerfil!;
this.profileIcons.forEach(icon => {
if (parseInt(icon.name.split('C')[1]) === this.profileIcon) {
icon.class = 'active';
@ -210,9 +253,9 @@ export class SettingsComponent implements OnInit {
...new UsuarioExtra(),
id: this.editForm.get(['id'])!.value,
nombre: this.editForm.get(['nombre'])!.value,
iconoPerfil: this.editForm.get(['iconoPerfil'])!.value,
iconoPerfil: this.profileIcon,
fechaNacimiento: this.editForm.get(['fechaNacimiento'])!.value
? dayjs(this.editForm.get(['fechaNacimiento'])!.value, DATE_TIME_FORMAT)
? dayjs(this.editForm.get(['fechaNacimiento'])!.value, DATE_FORMAT)
: undefined,
estado: this.editForm.get(['estado'])!.value,
user: this.editForm.get(['user'])!.value,
@ -225,6 +268,8 @@ export class SettingsComponent implements OnInit {
document.querySelectorAll('.active').forEach(e => e.classList.remove('active'));
event.target.classList.add('active');
this.profileIcon = +event.target.getAttribute('id')! + 1;
console.log(this.profileIcon);
}
}
}

View File

@ -9,7 +9,7 @@ import { TranslateModule, TranslateService, TranslateLoader, MissingTranslationH
import { NgxWebstorageModule, SessionStorageService } from 'ngx-webstorage';
import * as dayjs from 'dayjs';
import { NgbDateAdapter, NgbDatepickerConfig } from '@ng-bootstrap/ng-bootstrap';
import { LocalStorageService } from 'ngx-webstorage';
import { SERVER_API_URL } from './app.constants';
import { ApplicationConfigService } from 'app/core/config/application-config.service';
import './config/dayjs';
@ -35,6 +35,7 @@ import { SidebarComponent } from './layouts/sidebar/sidebar.component';
@NgModule({
imports: [
NgxWebstorageModule.forRoot(),
BrowserModule,
SharedModule,
HomeModule,

View File

@ -28,7 +28,7 @@ describe('Service Tests', () => {
elemDefault = {
id: 0,
nombre: 'AAAAAAA',
iconoPerfil: 'AAAAAAA',
iconoPerfil: 1,
fechaNacimiento: currentDate,
estado: EstadoUsuario.ACTIVE,
};

View File

@ -8,7 +8,7 @@ import { EstadoUsuario } from 'app/entities/enumerations/estado-usuario.model';
export interface IUsuarioExtra {
id?: number;
nombre?: string;
iconoPerfil?: string | null;
iconoPerfil?: number | null;
fechaNacimiento?: dayjs.Dayjs | null;
estado?: EstadoUsuario;
user?: IUser | null;
@ -21,7 +21,7 @@ export class UsuarioExtra implements IUsuarioExtra {
constructor(
public id?: number,
public nombre?: string,
public iconoPerfil?: string | null,
public iconoPerfil?: number | null,
public fechaNacimiento?: dayjs.Dayjs | null,
public estado?: EstadoUsuario,
public user?: IUser | null,

View File

@ -1,16 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { UsuarioGoogleLogInService } from './usuario-google-log-in.service';
describe('UsuarioGoogleLogInService', () => {
let service: UsuarioGoogleLogInService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(UsuarioGoogleLogInService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -1,9 +0,0 @@
import { Injectable } from '@angular/core';
import { Observable, ReplaySubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class UsuarioGoogleLogInService {
constructor() {}
}

View File

@ -1,6 +1,6 @@
{
"activate": {
"title": "Activación",
"title": "Activación de Cuenta",
"messages": {
"success": "<strong>Su cuenta ha sido activada.</strong> Ya puede ",
"error": "<strong>Su cuenta no pudo ser activada.</strong> Por favor, regístrese en DataSurvey."

View File

@ -66,6 +66,8 @@
"prefix": "Si desea ",
"link": "iniciar sesión",
"suffix": ", puede intentar con las cuentas predeterminadas:<br/>- Administrador (usuario=\"admin\" y contraseña=\"admin\") <br/>- Usuario (usuario=\"user\" y contraseña=\"user\").",
"updateForm": "Ocurrió un error al actualizar su información, favor revisar los campos e intentar de nuevo",
"passwordForm": "Ocurrió un error al actualizar su contraseña, favor revisar los campos e intentar de nuevo",
"botonInicio": "Iniciar Sesión"
},
"register": {
@ -108,7 +110,8 @@
"ribbon": {
"dev": "Development"
},
"item-count": "Mostrando {{first}} - {{second}} de {{total}} elementos."
"item-count": "Mostrando {{first}} - {{second}} de {{total}} elementos.",
"registerLink": "Registrarse"
},
"entity": {
"action": {

View File

@ -9,7 +9,8 @@
},
"messages": {
"error": {
"authentication": "Revise las credenciales e intente de nuevo "
"authentication": "Revise las credenciales e intente de nuevo ",
"isGoogle": "Al haber ingresado por medio de Google no cuenta con los permisos para modificar su contraseña"
}
},
"password": {