From 48d68d10050115951f05241e929819a6b3f89713 Mon Sep 17 00:00:00 2001 From: Hugo <hugo.cubino@estudiantes.uva.es> Date: Fri, 22 Nov 2024 15:32:17 +0100 Subject: [PATCH 1/5] =?UTF-8?q?A=C3=B1adidos=20componentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- angular/RestClient/src/app/app.routes.ts | 5 + .../features/auth/login/login.component.css | 131 ++++++++++++++++++ .../features/auth/login/login.component.html | 23 +++ .../auth/login/login.component.spec.ts | 23 +++ .../features/auth/login/login.component.ts | 28 ++++ .../auth/register/register.component.css | 131 ++++++++++++++++++ .../auth/register/register.component.html | 31 +++++ .../auth/register/register.component.spec.ts | 23 +++ .../auth/register/register.component.ts | 31 +++++ 9 files changed, 426 insertions(+) create mode 100644 angular/RestClient/src/app/core/features/auth/login/login.component.css create mode 100644 angular/RestClient/src/app/core/features/auth/login/login.component.html create mode 100644 angular/RestClient/src/app/core/features/auth/login/login.component.spec.ts create mode 100644 angular/RestClient/src/app/core/features/auth/login/login.component.ts create mode 100644 angular/RestClient/src/app/core/features/auth/register/register.component.css create mode 100644 angular/RestClient/src/app/core/features/auth/register/register.component.html create mode 100644 angular/RestClient/src/app/core/features/auth/register/register.component.spec.ts create mode 100644 angular/RestClient/src/app/core/features/auth/register/register.component.ts diff --git a/angular/RestClient/src/app/app.routes.ts b/angular/RestClient/src/app/app.routes.ts index b8ee77b..dc45a08 100644 --- a/angular/RestClient/src/app/app.routes.ts +++ b/angular/RestClient/src/app/app.routes.ts @@ -5,6 +5,7 @@ import { HotelRegisterComponent } from './core/features/hotel/hotel-register/hot import { MainPageComponent } from './core/features/user/main-page/main-page.component'; import { BookingListComponent } from './core/features/bookings/booking-list/booking-list.component'; import { UserBookingListComponent } from './core/features/user/user-booking-list/user-booking-list.component'; +import { LoginComponent } from './core/features/auth/login/login.component'; export const routes: Routes = [ { @@ -35,6 +36,10 @@ export const routes: Routes = [ path: 'hotels/:id', component: HotelRegisterComponent, }, + { + path: 'auth/login', + component: LoginComponent, + }, { path: '**', redirectTo: '', diff --git a/angular/RestClient/src/app/core/features/auth/login/login.component.css b/angular/RestClient/src/app/core/features/auth/login/login.component.css new file mode 100644 index 0000000..8fdfb8e --- /dev/null +++ b/angular/RestClient/src/app/core/features/auth/login/login.component.css @@ -0,0 +1,131 @@ +/* General container styles */ +.container { + max-width: 400px; + margin: 50px auto; + padding: 30px; + background: linear-gradient(135deg, #1e1e2f, #2a2a45); + border-radius: 12px; + box-shadow: 0 8px 15px rgba(0, 0, 0, 0.3); + color: #fff; + font-family: 'Roboto', sans-serif; + } + + h2 { + text-align: center; + font-size: 1.8em; + font-weight: bold; + margin-bottom: 20px; + color: #fff; + letter-spacing: 1px; + text-transform: uppercase; + background: linear-gradient(90deg, #7f7fd5, #86a8e7, #91eae4); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + + /* Form fields */ + form div { + margin-bottom: 20px; + } + + label { + font-size: 0.9em; + font-weight: bold; + margin-bottom: 8px; + display: block; + letter-spacing: 0.5px; + color: #b3b3d1; + } + + input { + width: 100%; + padding: 12px 15px; + font-size: 0.95em; + border: 1px solid #3e3e5e; + border-radius: 8px; + background: #252540; + color: #fff; + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3); + transition: all 0.3s ease-in-out; + } + + input:focus { + outline: none; + border-color: #7f7fd5; + background: #2e2e50; + box-shadow: 0 0 8px rgba(127, 127, 213, 0.8); + } + + /* Buttons */ + button { + width: 100%; + padding: 12px; + font-size: 1em; + font-weight: bold; + color: #fff; + background: linear-gradient(90deg, #7f7fd5, #86a8e7, #91eae4); + border: none; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; + transition: transform 0.2s, box-shadow 0.2s; + } + + button:hover { + transform: translateY(-3px); + box-shadow: 0 8px 15px rgba(127, 127, 213, 0.5); + } + + button:disabled { + background: #3e3e5e; + cursor: not-allowed; + opacity: 0.7; + box-shadow: none; + } + + /* Small error messages */ + small { + display: block; + margin-top: 5px; + font-size: 0.85em; + color: #ff6b6b; + } + + /* Extra animations and effects */ + .container::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(120deg, rgba(127, 127, 213, 0.2), rgba(86, 168, 231, 0.1)); + z-index: -1; + filter: blur(20px); + } + + input::placeholder { + color: #b3b3d1; + } + + form div:last-child { + margin-top: 30px; + } + + /* Responsiveness */ + @media (max-width: 768px) { + .container { + padding: 20px; + margin: 20px; + } + + h2 { + font-size: 1.5em; + } + + input, + button { + font-size: 0.9em; + } + } + \ No newline at end of file diff --git a/angular/RestClient/src/app/core/features/auth/login/login.component.html b/angular/RestClient/src/app/core/features/auth/login/login.component.html new file mode 100644 index 0000000..45790ed --- /dev/null +++ b/angular/RestClient/src/app/core/features/auth/login/login.component.html @@ -0,0 +1,23 @@ +<div class="login-container"> + <h2>Login</h2> + <form [formGroup]="loginForm" (ngSubmit)="onSubmit()"> + <div> + <label for="email">Email:</label> + <input id="email" type="email" formControlName="email" /> + <div *ngIf="loginForm.get('email')?.invalid && loginForm.get('email')?.touched"> + <small>Email is required and must be valid.</small> + </div> + </div> + + <div> + <label for="password">Password:</label> + <input id="password" type="password" formControlName="password" /> + <div *ngIf="loginForm.get('password')?.invalid && loginForm.get('password')?.touched"> + <small>Password is required.</small> + </div> + </div> + + <button type="submit" [disabled]="loginForm.invalid">Login</button> + </form> + </div> + diff --git a/angular/RestClient/src/app/core/features/auth/login/login.component.spec.ts b/angular/RestClient/src/app/core/features/auth/login/login.component.spec.ts new file mode 100644 index 0000000..18f3685 --- /dev/null +++ b/angular/RestClient/src/app/core/features/auth/login/login.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoginComponent } from './login.component'; + +describe('LoginComponent', () => { + let component: LoginComponent; + let fixture: ComponentFixture<LoginComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [LoginComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(LoginComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/angular/RestClient/src/app/core/features/auth/login/login.component.ts b/angular/RestClient/src/app/core/features/auth/login/login.component.ts new file mode 100644 index 0000000..b58031c --- /dev/null +++ b/angular/RestClient/src/app/core/features/auth/login/login.component.ts @@ -0,0 +1,28 @@ +import { Component } from '@angular/core'; +import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; + +@Component({ + standalone: true, + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.css'], + imports: [ReactiveFormsModule] +}) +export class LoginComponent { + loginForm: FormGroup; + + constructor(private fb: FormBuilder) { + this.loginForm = this.fb.group({ + email: ['', [Validators.required, Validators.email]], + password: ['', Validators.required] + }); + } + + onSubmit() { + if (this.loginForm.valid) { + const { email, password } = this.loginForm.value; + console.log('Login data:', { email, password }); + // Aquí iría el llamado al servicio de login con JWT + } + } +} diff --git a/angular/RestClient/src/app/core/features/auth/register/register.component.css b/angular/RestClient/src/app/core/features/auth/register/register.component.css new file mode 100644 index 0000000..8fdfb8e --- /dev/null +++ b/angular/RestClient/src/app/core/features/auth/register/register.component.css @@ -0,0 +1,131 @@ +/* General container styles */ +.container { + max-width: 400px; + margin: 50px auto; + padding: 30px; + background: linear-gradient(135deg, #1e1e2f, #2a2a45); + border-radius: 12px; + box-shadow: 0 8px 15px rgba(0, 0, 0, 0.3); + color: #fff; + font-family: 'Roboto', sans-serif; + } + + h2 { + text-align: center; + font-size: 1.8em; + font-weight: bold; + margin-bottom: 20px; + color: #fff; + letter-spacing: 1px; + text-transform: uppercase; + background: linear-gradient(90deg, #7f7fd5, #86a8e7, #91eae4); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + + /* Form fields */ + form div { + margin-bottom: 20px; + } + + label { + font-size: 0.9em; + font-weight: bold; + margin-bottom: 8px; + display: block; + letter-spacing: 0.5px; + color: #b3b3d1; + } + + input { + width: 100%; + padding: 12px 15px; + font-size: 0.95em; + border: 1px solid #3e3e5e; + border-radius: 8px; + background: #252540; + color: #fff; + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3); + transition: all 0.3s ease-in-out; + } + + input:focus { + outline: none; + border-color: #7f7fd5; + background: #2e2e50; + box-shadow: 0 0 8px rgba(127, 127, 213, 0.8); + } + + /* Buttons */ + button { + width: 100%; + padding: 12px; + font-size: 1em; + font-weight: bold; + color: #fff; + background: linear-gradient(90deg, #7f7fd5, #86a8e7, #91eae4); + border: none; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; + transition: transform 0.2s, box-shadow 0.2s; + } + + button:hover { + transform: translateY(-3px); + box-shadow: 0 8px 15px rgba(127, 127, 213, 0.5); + } + + button:disabled { + background: #3e3e5e; + cursor: not-allowed; + opacity: 0.7; + box-shadow: none; + } + + /* Small error messages */ + small { + display: block; + margin-top: 5px; + font-size: 0.85em; + color: #ff6b6b; + } + + /* Extra animations and effects */ + .container::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(120deg, rgba(127, 127, 213, 0.2), rgba(86, 168, 231, 0.1)); + z-index: -1; + filter: blur(20px); + } + + input::placeholder { + color: #b3b3d1; + } + + form div:last-child { + margin-top: 30px; + } + + /* Responsiveness */ + @media (max-width: 768px) { + .container { + padding: 20px; + margin: 20px; + } + + h2 { + font-size: 1.5em; + } + + input, + button { + font-size: 0.9em; + } + } + \ No newline at end of file diff --git a/angular/RestClient/src/app/core/features/auth/register/register.component.html b/angular/RestClient/src/app/core/features/auth/register/register.component.html new file mode 100644 index 0000000..8f54cfe --- /dev/null +++ b/angular/RestClient/src/app/core/features/auth/register/register.component.html @@ -0,0 +1,31 @@ +<div class="register-container"> + <h2>Register</h2> + <form [formGroup]="registerForm" (ngSubmit)="onSubmit()"> + <div> + <label for="email">Email:</label> + <input id="email" type="email" formControlName="email" /> + <div *ngIf="registerForm.get('email')?.invalid && registerForm.get('email')?.touched"> + <small>Email is required and must be valid.</small> + </div> + </div> + + <div> + <label for="password">Password:</label> + <input id="password" type="password" formControlName="password" /> + <div *ngIf="registerForm.get('password')?.invalid && registerForm.get('password')?.touched"> + <small>Password is required.</small> + </div> + </div> + + <div> + <label for="confirmPassword">Confirm Password:</label> + <input id="confirmPassword" type="password" formControlName="confirmPassword" /> + <div *ngIf="registerForm.get('confirmPassword')?.invalid && registerForm.get('confirmPassword')?.touched"> + <small>Passwords must match.</small> + </div> + </div> + + <button type="submit" [disabled]="registerForm.invalid">Register</button> + </form> + </div> + \ No newline at end of file diff --git a/angular/RestClient/src/app/core/features/auth/register/register.component.spec.ts b/angular/RestClient/src/app/core/features/auth/register/register.component.spec.ts new file mode 100644 index 0000000..757b895 --- /dev/null +++ b/angular/RestClient/src/app/core/features/auth/register/register.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RegisterComponent } from './register.component'; + +describe('RegisterComponent', () => { + let component: RegisterComponent; + let fixture: ComponentFixture<RegisterComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RegisterComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(RegisterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/angular/RestClient/src/app/core/features/auth/register/register.component.ts b/angular/RestClient/src/app/core/features/auth/register/register.component.ts new file mode 100644 index 0000000..586790f --- /dev/null +++ b/angular/RestClient/src/app/core/features/auth/register/register.component.ts @@ -0,0 +1,31 @@ +import { Component } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; + +@Component({ + selector: 'app-register', + templateUrl: './register.component.html', + styleUrls: ['./register.component.css'] +}) +export class RegisterComponent { + registerForm: FormGroup; + + constructor(private fb: FormBuilder) { + this.registerForm = this.fb.group({ + email: ['', [Validators.required, Validators.email]], + password: ['', Validators.required], + confirmPassword: ['', Validators.required] + }); + } + + onSubmit() { + if (this.registerForm.valid) { + const { email, password, confirmPassword } = this.registerForm.value; + if (password === confirmPassword) { + console.log('Register data:', { email, password }); + // Aquí iría el llamado al servicio de register con JWT + } else { + console.error('Passwords do not match.'); + } + } + } +} -- GitLab From 471c0d620e55babdb329c4c0a6ec4b816d6844f7 Mon Sep 17 00:00:00 2001 From: Hugo <hugo.cubino@estudiantes.uva.es> Date: Fri, 22 Nov 2024 16:17:56 +0100 Subject: [PATCH 2/5] Funciona register --- angular/RestClient/src/app/app.routes.ts | 5 ++ .../features/auth/login/login.component.ts | 35 +++++++-- .../auth/register/register.component.html | 74 ++++++++++++------- .../auth/register/register.component.ts | 46 +++++++++--- .../java/com/uva/roomBooking/Models/User.java | 14 +++- 5 files changed, 129 insertions(+), 45 deletions(-) diff --git a/angular/RestClient/src/app/app.routes.ts b/angular/RestClient/src/app/app.routes.ts index dc45a08..cbb0feb 100644 --- a/angular/RestClient/src/app/app.routes.ts +++ b/angular/RestClient/src/app/app.routes.ts @@ -6,6 +6,7 @@ import { MainPageComponent } from './core/features/user/main-page/main-page.comp import { BookingListComponent } from './core/features/bookings/booking-list/booking-list.component'; import { UserBookingListComponent } from './core/features/user/user-booking-list/user-booking-list.component'; import { LoginComponent } from './core/features/auth/login/login.component'; +import { RegisterComponent } from './core/features/auth/register/register.component'; export const routes: Routes = [ { @@ -40,6 +41,10 @@ export const routes: Routes = [ path: 'auth/login', component: LoginComponent, }, + { + path: 'auth/register', + component: RegisterComponent, + }, { path: '**', redirectTo: '', diff --git a/angular/RestClient/src/app/core/features/auth/login/login.component.ts b/angular/RestClient/src/app/core/features/auth/login/login.component.ts index b58031c..530355d 100644 --- a/angular/RestClient/src/app/core/features/auth/login/login.component.ts +++ b/angular/RestClient/src/app/core/features/auth/login/login.component.ts @@ -1,28 +1,53 @@ import { Component } from '@angular/core'; import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; +import { HttpClient } from '@angular/common/http'; +import { Router } from '@angular/router'; +import { CommonModule } from '@angular/common'; @Component({ standalone: true, selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.css'], - imports: [ReactiveFormsModule] + imports: [CommonModule, ReactiveFormsModule] }) + + export class LoginComponent { loginForm: FormGroup; - constructor(private fb: FormBuilder) { + constructor( + private fb: FormBuilder, + private http: HttpClient, + private router: Router + ) { this.loginForm = this.fb.group({ email: ['', [Validators.required, Validators.email]], - password: ['', Validators.required] + password: ['', [Validators.required]], }); } onSubmit() { if (this.loginForm.valid) { const { email, password } = this.loginForm.value; - console.log('Login data:', { email, password }); - // Aquí iría el llamado al servicio de login con JWT + + // Realizar la solicitud al backend + this.http.post('http://localhost:8101', { email, password }).subscribe({ + next: (response: any) => { + // Guardar el token en localStorage + localStorage.setItem('authToken', response.token); + + // Redirigir al dashboard + this.router.navigate(['/']); + }, + error: (err) => { + console.error('Error en el login:', err); + }, + }); } } + + isAuthenticated(): boolean { + return !!localStorage.getItem('authToken'); + } } diff --git a/angular/RestClient/src/app/core/features/auth/register/register.component.html b/angular/RestClient/src/app/core/features/auth/register/register.component.html index 8f54cfe..0661bf2 100644 --- a/angular/RestClient/src/app/core/features/auth/register/register.component.html +++ b/angular/RestClient/src/app/core/features/auth/register/register.component.html @@ -1,31 +1,51 @@ <div class="register-container"> - <h2>Register</h2> - <form [formGroup]="registerForm" (ngSubmit)="onSubmit()"> - <div> - <label for="email">Email:</label> - <input id="email" type="email" formControlName="email" /> - <div *ngIf="registerForm.get('email')?.invalid && registerForm.get('email')?.touched"> - <small>Email is required and must be valid.</small> - </div> + <h2>Regístrate</h2> + <form [formGroup]="registerForm" (ngSubmit)="onSubmit()"> + <div class="form-group"> + <label for="name">Nombre</label> + <input + id="name" + type="text" + formControlName="name" + placeholder="Introduce tu nombre" + required + /> + <div *ngIf="registerForm.get('name')?.invalid && registerForm.get('name')?.touched"> + <small>El nombre es obligatorio y debe tener al menos 3 caracteres.</small> </div> - - <div> - <label for="password">Password:</label> - <input id="password" type="password" formControlName="password" /> - <div *ngIf="registerForm.get('password')?.invalid && registerForm.get('password')?.touched"> - <small>Password is required.</small> - </div> + </div> + + <div class="form-group"> + <label for="email">Correo Electrónico</label> + <input + id="email" + type="email" + formControlName="email" + placeholder="Introduce tu correo" + required + /> + <div *ngIf="registerForm.get('email')?.invalid && registerForm.get('email')?.touched"> + <small>El correo electrónico no es válido.</small> </div> - - <div> - <label for="confirmPassword">Confirm Password:</label> - <input id="confirmPassword" type="password" formControlName="confirmPassword" /> - <div *ngIf="registerForm.get('confirmPassword')?.invalid && registerForm.get('confirmPassword')?.touched"> - <small>Passwords must match.</small> - </div> + </div> + + <div class="form-group"> + <label for="password">Contraseña</label> + <input + id="password" + type="password" + formControlName="password" + placeholder="Introduce tu contraseña" + required + /> + <div *ngIf="registerForm.get('password')?.invalid && registerForm.get('password')?.touched"> + <small>La contraseña debe tener al menos 6 caracteres.</small> </div> - - <button type="submit" [disabled]="registerForm.invalid">Register</button> - </form> - </div> - \ No newline at end of file + </div> + + <button type="submit" [disabled]="registerForm.invalid">Registrarse</button> + <div *ngIf="errorMessage" class="error-message"> + {{ errorMessage }} + </div> + </form> +</div> diff --git a/angular/RestClient/src/app/core/features/auth/register/register.component.ts b/angular/RestClient/src/app/core/features/auth/register/register.component.ts index 586790f..4b9f198 100644 --- a/angular/RestClient/src/app/core/features/auth/register/register.component.ts +++ b/angular/RestClient/src/app/core/features/auth/register/register.component.ts @@ -1,31 +1,53 @@ +import { CommonModule } from '@angular/common'; +import { HttpClient } from '@angular/common/http'; import { Component } from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; @Component({ + standalone: true, selector: 'app-register', templateUrl: './register.component.html', - styleUrls: ['./register.component.css'] + styleUrls: ['./register.component.css'], + imports: [ReactiveFormsModule, CommonModule] }) + export class RegisterComponent { registerForm: FormGroup; + errorMessage: string | null = null; - constructor(private fb: FormBuilder) { + constructor( + private fb: FormBuilder, + private http: HttpClient, + private router: Router + ) { this.registerForm = this.fb.group({ + name: ['', [Validators.required, Validators.minLength(3)]], email: ['', [Validators.required, Validators.email]], - password: ['', Validators.required], - confirmPassword: ['', Validators.required] + password: ['', [Validators.required, Validators.minLength(6)]], }); } onSubmit() { if (this.registerForm.valid) { - const { email, password, confirmPassword } = this.registerForm.value; - if (password === confirmPassword) { - console.log('Register data:', { email, password }); - // Aquí iría el llamado al servicio de register con JWT - } else { - console.error('Passwords do not match.'); - } + const { name, email, password } = this.registerForm.value; + + // Enviar solicitud al backend + this.http.post('http://localhost:8080/users', { name, email, password }).subscribe({ + next: () => { + alert('Usuario registrado con éxito.'); + this.router.navigate(['/auth/login']); // Redirigir al login + }, + error: (err) => { + if (err.error instanceof ErrorEvent) { + this.errorMessage = `Error: ${err.error.message}`; + } else { + // Si el backend devuelve un objeto de error + this.errorMessage = err.error.message || 'Ocurrió un error al registrar el usuario.'; + } + } + + }); } } } diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/User.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Models/User.java index c5373df..71b8bdf 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/User.java +++ b/java/roomBooking/src/main/java/com/uva/roomBooking/Models/User.java @@ -34,6 +34,9 @@ public class User { @Enumerated(EnumType.STRING) private UserStatus status = UserStatus.NO_BOOKINGS; + @Basic(optional = false) + private String password; + @JsonIgnore @OneToMany(mappedBy = "userId", fetch = FetchType.EAGER, cascade = CascadeType.ALL) private List<Booking> bookings; @@ -41,11 +44,12 @@ public class User { public User() { } - public User(int id, String name, String email, UserStatus status, List<Booking> bookings) { + public User(int id, String name, String email, UserStatus status, List<Booking> bookings, String password) { setId(id); setEmail(email); setStatus(status); setBookings(bookings); + setPassword(password); } public int getId() { @@ -87,4 +91,12 @@ public class User { public void setBookings(List<Booking> bookings) { this.bookings = bookings; } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } } -- GitLab From 2cf098312e79339ec89f0065e0f339c9f71d4495 Mon Sep 17 00:00:00 2001 From: migudel <miguel.moras@estudiantes.uva.es> Date: Fri, 29 Nov 2024 23:09:34 +0100 Subject: [PATCH 3/5] =?UTF-8?q?Resoluci=C3=B3n=20de=20conflictos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/uva/authentication/Models/User.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/java/services/auth/src/main/java/com/uva/authentication/Models/User.java b/java/services/auth/src/main/java/com/uva/authentication/Models/User.java index eff82ac..9f56935 100644 --- a/java/services/auth/src/main/java/com/uva/authentication/Models/User.java +++ b/java/services/auth/src/main/java/com/uva/authentication/Models/User.java @@ -5,47 +5,55 @@ import java.util.List; import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.Basic; -import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; import jakarta.persistence.Table; @Entity +@Inheritance(strategy = InheritanceType.JOINED) @Table(name = "users") public class User { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) + @Column(nullable = false) private int id; @Basic(optional = false) + @Column(nullable = false) private String name; @Basic(optional = false) + @Column(nullable = false, unique = true) private String email; + @JsonIgnore @Basic(optional = false) - @Enumerated(EnumType.STRING) - private UserStatus status = UserStatus.NO_BOOKINGS; - + @Column(nullable = false) private String password; - + @Basic(optional = false) + @Column(nullable = false) + @Enumerated(EnumType.STRING) + private UserRol rol = UserRol.CLIENT; public User() { } - public User(int id, String name, String email, UserStatus status, String password) { + public User(int id, String name, String email, String password, UserRol rol) { setId(id); + setName(name); setEmail(email); - setStatus(status); setPassword(password); + setRol(rol); } public int getId() { @@ -72,14 +80,6 @@ public class User { this.email = email; } - public UserStatus getStatus() { - return this.status; - } - - public void setStatus(UserStatus status) { - this.status = status; - } - public String getPassword() { return this.password; } -- GitLab From b07374845f950a58b9c700ba2a599fc85c690f33 Mon Sep 17 00:00:00 2001 From: migudel <miguel.moras@estudiantes.uva.es> Date: Fri, 29 Nov 2024 23:14:09 +0100 Subject: [PATCH 4/5] Revert "Funciona register" This reverts commit 471c0d620e55babdb329c4c0a6ec4b816d6844f7. --- angular/RestClient/src/app/app.routes.ts | 5 -- .../features/auth/login/login.component.ts | 35 ++------- .../auth/register/register.component.html | 74 +++++++------------ .../auth/register/register.component.ts | 46 +++--------- .../java/com/uva/roomBooking/Models/User.java | 14 +--- 5 files changed, 45 insertions(+), 129 deletions(-) diff --git a/angular/RestClient/src/app/app.routes.ts b/angular/RestClient/src/app/app.routes.ts index cbb0feb..dc45a08 100644 --- a/angular/RestClient/src/app/app.routes.ts +++ b/angular/RestClient/src/app/app.routes.ts @@ -6,7 +6,6 @@ import { MainPageComponent } from './core/features/user/main-page/main-page.comp import { BookingListComponent } from './core/features/bookings/booking-list/booking-list.component'; import { UserBookingListComponent } from './core/features/user/user-booking-list/user-booking-list.component'; import { LoginComponent } from './core/features/auth/login/login.component'; -import { RegisterComponent } from './core/features/auth/register/register.component'; export const routes: Routes = [ { @@ -41,10 +40,6 @@ export const routes: Routes = [ path: 'auth/login', component: LoginComponent, }, - { - path: 'auth/register', - component: RegisterComponent, - }, { path: '**', redirectTo: '', diff --git a/angular/RestClient/src/app/core/features/auth/login/login.component.ts b/angular/RestClient/src/app/core/features/auth/login/login.component.ts index 530355d..b58031c 100644 --- a/angular/RestClient/src/app/core/features/auth/login/login.component.ts +++ b/angular/RestClient/src/app/core/features/auth/login/login.component.ts @@ -1,53 +1,28 @@ import { Component } from '@angular/core'; import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; -import { HttpClient } from '@angular/common/http'; -import { Router } from '@angular/router'; -import { CommonModule } from '@angular/common'; @Component({ standalone: true, selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.css'], - imports: [CommonModule, ReactiveFormsModule] + imports: [ReactiveFormsModule] }) - - export class LoginComponent { loginForm: FormGroup; - constructor( - private fb: FormBuilder, - private http: HttpClient, - private router: Router - ) { + constructor(private fb: FormBuilder) { this.loginForm = this.fb.group({ email: ['', [Validators.required, Validators.email]], - password: ['', [Validators.required]], + password: ['', Validators.required] }); } onSubmit() { if (this.loginForm.valid) { const { email, password } = this.loginForm.value; - - // Realizar la solicitud al backend - this.http.post('http://localhost:8101', { email, password }).subscribe({ - next: (response: any) => { - // Guardar el token en localStorage - localStorage.setItem('authToken', response.token); - - // Redirigir al dashboard - this.router.navigate(['/']); - }, - error: (err) => { - console.error('Error en el login:', err); - }, - }); + console.log('Login data:', { email, password }); + // Aquí iría el llamado al servicio de login con JWT } } - - isAuthenticated(): boolean { - return !!localStorage.getItem('authToken'); - } } diff --git a/angular/RestClient/src/app/core/features/auth/register/register.component.html b/angular/RestClient/src/app/core/features/auth/register/register.component.html index 0661bf2..8f54cfe 100644 --- a/angular/RestClient/src/app/core/features/auth/register/register.component.html +++ b/angular/RestClient/src/app/core/features/auth/register/register.component.html @@ -1,51 +1,31 @@ <div class="register-container"> - <h2>Regístrate</h2> - <form [formGroup]="registerForm" (ngSubmit)="onSubmit()"> - <div class="form-group"> - <label for="name">Nombre</label> - <input - id="name" - type="text" - formControlName="name" - placeholder="Introduce tu nombre" - required - /> - <div *ngIf="registerForm.get('name')?.invalid && registerForm.get('name')?.touched"> - <small>El nombre es obligatorio y debe tener al menos 3 caracteres.</small> + <h2>Register</h2> + <form [formGroup]="registerForm" (ngSubmit)="onSubmit()"> + <div> + <label for="email">Email:</label> + <input id="email" type="email" formControlName="email" /> + <div *ngIf="registerForm.get('email')?.invalid && registerForm.get('email')?.touched"> + <small>Email is required and must be valid.</small> + </div> </div> - </div> - - <div class="form-group"> - <label for="email">Correo Electrónico</label> - <input - id="email" - type="email" - formControlName="email" - placeholder="Introduce tu correo" - required - /> - <div *ngIf="registerForm.get('email')?.invalid && registerForm.get('email')?.touched"> - <small>El correo electrónico no es válido.</small> + + <div> + <label for="password">Password:</label> + <input id="password" type="password" formControlName="password" /> + <div *ngIf="registerForm.get('password')?.invalid && registerForm.get('password')?.touched"> + <small>Password is required.</small> + </div> </div> - </div> - - <div class="form-group"> - <label for="password">Contraseña</label> - <input - id="password" - type="password" - formControlName="password" - placeholder="Introduce tu contraseña" - required - /> - <div *ngIf="registerForm.get('password')?.invalid && registerForm.get('password')?.touched"> - <small>La contraseña debe tener al menos 6 caracteres.</small> + + <div> + <label for="confirmPassword">Confirm Password:</label> + <input id="confirmPassword" type="password" formControlName="confirmPassword" /> + <div *ngIf="registerForm.get('confirmPassword')?.invalid && registerForm.get('confirmPassword')?.touched"> + <small>Passwords must match.</small> + </div> </div> - </div> - - <button type="submit" [disabled]="registerForm.invalid">Registrarse</button> - <div *ngIf="errorMessage" class="error-message"> - {{ errorMessage }} - </div> - </form> -</div> + + <button type="submit" [disabled]="registerForm.invalid">Register</button> + </form> + </div> + \ No newline at end of file diff --git a/angular/RestClient/src/app/core/features/auth/register/register.component.ts b/angular/RestClient/src/app/core/features/auth/register/register.component.ts index 4b9f198..586790f 100644 --- a/angular/RestClient/src/app/core/features/auth/register/register.component.ts +++ b/angular/RestClient/src/app/core/features/auth/register/register.component.ts @@ -1,53 +1,31 @@ -import { CommonModule } from '@angular/common'; -import { HttpClient } from '@angular/common/http'; import { Component } from '@angular/core'; -import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; -import { Router } from '@angular/router'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ - standalone: true, selector: 'app-register', templateUrl: './register.component.html', - styleUrls: ['./register.component.css'], - imports: [ReactiveFormsModule, CommonModule] + styleUrls: ['./register.component.css'] }) - export class RegisterComponent { registerForm: FormGroup; - errorMessage: string | null = null; - constructor( - private fb: FormBuilder, - private http: HttpClient, - private router: Router - ) { + constructor(private fb: FormBuilder) { this.registerForm = this.fb.group({ - name: ['', [Validators.required, Validators.minLength(3)]], email: ['', [Validators.required, Validators.email]], - password: ['', [Validators.required, Validators.minLength(6)]], + password: ['', Validators.required], + confirmPassword: ['', Validators.required] }); } onSubmit() { if (this.registerForm.valid) { - const { name, email, password } = this.registerForm.value; - - // Enviar solicitud al backend - this.http.post('http://localhost:8080/users', { name, email, password }).subscribe({ - next: () => { - alert('Usuario registrado con éxito.'); - this.router.navigate(['/auth/login']); // Redirigir al login - }, - error: (err) => { - if (err.error instanceof ErrorEvent) { - this.errorMessage = `Error: ${err.error.message}`; - } else { - // Si el backend devuelve un objeto de error - this.errorMessage = err.error.message || 'Ocurrió un error al registrar el usuario.'; - } - } - - }); + const { email, password, confirmPassword } = this.registerForm.value; + if (password === confirmPassword) { + console.log('Register data:', { email, password }); + // Aquí iría el llamado al servicio de register con JWT + } else { + console.error('Passwords do not match.'); + } } } } diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/User.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Models/User.java index 71b8bdf..c5373df 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/User.java +++ b/java/roomBooking/src/main/java/com/uva/roomBooking/Models/User.java @@ -34,9 +34,6 @@ public class User { @Enumerated(EnumType.STRING) private UserStatus status = UserStatus.NO_BOOKINGS; - @Basic(optional = false) - private String password; - @JsonIgnore @OneToMany(mappedBy = "userId", fetch = FetchType.EAGER, cascade = CascadeType.ALL) private List<Booking> bookings; @@ -44,12 +41,11 @@ public class User { public User() { } - public User(int id, String name, String email, UserStatus status, List<Booking> bookings, String password) { + public User(int id, String name, String email, UserStatus status, List<Booking> bookings) { setId(id); setEmail(email); setStatus(status); setBookings(bookings); - setPassword(password); } public int getId() { @@ -91,12 +87,4 @@ public class User { public void setBookings(List<Booking> bookings) { this.bookings = bookings; } - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } } -- GitLab From f7fc6df0b21021b38ba8443a48fc03ace34fa341 Mon Sep 17 00:00:00 2001 From: migudel <miguel.moras@estudiantes.uva.es> Date: Fri, 29 Nov 2024 23:19:45 +0100 Subject: [PATCH 5/5] Conflictos II --- angular/RestClient/src/app/app.routes.ts | 107 +++++++++++++++--- .../authentication/models/remote/User.java | 95 ++++++++++++++++ 2 files changed, 188 insertions(+), 14 deletions(-) create mode 100644 java/services/auth/src/main/java/com/uva/authentication/models/remote/User.java diff --git a/angular/RestClient/src/app/app.routes.ts b/angular/RestClient/src/app/app.routes.ts index dc45a08..435147a 100644 --- a/angular/RestClient/src/app/app.routes.ts +++ b/angular/RestClient/src/app/app.routes.ts @@ -5,41 +5,120 @@ import { HotelRegisterComponent } from './core/features/hotel/hotel-register/hot import { MainPageComponent } from './core/features/user/main-page/main-page.component'; import { BookingListComponent } from './core/features/bookings/booking-list/booking-list.component'; import { UserBookingListComponent } from './core/features/user/user-booking-list/user-booking-list.component'; + import { LoginComponent } from './core/features/auth/login/login.component'; +import { UserFormComponent } from './core/features/user/user-form/user-form.component'; export const routes: Routes = [ { path: '', // Ruta principal - component: MainPageComponent, // Componente de la página principal + component: MainPageComponent, }, + // auth { - path: 'bookings/search', - component: BookingListComponent, + path: 'login', + component: LoginComponent, }, { - path: 'bookings/new', - component: BookingComponent, + path: 'register', }, + // Hoteles { - path: 'users/:id/bookings', - component: UserBookingListComponent, + path: 'hotels', // Ruta para la lista de hoteles }, { - path: 'hotels', - component: HotelListComponent, + path: 'hotels/register', // Registrar nuevo hotel }, { - path: 'hotels/new', - component: HotelRegisterComponent, + path: 'hotels/:id', // Hotel concreto }, { - path: 'hotels/:id', - component: HotelRegisterComponent, + path: 'hotels/:id/edit', // Modificar hotel + }, + // Usuario + { + path: 'me', // Main + }, + { + path: 'me/edit', // Main + }, + // Usuario HOTEL admin + { + path: 'me/hotels', + }, + { + path: 'me/hotels/:id', }, { path: 'auth/login', - component: LoginComponent, }, + { + path: 'me/hotels/:id/bookings', + }, + { + path: 'me/hotels/:id/rooms', + }, + { + path: 'me/hotels/:id/rooms/:id', + }, + { + path: 'me/hotels/:id/rooms/:id/bookings', + }, + // Usuario Cliente + { + path: 'me/bookings', + }, + { + path: 'me/bookings/:id', + }, + { + path: 'me/bookings/new', + }, + // Administrador + { + path: 'admin', // Main + }, + { + path: 'admin/users', // Main + }, + { + path: 'admin/users/:id', // Main + }, + + // ! OTRO // NO MIRAR + + // { + // path: 'bookings/search', + // component: BookingListComponent, + // }, + // { + // path: 'bookings/new', + // component: BookingComponent, + // }, + // { + // path: 'users/:id/bookings', + // component: UserBookingListComponent, + // }, + // { + // path: 'hotels', + // component: HotelListComponent, + // }, + // { + // path: 'hotels/new', + // component: HotelRegisterComponent, + // }, + // { + // path: 'hotels/:id', + // component: HotelRegisterComponent, + // }, + // { + // path: 'users/:id', + // component: UserFormComponent, + // }, + // { + // path: 'register', + // component: UserFormComponent, + // }, { path: '**', redirectTo: '', diff --git a/java/services/auth/src/main/java/com/uva/authentication/models/remote/User.java b/java/services/auth/src/main/java/com/uva/authentication/models/remote/User.java new file mode 100644 index 0000000..a72ecfa --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/models/remote/User.java @@ -0,0 +1,95 @@ +package com.uva.authentication.models.remote; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.Table; + +@Entity +@Inheritance(strategy = InheritanceType.JOINED) +@Table(name = "users") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Basic(optional = false) + @Column(nullable = false) + private int id; + + @Basic(optional = false) + @Column(nullable = false) + private String name; + + @Basic(optional = false) + @Column(nullable = false, unique = true) + private String email; + + @JsonIgnore + @Basic(optional = false) + @Column(nullable = false) + private String password; + + @Basic(optional = false) + @Column(nullable = false) + @Enumerated(EnumType.STRING) + private UserRol rol = UserRol.CLIENT; + + public User() { + } + + public User(int id, String name, String email, String password, UserRol rol) { + setId(id); + setName(name); + setEmail(email); + setRol(rol); + } + + public int getId() { + return this.id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String rawPassword) { + this.password = rawPassword; + } + + public UserRol getRol() { + return this.rol; + } + + public void setRol(UserRol rol) { + this.rol = rol; + } +} -- GitLab