diff --git a/.gitignore b/.gitignore index d272472a60ed42d464084017fd58f4a764860e9e..9d69baa07a9349a0ed0d73d664ad697aa5e65a9f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,10 @@ ### Own ### taller *.pdf -**/target/ \ No newline at end of file +**/target/ +**/.vscode +**/tmp +**/*.tmp +*.ln +*.log + diff --git a/angular/RestClient/angular.json b/angular/RestClient/angular.json index 2fe5dbb241e8371e452ea965dee70c7249575f0c..32760665f49d122760236268ce4124bfaa0b6bde 100644 --- a/angular/RestClient/angular.json +++ b/angular/RestClient/angular.json @@ -32,12 +32,7 @@ "scripts": [ "node_modules/jquery/dist/jquery.min.js", "node_modules/bootstrap/dist/js/bootstrap.min.js" - ], - "server": "src/main.server.ts", - "prerender": true, - "ssr": { - "entry": "server.ts" - } + ] }, "configurations": { "production": { diff --git a/angular/RestClient/environments/environment.prod.ts b/angular/RestClient/environments/environment.prod.ts new file mode 100644 index 0000000000000000000000000000000000000000..e7abc07ec43af506db487532b2175c50676f3534 --- /dev/null +++ b/angular/RestClient/environments/environment.prod.ts @@ -0,0 +1,9 @@ +const monolithUrl = 'http://room-booking:8080'; + +export const environment = { + production: true, + authAPI: 'http://auth-api:8101', + userAPI: `http://${monolithUrl}`, + hotelAPI: `http://${monolithUrl}`, + bookingAPI: `http://${monolithUrl}`, +}; diff --git a/angular/RestClient/environments/environment.ts b/angular/RestClient/environments/environment.ts new file mode 100644 index 0000000000000000000000000000000000000000..d82bc7fa8278b4fb12dd2db673f4b2c116cf8e3b --- /dev/null +++ b/angular/RestClient/environments/environment.ts @@ -0,0 +1,9 @@ +const monolithUrl = 'localhost:8080'; + +export const environment = { + production: true, + authAPI: 'http://localhost:8101', + userAPI: `http://${monolithUrl}/users`, + hotelAPI: `http://${monolithUrl}/hotels`, + bookingAPI: `http://${monolithUrl}/bookings`, +}; diff --git a/angular/RestClient/package-lock.json b/angular/RestClient/package-lock.json index a5d201bf11869266cc967b0e328660d5d8870bc7..af241069cc8acddc06a48c70b6d1dd25125a07ac 100644 --- a/angular/RestClient/package-lock.json +++ b/angular/RestClient/package-lock.json @@ -25,6 +25,7 @@ "bootstrap": "^3.4.0", "express": "^4.18.2", "jquery": "^3.4.1", + "jwt-decode": "^4.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.14.10" @@ -5468,9 +5469,9 @@ "license": "ISC" }, "node_modules/bootstrap": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.0.tgz", - "integrity": "sha512-F1yTDO9OHKH0xjl03DsOe8Nu1OWBIeAugGMhy3UTIYDdbbIPesQIhCEbj+HEr6wqlwweGAlP8F3OBC6kEuhFuw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==", "license": "MIT", "engines": { "node": ">=6" @@ -6329,9 +6330,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -8555,9 +8556,9 @@ } }, "node_modules/jquery": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", - "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", "license": "MIT" }, "node_modules/js-tokens": { @@ -8654,6 +8655,15 @@ ], "license": "MIT" }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/karma": { "version": "6.4.4", "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", diff --git a/angular/RestClient/package.json b/angular/RestClient/package.json index 262eacd1144f0eaab113dda4aad24eedab9ff958..a17778b07370cfdb71c9dcc5f6137b413ab929cf 100644 --- a/angular/RestClient/package.json +++ b/angular/RestClient/package.json @@ -28,6 +28,7 @@ "bootstrap": "^3.4.0", "express": "^4.18.2", "jquery": "^3.4.1", + "jwt-decode": "^4.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.14.10" diff --git a/angular/RestClient/src/app/app.config.ts b/angular/RestClient/src/app/app.config.ts index 1f668ea1741efbdb605f6d418a9a93f53f1327fa..a7435caa914532ca9a3c5f085f6b02b3f36aa603 100644 --- a/angular/RestClient/src/app/app.config.ts +++ b/angular/RestClient/src/app/app.config.ts @@ -1,19 +1,22 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; -import { provideHttpClient, withFetch } from '@angular/common/http'; +import { + provideHttpClient, + withFetch, + withInterceptors, +} from '@angular/common/http'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; import { ReactiveFormsModule } from '@angular/forms'; // Added import for ReactiveFormsModule import { provideNativeDateAdapter } from '@angular/material/core'; -import { provideClientHydration } from '@angular/platform-browser'; +import { authRequest } from './auth/auth.interceptor'; export const appConfig: ApplicationConfig = { providers: [ provideNativeDateAdapter(), provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), - provideClientHydration(), - provideHttpClient(withFetch()), + provideHttpClient(withFetch(), withInterceptors([authRequest])), provideAnimationsAsync(), ReactiveFormsModule, ], diff --git a/angular/RestClient/src/app/app.routes.ts b/angular/RestClient/src/app/app.routes.ts index 435147aaba7cab6a92b72a93c0bf217eded0540d..13e66397bddf5dafcd427e12591f6b682ab1f4d2 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 { UserFormComponent } from './core/features/user/user-form/user-form.component'; import { LoginComponent } from './core/features/auth/login/login.component'; import { UserFormComponent } from './core/features/user/user-form/user-form.component'; @@ -49,9 +50,6 @@ export const routes: Routes = [ { path: 'me/hotels/:id', }, - { - path: 'auth/login', - }, { path: 'me/hotels/:id/bookings', }, diff --git a/angular/RestClient/src/app/auth/auth.interceptor.ts b/angular/RestClient/src/app/auth/auth.interceptor.ts new file mode 100644 index 0000000000000000000000000000000000000000..63a139b74505e95db8b5c3c88f508696e7ff73be --- /dev/null +++ b/angular/RestClient/src/app/auth/auth.interceptor.ts @@ -0,0 +1,32 @@ +import { HttpInterceptorFn } from '@angular/common/http'; +import { inject } from '@angular/core'; +import { LocalStorageService } from '../shared/local-storage.service'; + +const excluded = ['/login', '/register']; + +function isExcludedUrl(url: string) { + return excluded.some((excluded) => url.includes(excluded)); +} + +export const authRequest: HttpInterceptorFn = (req, next) => { + // Obtener el token desde localStorage (o cualquier otro mecanismo) + const storage = inject(LocalStorageService); // Obtener instancia del servicio + const token = storage.read<{ token: string }>('token'); + + if (isExcludedUrl(req.url) || !token) { + return next(req); // No modificar la solicitud + } + + // Clonar la solicitud y agregar el token al encabezado si existe + const authReq = token + ? req.clone({ + setHeaders: { + Authorization: `Bearer ${token.token}`, + 'Content-Type': 'application/json', + }, + }) + : req; + + // Pasar la solicitud modificada al siguiente manejador + return next(authReq); +}; diff --git a/angular/RestClient/src/app/core/features/bookings/booking-list/booking-list.component.ts b/angular/RestClient/src/app/core/features/bookings/booking-list/booking-list.component.ts index 5789a064b18d4aa50d9c6d9f163a87fb89bb7afc..6fb90798ea3a10e2dece5c0b0661e4a43ec393a4 100644 --- a/angular/RestClient/src/app/core/features/bookings/booking-list/booking-list.component.ts +++ b/angular/RestClient/src/app/core/features/bookings/booking-list/booking-list.component.ts @@ -7,7 +7,7 @@ import { import { FormsModule } from '@angular/forms'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; -import { Hotel, Room, RoomType, roomTypeArray } from '../../../../../types'; +import { Hotel, Room, RoomType, roomTypeArray } from '../../../../types'; import { Router } from '@angular/router'; import { MatCardModule } from '@angular/material/card'; import { MatChipsModule } from '@angular/material/chips'; diff --git a/angular/RestClient/src/app/core/features/bookings/booking/booking.component.ts b/angular/RestClient/src/app/core/features/bookings/booking/booking.component.ts index 9b99737e243b360d543e3ae57ff88d570a39a970..6ad8c379ae5b2e117c10a160eb07df12890f45fb 100644 --- a/angular/RestClient/src/app/core/features/bookings/booking/booking.component.ts +++ b/angular/RestClient/src/app/core/features/bookings/booking/booking.component.ts @@ -7,7 +7,7 @@ import { } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { Booking, User } from '../../../../../types'; +import { Booking, User } from '../../../../types'; import { LocalStorageService } from '../../../../shared/local-storage.service'; import { BookingClientService } from '../../../../shared/booking-client.service'; import { UserClientService } from '../../../../shared/user-client.service'; diff --git a/angular/RestClient/src/app/core/features/hotel/hotel-list/hotel-list.component.ts b/angular/RestClient/src/app/core/features/hotel/hotel-list/hotel-list.component.ts index 1bcaf64719ede78b63593bf0c504db6bb263488d..d951865749ebd766b23898f9428d593341cd73d6 100644 --- a/angular/RestClient/src/app/core/features/hotel/hotel-list/hotel-list.component.ts +++ b/angular/RestClient/src/app/core/features/hotel/hotel-list/hotel-list.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { RouterModule, Router } from '@angular/router'; -import { Hotel } from '../../../../../types'; +import { Hotel } from '../../../../types'; import { MatAccordion, MatExpansionPanel, diff --git a/angular/RestClient/src/app/core/features/hotel/hotel-register/hotel-register.component.ts b/angular/RestClient/src/app/core/features/hotel/hotel-register/hotel-register.component.ts index fad7415511aa5a15fc72df3af768f77454f0018f..9e2c2d433b6fa68621be16b30b7841e34ec8829f 100644 --- a/angular/RestClient/src/app/core/features/hotel/hotel-register/hotel-register.component.ts +++ b/angular/RestClient/src/app/core/features/hotel/hotel-register/hotel-register.component.ts @@ -13,7 +13,7 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatSelectModule } from '@angular/material/select'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { CommonModule } from '@angular/common'; -import { Address, Hotel, Room } from '../../../../../types'; +import { Address, Hotel, Room } from '../../../../types'; import { ActivatedRoute, Router } from '@angular/router'; import { HotelClientService } from '../../../../shared/hotel-client.service'; diff --git a/angular/RestClient/src/app/core/features/user/main-page/main-page.component.ts b/angular/RestClient/src/app/core/features/user/main-page/main-page.component.ts index e609b7e568a909e2d6f7efd995ddccb57472cb76..14b5a9d6c0e871d0e71b3d2154554f83e8ecc50d 100644 --- a/angular/RestClient/src/app/core/features/user/main-page/main-page.component.ts +++ b/angular/RestClient/src/app/core/features/user/main-page/main-page.component.ts @@ -1,11 +1,11 @@ -// main-page.component.ts import { Component, OnInit } from '@angular/core'; -import { User, UserStateFilter } from '../../../../../types'; +import { Client, User, UserStateFilter } from '../../../../types'; import { FormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; -import users from '../../../../../mocks/users.json'; import { RouterModule } from '@angular/router'; import { UserClientService } from '../../../../shared/user-client.service'; +import { users } from '../../../../../mocks/users'; // Renombrado para claridad + @Component({ standalone: true, imports: [FormsModule, CommonModule, RouterModule], @@ -14,23 +14,32 @@ import { UserClientService } from '../../../../shared/user-client.service'; styleUrls: ['./main-page.component.css'], }) export class MainPageComponent implements OnInit { - users: User[] = []; - filteredUsers: User[] = []; + users: Client[] = []; + filteredUsers: Client[] = []; selectedStatus: UserStateFilter = 'All'; constructor(private userClient: UserClientService) {} ngOnInit(): void { - this.users = users as unknown as User[]; - this.userClient.getAllUsers().subscribe((data: User[]) => { - this.users = data; - this.filteredUsers = data; // Inicialmente, muestra todos los usuarios + // Validar que el mock sea del tipo correcto + // const isValidMock = Array.isArray(mockUsers) && mockUsers.every(user => 'id' in user && 'name' in user && 'status' in user); + // this.users = isValidMock ? (mockUsers as User[]) : []; + this.users = users; + this.filteredUsers = [...this.users]; + + // Sobrescribir con datos reales si están disponibles + this.userClient.getAllUsers().subscribe({ + next: (data: Client[]) => { + this.users = data; + this.filteredUsers = [...data]; + }, + error: (err) => console.error('Error al cargar usuarios:', err), }); } filterUsers(): void { if (this.selectedStatus === 'All') { - this.filteredUsers = this.users; + this.filteredUsers = [...this.users]; } else { this.filteredUsers = this.users.filter( (user) => user.status === this.selectedStatus @@ -38,7 +47,7 @@ export class MainPageComponent implements OnInit { } } - getState(user: User) { + getState(user: Client): string { switch (user.status) { case 'NO_BOOKINGS': return 'SIN RESERVAS'; @@ -46,6 +55,8 @@ export class MainPageComponent implements OnInit { return 'CON RESERVAS ACTIVAS'; case 'WITH_INACTIVE_BOOKINGS': return 'CON RESERVAS INACTIVAS'; + default: + return 'ESTADO DESCONOCIDO'; } } } diff --git a/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.ts b/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.ts index 10be15d9b999d3d0f2a370236507605df40b4bbd..878e6446e5bc8a162d67e880edd8633a5cbb3a94 100644 --- a/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.ts +++ b/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; -import { Booking, User } from '../../../../../types'; +import { Booking, User } from '../../../../types'; import { ActivatedRoute, RouterModule } from '@angular/router'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; @@ -44,7 +44,7 @@ export class UserBookingListComponent { } updateBookings() { - this.bookingClient.getUserBookings(this.userId).subscribe({ + this.bookingClient.getBookingsByUser(this.userId).subscribe({ next: (bookings) => { this.search = true; switch (this.selectedState) { @@ -88,7 +88,7 @@ export class UserBookingListComponent { } updateUserStatus() { - this.bookingClient.getUserBookings(this.userId).subscribe({ + this.bookingClient.getBookingsByUser(this.userId).subscribe({ next: (bookings) => { const withActive = bookings.find( (booking) => this.genBookingState(booking) === 'Reserva activa' diff --git a/angular/RestClient/src/app/core/features/user/user-form/user-form.component.css b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.css new file mode 100644 index 0000000000000000000000000000000000000000..1eef9bba18e0bd279742ea1d297e8ab49da1c394 --- /dev/null +++ b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.css @@ -0,0 +1,81 @@ +.form-container { + max-width: 400px; + margin: 50px auto; + background: #f8f9fa; + padding: 20px; + border-radius: 10px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + font-family: Arial, sans-serif; +} + +h2 { + text-align: center; + margin-bottom: 20px; + color: #333; +} + +.form-group { + margin-bottom: 15px; +} + +label { + display: block; + font-weight: bold; + margin-bottom: 5px; + color: #555; +} + +input { + width: 100%; + padding: 10px; + font-size: 14px; + border: 1px solid #ccc; + border-radius: 5px; + background: #fff; +} + +input[readonly] { + background: #f3f3f3; +} + +.button-group { + display: flex; + justify-content: space-between; + margin-top: 20px; +} + +.btn { + padding: 10px 20px; + font-size: 14px; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.btn-primary { + background-color: #007bff; + color: white; +} + +.btn-primary:hover { + background-color: #0056b3; +} + +.btn-secondary { + background-color: #6c757d; + color: white; +} + +.btn-secondary:hover { + background-color: #5a6268; +} + +.btn-success { + background-color: #28a745; + color: white; +} + +.btn-success:hover { + background-color: #218838; +} diff --git a/angular/RestClient/src/app/core/features/user/user-form/user-form.component.html b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.html new file mode 100644 index 0000000000000000000000000000000000000000..d68f32bfd2d6a14846503422e0273bc04effd127 --- /dev/null +++ b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.html @@ -0,0 +1,75 @@ +<div class="form-container"> + <h2>Perfil de Usuario</h2> + <form [formGroup]="userForm" (ngSubmit)="saveChanges()"> + <!-- Campo Nombre --> + <div class="form-group"> + <label for="name">Nombre:</label> + <input + id="name" + type="text" + class="form-control" + formControlName="name" + [readonly]="!isEditing" + /> + </div> + + <!-- Campo Email --> + <div class="form-group"> + <label for="email">Email:</label> + <input + id="email" + type="email" + class="form-control" + formControlName="email" + [readonly]="!isEditing" + /> + </div> + + @if (isEditing) { + <!-- Campo Contraseña Actual (solo en edición) --> + <div class="form-group"> + <label for="currentPassword">Contraseña actual:</label> + <input + id="currentPassword" + type="password" + class="form-control" + formControlName="currentPassword" + placeholder="Introduce tu contraseña actual" + /> + </div> + + <!-- Campo Nueva Contraseña (solo en edición) --> + <div class="form-group"> + <label for="newPassword">Nueva contraseña:</label> + <input + id="newPassword" + type="password" + class="form-control" + formControlName="newPassword" + placeholder="Introduce tu nueva contraseña" + /> + </div> + } + + <!-- Grupo de Botones --> + <div class="button-group"> + @if (!isEditing) { + <button type="button" class="btn btn-primary" (click)="toggleEdit()"> + Editar + </button> + } @else { + <button type="button" class="btn btn-secondary" (click)="cancelEdit()"> + Cancelar + </button> + + <button + type="submit" + class="btn btn-success" + [disabled]="!userForm.valid" + > + Guardar + </button> + } + </div> + </form> +</div> diff --git a/angular/RestClient/src/app/core/features/user/user-form/user-form.component.spec.ts b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..292f234075dbcba5482794cf23e4a231e666ba17 --- /dev/null +++ b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.spec.ts @@ -0,0 +1,91 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { HttpResponse } from '@angular/common/http'; +import { UserFormComponent } from './user-form.component'; +import { UserClientService } from '../../../../shared/user-client.service'; +import { of } from 'rxjs'; + +describe('UserFormComponent', () => { + let component: UserFormComponent; + let fixture: ComponentFixture<UserFormComponent>; + let userService: UserClientService; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ReactiveFormsModule, FormsModule], + declarations: [UserFormComponent], + providers: [UserClientService], + }).compileComponents(); + + fixture = TestBed.createComponent(UserFormComponent); + component = fixture.componentInstance; + userService = TestBed.inject(UserClientService); + + spyOn(userService, 'getCurrentUser').and.returnValue( + of({ + id: 1, + name: 'John Doe', + email: 'johndoe@example.com', + rol: 'CONSUMER', + status: 'WITH_ACTIVE_BOOKINGS', + }) + ); + + spyOn(userService, 'updateUser').and.returnValue(of(new HttpResponse({ body: 'User updated successfully' }))); + spyOn(userService, 'updatePassword').and.returnValue(of(new HttpResponse({ body: 'Password updated successfully' }))); + + fixture.detectChanges(); + }); + + it('should create the component', () => { + expect(component).toBeTruthy(); + }); + + it('should load user data on initialization', () => { + expect(component.userForm.value).toEqual({ + name: 'John Doe', + email: 'johndoe@example.com', + password: '', + confirmPassword: '', + }); + }); + + it('should call updateUser when saving valid user data', () => { + component.userForm.patchValue({ + name: 'Jane Doe', + email: 'janedoe@example.com', + }); + + component.saveChanges(); + + expect(userService.updateUser).toHaveBeenCalledWith({ + name: 'Jane Doe', + email: 'janedoe@example.com', + }); + }); + + it('should call updatePassword when password is updated and matches confirmPassword', () => { + component.userForm.patchValue({ + password: 'newpassword123', + confirmPassword: 'newpassword123', + }); + + component.saveChanges(); + + expect(userService.updatePassword).toHaveBeenCalledWith( + '', + 'newpassword123' + ); + }); + + it('should not call updatePassword if password and confirmPassword do not match', () => { + component.userForm.patchValue({ + password: 'newpassword123', + confirmPassword: 'differentpassword', + }); + + component.saveChanges(); + + expect(userService.updatePassword).not.toHaveBeenCalled(); + }); +}); diff --git a/angular/RestClient/src/app/core/features/user/user-form/user-form.component.ts b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..558e1c58a73e3d7ef1eaf852bce1a989a40bc42b --- /dev/null +++ b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.ts @@ -0,0 +1,93 @@ +import { Component, OnInit } from '@angular/core'; +import { + FormBuilder, + FormGroup, + Validators, + ReactiveFormsModule, + FormsModule, +} from '@angular/forms'; +import { UserClientService } from '../../../../shared/user-client.service'; +import { users } from '../../../../../mocks/users'; +import { ActivatedRoute } from '@angular/router'; + +@Component({ + standalone: true, + selector: 'app-user-form', + templateUrl: './user-form.component.html', + styleUrls: ['./user-form.component.css'], + imports: [ReactiveFormsModule, FormsModule], +}) +export class UserFormComponent implements OnInit { + userForm!: FormGroup; + isEditing = false; + id = 0; + + constructor( + private fb: FormBuilder, + private userService: UserClientService, + private route: ActivatedRoute + ) {} + + ngOnInit(): void { + this.initializeForm(); + this.route.paramMap.subscribe({ + next: (params) => { + const id = Number(params.get('id')); + if (id) { + this.id = id; + this.isEditing = true; + this.loadUserData(); + } + }, + }); + } + + private initializeForm(): void { + this.userForm = this.fb.group({ + name: [{ value: '', disabled: true }, Validators.required], + email: [ + { value: '', disabled: true }, + [Validators.required, Validators.email], + ], + currentPassword: [''], // Solo habilitado en modo edición + newPassword: [''], // Solo habilitado en modo edición + }); + } + + private loadUserData(): void { + // this.userService.getCurrentUser().subscribe((user) => { + console.log({ id: this.id }); + users + .filter((u) => u.id == this.id) + .slice(0) + .map((user) => { + this.userForm.patchValue({ + name: user.name, + email: user.email, + }); + }); + } + + toggleEdit(): void { + this.isEditing = true; + this.userForm.get('name')?.enable(); + this.userForm.get('email')?.enable(); + } + + cancelEdit(): void { + this.isEditing = false; + this.loadUserData(); // Volver a cargar los datos originales + this.userForm.get('name')?.disable(); + this.userForm.get('email')?.disable(); + } + + saveChanges(): void { + if (this.userForm.valid) { + const updatedData = this.userForm.value; + this.userService.updateUser(updatedData).subscribe(() => { + this.isEditing = false; + this.loadUserData(); + }); + } + } +} diff --git a/angular/RestClient/src/app/core/navigation/navigation.component.css b/angular/RestClient/src/app/core/navigation/navigation.component.css index 200c21a3a62ba294324b6a77c75d043c2bd5574b..e3b01c1fac3de8d58e16185d24ac3791394e7b67 100644 --- a/angular/RestClient/src/app/core/navigation/navigation.component.css +++ b/angular/RestClient/src/app/core/navigation/navigation.component.css @@ -4,7 +4,7 @@ nav { padding: 1em; } -ul { +ul.nav { list-style: none; padding: 0; display: flex; @@ -14,15 +14,15 @@ li { margin-right: 20px; } -a, -a:visited { +a.nav-link, +a.nav-link:visited { color: white; text-decoration: none; transform: scale(1); transition: transform 0.3s ease; } -a:hover { +a.nav-link:hover { font-weight: bold; text-decoration: underline; color: yellow; @@ -34,6 +34,12 @@ a:hover { font-weight: bold; } +a.simple, +a.simple:visited { + color: white; + text-decoration: none; +} + @keyframes escalar { 0% { transform: scale(1); diff --git a/angular/RestClient/src/app/core/navigation/navigation.component.html b/angular/RestClient/src/app/core/navigation/navigation.component.html index 63615464cbbf7aec69cbd99e5e33ea9d1e5e08d8..94a99ba6dbf61fec024f7818dce9c8cc41115c6a 100644 --- a/angular/RestClient/src/app/core/navigation/navigation.component.html +++ b/angular/RestClient/src/app/core/navigation/navigation.component.html @@ -1,12 +1,72 @@ <nav> - <ul> - <li><a class="btn" [routerLink]="['/']">Home - Usuarios</a></li> + <ul class="nav"> + <li><a class="btn nav-link" [routerLink]="['/']">Home - Usuarios</a></li> <li> - <a class="btn" [routerLink]="['/hotels', 'new']">Registrar Hotel</a> + <a class="btn nav-link" [routerLink]="['/hotels', 'new']" + >Registrar Hotel</a + > </li> - <li><a class="btn" [routerLink]="['/hotels']">Hoteles</a></li> + <li><a class="btn nav-link" [routerLink]="['/hotels']">Hoteles</a></li> <li> - <a class="btn" [routerLink]="['/bookings', 'search']">Nueva Reserva</a> + <a class="btn nav-link" [routerLink]="['/bookings', 'search']" + >Nueva Reserva</a + > + </li> + <!-- Solucionar que no va --> + <!-- <li class="ml-auto"> --> + <li style="margin-left: auto"> + @if (isLogged){ + <!-- Dropdown para usuario registrado --> + + <div class="btn bg-blue-500 text-white rounded hover:bg-blue-600"> + <!-- mat-icon-button --> + <button + [matMenuTriggerFor]="sessionOptions" + class="flex items-center gap-3" + > + <span class="text-4xl">{{ user.name }}</span> + + @if (trigger?.menuOpen) { + <mat-icon class="text-4xl">arrow_drop_up</mat-icon> + }@else { + <mat-icon class="text-4xl">arrow_drop_down</mat-icon> + } + </button> + </div> + <mat-menu #sessionOptions="matMenu" xPosition="before"> + @for (section of sections; track section.id) { @if (section.link) { + <a [routerLink]="section.link" class="simple"> + <button mat-menu-item> + <mat-icon>{{ section.icon }}</mat-icon> + <span class="text-2xl">{{ section.text }}</span> + </button> + </a> + } @else { + <button mat-menu-item> + <mat-icon>{{ section.icon }}</mat-icon> + <span class="text-2xl">{{ section.text }}</span> + </button> + } } + <button mat-menu-item (click)="logout()"> + <mat-icon>logout</mat-icon> + <span class="text-2xl">Cerrar sesión</span> + </button> + </mat-menu> + + } @else { + <div + class="btn bg-blue-500 text-white hover:bg-blue-600 ml-auto" + (click)="login()" + > + <!-- <a class="simple" [routerLink]="['/login']"> --> + <a class="simple"> + <button class="flex items-center gap-3"> + <span class="text-4xl">Login</span> + <mat-icon>login</mat-icon> + </button> + </a> + </div> + } </li> </ul> </nav> diff --git a/angular/RestClient/src/app/core/navigation/navigation.component.ts b/angular/RestClient/src/app/core/navigation/navigation.component.ts index ccdab77b49379e3ed27abd65ada67e693882939a..1e7a72d5eb50276981b4f00a3950847105e06f0d 100644 --- a/angular/RestClient/src/app/core/navigation/navigation.component.ts +++ b/angular/RestClient/src/app/core/navigation/navigation.component.ts @@ -1,10 +1,122 @@ -import { Component } from '@angular/core'; -import { Router, RouterModule } from '@angular/router'; +import { OnInit, Component, ViewChild } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { MatButtonModule } from '@angular/material/button'; +import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu'; +import { MatIconModule } from '@angular/material/icon'; +import { User, UserRol } from '../../types'; +import { AuthInstance, SessionService } from '../../shared/session.service'; +import { UserClientService } from '../../shared/user-client.service'; +import { AuthClientService } from '../../shared/auth-client.service'; + +var comp_id = 0; + +export function genId() { + const comp = 'navigation'; + return `${comp}-${comp_id++}`; +} + +interface Section { + id: string; + icon: string; + text: string; + link: string; + allowRoles?: UserRol[]; +} + @Component({ selector: 'app-navigation', standalone: true, - imports: [RouterModule], + imports: [RouterModule, MatButtonModule, MatMenuModule, MatIconModule], templateUrl: './navigation.component.html', styleUrl: './navigation.component.css', }) -export class NavigationComponent {} +export class NavigationComponent implements OnInit { + @ViewChild(MatMenuTrigger) + trigger?: MatMenuTrigger; + isLogged = false; + user: AuthInstance = { + id: 0, + name: '', + email: '', + rol: 'CLIENT', + }; + sections: Section[] = []; + + constructor( + private sessionService: SessionService, + private auth: AuthClientService + ) {} + + ngOnInit() { + this.loadUser(); + } + + loadUser() { + const isLogged = this.sessionService.isValid(); + if (isLogged) { + this.user = this.sessionService.getSession(); + console.log({ user: this.user }); + this.sections = this.genSections(); + } + this.isLogged = isLogged; + } + + toggleDropdown() { + if (this.trigger) { + if (this.trigger.menuOpen) this.trigger.closeMenu(); + else this.trigger.openMenu(); + } + } + + schemaSections: Section[] = [ + { + id: genId(), + icon: 'person', + text: 'Información personal', + link: '/me', + }, + { + id: genId(), + icon: 'calendar_today', + text: 'Reservas', + allowRoles: ['CLIENT'], + link: '/users/1/bookings', + // link: '/bookings', + }, + { + id: genId(), + icon: 'hotel', + text: 'Hoteles', + allowRoles: ['HOTEL_ADMIN'], + link: '/hotels', + }, + ]; + + genSections() { + return this.schemaSections.filter( + (section) => + this.user.rol === 'ADMIN' || // Es administrador del sistema + !section.allowRoles || + section.allowRoles.length === 0 || // No tiene limitación + section.allowRoles.includes(this.user.rol) // El rol del usuario es aceptado + ); + } + + login() { + const email = 'client@dev.com'; + this.auth.login(email, 'NQSASorry').subscribe({ + next: (data: any) => { + console.log(email, data); + this.sessionService.login(data); + this.loadUser(); + }, + }); + } + + logout() { + if (confirm('You are trying to logout')) { + this.sessionService.logout(); + this.loadUser(); + } + } +} diff --git a/angular/RestClient/src/app/shared/auth-client.service.ts b/angular/RestClient/src/app/shared/auth-client.service.ts index ec3280b68da6db216a68e72c8847e5fee4e6b04d..931fc7dbacbec3db5e5d048722fa5980017355e7 100644 --- a/angular/RestClient/src/app/shared/auth-client.service.ts +++ b/angular/RestClient/src/app/shared/auth-client.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; -import { environment } from '../../environments/environment'; +import { environment } from '../../../environments/environment'; +import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root', @@ -7,5 +8,39 @@ import { environment } from '../../environments/environment'; export class AuthClientService { private readonly URI = environment.authAPI; - constructor() {} + constructor(private http: HttpClient) {} + + login(email: String, password: String) { + return this.http.post( + `${this.URI}/login`, + { email, password } + // { + // headers: { + // 'Content-Type': 'application/json', + // 'Access-Control-Allow-Origin': '*', + // 'Access-Control-Allow-Methods': + // 'GET, POST, OPTIONS, PUT, PATCH, DELETE', + // 'Access-Control-Allow-Headers': 'X-Requested-With,content-type', + // 'Access-Control-Allow-Credentials': 'true', + // }, + // } + ); + } + + register(name: String, email: String, password: String, rol?: String) { + return this.http.post( + `${this.URI}/register`, + { + name, + email, + password, + rol, + }, + { + headers: { + 'Content-Type': 'application/json', + }, + } + ); + } } diff --git a/angular/RestClient/src/app/shared/booking-client.service.ts b/angular/RestClient/src/app/shared/booking-client.service.ts index 7d38299878b9a5500ade1883c47d08585ca01ebb..3e44163b0944263f937334320090ec3ee2ef786e 100644 --- a/angular/RestClient/src/app/shared/booking-client.service.ts +++ b/angular/RestClient/src/app/shared/booking-client.service.ts @@ -1,8 +1,8 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { environment } from '../../environments/environment'; -import { Booking } from '../../types/Booking'; // Ajusta la ruta a tu modelo Booking +import { environment } from '../../../environments/environment'; +import { Booking } from '../types/Booking'; // Ajusta la ruta a tu modelo Booking @Injectable({ providedIn: 'root', @@ -31,9 +31,8 @@ export class BookingClientService { return this.http.get<Booking>(`${this.URI}/${id}`); } - getUserBookings(userId: number) { - // TODO revisar tras división en microservicios - return this.http.get<Booking[]>(`${this.URI}/${userId}/bookings`); + getBookingsByUser(userId: number) { + return this.http.get<Booking[]>(`${this.URI}?userId=${userId}`); } // Método para eliminar una reserva diff --git a/angular/RestClient/src/app/shared/hotel-client.service.ts b/angular/RestClient/src/app/shared/hotel-client.service.ts index f00b3e6d5259866c895bffa7856e8e838ae85deb..87756a392895ecc95b745101b7accaef0e20a3e1 100644 --- a/angular/RestClient/src/app/shared/hotel-client.service.ts +++ b/angular/RestClient/src/app/shared/hotel-client.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; -import { environment } from '../../environments/environment'; +import { environment } from '../../../environments/environment'; import { HttpClient } from '@angular/common/http'; -import { Hotel, Room } from '../../types'; +import { Hotel, Room } from '../types'; @Injectable({ providedIn: 'root', diff --git a/angular/RestClient/src/app/shared/local-storage.service.ts b/angular/RestClient/src/app/shared/local-storage.service.ts index e1526f8aaa1b56903668de93697f4a2b072d97ab..dc328655c80df4c87132a25305026eb3f00d1fec 100644 --- a/angular/RestClient/src/app/shared/local-storage.service.ts +++ b/angular/RestClient/src/app/shared/local-storage.service.ts @@ -1,32 +1,21 @@ -import { isPlatformBrowser } from '@angular/common'; -import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; +import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class LocalStorageService { - // isBrowser: boolean; - - // constructor(@Inject(PLATFORM_ID) private platformId: Object) { - // this.isBrowser = isPlatformBrowser(this.platformId); - // } - - save(key: string, value: any) { - // if (!this.isBrowser) return; - localStorage.setItem(key, JSON.stringify(value)); + save(key: string, value: object) { + const content = JSON.stringify(value); + localStorage.setItem(key, content); } read<T>(key: string) { - // if (!this.isBrowser) return null; - const json = localStorage.getItem(key); const ret = json ? (JSON.parse(json) as T) : null; return ret; } consume<T>(key: string) { - // if (!this.isBrowser) return null; - const value = this.read<T>(key); if (value !== null) { this.remove(key); @@ -35,8 +24,6 @@ export class LocalStorageService { } remove(key: string) { - // if (!this.isBrowser) return; - localStorage.removeItem(key); } } diff --git a/angular/RestClient/src/app/shared/session.service.spec.ts b/angular/RestClient/src/app/shared/session.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..4238e142b07aad273072a64a6df73c7960707501 --- /dev/null +++ b/angular/RestClient/src/app/shared/session.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { SessionService } from './session.service'; + +describe('SessionService', () => { + let service: SessionService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(SessionService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/angular/RestClient/src/app/shared/session.service.ts b/angular/RestClient/src/app/shared/session.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..82e9daaceed948aa6ed973b710f704421f5b30f5 --- /dev/null +++ b/angular/RestClient/src/app/shared/session.service.ts @@ -0,0 +1,58 @@ +import { Injectable } from '@angular/core'; +import { LocalStorageService } from './local-storage.service'; +import { UserRol } from '../types'; + +import { jwtDecode } from 'jwt-decode'; + +export interface AuthInstance { + id: number; + name: string; + email: string; + rol: UserRol; +} + +interface PersistenToken { + token: string; +} + +@Injectable({ + providedIn: 'root', +}) +export class SessionService { + constructor(private storage: LocalStorageService) {} + + private tokenKey = 'token'; + + login(session: PersistenToken) { + this.storage.save(this.tokenKey, session); + } + + logout() { + this.storage.remove(this.tokenKey); + } + + getToken() { + const savedToken = this.storage.read<PersistenToken>(this.tokenKey); + if (!savedToken) throw new Error('No session'); + return savedToken.token; + } + + getSession() { + const token = this.getToken(); + const r = jwtDecode<{ user: AuthInstance }>(token); + return r.user; + } + + isLogged() { + return !!this.storage.read<PersistenToken>(this.tokenKey); + } + + isValid() { + console.warn({ log: this.isLogged() }); + if (!this.isLogged()) return false; + const token = this.getToken(); + const r = jwtDecode(token); + // Validate if the token have been expired or not + return r.exp! > Math.floor(Date.now() / 1000); + } +} diff --git a/angular/RestClient/src/app/shared/user-client.service.ts b/angular/RestClient/src/app/shared/user-client.service.ts index ea51f7e5060cf349c86159e981748a028806ef80..2b2592e00c49b292df6799a76b4a6feb95b48380 100644 --- a/angular/RestClient/src/app/shared/user-client.service.ts +++ b/angular/RestClient/src/app/shared/user-client.service.ts @@ -1,25 +1,29 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { environment } from '../../environments/environment'; -import { User, UserState } from '../../types'; +import { environment } from '../../../environments/environment'; +import { Client, User, UserState } from '../types'; @Injectable({ providedIn: 'root', }) export class UserClientService { private readonly URI = environment.userAPI; + constructor(private http: HttpClient) {} + // Obtener un usuario por ID getUser(userId: number) { return this.http.get<User>(`${this.URI}/${userId}`); } + // Obtener todos los usuarios getAllUsers() { - return this.http.get<User[]>(this.URI, { + return this.http.get<Client[]>(this.URI, { observe: 'body', }); } + // Cambiar estado de un usuario alterUserStatus(userId: number, status: UserState) { return this.http.patch( `${this.URI}/${userId}`, @@ -32,4 +36,29 @@ export class UserClientService { } ); } + + // Obtener el usuario actual (autenticado) + getCurrentUser() { + return this.http.get<User>(`${this.URI}/me`); + } + + // Actualizar los datos del usuario + updateUser(user: Partial<User>) { + return this.http.patch(`${this.URI}/me`, user, { + observe: 'response', + responseType: 'text', + }); + } + + // Cambiar la contraseña del usuario + updatePassword(currentPassword: string, newPassword: string) { + return this.http.patch( + `${this.URI}/me/password`, + { currentPassword, newPassword }, + { + observe: 'response', + responseType: 'text', + } + ); + } } diff --git a/angular/RestClient/src/types/Address.d.ts b/angular/RestClient/src/app/types/Address.d.ts similarity index 100% rename from angular/RestClient/src/types/Address.d.ts rename to angular/RestClient/src/app/types/Address.d.ts diff --git a/angular/RestClient/src/types/Booking.d.ts b/angular/RestClient/src/app/types/Booking.d.ts similarity index 100% rename from angular/RestClient/src/types/Booking.d.ts rename to angular/RestClient/src/app/types/Booking.d.ts diff --git a/angular/RestClient/src/types/Hotel.d.ts b/angular/RestClient/src/app/types/Hotel.d.ts similarity index 100% rename from angular/RestClient/src/types/Hotel.d.ts rename to angular/RestClient/src/app/types/Hotel.d.ts diff --git a/angular/RestClient/src/types/Room.d.ts b/angular/RestClient/src/app/types/Room.d.ts similarity index 100% rename from angular/RestClient/src/types/Room.d.ts rename to angular/RestClient/src/app/types/Room.d.ts diff --git a/angular/RestClient/src/types/User.d.ts b/angular/RestClient/src/app/types/User.d.ts similarity index 51% rename from angular/RestClient/src/types/User.d.ts rename to angular/RestClient/src/app/types/User.d.ts index 1ecc3d7512e7ff0b644e5555d290c48e88518219..277f806a74fb1b2f854d733cc10acca67f18b840 100644 --- a/angular/RestClient/src/types/User.d.ts +++ b/angular/RestClient/src/app/types/User.d.ts @@ -2,10 +2,20 @@ export interface User { id: number; name: string; email: String; - // status: "noBookings" | "withActiveBookings" | "withInactiveBookings"; + rol: UserRol; +} + +export interface Client extends User { status: UserState; + // bookings: number[] // Booking[] } +export interface HotelAdmin extends User { + // hotels: number[] // Hotel[] +} + +export type UserRol = 'ADMIN' | 'CLIENT' | 'HOTEL_ADMIN'; + export type UserStateFilter = 'All' | UserState; export type UserState = diff --git a/angular/RestClient/src/types/index.ts b/angular/RestClient/src/app/types/index.ts similarity index 100% rename from angular/RestClient/src/types/index.ts rename to angular/RestClient/src/app/types/index.ts diff --git a/angular/RestClient/src/environments/environment.monolith.ts b/angular/RestClient/src/environments/environment.monolith.ts deleted file mode 100644 index 676025533ad47d166dedf355b0a08f5e8a96e904..0000000000000000000000000000000000000000 --- a/angular/RestClient/src/environments/environment.monolith.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Simple -> Un servicio fachada / monolito -const hostname = 'http://localhost:8080'; - -export const environment = { - production: false, - authAPI: `${hostname}/auth`, - userAPI: `${hostname}/users`, - hotelAPI: `${hostname}/hotels`, - bookingAPI: `${hostname}/bookings`, -}; diff --git a/angular/RestClient/src/environments/environment.prod.ts b/angular/RestClient/src/environments/environment.prod.ts deleted file mode 100644 index 9318edcf83573d82d0005c135849aca26dc609a2..0000000000000000000000000000000000000000 --- a/angular/RestClient/src/environments/environment.prod.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Disgregado en microservicios -export const environment = { - production: true, - authAPI: 'http://auth-api:8080', - userAPI: 'http://users-api:8080', - hotelAPI: 'http://hotels-api:8080', - bookingAPI: 'http://bookings-api:8080', -}; diff --git a/angular/RestClient/src/environments/environment.ts b/angular/RestClient/src/environments/environment.ts deleted file mode 100644 index b5fe467280faf9259227fb281e401cff79c5aa87..0000000000000000000000000000000000000000 --- a/angular/RestClient/src/environments/environment.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Disgregado en microservicios -export const environment = { - production: false, - authAPI: 'http://localhost:8101', - userAPI: 'http://localhost:8111', - hotelAPI: 'http://localhost:8121', - bookingAPI: 'http://localhost:8131', -}; diff --git a/angular/RestClient/src/mocks/bookings.json b/angular/RestClient/src/mocks/bookings.json deleted file mode 100644 index 7db55ff76f1627de21762d95a7732a4f7be1ce34..0000000000000000000000000000000000000000 --- a/angular/RestClient/src/mocks/bookings.json +++ /dev/null @@ -1,30 +0,0 @@ -[ - { - "user": { - "name": "John Doe", - "email": "john.doe@example.com", - "status": "NO_BOOKINGS" - }, - "room": { - "roomNumber": "101", - "type": "SINGLE", - "available": true - }, - "startDate": "2024-03-01", - "endDate": "2024-03-08" - }, - { - "user": { - "name": "Pepe", - "email": "pepe@example.com", - "status": "WITH_ACTIVE_BOOKINGS" - }, - "room": { - "roomNumber": "101", - "type": "SINGLE", - "available": true - }, - "startDate": "2024-03-15", - "endDate": "2024-03-22" - } -] diff --git a/angular/RestClient/src/mocks/hotels.json b/angular/RestClient/src/mocks/hotels.json deleted file mode 100644 index 11381112f37ac1123d22f06a2a0526c07825f211..0000000000000000000000000000000000000000 --- a/angular/RestClient/src/mocks/hotels.json +++ /dev/null @@ -1,46 +0,0 @@ -[ - { - "id": 1, - "name": "Hotel 1", - "address": { - "id": 1, - "streetName": "Aca al lao", - "streetKind": "Alargada", - "number": 12, - "postCode": "12345" - }, - "rooms": [ - { - "id": 1, - "roomNumber": "101", - "type": "SINGLE", - "available": true - }, - { - "id": 2, - "roomNumber": "102", - "type": "DOUBLE", - "available": false - } - ] - }, - { - "id": 2, - "name": "Hotel 2", - "address": { - "id": 2, - "streetName": "Calle de la plaza", - "streetKind": "Alargada", - "number": 12, - "postCode": "12345" - }, - "rooms": [ - { - "id": 3, - "roomNumber": "103", - "type": "SUITE", - "available": true - } - ] - } -] diff --git a/angular/RestClient/src/mocks/users.json b/angular/RestClient/src/mocks/users.json deleted file mode 100644 index 2f02d00125b0deaa2a86db47ea26f0c91f2e5fa3..0000000000000000000000000000000000000000 --- a/angular/RestClient/src/mocks/users.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "name": "John Doe", - "email": "john.doe@example.com", - "status": "NO_BOOKINGS" - }, - { - "name": "Pepe", - "email": "pepe@example.com", - "status": "WITH_ACTIVE_BOOKINGS" - } -] diff --git a/angular/RestClient/src/mocks/users.ts b/angular/RestClient/src/mocks/users.ts new file mode 100644 index 0000000000000000000000000000000000000000..f6fafe67e13993f0e5b1a48c5443d43f6d3c2c3d --- /dev/null +++ b/angular/RestClient/src/mocks/users.ts @@ -0,0 +1,18 @@ +import { Client, User } from '../app/types'; + +export const users: Client[] = [ + { + id: 1, + name: 'John Doe', + email: 'jon@com', + rol: 'CLIENT', + status: 'NO_BOOKINGS', + }, + { + id: 2, + name: 'Angela Doe', + email: 'angle@com', + rol: 'CLIENT', + status: 'NO_BOOKINGS', + }, +]; diff --git a/docker-compose.yml b/docker-compose.yml index 40484328bc7cb6aa6b3d94b2616393b3e0cab264..85641c264792a1c3cafb824d8b0b4337f2764ad1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ networks: services: Auth-API: image: auth-api-image - hostname: ${AUTH_SERVICE_HOSTNAME} + hostname: $${AUTH_SERVICE_HOSTNAME} build: context: ./java/services/auth dockerfile: Dockerfile @@ -18,13 +18,13 @@ services: networks: - kong-net environment: - SPRING_DATASOURCE_URL: jdbc:mysql://${DB_SERVICE_HOSTNAME}:3306/${DB_DATABASE_NAME}?createDatabaseIfNotExist=true + SPRING_DATASOURCE_URL: jdbc:mysql://$${DB_SERVICE_HOSTNAME}:3306/$${DB_DATABASE_NAME}?createDatabaseIfNotExist=true depends_on: - RoomsBooking-database Users-API: image: users-api-image - hostname: "${USERS_SERVICE_HOSTNAME}" + hostname: "$${USERS_SERVICE_HOSTNAME}" build: context: ./java/services/users dockerfile: Dockerfile @@ -34,13 +34,13 @@ services: networks: - kong-net environment: - SPRING_DATASOURCE_URL: jdbc:mysql://${DB_SERVICE_HOSTNAME}:3306/${DB_DATABASE_NAME}?createDatabaseIfNotExist=true + SPRING_DATASOURCE_URL: jdbc:mysql://$${DB_SERVICE_HOSTNAME}:3306/$${DB_DATABASE_NAME}?createDatabaseIfNotExist=true depends_on: - RoomsBooking-database Hotels-API: image: hotels-api-image - hostname: ${HOTELS_SERVICE_HOSTNAME} + hostname: $${HOTELS_SERVICE_HOSTNAME} build: context: ./java/services/hotels dockerfile: Dockerfile @@ -50,16 +50,16 @@ services: networks: - kong-net environment: - SPRING_DATASOURCE_URL: jdbc:mysql://${DB_SERVICE_HOSTNAME}:3306/${DB_DATABASE_NAME}?createDatabaseIfNotExist=true - SPRING_DATASOURCE_USER: ${USER_DATABASE} - SPRING_DATASOURCE_PASSWORD: ${} + SPRING_DATASOURCE_URL: jdbc:mysql://$${DB_SERVICE_HOSTNAME}:3306/$${DB_DATABASE_NAME}?createDatabaseIfNotExist=true + SPRING_DATASOURCE_USER: $${USER_DATABASE} + SPRING_DATASOURCE_PASSWORD: $${} depends_on: - RoomsBooking-database - Bookings-API Bookings-API: image: bookings-api-image - hostname: ${BOOKINGS_SERVICE_HOSTNAME} + hostname: $${BOOKINGS_SERVICE_HOSTNAME} build: context: ./java/services/bookings dockerfile: Dockerfile @@ -69,13 +69,13 @@ services: networks: - kong-net environment: - SPRING_DATASOURCE_URL: jdbc:mysql://${DB_SERVICE_HOSTNAME}:3306/${DB_DATABASE_NAME}?createDatabaseIfNotExist=true + SPRING_DATASOURCE_URL: jdbc:mysql://$${DB_SERVICE_HOSTNAME}:3306/$${DB_DATABASE_NAME}?createDatabaseIfNotExist=true depends_on: - RoomsBooking-database RoomsBooking-database: image: mysql - hostname: ${DB_SERVICE_HOSTNAME} + hostname: $${DB_SERVICE_HOSTNAME} cap_add: - SYS_NICE restart: unless-stopped @@ -103,6 +103,6 @@ services: networks: - kong-net environment: - SPRING_DATASOURCE_URL: jdbc:mysql://${DB_SERVICE_HOSTNAME}:3306/${DB_DATABASE_NAME}?createDatabaseIfNotExist=true + SPRING_DATASOURCE_URL: jdbc:mysql://$${DB_SERVICE_HOSTNAME}:3306/$${DB_DATABASE_NAME}?createDatabaseIfNotExist=true depends_on: - RoomsBooking-database diff --git a/java/roomBooking/pom.xml b/java/roomBooking/pom.xml index 476f735b695a459292a258d72d89261c89dca993..f6fa75bdb21b812320db5afa07b770891fb9bd95 100644 --- a/java/roomBooking/pom.xml +++ b/java/roomBooking/pom.xml @@ -49,6 +49,32 @@ <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-api</artifactId> + <version>0.11.5</version> + </dependency> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-impl</artifactId> + <version>0.11.5</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-jackson</artifactId> + <version>0.11.5</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <scope>provided</scope> + </dependency> </dependencies> <build> @@ -60,4 +86,4 @@ </plugins> </build> -</project> +</project> \ No newline at end of file diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/RoomBookingApplication.java b/java/roomBooking/src/main/java/com/uva/monolith/RoomBookingApplication.java similarity index 90% rename from java/roomBooking/src/main/java/com/uva/roomBooking/RoomBookingApplication.java rename to java/roomBooking/src/main/java/com/uva/monolith/RoomBookingApplication.java index 1a5f312d49b2d1db4ffe587e4ae02c35e1e9a506..0a5db248da6e6be909302e323931f79151b0ed62 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/RoomBookingApplication.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/RoomBookingApplication.java @@ -1,4 +1,4 @@ -package com.uva.roomBooking; +package com.uva.monolith; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/java/roomBooking/src/main/java/com/uva/monolith/config/SecurityConfig.java b/java/roomBooking/src/main/java/com/uva/monolith/config/SecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..5cc2695222079be62bcb16f493158c0452920569 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/config/SecurityConfig.java @@ -0,0 +1,46 @@ +package com.uva.monolith.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +import com.uva.monolith.filter.JwtAuthenticationFilter; +import com.uva.monolith.services.users.models.UserRol; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + private final JwtAuthenticationFilter jwtAuthenticationFilter; + + public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) { + this.jwtAuthenticationFilter = jwtAuthenticationFilter; + } + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http.csrf(csrf -> csrf.disable()) + .authorizeHttpRequests(authorize -> authorize + // Permitir OPTIONS sin autenticación + .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() + // Acceso restringido a usuarios y administradores + .requestMatchers("users", "users/**") + .hasAnyRole(UserRol.ADMIN.toString(), UserRol.CLIENT.toString()) + // Acceso restringido a gestores de hoteles y administradores + .requestMatchers("hotels", "hotels/**") + .hasAnyRole(UserRol.ADMIN.toString(), UserRol.HOTEL_ADMIN.toString()) + // Acceso restringido a cualquier usuario del sistema + .requestMatchers("bookings", "bookings/**") + .hasAnyRole(UserRol.ADMIN.toString(), UserRol.HOTEL_ADMIN.toString(), UserRol.CLIENT.toString()) + // Rechazar el resto + .anyRequest().denyAll()) + // Registra el filtro antes del filtro estándar de autenticación + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } +} diff --git a/java/services/users/src/main/java/com/uva/users/Exceptions/GlobalExceptionHandler.java b/java/roomBooking/src/main/java/com/uva/monolith/exceptions/GlobalExceptionHandler.java similarity index 98% rename from java/services/users/src/main/java/com/uva/users/Exceptions/GlobalExceptionHandler.java rename to java/roomBooking/src/main/java/com/uva/monolith/exceptions/GlobalExceptionHandler.java index 0e43ff06348e770f579e48bcbf056521f7f37da8..9428c51a9c63c3623d44752c9e3cbe6cf78ac19f 100644 --- a/java/services/users/src/main/java/com/uva/users/Exceptions/GlobalExceptionHandler.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/exceptions/GlobalExceptionHandler.java @@ -1,4 +1,4 @@ -package com.uva.users.Exceptions; +package com.uva.monolith.exceptions; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/HotelNotFoundException.java b/java/roomBooking/src/main/java/com/uva/monolith/exceptions/HotelNotFoundException.java similarity index 89% rename from java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/HotelNotFoundException.java rename to java/roomBooking/src/main/java/com/uva/monolith/exceptions/HotelNotFoundException.java index 4da802a0c6bc552386705da734c953d5a467fa70..129a0b1086b4b78eb1f1725b9f241f51ce5540f8 100644 --- a/java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/HotelNotFoundException.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/exceptions/HotelNotFoundException.java @@ -1,4 +1,4 @@ -package com.uva.hotelService.Exceptions; +package com.uva.monolith.exceptions; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/java/services/users/src/main/java/com/uva/users/Exceptions/InvalidDateRangeException.java b/java/roomBooking/src/main/java/com/uva/monolith/exceptions/InvalidDateRangeException.java similarity index 80% rename from java/services/users/src/main/java/com/uva/users/Exceptions/InvalidDateRangeException.java rename to java/roomBooking/src/main/java/com/uva/monolith/exceptions/InvalidDateRangeException.java index 7cf94e38ed83bc5cc1a10d67f6c48eb8c9b42a66..5fea986ef1e9279c459bc5aff10932049f283333 100644 --- a/java/services/users/src/main/java/com/uva/users/Exceptions/InvalidDateRangeException.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/exceptions/InvalidDateRangeException.java @@ -1,8 +1,7 @@ -package com.uva.users.Exceptions; +package com.uva.monolith.exceptions; public class InvalidDateRangeException extends RuntimeException { public InvalidDateRangeException(String message) { super(message); } } - diff --git a/java/services/bookings/src/main/java/com/uva/bookings/Exceptions/InvalidRequestException.java b/java/roomBooking/src/main/java/com/uva/monolith/exceptions/InvalidRequestException.java similarity index 88% rename from java/services/bookings/src/main/java/com/uva/bookings/Exceptions/InvalidRequestException.java rename to java/roomBooking/src/main/java/com/uva/monolith/exceptions/InvalidRequestException.java index 76432c4e307148cb13288a969cf755606e76428b..ca09e054420dd174c4d2c3424dcc8fe74b6c8576 100644 --- a/java/services/bookings/src/main/java/com/uva/bookings/Exceptions/InvalidRequestException.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/exceptions/InvalidRequestException.java @@ -1,4 +1,4 @@ -package com.uva.bookings.Exceptions; +package com.uva.monolith.exceptions; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/java/roomBooking/src/main/java/com/uva/monolith/filter/JwtAuthenticationFilter.java b/java/roomBooking/src/main/java/com/uva/monolith/filter/JwtAuthenticationFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..9b31d1a0e80f529075ef20bc4e9a955cfa825d30 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/filter/JwtAuthenticationFilter.java @@ -0,0 +1,124 @@ +package com.uva.monolith.filter; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.UnsupportedJwtException; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import io.jsonwebtoken.security.SignatureException; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; + +import com.uva.monolith.services.users.models.UserRol; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.Filter; +import java.io.IOException; +import java.security.Key; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.Date; + +@Component +public class JwtAuthenticationFilter implements Filter { + + private final String SECRET_KEY = "3cfa76ef14937c1c0ea519f8fc057a80fcd04a7420f8e8bcd0a7567c272e007b"; + + private Key getSignInKey() { + byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY); + return Keys.hmacShaKeyFor(keyBytes); + } + + private String getTokenFromRequest(HttpServletRequest request) { + String authHeader = request.getHeader("Authorization"); + if (authHeader == null || !authHeader.startsWith("Bearer ")) + return null; + return authHeader.substring(7); + } + + private Claims getClaimsFromToken(String token) { + return Jwts.parserBuilder() + .setSigningKey(getSignInKey()) + .build() + .parseClaimsJws(token) + .getBody(); + } + + private boolean validateToken(String token) { + if (token == null) + return false;// no token + try { + // Verifica y analiza el token + Claims claims = getClaimsFromToken(token); + + // Verifica que el token no esté expirado + return claims.getExpiration().after(new Date()); + } catch (ExpiredJwtException e) { + System.out.println("[" + LocalDateTime.now().toString() + "] Token expirado: " + e.getMessage()); + } catch (UnsupportedJwtException e) { + System.out.println("[" + LocalDateTime.now().toString() + "] Token no soportado: " + e.getMessage()); + } catch (MalformedJwtException e) { + System.out.println("[" + LocalDateTime.now().toString() + "] Token malformado: " + e.getMessage()); + } catch (SignatureException e) { + System.out.println("[" + LocalDateTime.now().toString() + "] Firma inválida: " + e.getMessage()); + } catch (IllegalArgumentException e) { + System.out.println("[" + LocalDateTime.now().toString() + "] Token vacío o nulo: " + e.getMessage()); + } + return false; // Si ocurre cualquier excepción, el token es inválido + + } + + private String getEmailFromToken(String token) { + return getClaimsFromToken(token).getSubject(); + } + + private UserRol getRoleFromToken(String token) { + String rol = getClaimsFromToken(token).get("rol", String.class); + return UserRol.valueOf(rol); + } + + public static String getRol(UserRol rol) { + return String.format("ROLE_%s", rol.toString()); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + String token = getTokenFromRequest(httpRequest); + + System.out.println("[" + LocalDateTime.now().toString() + "] TOKEN " + token); + + if (validateToken(token)) { + + String email = getEmailFromToken(token); + UserRol role = getRoleFromToken(token); // Extraer el rol del token + + if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + email, null, null); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest)); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + // Agregar el rol como autoridad + SimpleGrantedAuthority authority = new SimpleGrantedAuthority(getRol(role)); + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(email, null, + Collections.singletonList(authority)); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + chain.doFilter(request, response); + } + +} diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/bookings/controllers/BookingController.java b/java/roomBooking/src/main/java/com/uva/monolith/services/bookings/controllers/BookingController.java new file mode 100644 index 0000000000000000000000000000000000000000..602f16a2f96e27d3e855440136cbcb41f9b57ab0 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/bookings/controllers/BookingController.java @@ -0,0 +1,51 @@ +package com.uva.monolith.services.bookings.controllers; + +import com.uva.monolith.services.bookings.models.Booking; +import com.uva.monolith.services.bookings.services.BookingService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; +import java.util.List; + +@RestController +@RequestMapping("/bookings") +@CrossOrigin(origins = "*") +public class BookingController { + + private final BookingService bookingService; + + public BookingController(BookingService bookingService) { + this.bookingService = bookingService; + } + + @GetMapping + public List<Booking> getAllBookings( + @RequestParam(required = false) LocalDate start, + @RequestParam(required = false) LocalDate end, + @RequestParam(required = false) Integer roomId, + @RequestParam(required = false) Integer userId) { + return bookingService.getBookings(start, end, roomId, userId); + } + + @PostMapping + public Booking createBooking(@RequestBody Booking booking) { + return bookingService.createBooking(booking); + } + + @GetMapping("/{id}") + public Booking getBookingById(@PathVariable Integer id) { + return bookingService.getBookingById(id); + } + + @DeleteMapping("/{id}") + public ResponseEntity<Void> deleteBooking(@PathVariable Integer id) { + try { + bookingService.deleteBooking(id); + return new ResponseEntity<>(HttpStatus.ACCEPTED); + } catch (RuntimeException e) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } +} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/Booking.java b/java/roomBooking/src/main/java/com/uva/monolith/services/bookings/models/Booking.java similarity index 84% rename from java/roomBooking/src/main/java/com/uva/roomBooking/Models/Booking.java rename to java/roomBooking/src/main/java/com/uva/monolith/services/bookings/models/Booking.java index c546d1916b1c29a10f95c97f03db34e64ffbe7d2..533ee0c7a1fa053dce449b855f1e46e08dabbe66 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/Booking.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/bookings/models/Booking.java @@ -1,4 +1,4 @@ -package com.uva.roomBooking.Models; +package com.uva.monolith.services.bookings.models; import jakarta.persistence.Basic; import jakarta.persistence.CascadeType; @@ -13,6 +13,9 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import java.time.LocalDate; +import com.uva.monolith.services.hotels.models.Room; +import com.uva.monolith.services.users.models.Client; + @Entity @Table(name = "bookings") public class Booking { @@ -22,7 +25,7 @@ public class Booking { private int id; @JoinColumn(name = "user_id", referencedColumnName = "id") @ManyToOne(optional = false, fetch = FetchType.EAGER, cascade = CascadeType.MERGE) - private User userId; + private Client userId; @JoinColumn(name = "room_id", referencedColumnName = "id") @ManyToOne(optional = false, fetch = FetchType.EAGER, cascade = CascadeType.MERGE) private Room roomId; @@ -34,7 +37,7 @@ public class Booking { public Booking() { } - public Booking(int id, User userId, Room roomID, LocalDate startDate, LocalDate endDate) { + public Booking(int id, Client userId, Room roomID, LocalDate startDate, LocalDate endDate) { this.id = id; this.userId = userId; this.roomId = roomID; @@ -50,11 +53,11 @@ public class Booking { return this.id; } - public void setUserId(User userId) { + public void setUserId(Client userId) { this.userId = userId; } - public User getUserId() { + public Client getUserId() { return this.userId; } diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/bookings/repositories/BookingRepository.java b/java/roomBooking/src/main/java/com/uva/monolith/services/bookings/repositories/BookingRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..b5ace65939b898798e6e5416fedda793388f2615 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/bookings/repositories/BookingRepository.java @@ -0,0 +1,41 @@ +// BookingRepository.java +package com.uva.monolith.services.bookings.repositories; + +import jakarta.transaction.Transactional; + +import java.time.LocalDate; +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import com.uva.monolith.services.bookings.models.Booking; + +public interface BookingRepository extends JpaRepository<Booking, Integer> { + @Query("SELECT b FROM Booking b WHERE b.userId.id = ?1") + List<Booking> findByUserId(int userId); + + @Query("SELECT b FROM Booking b WHERE b.roomId.id = ?1") + List<Booking> findByRoomId(int roomId); + + @Query("SELECT b FROM Booking b WHERE b.startDate >= ?1 AND b.endDate <= ?2") + List<Booking> findByDateRange(@Param("startDate") LocalDate startDate, + @Param("endDate") LocalDate endDate); + + @Query("SELECT b FROM Booking b WHERE b.roomId.id = ?1 AND b.startDate < ?2 AND b.endDate > ?3") + List<Booking> findByRoomIdAndDateRange(@Param("roomId") int roomId, @Param("startDate") LocalDate startDate, + @Param("endDate") LocalDate endDate); + + @Transactional + @Modifying + @Query("DELETE FROM Booking b WHERE b.id = ?1") + void deleteBookingById(@Param("id") Integer id); + + @Transactional + @Modifying + @Query("DELETE FROM Booking b WHERE b.roomId.hotel.id = ?1") + void deleteAllByHotelId(int hotelId); + +} diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/bookings/services/BookingService.java b/java/roomBooking/src/main/java/com/uva/monolith/services/bookings/services/BookingService.java new file mode 100644 index 0000000000000000000000000000000000000000..176f49dd951630c9118b24536e8a7dd6f5a15521 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/bookings/services/BookingService.java @@ -0,0 +1,89 @@ +package com.uva.monolith.services.bookings.services; + +import com.uva.monolith.services.bookings.models.Booking; +import com.uva.monolith.services.bookings.repositories.BookingRepository; +import com.uva.monolith.services.hotels.models.Room; +import com.uva.monolith.services.hotels.repositories.RoomRepository; +import com.uva.monolith.services.users.models.Client; +import com.uva.monolith.services.users.repositories.ClientRepository; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.util.List; + +@Service +public class BookingService { + + @Autowired + private BookingRepository bookingRepository; + + @Autowired + private RoomRepository roomRepository; + + @Autowired + private ClientRepository clientRepository; + + public List<Booking> getBookings(LocalDate start, LocalDate end, Integer roomId, Integer userId) { + List<Booking> bookings = null; + + if (start != null && end != null) { + bookings = bookingRepository.findByDateRange(start, end); + } + if (roomId != null) { + if (bookings == null) { + bookings = bookingRepository.findByRoomId(roomId); + } else { + bookings = bookings.stream() + .filter(booking -> booking.getRoomId().getId() == roomId) + .toList(); + } + } + if (userId != null) { + if (bookings == null) { + bookings = bookingRepository.findByUserId(userId); + } else { + bookings = bookings.stream() + .filter(booking -> booking.getUserId().getId() == userId) + .toList(); + } + } + if (start == null && end == null && roomId == null && userId == null) { + bookings = bookingRepository.findAll(); + } + + return bookings; + } + + public Booking createBooking(Booking booking) { + Client user = clientRepository.findById(booking.getUserId().getId()) + .orElseThrow(() -> new RuntimeException("User not found")); + Room room = roomRepository.findById(booking.getRoomId().getId()) + .orElseThrow(() -> new RuntimeException("Room not found")); + + // Check availability + List<Booking> existingBookings = bookingRepository.findByRoomIdAndDateRange( + room.getId(), booking.getStartDate(), booking.getEndDate()); + + if (!existingBookings.isEmpty()) { + throw new RuntimeException("Room is not available for the selected dates"); + } + + booking.setUserId(user); + booking.setRoomId(room); + return bookingRepository.save(booking); + } + + public Booking getBookingById(Integer id) { + return bookingRepository.findById(id) + .orElseThrow(() -> new RuntimeException("Booking not found")); + } + + public void deleteBooking(Integer id) { + if (!bookingRepository.existsById(id)) { + throw new RuntimeException("Booking not found"); + } + bookingRepository.deleteBookingById(id); + } +} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/HotelController.java b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/controllers/HotelController.java similarity index 87% rename from java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/HotelController.java rename to java/roomBooking/src/main/java/com/uva/monolith/services/hotels/controllers/HotelController.java index 803edc35fdcbf2b5ec7fc96972e8ee2a7777391d..5852aa794da7dcd05a8359f2756e296c829a40da 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/HotelController.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/controllers/HotelController.java @@ -1,24 +1,23 @@ -package com.uva.roomBooking.Controllers; +package com.uva.monolith.services.hotels.controllers; import java.util.List; import java.util.Map; import java.time.LocalDate; -import com.uva.roomBooking.Exceptions.HotelNotFoundException; -import com.uva.roomBooking.Exceptions.InvalidDateRangeException; -import com.uva.roomBooking.Exceptions.InvalidRequestException; -import com.uva.roomBooking.Models.Booking; -import com.uva.roomBooking.Models.Hotel; -import com.uva.roomBooking.Models.Room; -import com.uva.roomBooking.Repositories.BookingRepository; -import com.uva.roomBooking.Repositories.HotelRepository; -import com.uva.roomBooking.Repositories.RoomRepository; - import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; +import com.uva.monolith.exceptions.HotelNotFoundException; +import com.uva.monolith.exceptions.InvalidDateRangeException; +import com.uva.monolith.exceptions.InvalidRequestException; +import com.uva.monolith.services.bookings.repositories.BookingRepository; +import com.uva.monolith.services.hotels.models.Hotel; +import com.uva.monolith.services.hotels.models.Room; +import com.uva.monolith.services.hotels.repositories.HotelRepository; +import com.uva.monolith.services.hotels.repositories.RoomRepository; + @RestController @RequestMapping("hotels") @CrossOrigin(origins = "*") diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/Address.java b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/Address.java similarity index 97% rename from java/roomBooking/src/main/java/com/uva/roomBooking/Models/Address.java rename to java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/Address.java index 5e51f55e710c68ac38d4cb1c5769e574b06654bf..5f31a2a530da46c00460ad6cc6151b0769c1da61 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/Address.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/Address.java @@ -1,4 +1,4 @@ -package com.uva.roomBooking.Models; +package com.uva.monolith.services.hotels.models; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/Hotel.java b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/Hotel.java similarity index 76% rename from java/roomBooking/src/main/java/com/uva/roomBooking/Models/Hotel.java rename to java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/Hotel.java index 5a23005de99c022b5fff9570e2c515fcfc75e07e..21f5cec8b44f9fae1a566b7af92964d30b654546 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/Hotel.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/Hotel.java @@ -1,9 +1,8 @@ -package com.uva.roomBooking.Models; +package com.uva.monolith.services.hotels.models; import java.util.List; -import com.fasterxml.jackson.annotation.JsonIdentityInfo; -import com.fasterxml.jackson.annotation.ObjectIdGenerators; +import com.uva.monolith.services.users.models.HotelManager; import jakarta.persistence.Basic; import jakarta.persistence.CascadeType; @@ -13,6 +12,7 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; @@ -38,14 +38,19 @@ public class Hotel { @OneToMany(mappedBy = "hotel", fetch = FetchType.EAGER, cascade = CascadeType.ALL) private List<Room> rooms; + @ManyToOne(optional = false) + @JoinColumn(name = "hotel_manager", referencedColumnName = "id") + private HotelManager hotelManager; + public Hotel() { } - public Hotel(int id, String name, Address address, List<Room> rooms) { + public Hotel(int id, String name, Address address, List<Room> rooms, HotelManager hotelManager) { setId(id); setName(name); setAddress(address); setRooms(rooms); + setHotelManager(hotelManager); } public int getId() { @@ -81,4 +86,11 @@ public class Hotel { rooms.forEach(room -> room.setHotel(this)); } + public void setHotelManager(HotelManager hotelManager) { + this.hotelManager = hotelManager; + } + + public HotelManager getHotelManager() { + return hotelManager; + } } diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/Room.java b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/Room.java similarity index 86% rename from java/roomBooking/src/main/java/com/uva/roomBooking/Models/Room.java rename to java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/Room.java index 639dfdb0bd3be629b16c719373fa51c9a7584898..72a6a728f729dc7b93b727606172de7cbe385ebb 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/Room.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/Room.java @@ -1,10 +1,9 @@ -package com.uva.roomBooking.Models; +package com.uva.monolith.services.hotels.models; import java.util.List; -import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.ObjectIdGenerators; +import com.uva.monolith.services.bookings.models.Booking; import jakarta.persistence.Basic; import jakarta.persistence.CascadeType; @@ -36,7 +35,7 @@ public class Room { @Column(name = "room_number", nullable = false) private String roomNumber; @Column(name = "type", nullable = false) - private Tipo type; + private RoomType type; @Column(name = "available", nullable = false) private boolean available; @JsonIgnore @@ -46,7 +45,7 @@ public class Room { public Room() { } - public Room(int id, Hotel hotelId, String roomNumber, Tipo type, boolean available, List<Booking> bookings) { + public Room(int id, Hotel hotelId, String roomNumber, RoomType type, boolean available, List<Booking> bookings) { this.id = id; this.hotel = hotelId; this.roomNumber = roomNumber; @@ -79,11 +78,11 @@ public class Room { return this.roomNumber; } - public void setType(Tipo type) { + public void setType(RoomType type) { this.type = type; } - public Tipo getType() { + public RoomType getType() { return this.type; } diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/RoomType.java b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/RoomType.java new file mode 100644 index 0000000000000000000000000000000000000000..b9e82584850795afa7c7392248e3a6472ce24ac0 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/models/RoomType.java @@ -0,0 +1,7 @@ +package com.uva.monolith.services.hotels.models; + +public enum RoomType { + SINGLE, + DOUBLE, + SUITE +} diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/Repositories/HotelRepository.java b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/repositories/HotelRepository.java similarity index 56% rename from java/services/hotels/src/main/java/com/uva/hotelService/Repositories/HotelRepository.java rename to java/roomBooking/src/main/java/com/uva/monolith/services/hotels/repositories/HotelRepository.java index ae05426286ff6fb316513da9869ff4b715040703..ad88e98985f82e695aa9ed40df30d1501990eff5 100644 --- a/java/services/hotels/src/main/java/com/uva/hotelService/Repositories/HotelRepository.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/repositories/HotelRepository.java @@ -1,8 +1,8 @@ -package com.uva.hotelService.Repositories; +package com.uva.monolith.services.hotels.repositories; import org.springframework.data.jpa.repository.JpaRepository; -import com.uva.hotelService.Models.Hotel; +import com.uva.monolith.services.hotels.models.Hotel; public interface HotelRepository extends JpaRepository<Hotel, Integer> { diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/RoomRepository.java b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/repositories/RoomRepository.java similarity index 90% rename from java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/RoomRepository.java rename to java/roomBooking/src/main/java/com/uva/monolith/services/hotels/repositories/RoomRepository.java index 3df9937f1ba7dc7c8bc0aa839a7a93ffd0baa8de..78187e4389873bb649fd451ae4cb7ed1f1f0c473 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/RoomRepository.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/hotels/repositories/RoomRepository.java @@ -1,9 +1,10 @@ -package com.uva.roomBooking.Repositories; +package com.uva.monolith.services.hotels.repositories; -import com.uva.roomBooking.Models.Room; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import com.uva.monolith.services.hotels.models.Room; + import java.time.LocalDate; import java.util.List; import java.util.Optional; diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/controllers/UserController.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/controllers/UserController.java new file mode 100644 index 0000000000000000000000000000000000000000..32b8c4d9fdfe17b26a913dd062fe19302e1bb90c --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/controllers/UserController.java @@ -0,0 +1,110 @@ +package com.uva.monolith.services.users.controllers; + +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.HttpClientErrorException; + +import com.uva.monolith.services.users.models.User; +import com.uva.monolith.services.users.models.UserStatus; +import com.uva.monolith.services.users.services.UserService; + +@RestController +@RequestMapping("users") +@CrossOrigin(origins = "*") +public class UserController { + + @Autowired + private UserService userService; + + @GetMapping + public ResponseEntity<List<User>> getAllUsers() { + List<User> users = userService.getAllUsers(); + return ResponseEntity.ok(users); + } + + @GetMapping(params = { "email" }) + public ResponseEntity<?> getUserByEmail(@RequestParam String email) { + try { + return ResponseEntity.ok(userService.getUserByEmail(email)); + } catch (HttpClientErrorException e) { + if (e.getStatusCode() == HttpStatus.NOT_FOUND) + return new ResponseEntity<String>(HttpStatus.NOT_FOUND); + throw e; + } + } + + @PostMapping + public ResponseEntity<?> addUser(@RequestBody User user) { + userService.addUser(user); + return new ResponseEntity<>(HttpStatus.ACCEPTED); + } + + @GetMapping("/{id}") + public ResponseEntity<?> getUserById(@PathVariable int id) { + return ResponseEntity.ok(userService.getUserById(id)); + } + + @PutMapping("/{id}") + public ResponseEntity<?> updateUserData(@PathVariable int id, @RequestBody Map<String, String> json) { + String name = json.get("name"); + String email = json.get("email"); + if (name == null || email == null) { + return new ResponseEntity<String>("Missing required fields", HttpStatus.BAD_REQUEST); + } + try { + User user = userService.updateUserData(id, name, email); + return new ResponseEntity<User>(user, HttpStatus.OK); + } catch (HttpClientErrorException e) { + if (e.getStatusCode() == HttpStatus.NOT_FOUND) + return new ResponseEntity<String>(HttpStatus.NOT_FOUND); + throw e; + } + } + + @PatchMapping("/{id}") + public ResponseEntity<?> updateUserState(@PathVariable int id, @RequestBody Map<String, String> json) { + + String strStatus = json.get("status"); + if (strStatus == null) { + return new ResponseEntity<String>("Missing required fields", HttpStatus.BAD_REQUEST); + } + try { + UserStatus userStatus = UserStatus.valueOf(strStatus); + return ResponseEntity.ok(userService.updateUserStatus(id, userStatus)); + } catch (IllegalArgumentException e) { + return new ResponseEntity<String>("Unknown user state", HttpStatus.BAD_REQUEST); + } catch (HttpClientErrorException e) { + if (e.getStatusCode() == HttpStatus.NOT_FOUND) + return new ResponseEntity<String>(HttpStatus.NOT_FOUND); + throw e; + } + + } + + @DeleteMapping("/{id}") + public ResponseEntity<?> deleteUser(@PathVariable Integer id) { + try { + return ResponseEntity.ok(userService.deleteUserById(id)); + } catch (HttpClientErrorException e) { + if (e.getStatusCode() == HttpStatus.NOT_FOUND) + return new ResponseEntity<String>(HttpStatus.NOT_FOUND); + throw e; + } + } + +} diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/AuthResponse.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/AuthResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..8f334813beee8cb95caa275c66e46c9c539f2bd5 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/AuthResponse.java @@ -0,0 +1,51 @@ +package com.uva.monolith.services.users.models; + +public class AuthResponse { + + private int id; + private String username; + private String email; + private String password; + private UserRol rol; + + public int getId() { + return this.id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + + public UserRol getRol() { + return this.rol; + } + + public void setRol(UserRol rol) { + this.rol = rol; + } + +} diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/Client.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/Client.java new file mode 100644 index 0000000000000000000000000000000000000000..e106ecd3789a0237602e3194feacab7ddcbf4dfd --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/Client.java @@ -0,0 +1,65 @@ +package com.uva.monolith.services.users.models; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.uva.monolith.services.bookings.models.Booking; + +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.OneToMany; +import jakarta.persistence.Table; + +@Entity +@Table(name = "user_client") +public class Client extends User { + + @Basic(optional = false) + @Column(nullable = false) + @Enumerated(EnumType.STRING) + private UserStatus status; + + @JsonIgnore + @OneToMany(mappedBy = "userId", fetch = FetchType.EAGER, cascade = CascadeType.ALL) + private List<Booking> bookings; + + public Client() { + super(); + bookings = new ArrayList<>(); + status = UserStatus.NO_BOOKINGS; + } + + public Client(int id, String name, String email, String password, UserStatus status, + List<Booking> bookings) { + super(id, name, email, password, UserRol.CLIENT); + setStatus(status); + setBookings(bookings); + } + + public UserStatus getStatus() { + if (getBookings() == null || getBookings().isEmpty()) + return UserStatus.NO_BOOKINGS; + boolean activeBookings = getBookings().stream() + .anyMatch(booking -> !booking.getEndDate().isBefore(LocalDate.now())); // reserva >= ahora + return activeBookings ? UserStatus.WITH_ACTIVE_BOOKINGS : UserStatus.WITH_INACTIVE_BOOKINGS; + } + + public void setStatus(UserStatus status) { + this.status = status; + } + + public List<Booking> getBookings() { + return this.bookings; + } + + public void setBookings(List<Booking> bookings) { + this.bookings = bookings; + } +} diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/HotelManager.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/HotelManager.java new file mode 100644 index 0000000000000000000000000000000000000000..0e6f4b0aafa35ab8b23d202814c1fabefdcf86ed --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/HotelManager.java @@ -0,0 +1,38 @@ +package com.uva.monolith.services.users.models; + +import java.util.ArrayList; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.uva.monolith.services.hotels.models.Hotel; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + +@Entity +@Table(name = "hotel_manager_user") +public class HotelManager extends User { + + @JsonIgnore + @OneToMany(mappedBy = "hotelManager", fetch = FetchType.EAGER, cascade = CascadeType.ALL) + private List<Hotel> hotels; + + public HotelManager() { + super(); + hotels = new ArrayList<>(); + } + + public HotelManager(int id, String name, String email, String password, List<Hotel> hotels) { + super(id, name, email, password, UserRol.HOTEL_ADMIN); + setHotels(hotels); + } + + public List<Hotel> getHotels() { + return this.hotels; + } + + public void setHotels(List<Hotel> hotels) { + this.hotels = hotels; + } +} diff --git a/java/services/auth/src/main/java/com/uva/authentication/Models/User.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/User.java similarity index 86% rename from java/services/auth/src/main/java/com/uva/authentication/Models/User.java rename to java/roomBooking/src/main/java/com/uva/monolith/services/users/models/User.java index 9f56935cfafa594913501c6f110b6b0967ff9bad..45decd686b3972058eb920f6c2e07cd4293f1e05 100644 --- a/java/services/auth/src/main/java/com/uva/authentication/Models/User.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/User.java @@ -1,6 +1,4 @@ -package com.uva.authentication.Models; - -import java.util.List; +package com.uva.monolith.services.users.models; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -52,7 +50,6 @@ public class User { setId(id); setName(name); setEmail(email); - setPassword(password); setRol(rol); } @@ -81,10 +78,18 @@ public class User { } public String getPassword() { - return this.password; + return password; + } + + public void setPassword(String rawPassword) { + this.password = rawPassword; + } + + public UserRol getRol() { + return this.rol; } - public void setPassword(String password) { - this.password = password; + public void setRol(UserRol rol) { + this.rol = rol; } } diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/UserRol.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/UserRol.java new file mode 100644 index 0000000000000000000000000000000000000000..f408ba5ef9d34d96c32d3c42a6c2c51b1c6f22b1 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/UserRol.java @@ -0,0 +1,5 @@ +package com.uva.monolith.services.users.models; + +public enum UserRol { + ADMIN, HOTEL_ADMIN, CLIENT +} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/UserStatus.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/UserStatus.java similarity index 64% rename from java/roomBooking/src/main/java/com/uva/roomBooking/Models/UserStatus.java rename to java/roomBooking/src/main/java/com/uva/monolith/services/users/models/UserStatus.java index 41adce4ba6df6332286f0971b7f8e43b9126e401..362b8688260d4c13dc4a8eae205411c9d5533d79 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/UserStatus.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/UserStatus.java @@ -1,4 +1,4 @@ -package com.uva.roomBooking.Models; +package com.uva.monolith.services.users.models; public enum UserStatus { NO_BOOKINGS, WITH_ACTIVE_BOOKINGS, WITH_INACTIVE_BOOKINGS; diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/repositories/ClientRepository.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/repositories/ClientRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..1c1b46fbe665075b8f817367ff14ee65cf69ff76 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/repositories/ClientRepository.java @@ -0,0 +1,10 @@ +package com.uva.monolith.services.users.repositories; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.uva.monolith.services.users.models.Client; + +public interface ClientRepository extends JpaRepository<Client, Integer> { + Optional<Client> findByEmail(String email); +} \ No newline at end of file diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/repositories/HotelManagerRepository.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/repositories/HotelManagerRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..092a251b199fdecd80a2654fc3e6c96d1b7eb7f4 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/repositories/HotelManagerRepository.java @@ -0,0 +1,10 @@ +package com.uva.monolith.services.users.repositories; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.uva.monolith.services.users.models.HotelManager; + +public interface HotelManagerRepository extends JpaRepository<HotelManager, Integer> { + Optional<HotelManager> findByEmail(String email); +} \ No newline at end of file diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/repositories/UserRepository.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/repositories/UserRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..e5b44c976f095719854aa8070abc843b898036fe --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/repositories/UserRepository.java @@ -0,0 +1,11 @@ +package com.uva.monolith.services.users.repositories; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.uva.monolith.services.users.models.User; + +public interface UserRepository extends JpaRepository<User, Integer> { + Optional<User> findByEmail(String email); +} diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/services/UserService.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/services/UserService.java new file mode 100644 index 0000000000000000000000000000000000000000..193d736853b1f0d84ff86a4b24cfd0f8db52172d --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/services/UserService.java @@ -0,0 +1,107 @@ +package com.uva.monolith.services.users.services; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; + +import com.uva.monolith.services.users.models.AuthResponse; +import com.uva.monolith.services.users.models.Client; +import com.uva.monolith.services.users.models.User; +import com.uva.monolith.services.users.models.UserStatus; +import com.uva.monolith.services.users.repositories.ClientRepository; +import com.uva.monolith.services.users.repositories.UserRepository; + +@Service +public class UserService { + + @Autowired + private UserRepository userRepository; + + @Autowired + private ClientRepository clientRepository; + + public List<User> getAllUsers() { + return userRepository.findAll(); + } + + private User assertUser(Optional<? extends User> opUser) { + return opUser.orElseThrow(() -> new HttpClientErrorException(HttpStatus.NOT_FOUND)); + } + + public User getUserById(int id) { + return assertUser(userRepository.findById(id)); + } + + public AuthResponse getUserByEmail(String email) { + User u = assertUser(userRepository.findByEmail(email)); + AuthResponse auth = new AuthResponse(); + BeanUtils.copyProperties(u, auth); + auth.setUsername(u.getName()); + return auth; + } + + public User addUser(User user) { + // Actualmente está en el servicio AUTH + // TODO adaptar adecuadamente + throw new HttpClientErrorException(HttpStatus.MOVED_PERMANENTLY, "servicio actual en http://localhost:8101/login"); + // user.setStatus(UserStatus.NO_BOOKINGS); + // if (user.getRol() == null) // Rol por defecto + // user.setRol(UserRol.CONSUMER); + // // Guardamos + // return userRepository.save(user); + } + + public User updateUserData(int id, String name, String email) { + User user = getUserById(id); + user.setName(name); + user.setEmail(email); + return userRepository.save(user); + } + + public User updateUserStatus(int id, UserStatus status) { + + Client user = (Client) assertUser(clientRepository.findById(id)); + + boolean activeBookings = user.getBookings().stream() + .anyMatch(booking -> !booking.getEndDate().isBefore(LocalDate.now())); // reserva >= ahora + boolean inactiveBookings = user.getBookings().stream() + .anyMatch(booking -> booking.getStartDate().isBefore(LocalDate.now())); // reserva < ahora + + switch (status) { + case NO_BOOKINGS: + if (!user.getBookings().isEmpty()) + throw new IllegalArgumentException("Invalid State: The user has at least one booking"); + break; + case WITH_ACTIVE_BOOKINGS: + if (user.getBookings().isEmpty()) + throw new IllegalArgumentException("Invalid State: The user don't has bookings"); + if (!activeBookings) + throw new IllegalArgumentException("Invalid State: The user don't has active bookings"); + break; + case WITH_INACTIVE_BOOKINGS: + if (user.getBookings().isEmpty()) + throw new IllegalArgumentException("Invalid State: The user don't has bookings"); + if (!inactiveBookings) + throw new IllegalArgumentException("Invalid State: The user don't has inactive bookings"); + break; + default: + break; + } + user.setStatus(status); + return userRepository.save(user); + } + + public User deleteUserById(int id) { + User user = getUserById(id); + // TODO eliminar reservas de usuario ahora mismo no por el modo cascada pero a + // futuro sí, después de la disgregación en microservicios + userRepository.deleteById(id); + return user; + } +} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/BookingController.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/BookingController.java deleted file mode 100644 index 5baa50358b36dfffd3184fd0e7e46a9177b2ef55..0000000000000000000000000000000000000000 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/BookingController.java +++ /dev/null @@ -1,80 +0,0 @@ -// BookingController.java -package com.uva.roomBooking.Controllers; - -import com.uva.roomBooking.Models.Booking; -import com.uva.roomBooking.Models.Room; -import com.uva.roomBooking.Models.User; -import com.uva.roomBooking.Repositories.BookingRepository; -import com.uva.roomBooking.Repositories.RoomRepository; -import com.uva.roomBooking.Repositories.UserRepository; - -import jakarta.transaction.Transactional; - -import org.springframework.http.HttpStatus; -import org.springframework.http.HttpStatusCode; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping("/bookings") -@CrossOrigin(origins = "*") -public class BookingController { - - private final BookingRepository bookingRepository; - private final UserRepository userRepository; - private final RoomRepository roomRepository; - - public BookingController(BookingRepository bookingRepository, UserRepository userRepository, - RoomRepository roomRepository) { - this.bookingRepository = bookingRepository; - this.userRepository = userRepository; - this.roomRepository = roomRepository; - } - - @GetMapping - public List<Booking> getAllBookings() { - return bookingRepository.findAll(); - } - - @PostMapping - public Booking createBooking(@RequestBody Booking booking) { - User user = userRepository.findById(booking.getUserId().getId()) - .orElseThrow(() -> new RuntimeException("User not found")); - Room room = roomRepository.findById(booking.getRoomId().getId()) - .orElseThrow(() -> new RuntimeException("Room not found")); - - // Verificar disponibilidad - List<Booking> existingBookings = bookingRepository.findByRoomIdAndDateRange( - room.getId(), booking.getStartDate(), booking.getEndDate()); - - if (!existingBookings.isEmpty()) { - throw new RuntimeException("Room is not available for the selected dates"); - } - - booking.setUserId(user); - booking.setRoomId(room); - return bookingRepository.save(booking); - } - - @GetMapping("/{id}") - public Booking getBookingById(@PathVariable Integer id) { - return bookingRepository.findById(id) - .orElseThrow(() -> new RuntimeException("Booking not found")); - } - - @DeleteMapping("/{id}") - @Transactional - public ResponseEntity<Void> deleteBooking(@PathVariable Integer id) { - try { - if (!bookingRepository.existsById(id)) - return new ResponseEntity<>(HttpStatus.NOT_FOUND); - - bookingRepository.deleteBookingById(id); - return new ResponseEntity<>(HttpStatus.ACCEPTED); - } catch (Exception e) { - return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); - } - } -} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/UserController.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/UserController.java deleted file mode 100644 index a0e6397b9cabc191f7d5d24ecde162e8da6b2f14..0000000000000000000000000000000000000000 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/UserController.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.uva.roomBooking.Controllers; - -import java.time.LocalDate; -import java.util.List; -import java.util.Map; - -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import com.uva.roomBooking.Models.UserStatus; -import com.uva.roomBooking.Models.Booking; -import com.uva.roomBooking.Models.User; -import com.uva.roomBooking.Repositories.UserRepository; - -@RestController -@RequestMapping("users") -@CrossOrigin(origins = "*") -public class UserController { - private final UserRepository userRepository; - - public UserController(UserRepository userRepository) { - this.userRepository = userRepository; - } - - @GetMapping - public List<User> getAllUsers() { - return userRepository.findAll(); - } - - @PostMapping - public User addUser(@RequestBody User user) { - // TODO revisar como se desea manejar estado por defecto - user.setStatus(UserStatus.NO_BOOKINGS); - // Aunque se asegure a lo mejor no es la forma de manejo esperada - return userRepository.save(user); - } - - @GetMapping("/{id}") - public User getUserById(@PathVariable int id) { - return userRepository.findById(id).orElseThrow(); - } - - @PutMapping("/{id}") - public User updateUserData(@PathVariable int id, @RequestBody Map<String, String> json) { - User target = userRepository.findById(id).orElseThrow(); - if (!json.containsKey("name") || !json.containsKey("email")) { - // TODO cambiar manejo - throw new RuntimeException("Missing required fields"); - } - target.setName(json.get("name")); - target.setEmail(json.get("email")); - return userRepository.save(target); - } - - @PatchMapping("/{id}") - public User updateUserState(@PathVariable int id, @RequestBody Map<String, String> json) { - User target = userRepository.findById(id).orElseThrow(); - String strStatus = json.get("status"); - if (strStatus == null) { - // TODO cambiar manejo - throw new RuntimeException("Missing required fields"); - } - UserStatus userStatus = UserStatus.valueOf(strStatus); - - boolean activeBookings = target.getBookings().stream() - .anyMatch(booking -> !booking.getEndDate().isBefore(LocalDate.now())); // reserva >= ahora - boolean inactiveBookings = target.getBookings().stream() - .anyMatch(booking -> booking.getStartDate().isBefore(LocalDate.now())); // reserva < ahora - - switch (userStatus) { - // TODO Buscar como validar las (in)active bookings - case NO_BOOKINGS: - if (!target.getBookings().isEmpty()) - throw new IllegalArgumentException("Invalid State: The user has at least one booking"); - break; - case WITH_ACTIVE_BOOKINGS: - if (target.getBookings().isEmpty()) - throw new IllegalArgumentException("Invalid State: The user don't has bookings"); - if (!activeBookings) - throw new IllegalArgumentException("Invalid State: The user don't has active bookings"); - break; - case WITH_INACTIVE_BOOKINGS: - if (target.getBookings().isEmpty()) - throw new IllegalArgumentException("Invalid State: The user don't has bookings"); - if (!inactiveBookings) - throw new IllegalArgumentException("Invalid State: The user don't has inactive bookings"); - break; - default: - break; - } - target.setStatus(userStatus); - return userRepository.save(target); - } - - @DeleteMapping("/{id}") - public User deleteUser(@PathVariable Integer id) { - User target; - if ((target = userRepository.findById(id).orElseThrow()) != null) { - userRepository.deleteById(id); - } - return target; - } - - @GetMapping("/{id}/bookings") - public List<Booking> getUserBookingsById(@PathVariable int id) { - User user = userRepository.findById(id).orElseThrow(); - return user.getBookings(); - } -} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/GlobalExceptionHandler.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/GlobalExceptionHandler.java deleted file mode 100644 index 03b21e27ffa7e4e921cc9801187911d9f1be6a52..0000000000000000000000000000000000000000 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/GlobalExceptionHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.uva.roomBooking.Exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.Map; - -@ControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(HotelNotFoundException.class) - public ResponseEntity<Map<String, Object>> handleHotelNotFound(HotelNotFoundException ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.NOT_FOUND); - } - - @ExceptionHandler(InvalidRequestException.class) - public ResponseEntity<Map<String, Object>> handleInvalidRequest(InvalidRequestException ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler(InvalidDateRangeException.class) - public ResponseEntity<Map<String, Object>> handleInvalidDateRange(InvalidDateRangeException ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler(Exception.class) - public ResponseEntity<Map<String, Object>> handleGeneralException(Exception ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", "An unexpected error occurred: " + ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR); - } -} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/HotelNotFoundException.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/HotelNotFoundException.java deleted file mode 100644 index 3d47f5efad71b6fbf3b3f5912493c9c0af1ca412..0000000000000000000000000000000000000000 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/HotelNotFoundException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.uva.roomBooking.Exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(HttpStatus.NOT_FOUND) // Devuelve un 404 cuando se lanza la excepción -public class HotelNotFoundException extends RuntimeException { - public HotelNotFoundException(int id) { - super("Hotel not found with id: " + id); - } -} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/InvalidDateRangeException.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/InvalidDateRangeException.java deleted file mode 100644 index 17a8420453ef402411b61b965d001560a4dd51ce..0000000000000000000000000000000000000000 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/InvalidDateRangeException.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.uva.roomBooking.Exceptions; - -public class InvalidDateRangeException extends RuntimeException { - public InvalidDateRangeException(String message) { - super(message); - } -} - diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/Tipo.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Models/Tipo.java deleted file mode 100644 index e1a48b53450e1f87ae070b1bf70bd6a9afc1ea34..0000000000000000000000000000000000000000 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/Tipo.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.uva.roomBooking.Models; - -public enum Tipo { - SINGLE, - DOUBLE, - SUITE -} 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 deleted file mode 100644 index c5373df6edc5e936d9c94f794ae36d3289d173d5..0000000000000000000000000000000000000000 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Models/User.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.uva.roomBooking.Models; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import jakarta.persistence.Basic; -import jakarta.persistence.CascadeType; -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.Table; - -@Entity -@Table(name = "users") -public class User { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Basic(optional = false) - private int id; - - @Basic(optional = false) - private String name; - - @Basic(optional = false) - private String email; - - @Basic(optional = false) - @Enumerated(EnumType.STRING) - private UserStatus status = UserStatus.NO_BOOKINGS; - - @JsonIgnore - @OneToMany(mappedBy = "userId", fetch = FetchType.EAGER, cascade = CascadeType.ALL) - private List<Booking> bookings; - - public User() { - } - - public User(int id, String name, String email, UserStatus status, List<Booking> bookings) { - setId(id); - setEmail(email); - setStatus(status); - setBookings(bookings); - } - - 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 UserStatus getStatus() { - return this.status; - } - - public void setStatus(UserStatus status) { - this.status = status; - } - - public List<Booking> getBookings() { - return this.bookings; - } - - public void setBookings(List<Booking> bookings) { - this.bookings = bookings; - } -} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/BookingRepository.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/BookingRepository.java deleted file mode 100644 index 16c860a30fd168d4e03018ef02466dcd5adb7f99..0000000000000000000000000000000000000000 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/BookingRepository.java +++ /dev/null @@ -1,32 +0,0 @@ -// BookingRepository.java -package com.uva.roomBooking.Repositories; - -import com.uva.roomBooking.Models.Booking; - -import jakarta.transaction.Transactional; - -import java.time.LocalDate; -import java.util.List; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; - -public interface BookingRepository extends JpaRepository<Booking, Integer> { - - @Query("SELECT b FROM Booking b WHERE b.roomId.id = ?1 AND b.startDate < ?2 AND b.endDate > ?3") - List<Booking> findByRoomIdAndDateRange(@Param("roomId") int roomId, @Param("startDate") LocalDate startDate, - @Param("endDate") LocalDate endDate); - - @Transactional - @Modifying - @Query("DELETE FROM Booking b WHERE b.id = ?1") - void deleteBookingById(@Param("id") Integer id); - - @Transactional - @Modifying - @Query("DELETE FROM Booking b WHERE b.roomId.hotel.id = ?1") - void deleteAllByHotelId(int hotelId); - -} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/HotelRepository.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/HotelRepository.java deleted file mode 100644 index 290f129a7be376279300062d4bf3d7a614abefcc..0000000000000000000000000000000000000000 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/HotelRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.uva.roomBooking.Repositories; - -import com.uva.roomBooking.Models.Hotel; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface HotelRepository extends JpaRepository<Hotel, Integer> { - -} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/UserRepository.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/UserRepository.java deleted file mode 100644 index 5f02f6d4a3b2147d181b8db36736d85ccfd884b5..0000000000000000000000000000000000000000 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/UserRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.uva.roomBooking.Repositories; - -import org.springframework.data.jpa.repository.JpaRepository; - -import com.uva.roomBooking.Models.User; - -public interface UserRepository extends JpaRepository<User, Integer> { - -} diff --git a/java/roomBooking/src/main/resources/application.properties b/java/roomBooking/src/main/resources/application.properties index 563d4ad07ad10e7fb52bb3defcc3b736d889447b..e9a1304c8364b789ce008c161df0f98daf1238a9 100644 --- a/java/roomBooking/src/main/resources/application.properties +++ b/java/roomBooking/src/main/resources/application.properties @@ -7,4 +7,5 @@ spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # Usar esto para alternar entre las exposición del room repository ya que no es necesario su uso pero por defecto, al no cubrir su ruta, se expone -# spring.data.rest.base-path=false \ No newline at end of file +# spring.data.rest.base-path=false +external.services.auth.host=localhost:8101 \ No newline at end of file diff --git a/java/services/auth/pom.xml b/java/services/auth/pom.xml index 9cbd96d71de023623d5eeb168a533f99b9dc8ccc..19b9923d7ad2a8b056e02681630234471de0a9d3 100644 --- a/java/services/auth/pom.xml +++ b/java/services/auth/pom.xml @@ -49,20 +49,26 @@ <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> + <!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core --> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-core</artifactId> + <version>6.4.1</version> + </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> - <version>0.11.2</version> + <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> - <version>0.11.2</version> + <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> - <version>0.11.2</version> + <version>0.11.5</version> </dependency> </dependencies> @@ -75,4 +81,4 @@ </plugins> </build> -</project> +</project> \ No newline at end of file diff --git a/java/services/auth/src/main/java/com/uva/authentication/Controllers/AuthenticationController.java b/java/services/auth/src/main/java/com/uva/authentication/Controllers/AuthenticationController.java deleted file mode 100644 index f650865625d8d7364c2b0718598351606ad546ce..0000000000000000000000000000000000000000 --- a/java/services/auth/src/main/java/com/uva/authentication/Controllers/AuthenticationController.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.uva.authentication.Controllers; - -import com.uva.authentication.Models.User; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.client.RestTemplate; - -import java.util.Date; - -@RestController -@RequestMapping("/auth") -public class AuthenticationController { - - @Autowired - private RestTemplate restTemplate; // Usamos RestTemplate para acceder al microservicio de usuarios - - private final String USER_SERVICE_URL = "http://user-service/users"; // URL del microservicio de usuarios - - // Clave secreta para firmar el token JWT - private final String SECRET_KEY = "your-secret-key"; // Cambia esto por una clave secreta segura - - @PostMapping("/login") - public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) { - // Hacemos una llamada al microservicio de usuarios para obtener el usuario por correo - ResponseEntity<User> userResponse = restTemplate.getForEntity( - USER_SERVICE_URL + "/{email}", - User.class, - loginRequest.getEmail() - ); - - // Verificamos si el usuario existe - if (userResponse.getStatusCode().is2xxSuccessful()) { - User user = userResponse.getBody(); - // Verificamos que la contraseña coincida (esto debería hacerse de forma segura en un servicio real) - if (user != null && user.getPassword().equals(loginRequest.getPassword())) { - // Generamos el token JWT si la autenticación es correcta - String token = generateToken(user.getName(), user.getEmail()); - return ResponseEntity.ok(new AuthResponse(token)); - } - } - - // Si el usuario no existe o la contraseña es incorrecta - return ResponseEntity.status(401).body("Invalid email or password"); - } - - // Método para generar el token JWT - private String generateToken(String name, String email) { - return Jwts.builder() - .setSubject(name) - .claim("email", email) // Añadimos el correo como parte del payload - .setIssuedAt(new Date()) // Fecha de emisión - .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // Expira en 1 hora - .signWith(SignatureAlgorithm.HS512, SECRET_KEY) // Firma con la clave secreta - .compact(); - } - - public static class LoginRequest { - private String email; - private String password; - - // Getters and setters - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - } - - public static class AuthResponse { - private String token; - - public AuthResponse(String token) { - this.token = token; - } - - // Getter - public String getToken() { - return token; - } - } -} diff --git a/java/services/auth/src/main/java/com/uva/authentication/Exceptions/GlobalExceptionHandler.java b/java/services/auth/src/main/java/com/uva/authentication/Exceptions/GlobalExceptionHandler.java deleted file mode 100644 index f8c8057c9c856a01ee309437de85576d34b0ff13..0000000000000000000000000000000000000000 --- a/java/services/auth/src/main/java/com/uva/authentication/Exceptions/GlobalExceptionHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.uva.authentication.Exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.Map; - -@ControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(HotelNotFoundException.class) - public ResponseEntity<Map<String, Object>> handleHotelNotFound(HotelNotFoundException ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.NOT_FOUND); - } - - @ExceptionHandler(InvalidRequestException.class) - public ResponseEntity<Map<String, Object>> handleInvalidRequest(InvalidRequestException ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler(InvalidDateRangeException.class) - public ResponseEntity<Map<String, Object>> handleInvalidDateRange(InvalidDateRangeException ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler(Exception.class) - public ResponseEntity<Map<String, Object>> handleGeneralException(Exception ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", "An unexpected error occurred: " + ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR); - } -} diff --git a/java/services/auth/src/main/java/com/uva/authentication/Exceptions/HotelNotFoundException.java b/java/services/auth/src/main/java/com/uva/authentication/Exceptions/HotelNotFoundException.java deleted file mode 100644 index 13270b07b214169a995fa980ddbd72cd45aa728f..0000000000000000000000000000000000000000 --- a/java/services/auth/src/main/java/com/uva/authentication/Exceptions/HotelNotFoundException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.uva.authentication.Exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(HttpStatus.NOT_FOUND) // Devuelve un 404 cuando se lanza la excepción -public class HotelNotFoundException extends RuntimeException { - public HotelNotFoundException(int id) { - super("Hotel not found with id: " + id); - } -} diff --git a/java/services/auth/src/main/java/com/uva/authentication/Exceptions/InvalidDateRangeException.java b/java/services/auth/src/main/java/com/uva/authentication/Exceptions/InvalidDateRangeException.java deleted file mode 100644 index 699ddc9124f4aea097659ad8dac1d6d4321654b8..0000000000000000000000000000000000000000 --- a/java/services/auth/src/main/java/com/uva/authentication/Exceptions/InvalidDateRangeException.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.uva.authentication.Exceptions; - -public class InvalidDateRangeException extends RuntimeException { - public InvalidDateRangeException(String message) { - super(message); - } -} - diff --git a/java/services/auth/src/main/java/com/uva/authentication/Exceptions/InvalidRequestException.java b/java/services/auth/src/main/java/com/uva/authentication/Exceptions/InvalidRequestException.java deleted file mode 100644 index 20bd4d00df753bad8b6bfa53ca5f2fc1b74284b0..0000000000000000000000000000000000000000 --- a/java/services/auth/src/main/java/com/uva/authentication/Exceptions/InvalidRequestException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.uva.authentication.Exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(HttpStatus.BAD_REQUEST) -public class InvalidRequestException extends RuntimeException { - public InvalidRequestException(String message) { - super(message); - } -} diff --git a/java/services/auth/src/main/java/com/uva/authentication/Models/UserStatus.java b/java/services/auth/src/main/java/com/uva/authentication/Models/UserStatus.java deleted file mode 100644 index 7d37403ba4c02364414e2cdf99cd4f9db269aa3f..0000000000000000000000000000000000000000 --- a/java/services/auth/src/main/java/com/uva/authentication/Models/UserStatus.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.uva.authentication.Models; - -public enum UserStatus { - NO_BOOKINGS, WITH_ACTIVE_BOOKINGS, WITH_INACTIVE_BOOKINGS; -} diff --git a/java/services/auth/src/main/java/com/uva/authentication/api/UserAPI.java b/java/services/auth/src/main/java/com/uva/authentication/api/UserAPI.java new file mode 100644 index 0000000000000000000000000000000000000000..d4aa44728a593f54275339d99c9e603b20b802e9 --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/api/UserAPI.java @@ -0,0 +1,74 @@ +// TODO eliminar si realmente no necesitamos comunicar un servicio con otro +package com.uva.authentication.api; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import com.uva.authentication.models.RegisterRequest; +import com.uva.authentication.models.remote.User; +import com.uva.authentication.models.remote.UserRol; +import com.uva.authentication.utils.JwtUtil; + +@Component +public class UserAPI { + + @Autowired + private RestTemplate restTemplate; + + @Value("${external.services.users.baseurl}") + private String USER_API_URL; + + @Autowired + private JwtUtil jwtUtil; + + private String token; + private final User USER = new User(-1, "admin", null, null, UserRol.ADMIN); + + private String getAccessToken() { + if (token == null || token.isEmpty() || jwtUtil.isTokenValid(token, USER)) { + token = jwtUtil.generateToken(USER); + } + return token; + } + + public User getUserByEmail(String email) { + + // Implementación para acceder con autentificación + // String token = getAccessToken(); + // HttpHeaders headers = new HttpHeaders(); + // headers.set("Authorization", "Bearer " + token); + // HttpEntity<Void> entity = new HttpEntity<>(headers); + + String url = USER_API_URL + "?email={" + email + "}"; + try { + ResponseEntity<User> userResponse = restTemplate.getForEntity(url, User.class, email); + // restTemplate.exchange(url, HttpMethod.GET, entity, User.class); + return userResponse.getBody(); + } catch (HttpClientErrorException e) { + if (e.getStatusCode() != HttpStatus.NOT_FOUND) + throw e; + return null; + } + } + + public User registerUser(RegisterRequest registerRequest) { + + String token = getAccessToken(); + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", "Bearer " + token); + + String url = USER_API_URL; + ResponseEntity<User> userResponse = restTemplate.postForEntity(url, registerRequest, User.class, headers); + if (!userResponse.getStatusCode().is2xxSuccessful()) + throw new RuntimeException("Failed to register user"); + + return userResponse.getBody(); + } + +} diff --git a/java/services/auth/src/main/java/com/uva/authentication/controllers/AuthController.java b/java/services/auth/src/main/java/com/uva/authentication/controllers/AuthController.java new file mode 100644 index 0000000000000000000000000000000000000000..23625a6e7824cadda471d847ecede0b94cb565da --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/controllers/AuthController.java @@ -0,0 +1,50 @@ +package com.uva.authentication.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.HttpClientErrorException; +import com.uva.authentication.models.*; +import com.uva.authentication.services.AuthService; + +@RestController +@CrossOrigin(origins = "*") +public class AuthController { + + @Autowired + private AuthService authService; + + @PostMapping("/login") + public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) { + try { + String token = authService.login(loginRequest); + return ResponseEntity.ok(new JwtAuthResponse(token)); + } catch (HttpClientErrorException e) { + if (e.getStatusCode() == HttpStatus.FORBIDDEN) { + return new ResponseEntity<String>(e.getMessage(), HttpStatus.FORBIDDEN); + } + } + return new ResponseEntity<String>("Algo no fue bien", HttpStatus.UNAUTHORIZED); + } + + @PostMapping("/register") + public ResponseEntity<?> register(@RequestBody RegisterRequest registerRequest) { + try { + LoginRequest loginRequest = new LoginRequest(); + loginRequest.setEmail(registerRequest.getEmail()); + loginRequest.setPassword(registerRequest.getPassword()); + + authService.register(registerRequest); + return login(loginRequest); + } catch (HttpClientErrorException e) { + if (e.getStatusCode() == HttpStatus.CONFLICT) { + return new ResponseEntity<String>(e.getMessage(), HttpStatus.CONFLICT); + } + e.fillInStackTrace(); + } + + return new ResponseEntity<String>("Algo no fue bien", HttpStatus.UNAUTHORIZED); + } + +} diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/GlobalExceptionHandler.java b/java/services/auth/src/main/java/com/uva/authentication/exceptions/GlobalExceptionHandler.java similarity index 76% rename from java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/GlobalExceptionHandler.java rename to java/services/auth/src/main/java/com/uva/authentication/exceptions/GlobalExceptionHandler.java index 29c475c6cb4f50505fd4ea798423fdbabc74d502..6d4b8d58dbb5560de50b5b2149cbe3f181687446 100644 --- a/java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/GlobalExceptionHandler.java +++ b/java/services/auth/src/main/java/com/uva/authentication/exceptions/GlobalExceptionHandler.java @@ -1,4 +1,4 @@ -package com.uva.hotelService.Exceptions; +package com.uva.authentication.exceptions; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -39,12 +39,13 @@ public class GlobalExceptionHandler { return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST); } - @ExceptionHandler(Exception.class) - public ResponseEntity<Map<String, Object>> handleGeneralException(Exception ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", "An unexpected error occurred: " + ex.getMessage()); + // @ExceptionHandler(Exception.class) + // public ResponseEntity<Map<String, Object>> handleGeneralException(Exception + // ex) { + // Map<String, Object> body = new HashMap<>(); + // body.put("timestamp", LocalDateTime.now()); + // body.put("message", "An unexpected error occurred: " + ex.getMessage()); - return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR); - } + // return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR); + // } } diff --git a/java/services/users/src/main/java/com/uva/users/Exceptions/HotelNotFoundException.java b/java/services/auth/src/main/java/com/uva/authentication/exceptions/HotelNotFoundException.java similarity index 67% rename from java/services/users/src/main/java/com/uva/users/Exceptions/HotelNotFoundException.java rename to java/services/auth/src/main/java/com/uva/authentication/exceptions/HotelNotFoundException.java index ef8366dc04e7c03a6758a60c8133b606b114d80b..c642139b421a5cf864218fa2d0063f955335c5b7 100644 --- a/java/services/users/src/main/java/com/uva/users/Exceptions/HotelNotFoundException.java +++ b/java/services/auth/src/main/java/com/uva/authentication/exceptions/HotelNotFoundException.java @@ -1,9 +1,9 @@ -package com.uva.users.Exceptions; +package com.uva.authentication.exceptions; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; -@ResponseStatus(HttpStatus.NOT_FOUND) // Devuelve un 404 cuando se lanza la excepción +@ResponseStatus(HttpStatus.NOT_FOUND) // Devuelve un 404 cuando se lanza la excepción public class HotelNotFoundException extends RuntimeException { public HotelNotFoundException(int id) { super("Hotel not found with id: " + id); diff --git a/java/services/bookings/src/main/java/com/uva/bookings/Exceptions/InvalidDateRangeException.java b/java/services/auth/src/main/java/com/uva/authentication/exceptions/InvalidDateRangeException.java similarity index 78% rename from java/services/bookings/src/main/java/com/uva/bookings/Exceptions/InvalidDateRangeException.java rename to java/services/auth/src/main/java/com/uva/authentication/exceptions/InvalidDateRangeException.java index adca056e50cc8a5a27e06510b4eefe0ebcfb3207..c3dc917fb03495480007365b117e185521cf7bf2 100644 --- a/java/services/bookings/src/main/java/com/uva/bookings/Exceptions/InvalidDateRangeException.java +++ b/java/services/auth/src/main/java/com/uva/authentication/exceptions/InvalidDateRangeException.java @@ -1,8 +1,7 @@ -package com.uva.bookings.Exceptions; +package com.uva.authentication.exceptions; public class InvalidDateRangeException extends RuntimeException { public InvalidDateRangeException(String message) { super(message); } } - diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/InvalidRequestException.java b/java/services/auth/src/main/java/com/uva/authentication/exceptions/InvalidRequestException.java similarity index 87% rename from java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/InvalidRequestException.java rename to java/services/auth/src/main/java/com/uva/authentication/exceptions/InvalidRequestException.java index a8433b6f620da742dab87dae96a2e0f0193709ff..499a320e58ecd7576cbfff39101db14395f0edbe 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Exceptions/InvalidRequestException.java +++ b/java/services/auth/src/main/java/com/uva/authentication/exceptions/InvalidRequestException.java @@ -1,4 +1,4 @@ -package com.uva.roomBooking.Exceptions; +package com.uva.authentication.exceptions; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/java/services/auth/src/main/java/com/uva/authentication/models/AuthResponse.java b/java/services/auth/src/main/java/com/uva/authentication/models/AuthResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..e943a69108d5da38d4956509242935a6e4eb659e --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/models/AuthResponse.java @@ -0,0 +1,53 @@ +package com.uva.authentication.models; + +import com.uva.authentication.models.remote.UserRol; + +public class AuthResponse { + + private int id; + private String username; + private String email; + private String password; + private UserRol rol; + + public int getId() { + return this.id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + + public UserRol getRol() { + return this.rol; + } + + public void setRol(UserRol rol) { + this.rol = rol; + } + +} diff --git a/java/services/auth/src/main/java/com/uva/authentication/models/JwtAuthResponse.java b/java/services/auth/src/main/java/com/uva/authentication/models/JwtAuthResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..a9566954c35ce71864881e320843e270a998b9da --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/models/JwtAuthResponse.java @@ -0,0 +1,14 @@ +package com.uva.authentication.models; + +public class JwtAuthResponse { + private String token; + + public JwtAuthResponse(String token) { + this.token = token; + } + + // Getter + public String getToken() { + return token; + } +} diff --git a/java/services/auth/src/main/java/com/uva/authentication/models/LoginRequest.java b/java/services/auth/src/main/java/com/uva/authentication/models/LoginRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..d829de96fd9a45ed458976f03107f38e8933e797 --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/models/LoginRequest.java @@ -0,0 +1,26 @@ +package com.uva.authentication.models; + +import java.util.Objects; + +public class LoginRequest { + private String email; + private String password = String.valueOf(Objects.hashCode("hi")); + + // Getters and setters + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + +} diff --git a/java/services/auth/src/main/java/com/uva/authentication/models/RegisterRequest.java b/java/services/auth/src/main/java/com/uva/authentication/models/RegisterRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..b3c98e8e71e7ff14f2bb90c9f1b4e0cecf7e8ae7 --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/models/RegisterRequest.java @@ -0,0 +1,25 @@ +package com.uva.authentication.models; + +import com.uva.authentication.models.remote.UserRol; + +public class RegisterRequest extends LoginRequest { + private UserRol rol; + private String name; + + public UserRol getRol() { + return this.rol; + } + + public void setRol(UserRol rol) { + this.rol = rol; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/java/services/auth/src/main/java/com/uva/authentication/models/remote/Client.java b/java/services/auth/src/main/java/com/uva/authentication/models/remote/Client.java new file mode 100644 index 0000000000000000000000000000000000000000..69bb23c34c2f3c47f53365fab16abfda76871c60 --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/models/remote/Client.java @@ -0,0 +1,52 @@ +package com.uva.authentication.models.remote; + +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Table; + +@Entity +@Table(name = "user_client") +public class Client extends User { + + @Basic(optional = false) + @Column(nullable = false) + @Enumerated(EnumType.STRING) + private UserStatus status; + + // @JsonIgnore + // @OneToMany(mappedBy = "userId", fetch = FetchType.EAGER, cascade = + // CascadeType.ALL) + // private List<?> bookings; + + public Client() { + super(); + // bookings = new ArrayList<>(); + status = UserStatus.NO_BOOKINGS; + } + + public Client(int id, String name, String email, String password, UserStatus status) { + // , List<?> bookings) { + super(id, name, email, password, UserRol.CLIENT); + setStatus(status); + // setBookings(bookings); + } + + public UserStatus getStatus() { + return this.status; + } + + public void setStatus(UserStatus status) { + this.status = status; + } + + // public List<?> getBookings() { + // return this.bookings; + // } + + // public void setBookings(List<?> bookings) { + // this.bookings = bookings; + // } +} diff --git a/java/services/auth/src/main/java/com/uva/authentication/models/remote/HotelManager.java b/java/services/auth/src/main/java/com/uva/authentication/models/remote/HotelManager.java new file mode 100644 index 0000000000000000000000000000000000000000..584a33677a7a846d2896dc300c811b9759c9168f --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/models/remote/HotelManager.java @@ -0,0 +1,33 @@ +package com.uva.authentication.models.remote; + +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +@Entity +@Table(name = "hotel_manager_user") +public class HotelManager extends User { + + // TODO tener en cuenta que esto hay que tener un control adecuado + // @JsonIgnore + // @OneToMany(mappedBy = "userId", fetch = FetchType.EAGER, cascade = + // CascadeType.ALL) + // private List<?> hotels; + + public HotelManager() { + super(); + // hotels = new ArrayList<>(); + } + + public HotelManager(int id, String name, String email, String password) { // , List<?> hotels) { + super(id, name, email, password, UserRol.HOTEL_ADMIN); + // setHotels(hotels); + } + + // public List<?> getHotels() { + // return this.hotels; + // } + + // public void setHotels(List<?> hotels) { + // this.hotels = hotels; + // } +} diff --git a/java/services/auth/src/main/java/com/uva/authentication/models/remote/UserRol.java b/java/services/auth/src/main/java/com/uva/authentication/models/remote/UserRol.java new file mode 100644 index 0000000000000000000000000000000000000000..fe4d90dd1dd595f4c09ec699b452910352b406d5 --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/models/remote/UserRol.java @@ -0,0 +1,5 @@ +package com.uva.authentication.models.remote; + +public enum UserRol { + ADMIN, HOTEL_ADMIN, CLIENT +} diff --git a/java/services/users/src/main/java/com/uva/users/Models/UserStatus.java b/java/services/auth/src/main/java/com/uva/authentication/models/remote/UserStatus.java similarity index 65% rename from java/services/users/src/main/java/com/uva/users/Models/UserStatus.java rename to java/services/auth/src/main/java/com/uva/authentication/models/remote/UserStatus.java index 95ebb033127fd89a1af9685deded8c842786645d..5dd62bc5c75271eafa9daa58ad332aa8ad56d413 100644 --- a/java/services/users/src/main/java/com/uva/users/Models/UserStatus.java +++ b/java/services/auth/src/main/java/com/uva/authentication/models/remote/UserStatus.java @@ -1,4 +1,4 @@ -package com.uva.users.Models; +package com.uva.authentication.models.remote; public enum UserStatus { NO_BOOKINGS, WITH_ACTIVE_BOOKINGS, WITH_INACTIVE_BOOKINGS; diff --git a/java/services/auth/src/main/java/com/uva/authentication/repositories/ClientRepository.java b/java/services/auth/src/main/java/com/uva/authentication/repositories/ClientRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..3019f8145452aa3f8e1347ab9f9296b2ffeea71a --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/repositories/ClientRepository.java @@ -0,0 +1,11 @@ +package com.uva.authentication.repositories; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.uva.authentication.models.remote.Client; +import com.uva.authentication.models.remote.User; + +public interface ClientRepository extends JpaRepository<User, Integer> { + Optional<Client> findByEmail(String email); +} \ No newline at end of file diff --git a/java/services/auth/src/main/java/com/uva/authentication/repositories/HotelManagerRepository.java b/java/services/auth/src/main/java/com/uva/authentication/repositories/HotelManagerRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..2d50305d0fc98a1ca2fdfb55cf4dd8de4fd4b659 --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/repositories/HotelManagerRepository.java @@ -0,0 +1,11 @@ +package com.uva.authentication.repositories; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.uva.authentication.models.remote.HotelManager; +import com.uva.authentication.models.remote.User; + +public interface HotelManagerRepository extends JpaRepository<User, Integer> { + Optional<HotelManager> findByEmail(String email); +} \ No newline at end of file diff --git a/java/services/users/src/main/java/com/uva/users/Repositories/UserRepository.java b/java/services/auth/src/main/java/com/uva/authentication/repositories/UserRepository.java similarity index 53% rename from java/services/users/src/main/java/com/uva/users/Repositories/UserRepository.java rename to java/services/auth/src/main/java/com/uva/authentication/repositories/UserRepository.java index 730510d96586d62c9596fae8b711c06840cd2ff9..65f98edd7f2d0700de933199ae54c484eb8c71a3 100644 --- a/java/services/users/src/main/java/com/uva/users/Repositories/UserRepository.java +++ b/java/services/auth/src/main/java/com/uva/authentication/repositories/UserRepository.java @@ -1,11 +1,10 @@ -package com.uva.users.Repositories; +package com.uva.authentication.repositories; import java.util.Optional; - import org.springframework.data.jpa.repository.JpaRepository; -import com.uva.users.Models.User; +import com.uva.authentication.models.remote.User; public interface UserRepository extends JpaRepository<User, Integer> { - Optional<User> findByEmail(String email); -} + Optional<User> findByEmail(String email); +} \ No newline at end of file diff --git a/java/services/auth/src/main/java/com/uva/authentication/services/AuthService.java b/java/services/auth/src/main/java/com/uva/authentication/services/AuthService.java new file mode 100644 index 0000000000000000000000000000000000000000..e392a7bb693ab2db0b176eae4dc69aafc44db6b3 --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/services/AuthService.java @@ -0,0 +1,98 @@ +package com.uva.authentication.services; + +import java.util.Optional; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; + +import com.uva.authentication.models.LoginRequest; +import com.uva.authentication.models.RegisterRequest; +import com.uva.authentication.models.remote.Client; +import com.uva.authentication.models.remote.HotelManager; +import com.uva.authentication.models.remote.User; +import com.uva.authentication.models.remote.UserRol; +import com.uva.authentication.repositories.ClientRepository; +import com.uva.authentication.repositories.HotelManagerRepository; +import com.uva.authentication.repositories.UserRepository; +import com.uva.authentication.utils.JwtUtil; +import com.uva.authentication.utils.SecurityUtils; + +@Service +public class AuthService { + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private HotelManagerRepository hotelManagerRepository; + + @Autowired + private ClientRepository clientRepository; + + @Autowired + private UserRepository userRepository; + + private boolean authenticateUser(LoginRequest request, User user) { + if (user == null) + return false; + return SecurityUtils.checkPassword(request.getPassword(), user.getPassword()); + } + + public String login(LoginRequest loginRequest) { + User user = userRepository.findByEmail(loginRequest.getEmail()) + .orElseThrow(() -> new HttpClientErrorException(HttpStatus.FORBIDDEN, + "Invalid credentials")); + + if (!authenticateUser(loginRequest, user)) { + throw new HttpClientErrorException(HttpStatus.FORBIDDEN, "Invalid credentials"); + } + + return jwtUtil.generateToken(user); + } + + public User register(RegisterRequest registerRequest) { + Optional<User> user = userRepository.findByEmail(registerRequest.getEmail()); + if (user.isPresent()) + throw new HttpClientErrorException(HttpStatus.CONFLICT, "Email already in use"); + + return registerNewUser(registerRequest); + } + + private User registerNewUser(RegisterRequest registerRequest) { + User newUser; + + // Ciframos la contraseña + String hashPass = SecurityUtils.encrypt(registerRequest.getPassword()); + registerRequest.setPassword(hashPass); + + // Aseguramos que tenga un rol, por defecto es cliente + if (registerRequest.getRol() == null) + registerRequest.setRol(UserRol.CLIENT); + + switch (registerRequest.getRol()) { + case HOTEL_ADMIN: + HotelManager hm = new HotelManager(); + BeanUtils.copyProperties(registerRequest, hm); + newUser = hotelManagerRepository.save(hm); + break; + + case ADMIN: // TODO revisar + User admin = new User(); + BeanUtils.copyProperties(registerRequest, admin); + newUser = userRepository.save(admin); + break; + + case CLIENT: // Por defecto cliente normal + default: + Client client = new Client(); + BeanUtils.copyProperties(registerRequest, client); + client.setRol(UserRol.CLIENT); + newUser = clientRepository.save(client); + break; + } + return newUser; + } +} diff --git a/java/services/auth/src/main/java/com/uva/authentication/utils/JwtUtil.java b/java/services/auth/src/main/java/com/uva/authentication/utils/JwtUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..518261304ec00dc5c48dd4f860a519cb46b03f75 --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/utils/JwtUtil.java @@ -0,0 +1,85 @@ +package com.uva.authentication.utils; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; + +import java.security.Key; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import com.uva.authentication.models.remote.User; + +@Component +public class JwtUtil { + + @Value("${security.jwt.secret-key}") + private String secretKey; + + @Value("${security.jwt.expiration-time}") + private long jwtExpiration; + + public String extractUsername(String token) { + return extractClaim(token, Claims::getSubject); + } + + public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) { + final Claims claims = extractAllClaims(token); + return claimsResolver.apply(claims); + } + + public long getExpirationTime() { + return jwtExpiration; + } + + public String generateToken(User user) { + Map<String, Object> extraClaims = new HashMap<>(); + extraClaims.put("email", user.getEmail()); + extraClaims.put("rol", user.getRol()); + extraClaims.put("user", user); + long expiration = jwtExpiration; + + return Jwts + .builder() + .setClaims(extraClaims) + .setSubject(user.getName()) + .setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + expiration)) + .signWith(getSignInKey(), SignatureAlgorithm.HS256) + .compact(); + } + + public boolean isTokenValid(String token, User user) { + final String username = extractUsername(token); + return (username.equals(user.getName())) && !isTokenExpired(token); + } + + private boolean isTokenExpired(String token) { + return extractExpiration(token).before(new Date()); + } + + private Date extractExpiration(String token) { + return extractClaim(token, Claims::getExpiration); + } + + private Claims extractAllClaims(String token) { + return Jwts + .parserBuilder() + .setSigningKey(getSignInKey()) + .build() + .parseClaimsJws(token) + .getBody(); + } + + private Key getSignInKey() { + byte[] keyBytes = Decoders.BASE64.decode(secretKey); + return Keys.hmacShaKeyFor(keyBytes); + } +} diff --git a/java/services/auth/src/main/java/com/uva/authentication/utils/SecurityUtils.java b/java/services/auth/src/main/java/com/uva/authentication/utils/SecurityUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..2df069eabbe53bdeaccbdbd58094bf8022ff35c7 --- /dev/null +++ b/java/services/auth/src/main/java/com/uva/authentication/utils/SecurityUtils.java @@ -0,0 +1,18 @@ +package com.uva.authentication.utils; + +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +public class SecurityUtils { + + private static BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + + public static String encrypt(String value) { + return encoder.encode(value); + } + + // Método para comparar la contraseña ingresada con el hash almacenado + public static boolean checkPassword(String rawPassword, String encodedPassword) { + return encoder.matches(rawPassword, encodedPassword); // Comparar la contraseña con el hash + } + +} diff --git a/java/services/auth/src/main/resources/application.properties b/java/services/auth/src/main/resources/application.properties index 394adbeb066350dbc703341658ee10a64b666856..f08d9f6bd82253e53914fa3c4b695d4c25ba6f24 100644 --- a/java/services/auth/src/main/resources/application.properties +++ b/java/services/auth/src/main/resources/application.properties @@ -8,4 +8,9 @@ spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # Usar esto para alternar entre las exposición del room repository ya que no es necesario su uso pero por defecto, al no cubrir su ruta, se expone -# spring.data.rest.base-path=false \ No newline at end of file +# spring.data.rest.base-path=false +security.jwt.secret-key=3cfa76ef14937c1c0ea519f8fc057a80fcd04a7420f8e8bcd0a7567c272e007b +# 1h in millisecond +security.jwt.expiration-time=3600000 + +external.services.users.baseurl=http://localhost:8080/users \ No newline at end of file diff --git a/java/services/bookings/.gitignore b/java/services/bookings/.gitignore deleted file mode 100644 index 549e00a2a96fa9d7c5dbc9859664a78d980158c2..0000000000000000000000000000000000000000 --- a/java/services/bookings/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ diff --git a/java/services/bookings/Dockerfile b/java/services/bookings/Dockerfile deleted file mode 100644 index 8d0b79d6514534deddac782fc9367bcdbcaf89c3..0000000000000000000000000000000000000000 --- a/java/services/bookings/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM maven:3-openjdk-17 AS maven -WORKDIR /app -COPY ./ ./ -RUN mvn -Dmaven.test.skip clean package -FROM openjdk:17-jdk-oracle -ARG JAR_FILE=/app/target/*.jar -COPY --from=maven ${JAR_FILE} app.jar -ENV PORT 8080 -EXPOSE $PORT -ENTRYPOINT ["java","-jar", "/app.jar"] \ No newline at end of file diff --git a/java/services/bookings/mvnw b/java/services/bookings/mvnw deleted file mode 100755 index 19529ddf8c6eaa08c5c75ff80652d21ce4b72f8c..0000000000000000000000000000000000000000 --- a/java/services/bookings/mvnw +++ /dev/null @@ -1,259 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.2 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - if [ -n "${JAVA_HOME-}" ]; then - if [ -x "$JAVA_HOME/jre/sh/java" ]; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash> -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/java/services/bookings/mvnw.cmd b/java/services/bookings/mvnw.cmd deleted file mode 100644 index 249bdf3822221aa612d1da2605316cabd7b07e50..0000000000000000000000000000000000000000 --- a/java/services/bookings/mvnw.cmd +++ /dev/null @@ -1,149 +0,0 @@ -<# : batch portion -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.2 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash> -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' -$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" -if ($env:MAVEN_USER_HOME) { - $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" -} -$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/java/services/bookings/pom.xml b/java/services/bookings/pom.xml deleted file mode 100644 index 957ab2baae5bc9cd55fd13fa4610617dcf4153a0..0000000000000000000000000000000000000000 --- a/java/services/bookings/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-parent</artifactId> - <version>3.3.4</version> - <relativePath/> <!-- lookup parent from repository --> - </parent> - <groupId>com.uva</groupId> - <artifactId>bookingService</artifactId> - <version>0.0.1-SNAPSHOT</version> - <name>bookingService</name> - <description>Booking Microservice</description> - <url/> - <licenses> - <license/> - </licenses> - <developers> - <developer/> - </developers> - <scm> - <connection/> - <developerConnection/> - <tag/> - <url/> - </scm> - <properties> - <java.version>17</java.version> - </properties> - <dependencies> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-data-jpa</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-data-rest</artifactId> - </dependency> - - <dependency> - <groupId>com.mysql</groupId> - <artifactId>mysql-connector-j</artifactId> - <scope>runtime</scope> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-test</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - </plugin> - </plugins> - </build> - -</project> diff --git a/java/services/bookings/src/main/java/com/uva/bookings/Controllers/BookingController.java b/java/services/bookings/src/main/java/com/uva/bookings/Controllers/BookingController.java deleted file mode 100644 index 66b49481d04a156fb1a4ab509612ca3a7a601234..0000000000000000000000000000000000000000 --- a/java/services/bookings/src/main/java/com/uva/bookings/Controllers/BookingController.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.uva.bookings.Controllers; - -import com.uva.bookings.Models.Booking; -import com.uva.bookings.Repositories.BookingRepository; - -import jakarta.transaction.Transactional; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.client.RestTemplate; - -import java.util.List; - -@RestController -@RequestMapping("/bookings") -@CrossOrigin(origins = "*") -public class BookingController { - - @Autowired - private BookingRepository bookingRepository; - - @Autowired - private RestTemplate restTemplate; - - @GetMapping - public ResponseEntity<List<Booking>> getBookings( - @RequestParam(required = false) String startDate, - @RequestParam(required = false) String endDate, - @RequestParam(required = false) Integer roomId) { - - // Si no se proporcionan filtros, devolver todas las reservas - if (startDate == null && endDate == null && roomId == null) { - return ResponseEntity.ok(bookingRepository.findAll()); - } - - // Obtener reservas filtradas por los parámetros dados - List<Booking> bookings = bookingRepository.findByFilters(startDate, endDate, roomId); - if (bookings.isEmpty()) { - return ResponseEntity.noContent().build(); - } - - return ResponseEntity.ok(bookings); - } - - @PostMapping - public Booking createBooking(@RequestBody Booking booking) { - // Llamada al microservicio de usuarios para validar al usuario - ResponseEntity<Void> userResponse = restTemplate.exchange( - "http://user-service/users/{userId}", - HttpMethod.GET, - null, - Void.class, - booking.getUserId() - ); - if (!userResponse.getStatusCode().is2xxSuccessful()) { - throw new RuntimeException("User not found"); - } - - // Llamada al microservicio de habitaciones para validar la habitación - ResponseEntity<Void> roomResponse = restTemplate.exchange( - "http://room-service/rooms/{roomId}", - HttpMethod.GET, - null, - Void.class, - booking.getRoomId() - ); - if (!roomResponse.getStatusCode().is2xxSuccessful()) { - throw new RuntimeException("Room not found"); - } - - // Verificar disponibilidad - List<Booking> existingBookings = bookingRepository.findByRoomIdAndDateRange( - booking.getRoomId(), booking.getStartDate(), booking.getEndDate()); - - if (!existingBookings.isEmpty()) { - throw new RuntimeException("Room is not available for the selected dates"); - } - - return bookingRepository.save(booking); - } - - @GetMapping("/{id}") - public Booking getBookingById(@PathVariable Integer id) { - return bookingRepository.findById(id) - .orElseThrow(() -> new RuntimeException("Booking not found")); - } - - @GetMapping(params = "userId") - public ResponseEntity<List<Booking>> getBookingsByUserId(@RequestParam Integer userId) { - // Llamada al microservicio de usuarios para validar la existencia del usuario - ResponseEntity<Void> userResponse = restTemplate.exchange( - "http://user-service/users/{userId}", - HttpMethod.GET, - null, - Void.class, - userId - ); - - if (!userResponse.getStatusCode().is2xxSuccessful()) { - return ResponseEntity.noContent().build(); - } - - List<Booking> bookings = bookingRepository.findByUserId(userId); - if (bookings.isEmpty()) { - return ResponseEntity.noContent().build(); - } - return ResponseEntity.ok(bookings); - } - - @DeleteMapping("/{id}") - @Transactional - public ResponseEntity<Void> deleteBooking(@PathVariable Integer id) { - try { - if (!bookingRepository.existsById(id)) - return new ResponseEntity<>(HttpStatus.NOT_FOUND); - - bookingRepository.deleteBookingById(id); - return new ResponseEntity<>(HttpStatus.ACCEPTED); - } catch (Exception e) { - return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); - } - } -} diff --git a/java/services/bookings/src/main/java/com/uva/bookings/Exceptions/GlobalExceptionHandler.java b/java/services/bookings/src/main/java/com/uva/bookings/Exceptions/GlobalExceptionHandler.java deleted file mode 100644 index 8a9f4447dd4c4a94fbc32379ced1c86e8bd75e8c..0000000000000000000000000000000000000000 --- a/java/services/bookings/src/main/java/com/uva/bookings/Exceptions/GlobalExceptionHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.uva.bookings.Exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.Map; - -@ControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(HotelNotFoundException.class) - public ResponseEntity<Map<String, Object>> handleHotelNotFound(HotelNotFoundException ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.NOT_FOUND); - } - - @ExceptionHandler(InvalidRequestException.class) - public ResponseEntity<Map<String, Object>> handleInvalidRequest(InvalidRequestException ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler(InvalidDateRangeException.class) - public ResponseEntity<Map<String, Object>> handleInvalidDateRange(InvalidDateRangeException ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler(Exception.class) - public ResponseEntity<Map<String, Object>> handleGeneralException(Exception ex) { - Map<String, Object> body = new HashMap<>(); - body.put("timestamp", LocalDateTime.now()); - body.put("message", "An unexpected error occurred: " + ex.getMessage()); - - return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR); - } -} diff --git a/java/services/bookings/src/main/java/com/uva/bookings/Exceptions/HotelNotFoundException.java b/java/services/bookings/src/main/java/com/uva/bookings/Exceptions/HotelNotFoundException.java deleted file mode 100644 index b0f7409bd4ea5bf89816d979c1643dccbe2dea47..0000000000000000000000000000000000000000 --- a/java/services/bookings/src/main/java/com/uva/bookings/Exceptions/HotelNotFoundException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.uva.bookings.Exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(HttpStatus.NOT_FOUND) // Devuelve un 404 cuando se lanza la excepción -public class HotelNotFoundException extends RuntimeException { - public HotelNotFoundException(int id) { - super("Hotel not found with id: " + id); - } -} diff --git a/java/services/bookings/src/main/java/com/uva/bookings/Models/Booking.java b/java/services/bookings/src/main/java/com/uva/bookings/Models/Booking.java deleted file mode 100644 index 269daf37234145f3d248ff0782e3b99c0b138168..0000000000000000000000000000000000000000 --- a/java/services/bookings/src/main/java/com/uva/bookings/Models/Booking.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.uva.bookings.Models; - -import jakarta.persistence.Basic; -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; -import java.time.LocalDate; - -@Entity -@Table(name = "bookings") -public class Booking { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Basic(optional = false) - private int id; - @Column(name = "user_id", nullable = false) - private int userId; - @Column(name = "room_id", nullable = false) - private int roomId; - @Column(name = "start_date", nullable = false) - private LocalDate startDate; - @Column(name = "end_date", nullable = false) - private LocalDate endDate; - - public Booking() { - } - - public Booking(int id, int userId, int roomID, LocalDate startDate, LocalDate endDate) { - this.id = id; - this.userId = userId; - this.roomId = roomID; - this.startDate = startDate; - this.endDate = endDate; - } - - public void setId(int id) { - this.id = id; - } - - public int getId() { - return this.id; - } - - public void setUserId(int userId) { - this.userId = userId; - } - - public int getUserId() { - return this.userId; - } - - public void setRoomId(int roomID) { - this.roomId = roomID; - } - - public int getRoomId() { - return this.roomId; - } - - public void setStartDate(LocalDate startDate) { - this.startDate = startDate; - } - - public LocalDate getStartDate() { - return this.startDate; - } - - public void setEndDate(LocalDate endDate) { - this.endDate = endDate; - } - - public LocalDate getEndDate() { - return this.endDate; - } - -} diff --git a/java/services/bookings/src/main/java/com/uva/bookings/Repositories/BookingRepository.java b/java/services/bookings/src/main/java/com/uva/bookings/Repositories/BookingRepository.java deleted file mode 100644 index 8459911ba59cbf0095b2a7406c0022004f17cd9f..0000000000000000000000000000000000000000 --- a/java/services/bookings/src/main/java/com/uva/bookings/Repositories/BookingRepository.java +++ /dev/null @@ -1,40 +0,0 @@ -// BookingRepository.java -package com.uva.bookings.Repositories; - -import com.uva.bookings.Models.Booking; - -import jakarta.transaction.Transactional; - -import java.time.LocalDate; -import java.util.List; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; - -public interface BookingRepository extends JpaRepository<Booking, Integer> { - - @Query("SELECT b FROM Booking b WHERE b.roomId = ?1 AND b.startDate < ?2 AND b.endDate > ?3") - List<Booking> findByRoomIdAndDateRange(@Param("roomId") int roomId, @Param("startDate") LocalDate startDate, - @Param("endDate") LocalDate endDate); - - @Transactional - @Modifying - @Query("DELETE FROM Booking b WHERE b.id = ?1") - void deleteBookingById(@Param("id") Integer id); - - - List<Booking> findByUserId(Integer userId); - - @Query("SELECT b FROM Booking b WHERE " - + "(:roomId IS NULL OR b.roomId = :roomId) AND " - + "(:startDate IS NULL OR b.startDate >= :startDate) AND " - + "(:endDate IS NULL OR b.endDate <= :endDate)") - List<Booking> findByFilters(@Param("startDate") String startDate, - @Param("endDate") String endDate, - @Param("roomId") Integer roomId); - - - -} diff --git a/java/services/bookings/src/main/java/com/uva/bookings/bookingServiceApplication.java b/java/services/bookings/src/main/java/com/uva/bookings/bookingServiceApplication.java deleted file mode 100644 index ae4765caf5111f18fdbceafd5a66272e8aafd775..0000000000000000000000000000000000000000 --- a/java/services/bookings/src/main/java/com/uva/bookings/bookingServiceApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.uva.bookings; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class bookingServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(bookingServiceApplication.class, args); - } - -} diff --git a/java/services/bookings/src/main/java/com/uva/bookings/config/RestTemplateConfig.java b/java/services/bookings/src/main/java/com/uva/bookings/config/RestTemplateConfig.java deleted file mode 100644 index 9891319840494a78fb1f0c8c67a1001461d4467b..0000000000000000000000000000000000000000 --- a/java/services/bookings/src/main/java/com/uva/bookings/config/RestTemplateConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.uva.bookings.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; - -@Configuration -public class RestTemplateConfig { - - @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); - } -} diff --git a/java/services/bookings/src/main/resources/application.properties b/java/services/bookings/src/main/resources/application.properties deleted file mode 100644 index afaa0e3df29833b5a13dc71cbbdfb523897f4cc8..0000000000000000000000000000000000000000 --- a/java/services/bookings/src/main/resources/application.properties +++ /dev/null @@ -1,11 +0,0 @@ -spring.application.name=bookingService -server.port=8131 -spring.jpa.hibernate.ddl-auto=update -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect -spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/RoomsBooking?createDatabaseIfNotExist=true -spring.datasource.username=user -spring.datasource.password=password -spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver - -# Usar esto para alternar entre las exposición del room repository ya que no es necesario su uso pero por defecto, al no cubrir su ruta, se expone -# spring.data.rest.base-path=false \ No newline at end of file diff --git a/java/services/bookings/src/test/java/com/uva/roomBooking/RoomBookingApplicationTests.java b/java/services/bookings/src/test/java/com/uva/roomBooking/RoomBookingApplicationTests.java deleted file mode 100644 index 3b50599492c36017391c0dcabd81573f123a809a..0000000000000000000000000000000000000000 --- a/java/services/bookings/src/test/java/com/uva/roomBooking/RoomBookingApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.uva.roomBooking; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class RoomBookingApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/java/services/check_service.sh b/java/services/check_service.sh deleted file mode 100644 index 2a474f277d1a5b2d2974f793b9f2dd4b169bb6ee..0000000000000000000000000000000000000000 --- a/java/services/check_service.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/bash -servicesdir="$PWD" -for i in $(ls $servicesdir); do - if [ -d "$servicesdir/$i" ]; then - logfile="/tmp/debug_$i.log" - echo -n Log file for $i service: - [ ! -f ] && echo -n " NOT" - echo " FOUND" - fi -done - -for i in {0..30..10}; do - port=$((8101 + $i)) - curl "http://localhost:$port" > /dev/null 2>/dev/null - if [ $? -eq 0 ]; then - echo "Port $port is open" - else - echo "Port $port is closed" - fi -done \ No newline at end of file diff --git a/java/services/hotels/.gitignore b/java/services/hotels/.gitignore deleted file mode 100644 index 549e00a2a96fa9d7c5dbc9859664a78d980158c2..0000000000000000000000000000000000000000 --- a/java/services/hotels/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ diff --git a/java/services/hotels/.mvn/wrapper/maven-wrapper.properties b/java/services/hotels/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index d58dfb70bab565a697e6854eb012d17e0fd39bd4..0000000000000000000000000000000000000000 --- a/java/services/hotels/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -wrapperVersion=3.3.2 -distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/java/services/hotels/Dockerfile b/java/services/hotels/Dockerfile deleted file mode 100644 index 8d0b79d6514534deddac782fc9367bcdbcaf89c3..0000000000000000000000000000000000000000 --- a/java/services/hotels/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM maven:3-openjdk-17 AS maven -WORKDIR /app -COPY ./ ./ -RUN mvn -Dmaven.test.skip clean package -FROM openjdk:17-jdk-oracle -ARG JAR_FILE=/app/target/*.jar -COPY --from=maven ${JAR_FILE} app.jar -ENV PORT 8080 -EXPOSE $PORT -ENTRYPOINT ["java","-jar", "/app.jar"] \ No newline at end of file diff --git a/java/services/hotels/mvnw b/java/services/hotels/mvnw deleted file mode 100755 index 19529ddf8c6eaa08c5c75ff80652d21ce4b72f8c..0000000000000000000000000000000000000000 --- a/java/services/hotels/mvnw +++ /dev/null @@ -1,259 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.2 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - if [ -n "${JAVA_HOME-}" ]; then - if [ -x "$JAVA_HOME/jre/sh/java" ]; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash> -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/java/services/hotels/mvnw.cmd b/java/services/hotels/mvnw.cmd deleted file mode 100644 index 249bdf3822221aa612d1da2605316cabd7b07e50..0000000000000000000000000000000000000000 --- a/java/services/hotels/mvnw.cmd +++ /dev/null @@ -1,149 +0,0 @@ -<# : batch portion -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.2 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash> -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' -$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" -if ($env:MAVEN_USER_HOME) { - $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" -} -$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/java/services/hotels/pom.xml b/java/services/hotels/pom.xml deleted file mode 100644 index fd6521678ea85077d527d118898ab02c8c8d9e79..0000000000000000000000000000000000000000 --- a/java/services/hotels/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-parent</artifactId> - <version>3.3.4</version> - <relativePath/> <!-- lookup parent from repository --> - </parent> - <groupId>com.uva</groupId> - <artifactId>hotelService</artifactId> - <version>0.0.1-SNAPSHOT</version> - <name>hotelService</name> - <description>Hotel Microservice REST</description> - <url/> - <licenses> - <license/> - </licenses> - <developers> - <developer/> - </developers> - <scm> - <connection/> - <developerConnection/> - <tag/> - <url/> - </scm> - <properties> - <java.version>17</java.version> - </properties> - <dependencies> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-data-jpa</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-data-rest</artifactId> - </dependency> - - <dependency> - <groupId>com.mysql</groupId> - <artifactId>mysql-connector-j</artifactId> - <scope>runtime</scope> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-test</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - </plugin> - </plugins> - </build> - -</project> \ No newline at end of file diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/Controllers/HotelController.java b/java/services/hotels/src/main/java/com/uva/hotelService/Controllers/HotelController.java deleted file mode 100644 index fc949f5efce63f12785a858a307ef61b7d41d70d..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/main/java/com/uva/hotelService/Controllers/HotelController.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.uva.hotelService.Controllers; - -import java.util.List; -import java.util.Map; -import java.time.LocalDate; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.client.RestTemplate; - -import com.uva.hotelService.Exceptions.HotelNotFoundException; -import com.uva.hotelService.Exceptions.InvalidDateRangeException; -import com.uva.hotelService.Exceptions.InvalidRequestException; -import com.uva.hotelService.Models.Hotel; -import com.uva.hotelService.Models.Room; -import com.uva.hotelService.Repositories.HotelRepository; -import com.uva.hotelService.Repositories.RoomRepository; - -@RestController -@RequestMapping("hotels") -@CrossOrigin(origins = "*") -public class HotelController { - - @Autowired - private HotelRepository hotelRepository; - - @Autowired - private RoomRepository roomRepository; - - @Autowired - private RestTemplate restTemplate; - - // Obtener todos los hoteles - @GetMapping - public List<Hotel> getAllHotels() { - return hotelRepository.findAll(); - } - - // Añadir un hotel con sus habitaciones - @PostMapping - public ResponseEntity<Hotel> addHotel(@RequestBody Hotel hotel) { - Hotel savedHotel = hotelRepository.save(hotel); - return new ResponseEntity<>(savedHotel, HttpStatus.CREATED); - } - - // Obtener un hotel por su ID - @GetMapping("/{id}") - public Hotel getHotelById(@PathVariable int id) { - return hotelRepository.findById(id) - .orElseThrow(() -> new HotelNotFoundException(id)); - } - - // Borrar un hotel junto con sus habitaciones (borrado en cascada) - @DeleteMapping("/{id}") - @Transactional - public ResponseEntity<Void> deleteHotel(@PathVariable Integer id) { - Hotel target = hotelRepository.findById(id) - .orElseThrow(() -> new HotelNotFoundException(id)); - // bookingRepository.deleteAllByHotelId(id); - // TODO revisar como se va a hacer cuando se haga lo de reservas - String deleteUrl = String.format("http://reservas-service/?hotelId=%d", target.getId()); - restTemplate.delete(deleteUrl); - hotelRepository.delete(target); - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - // Obtener habitaciones de un hotel según disponibilidad y fechas - @GetMapping("/{hotelId}/rooms") - public ResponseEntity<List<Room>> getRoomsFromHotel( - @PathVariable int hotelId, - @RequestParam(required = false) LocalDate start, - @RequestParam(required = false) LocalDate end) { - - List<Room> rooms; - rooms = roomRepository.findAllByHotelIdAndAvailable(hotelId, true); - if (start != null && end != null) { - if (!start.isBefore(end)) { - throw new InvalidDateRangeException("La fecha de inicio debe ser anterior a la fecha de fin"); - } - rooms = rooms.stream().filter( - room -> { - // TODO revisar - String url = String.format("http://reservas-service/?hotelId=%d&start=%s&end=%s", room.getId(), - start, end); - return Boolean.parseBoolean( - restTemplate.exchange( - url, - HttpMethod.GET, - null, - Boolean.class).toString()); - }).toList(); - - } - return new ResponseEntity<>(rooms, HttpStatus.OK); - } - - // Actualizar disponibilidad de una habitación específica en un hotel - @PatchMapping("/{hotelId}/rooms/{roomId}") - public ResponseEntity<Room> updateRoomAvailability( - @PathVariable int hotelId, - @PathVariable int roomId, - @RequestBody Map<String, Boolean> body) { - - if (!body.containsKey("available")) { - throw new InvalidRequestException("El campo 'available' es obligatorio"); - } - - Room targetRoom = roomRepository.findByIdAndHotelId(roomId, hotelId) - .orElseThrow(() -> new IllegalArgumentException("Habitación no encontrada")); - - targetRoom.setAvailable(body.get("available")); - roomRepository.save(targetRoom); - - return new ResponseEntity<>(targetRoom, HttpStatus.OK); - } - - // Obtener los detalles de una habitación específica en un hotel - @GetMapping("/{hotelId}/rooms/{roomId}") - public Room getRoomByIdFromHotel( - @PathVariable int hotelId, @PathVariable int roomId) { - return roomRepository.findByIdAndHotelId(roomId, hotelId) - .orElseThrow(() -> new HotelNotFoundException(hotelId)); - } -} diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/InvalidDateRangeException.java b/java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/InvalidDateRangeException.java deleted file mode 100644 index 5bddd4c9083a7dd7ca896f7af916dbd5f70aab09..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/InvalidDateRangeException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.uva.hotelService.Exceptions; - -public class InvalidDateRangeException extends RuntimeException { - public InvalidDateRangeException(String message) { - super(message); - } -} diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/InvalidRequestException.java b/java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/InvalidRequestException.java deleted file mode 100644 index cd714aa29347e661eff5099c835178a67f38a279..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/main/java/com/uva/hotelService/Exceptions/InvalidRequestException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.uva.hotelService.Exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(HttpStatus.BAD_REQUEST) -public class InvalidRequestException extends RuntimeException { - public InvalidRequestException(String message) { - super(message); - } -} diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/Models/Address.java b/java/services/hotels/src/main/java/com/uva/hotelService/Models/Address.java deleted file mode 100644 index 43bc9642cd9b75d8bd98ea135707e02be1749d04..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/main/java/com/uva/hotelService/Models/Address.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.uva.hotelService.Models; - -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.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToOne; -import jakarta.persistence.Table; - -@Entity -@Table(name = "addresses") -public class Address { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Basic(optional = false) - private int id; - - @Basic(optional = false) - @Column(name = "street_kind") - private String streetKind; - - @Basic(optional = false) - @Column(name = "street_name") - private String streetName; - - @Basic(optional = false) - private int number; - - @Basic(optional = false) - @Column(name = "post_code") - private String postCode; - - @Basic(optional = true) - @Column(name = "other_info") - private String otherInfo; - - @JsonIgnore - @OneToOne(mappedBy = "address", fetch = FetchType.EAGER, cascade = CascadeType.ALL) - private Hotel hotel; - - public Address() { - } - - public Address(String streetKind, String streetName, int number, String postCode, String otherInfo, Hotel hotel) { - setStreetKind(streetKind); - setStreetName(streetName); - setNumber(number); - setPostCode(postCode); - setOtherInfo(otherInfo); - setHotel(hotel); - } - - public int getId() { - return this.id; - } - - public void setId(int id) { - this.id = id; - } - - public String getStreetKind() { - return this.streetKind; - } - - public void setStreetKind(String streetKind) { - this.streetKind = streetKind; - } - - public String getStreetName() { - return this.streetName; - } - - public void setStreetName(String streetName) { - this.streetName = streetName; - } - - public int getNumber() { - return this.number; - } - - public void setNumber(int number) { - this.number = number; - } - - public String getPostCode() { - return this.postCode; - } - - public void setPostCode(String postCode) { - this.postCode = postCode; - } - - public String getOtherInfo() { - return this.otherInfo; - } - - public void setOtherInfo(String otherInfo) { - this.otherInfo = otherInfo; - } - - public Hotel getHotel() { - return this.hotel; - } - - public void setHotel(Hotel hotel) { - this.hotel = hotel; - } -} diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/Models/Hotel.java b/java/services/hotels/src/main/java/com/uva/hotelService/Models/Hotel.java deleted file mode 100644 index 672f8d8b74030707319b6d8368c0bb0f941d90e7..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/main/java/com/uva/hotelService/Models/Hotel.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.uva.hotelService.Models; - -import java.util.List; -import jakarta.persistence.Basic; -import jakarta.persistence.CascadeType; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.OneToMany; -import jakarta.persistence.OneToOne; -import jakarta.persistence.Table; - -@Entity -@Table(name = "hotels") -// @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, -// property = "id") -public class Hotel { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Basic(optional = false) - private int id; - - @Basic(optional = false) - private String name; - - @JoinColumn(name = "address_id", referencedColumnName = "id") - @OneToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER) - private Address address; - - @OneToMany(mappedBy = "hotel", fetch = FetchType.EAGER, cascade = CascadeType.ALL) - private List<Room> rooms; - - public Hotel() { - } - - public Hotel(int id, String name, Address address, List<Room> rooms) { - setId(id); - setName(name); - setAddress(address); - setRooms(rooms); - } - - 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 Address getAddress() { - return this.address; - } - - public void setAddress(Address address) { - this.address = address; - } - - public List<Room> getRooms() { - return this.rooms; - } - - public void setRooms(List<Room> rooms) { - this.rooms = rooms; - rooms.forEach(room -> room.setHotel(this)); - } - -} diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/Models/Room.java b/java/services/hotels/src/main/java/com/uva/hotelService/Models/Room.java deleted file mode 100644 index 0d09d6f81477c0331691c8e4b5e36ac58e0d0d24..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/main/java/com/uva/hotelService/Models/Room.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.uva.hotelService.Models; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; - -@Entity -@Table(name = "rooms") -// @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, -// property = "id") -public class Room { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Basic(optional = false) - private int id; - - @ManyToOne - @JoinColumn(name = "hotel_id", referencedColumnName = "id") - @JsonIgnore - private Hotel hotel; - @Column(name = "room_number", nullable = false) - private String roomNumber; - @Column(name = "type", nullable = false) - private Tipo type; - @Column(name = "available", nullable = false) - private boolean available; - - public Room() { - } - - public Room(int id, Hotel hotelId, String roomNumber, Tipo type, boolean available) { - this.id = id; - this.hotel = hotelId; - this.roomNumber = roomNumber; - this.type = type; - this.available = available; - } - - public void setId(int id) { - this.id = id; - } - - public int getId() { - return this.id; - } - - public void setHotel(Hotel hotelId) { - this.hotel = hotelId; - } - - public Hotel getHotel() { - return this.hotel; - } - - public void setRoomNumber(String roomNumber) { - this.roomNumber = roomNumber; - } - - public String getRoomNumber() { - return this.roomNumber; - } - - public void setType(Tipo type) { - this.type = type; - } - - public Tipo getType() { - return this.type; - } - - public void setAvailable(boolean available) { - this.available = available; - } - - public boolean isAvailable() { - return this.available; - } -} diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/Models/Tipo.java b/java/services/hotels/src/main/java/com/uva/hotelService/Models/Tipo.java deleted file mode 100644 index b893a7c4e5da3792e6de1d86972c8946d990f9da..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/main/java/com/uva/hotelService/Models/Tipo.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.uva.hotelService.Models; - -public enum Tipo { - SINGLE, - DOUBLE, - SUITE -} diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/Repositories/RoomRepository.java b/java/services/hotels/src/main/java/com/uva/hotelService/Repositories/RoomRepository.java deleted file mode 100644 index c84a86eb58035937dba9638933036196c2d1a470..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/main/java/com/uva/hotelService/Repositories/RoomRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.uva.hotelService.Repositories; - -import org.springframework.data.jpa.repository.JpaRepository; -import com.uva.hotelService.Models.Room; -import java.util.List; -import java.util.Optional; - -public interface RoomRepository extends JpaRepository<Room, Integer> { - - Optional<Room> findByIdAndHotelId(int id, int hotelId); - - List<Room> findAllByHotelId(int hotelId); - - List<Room> findAllByHotelIdAndAvailable(int hotelId, boolean available); -} diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/config/RestTemplateConfig.java b/java/services/hotels/src/main/java/com/uva/hotelService/config/RestTemplateConfig.java deleted file mode 100644 index 05af4ebcc1528bb428c9ac6022d61f109c7dc4d5..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/main/java/com/uva/hotelService/config/RestTemplateConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.uva.hotelService.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; - -@Configuration -public class RestTemplateConfig { - - @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); - } -} diff --git a/java/services/hotels/src/main/java/com/uva/hotelService/hotelServiceApplication.java b/java/services/hotels/src/main/java/com/uva/hotelService/hotelServiceApplication.java deleted file mode 100644 index 0068b98f3b84aa2f29a70339223880279ecb7e09..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/main/java/com/uva/hotelService/hotelServiceApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.uva.hotelService; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class hotelServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(hotelServiceApplication.class, args); - } - -} diff --git a/java/services/hotels/src/main/resources/application.properties b/java/services/hotels/src/main/resources/application.properties deleted file mode 100644 index 5021e2005773ae5544474798099ed2b72bb1edb4..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/main/resources/application.properties +++ /dev/null @@ -1,8 +0,0 @@ -spring.application.name=hotelService -server.port=8121 -spring.jpa.hibernate.ddl-auto=update -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect -spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/RoomsBooking?createDatabaseIfNotExist=true -spring.datasource.username=user -spring.datasource.password=password -spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver \ No newline at end of file diff --git a/java/services/hotels/src/test/java/com/uva/roomBooking/RoomBookingApplicationTests.java b/java/services/hotels/src/test/java/com/uva/roomBooking/RoomBookingApplicationTests.java deleted file mode 100644 index 3b50599492c36017391c0dcabd81573f123a809a..0000000000000000000000000000000000000000 --- a/java/services/hotels/src/test/java/com/uva/roomBooking/RoomBookingApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.uva.roomBooking; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class RoomBookingApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/java/services/launch.sh b/java/services/launch.sh deleted file mode 100644 index 7224e675de8f43307adc80214a8453266d140fbb..0000000000000000000000000000000000000000 --- a/java/services/launch.sh +++ /dev/null @@ -1,16 +0,0 @@ -#! /usr/bin/bash -servicesdir="$PWD" -pidfile=$servicesdir/servers.pid -echo "Pids of launch `date`" > $pidfile -for i in $(ls $servicesdir); do - if [ -d $servicesdir/$i ]; then - cd $servicesdir/$i - logfile="/tmp/debug_$i.log" - mvn spring-boot:run > $logfile & - pid=$! - # echo "El servicio se está ejecutando en segundo plano con PID: $pid" - # Opcionalmente, puedes guardar el PID en un archivo - echo "$i running in pid $pid" >> $pidfile - echo Launched $i service, view the log in $logfile - fi -done diff --git a/java/services/servers.pid b/java/services/servers.pid deleted file mode 100644 index 689f217b8da2a2b0f56e68aeeebb43cfa149e491..0000000000000000000000000000000000000000 --- a/java/services/servers.pid +++ /dev/null @@ -1,5 +0,0 @@ -Pids of launch dom 17 nov 2024 12:30:54 CET -auth running in pid 104539 -bookings running in pid 104540 -hotels running in pid 104541 -users running in pid 104542 diff --git a/java/services/stop-service.sh b/java/services/stop-service.sh deleted file mode 100644 index 87a710ea48416c38e6ccfada5a7fe6bb96bdb530..0000000000000000000000000000000000000000 --- a/java/services/stop-service.sh +++ /dev/null @@ -1,4 +0,0 @@ -for i in {0..30..10}; do - port=$((8101 + $i)) - kill `sudo lsof -t -i :$port` -done \ No newline at end of file diff --git a/java/services/users/.gitignore b/java/services/users/.gitignore deleted file mode 100644 index 549e00a2a96fa9d7c5dbc9859664a78d980158c2..0000000000000000000000000000000000000000 --- a/java/services/users/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ diff --git a/java/services/users/.mvn/wrapper/maven-wrapper.properties b/java/services/users/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index d58dfb70bab565a697e6854eb012d17e0fd39bd4..0000000000000000000000000000000000000000 --- a/java/services/users/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -wrapperVersion=3.3.2 -distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/java/services/users/Dockerfile b/java/services/users/Dockerfile deleted file mode 100644 index 8d0b79d6514534deddac782fc9367bcdbcaf89c3..0000000000000000000000000000000000000000 --- a/java/services/users/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM maven:3-openjdk-17 AS maven -WORKDIR /app -COPY ./ ./ -RUN mvn -Dmaven.test.skip clean package -FROM openjdk:17-jdk-oracle -ARG JAR_FILE=/app/target/*.jar -COPY --from=maven ${JAR_FILE} app.jar -ENV PORT 8080 -EXPOSE $PORT -ENTRYPOINT ["java","-jar", "/app.jar"] \ No newline at end of file diff --git a/java/services/users/mvnw b/java/services/users/mvnw deleted file mode 100755 index 19529ddf8c6eaa08c5c75ff80652d21ce4b72f8c..0000000000000000000000000000000000000000 --- a/java/services/users/mvnw +++ /dev/null @@ -1,259 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.2 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - if [ -n "${JAVA_HOME-}" ]; then - if [ -x "$JAVA_HOME/jre/sh/java" ]; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash> -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/java/services/users/mvnw.cmd b/java/services/users/mvnw.cmd deleted file mode 100644 index 249bdf3822221aa612d1da2605316cabd7b07e50..0000000000000000000000000000000000000000 --- a/java/services/users/mvnw.cmd +++ /dev/null @@ -1,149 +0,0 @@ -<# : batch portion -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.2 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash> -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' -$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" -if ($env:MAVEN_USER_HOME) { - $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" -} -$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/java/services/users/pom.xml b/java/services/users/pom.xml deleted file mode 100644 index e5ab046cdc0ae6ece6da29550f9df9fde7963bf1..0000000000000000000000000000000000000000 --- a/java/services/users/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-parent</artifactId> - <version>3.3.4</version> - <relativePath/> <!-- lookup parent from repository --> - </parent> - <groupId>com.uva</groupId> - <artifactId>usersService</artifactId> - <version>0.0.1-SNAPSHOT</version> - <name>usersService</name> - <description>Users microservice</description> - <url/> - <licenses> - <license/> - </licenses> - <developers> - <developer/> - </developers> - <scm> - <connection/> - <developerConnection/> - <tag/> - <url/> - </scm> - <properties> - <java.version>17</java.version> - </properties> - <dependencies> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-data-jpa</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-data-rest</artifactId> - </dependency> - - <dependency> - <groupId>com.mysql</groupId> - <artifactId>mysql-connector-j</artifactId> - <scope>runtime</scope> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-test</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - </plugin> - </plugins> - </build> - -</project> diff --git a/java/services/users/src/main/java/com/uva/users/Controllers/UserController.java b/java/services/users/src/main/java/com/uva/users/Controllers/UserController.java deleted file mode 100644 index 30274d83e081b0d39b701e3c711b63b2e06ee5eb..0000000000000000000000000000000000000000 --- a/java/services/users/src/main/java/com/uva/users/Controllers/UserController.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.uva.users.Controllers; - -import java.time.LocalDate; -import java.util.List; -import java.util.Map; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.http.HttpMethod; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestTemplate; -import org.springframework.core.ParameterizedTypeReference; - -import com.uva.users.Models.UserStatus; -import com.uva.users.Models.User; -import com.uva.users.Repositories.UserRepository; - -@RestController -@RequestMapping("users") -@CrossOrigin(origins = "*") - -public class UserController { - - private UserRepository userRepository; - @Autowired - private RestTemplate restTemplate; - - @GetMapping - public List<User> getAllUsers() { - return userRepository.findAll(); - } - - @PostMapping - public User addUser(@RequestBody User user) { - user.setStatus(UserStatus.NO_BOOKINGS); - return userRepository.save(user); - } - - @GetMapping("/{id}") - public User getUserById(@PathVariable int id) { - return userRepository.findById(id).orElseThrow(); - } - - @PutMapping("/{id}") - public User updateUserData(@PathVariable int id, @RequestBody Map<String, String> json) { - User target = userRepository.findById(id).orElseThrow(); - if (!json.containsKey("name") || !json.containsKey("email")) { - throw new RuntimeException("Missing required fields"); - } - target.setName(json.get("name")); - target.setEmail(json.get("email")); - return userRepository.save(target); - } - - @PatchMapping("/{id}") - public User updateUserState(@PathVariable int id, @RequestBody Map<String, String> json) { - User target = userRepository.findById(id).orElseThrow(); - String strStatus = json.get("status"); - if (strStatus == null) { - throw new RuntimeException("Missing required fields"); - } - UserStatus userStatus = UserStatus.valueOf(strStatus); - - // Consultar el microservicio de booking - ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange( - "http://booking-service/users/{id}/bookings", - HttpMethod.GET, - null, - new ParameterizedTypeReference<List<Map<String, Object>>>() {}, - id - ); - List<Map<String, Object>> bookings = response.getBody(); - - boolean activeBookings = bookings.stream() - .anyMatch(booking -> LocalDate.parse((String) booking.get("endDate")).isAfter(LocalDate.now())); - boolean inactiveBookings = bookings.stream() - .anyMatch(booking -> LocalDate.parse((String) booking.get("startDate")).isBefore(LocalDate.now())); - - switch (userStatus) { - case NO_BOOKINGS: - if (!bookings.isEmpty()) - throw new IllegalArgumentException("Invalid State: The user has at least one booking"); - break; - case WITH_ACTIVE_BOOKINGS: - if (bookings.isEmpty() || !activeBookings) - throw new IllegalArgumentException("Invalid State: The user doesn't have active bookings"); - break; - case WITH_INACTIVE_BOOKINGS: - if (bookings.isEmpty() || !inactiveBookings) - throw new IllegalArgumentException("Invalid State: The user doesn't have inactive bookings"); - break; - default: - break; - } - target.setStatus(userStatus); - return userRepository.save(target); - } - - @DeleteMapping("/{id}") - public User deleteUser(@PathVariable Integer id) { - User target = userRepository.findById(id).orElseThrow(); - userRepository.deleteById(id); - return target; - } - - @GetMapping("/{id}/bookings") - public List<Map<String, Object>> getUserBookingsById(@PathVariable int id) { - // Llamada al microservicio de reservas - ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange( - "http://booking-service/users/{id}/bookings", - HttpMethod.GET, - null, - new ParameterizedTypeReference<List<Map<String, Object>>>() {}, - id - ); - return response.getBody(); - } - - @GetMapping(params = "email") - public ResponseEntity<User> getUserByEmail(@RequestParam String email) { - return userRepository.findByEmail(email) - .map(ResponseEntity::ok) - .orElse(ResponseEntity.noContent().build()); -} - -} diff --git a/java/services/users/src/main/java/com/uva/users/Exceptions/InvalidRequestException.java b/java/services/users/src/main/java/com/uva/users/Exceptions/InvalidRequestException.java deleted file mode 100644 index 7b2712bccf3907b24cbbf6e664e5250865bb8064..0000000000000000000000000000000000000000 --- a/java/services/users/src/main/java/com/uva/users/Exceptions/InvalidRequestException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.uva.users.Exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(HttpStatus.BAD_REQUEST) -public class InvalidRequestException extends RuntimeException { - public InvalidRequestException(String message) { - super(message); - } -} diff --git a/java/services/users/src/main/java/com/uva/users/Models/User.java b/java/services/users/src/main/java/com/uva/users/Models/User.java deleted file mode 100644 index 455ef0282362759424cba7a75a3385073de48e4e..0000000000000000000000000000000000000000 --- a/java/services/users/src/main/java/com/uva/users/Models/User.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.uva.users.Models; - -import jakarta.persistence.Basic; -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.Table; -@Entity -@Table(name = "users") -public class User { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Basic(optional = false) - private int id; - - @Basic(optional = false) - private String name; - - @Basic(optional = false) - private String email; - - @Basic(optional = false) - @Enumerated(EnumType.STRING) - private UserStatus status = UserStatus.NO_BOOKINGS; - - @Basic (optional = false) - private String password; - - public User() { - } - - public User(int id, String name, String email, UserStatus status, String password) { - setId(id); - setName(name); - setEmail(email); - setStatus(status); - setPassword(password); - } - - // Getters y setters - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public UserStatus getStatus() { - return status; - } - - public void setStatus(UserStatus status) { - this.status = status; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } -} diff --git a/java/services/users/src/main/java/com/uva/users/UserServiceApplication.java b/java/services/users/src/main/java/com/uva/users/UserServiceApplication.java deleted file mode 100644 index 842ddd66f511f1c766c963b9604924a60919993b..0000000000000000000000000000000000000000 --- a/java/services/users/src/main/java/com/uva/users/UserServiceApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.uva.users; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class UserServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(UserServiceApplication.class, args); - } - -} diff --git a/java/services/users/src/main/java/com/uva/users/config/RestTemplateConfig.java b/java/services/users/src/main/java/com/uva/users/config/RestTemplateConfig.java deleted file mode 100644 index 9343721935b419c627937c713f56b64f40d894d1..0000000000000000000000000000000000000000 --- a/java/services/users/src/main/java/com/uva/users/config/RestTemplateConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.uva.users.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; - -@Configuration -public class RestTemplateConfig { - - @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); - } -} diff --git a/java/services/users/src/main/resources/application.properties b/java/services/users/src/main/resources/application.properties deleted file mode 100644 index f56d92d0392f20307e5c1cb9e27f16cfb2162ba2..0000000000000000000000000000000000000000 --- a/java/services/users/src/main/resources/application.properties +++ /dev/null @@ -1,11 +0,0 @@ -spring.application.name=userService -server.port=8111 -spring.jpa.hibernate.ddl-auto=update -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect -spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/RoomsBooking?createDatabaseIfNotExist=true -spring.datasource.username=user -spring.datasource.password=password -spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver - -# Usar esto para alternar entre las exposición del room repository ya que no es necesario su uso pero por defecto, al no cubrir su ruta, se expone -# spring.data.rest.base-path=false \ No newline at end of file diff --git a/java/services/users/src/test/java/com/uva/roomBooking/RoomBookingApplicationTests.java b/java/services/users/src/test/java/com/uva/roomBooking/RoomBookingApplicationTests.java deleted file mode 100644 index 3b50599492c36017391c0dcabd81573f123a809a..0000000000000000000000000000000000000000 --- a/java/services/users/src/test/java/com/uva/roomBooking/RoomBookingApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.uva.roomBooking; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class RoomBookingApplicationTests { - - @Test - void contextLoads() { - } - -}