se cambia a springboot mejor xd

This commit is contained in:
luis cespedes 2025-04-23 18:09:47 -04:00
parent a441cec5cb
commit ffd6b0710d
38 changed files with 883 additions and 1731 deletions

View File

@ -1,24 +1,28 @@
FROM maven:3.9-eclipse-temurin-21 AS build FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /app WORKDIR /app
COPY . .
# Compilar la aplicación sin ejecutar tests # Copy project dependencies
RUN mvn package -DskipTests COPY pom.xml .
COPY src ./src
FROM registry.access.redhat.com/ubi8/openjdk-21-runtime:latest # Build the project
RUN mvn clean package -DskipTests
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app WORKDIR /app
COPY --from=build /app/target/quarkus-app /app/
# Puerto que expondrá la aplicación # Create uploads directory
RUN mkdir -p /app/uploads
# Copy built jar
COPY --from=build /app/target/*.jar app.jar
# Copy initial images
COPY uploads /app/uploads
# Setting environment variables
ENV SPRING_PROFILES_ACTIVE=prod
EXPOSE 8080 EXPOSE 8080
# Variables de entorno para configuración de DB y perfil ENTRYPOINT ["java", "-jar", "app.jar"]
ENV QUARKUS_PROFILE="prod" \
QUARKUS_DATASOURCE_USERNAME=${DB_USERNAME} \
QUARKUS_DATASOURCE_PASSWORD=${DB_PASSWORD} \
QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://${POSTGRESSHOST}:${POSTGRESSPORT}/${POSTGRESSDATABASE}
# Comando para iniciar la aplicación
CMD ["java", "-Dquarkus.profile=${QUARKUS_PROFILE}", "-jar", "quarkus-run.jar"]

112
README.md
View File

@ -1,93 +1,65 @@
# gym-backend # Gym Backend (Spring Boot)
This project uses Quarkus, the Supersonic Subatomic Java Framework. A Spring Boot backend application for a gym management system. This application provides RESTful APIs for managing users, gym classes and bookings.
If you want to learn more about Quarkus, please visit its website: <https://quarkus.io/>. ## Requirements
## Running the application in dev mode - Java 17 or higher
- Maven 3.8+
- PostgreSQL
You can run your application in dev mode that enables live coding using: ## Getting Started
```shell script ### Running Locally
./mvnw quarkus:dev
1. Clone the repository
2. Configure PostgreSQL database (default credentials in application.properties)
3. Run the application:
```bash
mvn spring-boot:run
``` ```
> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at <http://localhost:8080/q/dev/>. The application will start at http://localhost:8080
## Packaging and running the application ### Using Docker
The application can be packaged using: 1. Build the Docker image:
```shell script ```bash
./mvnw package docker build -t gym-backend .
``` ```
It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory. 2. Run the container:
Be aware that its not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory.
The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`. ```bash
docker run -p 8080:8080 gym-backend
If you want to build an _über-jar_, execute the following command:
```shell script
./mvnw package -Dquarkus.package.jar.type=uber-jar
``` ```
The application, packaged as an _über-jar_, is now runnable using `java -jar target/*-runner.jar`. ## API Endpoints
## Creating a native executable ### Users
You can create a native executable using: - `GET /api/users`: Get all users
- `GET /api/users/{id}`: Get user by ID
- `POST /api/users`: Create new user
- `PUT /api/users/{id}`: Update user
```shell script ### Gym Classes
./mvnw package -Dnative
```
Or, if you don't have GraalVM installed, you can run the native executable build in a container using: - `GET /api/classes`: Get all classes
- `GET /api/classes/{id}`: Get class by ID
- `POST /api/classes`: Create new class
- `PUT /api/classes/{id}`: Update class
- `DELETE /api/classes/{id}`: Delete class
```shell script ### Bookings
./mvnw package -Dnative -Dquarkus.native.container-build=true
```
You can then execute your native executable with: `./target/gym-backend-1.0.0-SNAPSHOT-runner` - `GET /api/bookings`: Get all bookings
- `GET /api/bookings/user/{userId}`: Get bookings by user ID
- `POST /api/bookings`: Create new booking
- `PUT /api/bookings/{id}/cancel`: Cancel booking
If you want to learn more about building native executables, please consult <https://quarkus.io/guides/maven-tooling>. ### File Upload
## Related Guides - `POST /api/upload`: Upload files (for profile pictures and class images)
- Picocli ([guide](https://quarkus.io/guides/picocli)): Develop command line applications with Picocli
- RESTEasy Classic Multipart ([guide](https://quarkus.io/guides/rest-json#multipart-support)): Multipart support for RESTEasy Classic
- Hibernate ORM with Panache ([guide](https://quarkus.io/guides/hibernate-orm-panache)): Simplify your persistence code for Hibernate ORM via the active record or the repository pattern
- SmallRye JWT ([guide](https://quarkus.io/guides/security-jwt)): Secure your applications with JSON Web Token
- JDBC Driver - PostgreSQL ([guide](https://quarkus.io/guides/datasource)): Connect to the PostgreSQL database via JDBC
## Provided Code
### Hibernate ORM
Create your first JPA entity
[Related guide section...](https://quarkus.io/guides/hibernate-orm)
[Related Hibernate with Panache section...](https://quarkus.io/guides/hibernate-orm-panache)
### Picocli Example
Hello and goodbye are civilization fundamentals. Let's not forget it with this example picocli application by changing the <code>command</code> and <code>parameters</code>.
[Related guide section...](https://quarkus.io/guides/picocli#command-line-application-with-multiple-commands)
Also for picocli applications the dev mode is supported. When running dev mode, the picocli application is executed and on press of the Enter key, is restarted.
As picocli applications will often require arguments to be passed on the commandline, this is also possible in dev mode via:
```shell script
./mvnw quarkus:dev -Dquarkus.args='Quarky'
```
### RESTEasy JAX-RS
Easily start your RESTful Web Services
[Related guide section...](https://quarkus.io/guides/getting-started#the-jax-rs-resources)

332
mvnw vendored
View File

@ -1,332 +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
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ]; then
if [ -f /usr/local/etc/mavenrc ]; then
. /usr/local/etc/mavenrc
fi
if [ -f /etc/mavenrc ]; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ]; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false
darwin=false
mingw=false
case "$(uname)" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true ;;
Darwin*)
darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
JAVA_HOME="$(/usr/libexec/java_home)"
export JAVA_HOME
else
JAVA_HOME="/Library/Java/Home"
export JAVA_HOME
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ]; then
if [ -r /etc/gentoo-release ]; then
JAVA_HOME=$(java-config --jre-home)
fi
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin; then
[ -n "$JAVA_HOME" ] \
&& JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
[ -n "$CLASSPATH" ] \
&& CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw; then
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] \
&& JAVA_HOME="$(
cd "$JAVA_HOME" || (
echo "cannot cd into $JAVA_HOME." >&2
exit 1
)
pwd
)"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="$(which javac)"
if [ -n "$javaExecutable" ] && ! [ "$(expr "$javaExecutable" : '\([^ ]*\)')" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=$(which readlink)
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
if $darwin; then
javaHome="$(dirname "$javaExecutable")"
javaExecutable="$(cd "$javaHome" && pwd -P)/javac"
else
javaExecutable="$(readlink -f "$javaExecutable")"
fi
javaHome="$(dirname "$javaExecutable")"
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ]; then
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"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="$(
\unset -f command 2>/dev/null
\command -v java
)"
fi
fi
if [ ! -x "$JAVACMD" ]; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ]; then
echo "Warning: JAVA_HOME environment variable is not set." >&2
fi
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]; then
echo "Path not specified to find_maven_basedir" >&2
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ]; do
if [ -d "$wdir"/.mvn ]; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=$(
cd "$wdir/.." || exit 1
pwd
)
fi
# end of workaround
done
printf '%s' "$(
cd "$basedir" || exit 1
pwd
)"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
# Remove \r in case we run on Windows within Git Bash
# and check out the repository with auto CRLF management
# enabled. Otherwise, we may read lines that are delimited with
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
# splitting rules.
tr -s '\r\n' ' ' <"$1"
fi
}
log() {
if [ "$MVNW_VERBOSE" = true ]; then
printf '%s\n' "$1"
fi
}
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
if [ -z "$BASE_DIR" ]; then
exit 1
fi
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
export MAVEN_PROJECTBASEDIR
log "$MAVEN_PROJECTBASEDIR"
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
if [ -r "$wrapperJarPath" ]; then
log "Found $wrapperJarPath"
else
log "Couldn't find $wrapperJarPath, downloading it ..."
if [ -n "$MVNW_REPOURL" ]; then
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
else
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
fi
while IFS="=" read -r key value; do
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
safeValue=$(echo "$value" | tr -d '\r')
case "$key" in wrapperUrl)
wrapperUrl="$safeValue"
break
;;
esac
done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
log "Downloading from: $wrapperUrl"
if $cygwin; then
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
fi
if command -v wget >/dev/null; then
log "Found wget ... using wget"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl >/dev/null; then
log "Found curl ... using curl"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
else
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
fi
else
log "Falling back to using Java to download"
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaSource=$(cygpath --path --windows "$javaSource")
javaClass=$(cygpath --path --windows "$javaClass")
fi
if [ -e "$javaSource" ]; then
if [ ! -e "$javaClass" ]; then
log " - Compiling MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/javac" "$javaSource")
fi
if [ -e "$javaClass" ]; then
log " - Running MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
wrapperSha256Sum=""
while IFS="=" read -r key value; do
case "$key" in wrapperSha256Sum)
wrapperSha256Sum=$value
break
;;
esac
done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
if [ -n "$wrapperSha256Sum" ]; then
wrapperSha256Result=false
if command -v sha256sum >/dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c >/dev/null 2>&1; then
wrapperSha256Result=true
fi
elif command -v shasum >/dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c >/dev/null 2>&1; then
wrapperSha256Result=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 'wrapperSha256Sum' from your maven-wrapper.properties." >&2
exit 1
fi
if [ $wrapperSha256Result = false ]; then
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
exit 1
fi
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$JAVA_HOME" ] \
&& JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
[ -n "$CLASSPATH" ] \
&& CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
[ -n "$MAVEN_PROJECTBASEDIR" ] \
&& MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
# shellcheck disable=SC2086 # safe args
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

206
mvnw.cmd vendored
View File

@ -1,206 +0,0 @@
@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 Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo. >&2
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo. >&2
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo. >&2
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo. >&2
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %WRAPPER_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
SET WRAPPER_SHA_256_SUM=""
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
)
IF NOT %WRAPPER_SHA_256_SUM%=="" (
powershell -Command "&{"^
"Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash;"^
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
" Write-Error 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
" Write-Error 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
" Write-Error 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
" exit 1;"^
"}"^
"}"
if ERRORLEVEL 1 goto error
)
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %WRAPPER_JAR% ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%

139
pom.xml
View File

@ -1,81 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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"> 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> <modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.valposystems</groupId> <groupId>com.valposystems</groupId>
<artifactId>gym-backend</artifactId> <artifactId>gym-backend</artifactId>
<version>1.0.0-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<name>gym-backend</name>
<description>Gym backend application</description>
<properties> <properties>
<compiler-plugin.version>3.11.0</compiler-plugin.version> <java.version>17</java.version>
<maven.compiler.release>11</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.6.3</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.2.2</surefire-plugin.version>
</properties> </properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>quarkus-arc</artifactId> <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>quarkus-resteasy</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId> <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>org.projectlombok</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId> <artifactId>lombok</artifactId>
<optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId> <artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-multipart</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-picocli</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jaxb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-undertow</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@ -83,52 +50,18 @@
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>${quarkus.platform.group-id}</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>quarkus-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration> <configuration>
<parameters>true</parameters> <excludes>
</configuration> <exclude>
</plugin> <groupId>org.projectlombok</groupId>
<plugin> <artifactId>lombok</artifactId>
<artifactId>maven-surefire-plugin</artifactId> </exclude>
<version>${surefire-plugin.version}</version> </excludes>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<skipITs>false</skipITs>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
</project> </project>

View File

@ -1,98 +0,0 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
#
# Before building the container image run:
#
# ./mvnw package
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/gym-backend-jvm .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/gym-backend-jvm
#
# If you want to include the debug port into your docker image
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
# when running the container
#
# Then run the container using :
#
# docker run -i --rm -p 8080:8080 quarkus/gym-backend-jvm
#
# This image uses the `run-java.sh` script to run the application.
# This scripts computes the command line to execute your Java application, and
# includes memory/GC tuning.
# You can configure the behavior using the following environment properties:
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") - Be aware that this will override
# the default JVM options, use `JAVA_OPTS_APPEND` to append options
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
# in JAVA_OPTS (example: "-Dsome.property=foo")
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
# used to calculate a default maximal heap memory based on a containers restriction.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
# of the container available memory as set here. The default is `50` which means 50%
# of the available memory is used as an upper boundary. You can skip this mechanism by
# setting this value to `0` in which case no `-Xmx` option is added.
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
# is used to calculate a default initial heap memory based on the maximum heap memory.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
# is used as the initial heap size. You can skip this mechanism by setting this value
# to `0` in which case no `-Xms` option is added (example: "25")
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
# This is used to calculate the maximum value of the initial heap memory. If used in
# a container without any memory constraints for the container then this option has
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
# here. The default is 4096MB which means the calculated value of `-Xms` never will
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
# when things are happening. This option, if set to true, will set
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
# true").
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
# (example: "20")
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
# (example: "40")
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
# (example: "4")
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
# previous GC times. (example: "90")
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
# contain the necessary JRE command-line options to specify the required GC, which
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
# accessed directly. (example: "foo.example.com,bar.example.com")
#
###
FROM registry.access.redhat.com/ubi9/openjdk-21:1.21
ENV LANGUAGE='en_US:en'
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]

View File

@ -1,94 +0,0 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
#
# Before building the container image run:
#
# ./mvnw package -Dquarkus.package.jar.type=legacy-jar
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/gym-backend-legacy-jar .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/gym-backend-legacy-jar
#
# If you want to include the debug port into your docker image
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
# when running the container
#
# Then run the container using :
#
# docker run -i --rm -p 8080:8080 quarkus/gym-backend-legacy-jar
#
# This image uses the `run-java.sh` script to run the application.
# This scripts computes the command line to execute your Java application, and
# includes memory/GC tuning.
# You can configure the behavior using the following environment properties:
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") - Be aware that this will override
# the default JVM options, use `JAVA_OPTS_APPEND` to append options
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
# in JAVA_OPTS (example: "-Dsome.property=foo")
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
# used to calculate a default maximal heap memory based on a containers restriction.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
# of the container available memory as set here. The default is `50` which means 50%
# of the available memory is used as an upper boundary. You can skip this mechanism by
# setting this value to `0` in which case no `-Xmx` option is added.
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
# is used to calculate a default initial heap memory based on the maximum heap memory.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
# is used as the initial heap size. You can skip this mechanism by setting this value
# to `0` in which case no `-Xms` option is added (example: "25")
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
# This is used to calculate the maximum value of the initial heap memory. If used in
# a container without any memory constraints for the container then this option has
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
# here. The default is 4096MB which means the calculated value of `-Xms` never will
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
# when things are happening. This option, if set to true, will set
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
# true").
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
# (example: "20")
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
# (example: "40")
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
# (example: "4")
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
# previous GC times. (example: "90")
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
# contain the necessary JRE command-line options to specify the required GC, which
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
# accessed directly. (example: "foo.example.com,bar.example.com")
#
###
FROM registry.access.redhat.com/ubi9/openjdk-21:1.21
ENV LANGUAGE='en_US:en'
COPY target/lib/* /deployments/lib/
COPY target/*-runner.jar /deployments/quarkus-run.jar
EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]

View File

@ -1,29 +0,0 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
#
# Before building the container image run:
#
# ./mvnw package -Dnative
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.native -t quarkus/gym-backend .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/gym-backend
#
# The ` registry.access.redhat.com/ubi8/ubi-minimal:8.10` base image is based on UBI 9.
# To use UBI 8, switch to `quay.io/ubi8/ubi-minimal:8.10`.
###
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.10
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root --chmod=0755 target/*-runner /work/application
EXPOSE 8080
USER 1001
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]

View File

@ -1,32 +0,0 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
# It uses a micro base image, tuned for Quarkus native executables.
# It reduces the size of the resulting container image.
# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image.
#
# Before building the container image run:
#
# ./mvnw package -Dnative
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/gym-backend .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/gym-backend
#
# The `quay.io/quarkus/quarkus-micro-image:2.0` base image is based on UBI 9.
# To use UBI 8, switch to `quay.io/quarkus/quarkus-micro-image:2.0`.
###
FROM quay.io/quarkus/quarkus-micro-image:2.0
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root --chmod=0755 target/*-runner /work/application
EXPOSE 8080
USER 1001
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]

View File

@ -1,18 +1,34 @@
package com.valposystems; package com.valposystems;
import io.quarkus.runtime.Quarkus; import org.springframework.boot.SpringApplication;
import io.quarkus.runtime.QuarkusApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import io.quarkus.runtime.annotations.QuarkusMain; import org.springframework.context.annotation.Bean;
import jakarta.enterprise.context.ApplicationScoped; import org.springframework.web.cors.CorsConfiguration;
import org.jboss.logging.Logger; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@QuarkusMain import java.util.Arrays;
@SpringBootApplication
public class GymApplication { public class GymApplication {
private static final Logger LOG = Logger.getLogger(GymApplication.class); public static void main(String[] args) {
SpringApplication.run(GymApplication.class, args);
public static void main(String... args) { }
LOG.info("Iniciando aplicación Gym Backend...");
Quarkus.run(args); @Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
corsConfiguration.setAllowedHeaders(Arrays.asList("Origin", "Access-Control-Allow-Origin", "Content-Type",
"Accept", "Authorization", "Origin, Accept", "X-Requested-With",
"Access-Control-Request-Method", "Access-Control-Request-Headers"));
corsConfiguration.setExposedHeaders(Arrays.asList("Origin", "Content-Type", "Accept", "Authorization",
"Access-Control-Allow-Origin", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials", "Content-Disposition"));
corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
} }
} }

View File

@ -0,0 +1,83 @@
package com.valposystems.controller;
import com.valposystems.dto.BookingDTO;
import com.valposystems.service.BookingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/bookings")
@CrossOrigin
public class BookingController {
private static final Logger logger = LoggerFactory.getLogger(BookingController.class);
private final BookingService bookingService;
@Autowired
public BookingController(BookingService bookingService) {
this.bookingService = bookingService;
}
@GetMapping
public ResponseEntity<List<BookingDTO>> getAllBookings() {
try {
List<BookingDTO> bookings = bookingService.getAllBookings();
return ResponseEntity.ok(bookings);
} catch (Exception e) {
logger.error("Error getting bookings", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@GetMapping("/user/{userId}")
public ResponseEntity<List<BookingDTO>> getBookingsByUserId(@PathVariable Long userId) {
try {
List<BookingDTO> bookings = bookingService.getBookingsByUserId(userId);
return ResponseEntity.ok(bookings);
} catch (Exception e) {
logger.error("Error getting bookings for user: {}", userId, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@PostMapping
public ResponseEntity<?> createBooking(@RequestBody BookingDTO dto) {
try {
BookingDTO created = bookingService.createBooking(dto);
if (created == null) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body("{\"message\": \"No spots available or the user/class doesn't exist\"}");
}
return ResponseEntity.status(HttpStatus.CREATED).body(created);
} catch (Exception e) {
logger.error("Error creating booking", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("{\"error\": \"" + e.getMessage() + "\"}");
}
}
@PutMapping("/{id}/cancel")
public ResponseEntity<?> cancelBooking(@PathVariable Long id) {
try {
BookingDTO cancelled = bookingService.cancelBooking(id);
if (cancelled == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("{\"message\": \"The booking doesn't exist or isn't in confirmed state\"}");
}
return ResponseEntity.ok(cancelled);
} catch (Exception e) {
logger.error("Error cancelling booking with ID: {}", id, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("{\"error\": \"" + e.getMessage() + "\"}");
}
}
}

View File

@ -0,0 +1,96 @@
package com.valposystems.controller;
import com.valposystems.dto.GymClassDTO;
import com.valposystems.service.GymClassService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/classes")
@CrossOrigin
public class GymClassController {
private static final Logger logger = LoggerFactory.getLogger(GymClassController.class);
private final GymClassService gymClassService;
@Autowired
public GymClassController(GymClassService gymClassService) {
this.gymClassService = gymClassService;
}
@GetMapping
public ResponseEntity<List<GymClassDTO>> getAllClasses() {
try {
List<GymClassDTO> classes = gymClassService.getAllClasses();
return ResponseEntity.ok(classes);
} catch (Exception e) {
logger.error("Error getting classes", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@GetMapping("/{id}")
public ResponseEntity<GymClassDTO> getClassById(@PathVariable Long id) {
try {
GymClassDTO gymClass = gymClassService.getClassById(id);
if (gymClass == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(gymClass);
} catch (Exception e) {
logger.error("Error getting class with ID: {}", id, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@PostMapping
public ResponseEntity<GymClassDTO> createClass(@RequestBody GymClassDTO dto) {
try {
GymClassDTO created = gymClassService.createClass(dto);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
} catch (Exception e) {
logger.error("Error creating class", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@PutMapping("/{id}")
public ResponseEntity<GymClassDTO> updateClass(@PathVariable Long id, @RequestBody GymClassDTO dto) {
try {
GymClassDTO updated = gymClassService.updateClass(id, dto);
if (updated == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(updated);
} catch (Exception e) {
logger.error("Error updating class with ID: {}", id, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteClass(@PathVariable Long id) {
try {
boolean deleted = gymClassService.deleteClass(id);
if (!deleted) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.noContent().build();
} catch (Exception e) {
logger.error("Error deleting class with ID: {}", id, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.build();
}
}
}

View File

@ -0,0 +1,76 @@
package com.valposystems.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
@RestController
@RequestMapping("/api/upload")
@CrossOrigin
public class UploadController {
private static final Logger logger = LoggerFactory.getLogger(UploadController.class);
@Value("${app.upload.dir:uploads}")
private String uploadDir;
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> uploadFile(@RequestParam("file") MultipartFile file) {
try {
logger.info("Receiving file upload request");
if (file.isEmpty()) {
logger.warn("No file provided");
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body("{\"error\":\"No file uploaded\"}");
}
// Create directory if it doesn't exist
File directory = new File(uploadDir);
if (!directory.exists()) {
directory.mkdirs();
logger.info("Upload directory created: {}", directory.getAbsolutePath());
}
// Get file extension
String originalFilename = file.getOriginalFilename();
String extension = "";
if (originalFilename != null && originalFilename.contains(".")) {
extension = originalFilename.substring(originalFilename.lastIndexOf("."));
} else {
extension = ".jpg";
}
// Generate unique filename
String fileName = UUID.randomUUID().toString() + extension;
Path filePath = Paths.get(uploadDir, fileName);
logger.info("Saving file as: {}", filePath);
// Save file
Files.copy(file.getInputStream(), filePath);
// Return file URL
String fileUrl = "/uploads/" + fileName;
logger.info("File uploaded successfully. URL: {}", fileUrl);
return ResponseEntity.ok("{\"url\":\"" + fileUrl + "\"}");
} catch (IOException e) {
logger.error("Error uploading file", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("{\"error\":\"" + e.getMessage() + "\"}");
}
}
}

View File

@ -0,0 +1,89 @@
package com.valposystems.controller;
import com.valposystems.dto.UserDTO;
import com.valposystems.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
@CrossOrigin
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public ResponseEntity<List<UserDTO>> getAllUsers() {
try {
logger.info("Getting all users");
List<UserDTO> users = userService.getAllUsers();
return ResponseEntity.ok(users);
} catch (Exception e) {
logger.error("Error getting users", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUserById(@PathVariable Long id) {
try {
logger.info("Getting user with ID: {}", id);
UserDTO user = userService.getUserById(id);
if (user == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(user);
} catch (Exception e) {
logger.error("Error getting user with ID: {}", id, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@PostMapping
public ResponseEntity<?> createUser(@RequestBody UserDTO dto) {
try {
logger.info("Creating new user: {}", dto.getEmail());
UserDTO created = userService.createUser(dto);
if (created == null) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body("{\"message\": \"A user with that email already exists\"}");
}
return ResponseEntity.status(HttpStatus.CREATED).body(created);
} catch (Exception e) {
logger.error("Error creating user", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("{\"error\": \"" + e.getMessage() + "\"}");
}
}
@PutMapping("/{id}")
public ResponseEntity<UserDTO> updateUser(@PathVariable Long id, @RequestBody UserDTO dto) {
try {
logger.info("Updating user with ID: {}", id);
UserDTO updated = userService.updateUser(id, dto);
if (updated == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(updated);
} catch (Exception e) {
logger.error("Error updating user with ID: {}", id, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
}

View File

@ -1,31 +1,34 @@
package com.valposystems.dto; package com.valposystems.dto;
import com.valposystems.model.Booking; import com.valposystems.model.Booking;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BookingDTO { public class BookingDTO {
public Long id; private Long id;
public Long userId; private Long userId;
public String userName; private String userName;
public Long classId; private Long classId;
public String className; private String className;
public LocalDateTime bookingDate; private LocalDateTime bookingDate;
public String status; private String status;
public BookingDTO() {
}
public static BookingDTO from(Booking booking) { public static BookingDTO from(Booking booking) {
BookingDTO dto = new BookingDTO(); BookingDTO dto = new BookingDTO();
dto.id = booking.id; dto.setId(booking.getId());
dto.userId = booking.user.id; dto.setUserId(booking.getUser().getId());
dto.userName = booking.user.name; dto.setUserName(booking.getUser().getName());
dto.classId = booking.gymClass.id; dto.setClassId(booking.getGymClass().getId());
dto.className = booking.gymClass.name; dto.setClassName(booking.getGymClass().getName());
dto.bookingDate = booking.bookingDate; dto.setBookingDate(booking.getBookingDate());
dto.status = booking.status; dto.setStatus(booking.getStatus());
return dto; return dto;
} }
} }

View File

@ -1,37 +1,40 @@
package com.valposystems.dto; package com.valposystems.dto;
import com.valposystems.model.GymClass; import com.valposystems.model.GymClass;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GymClassDTO { public class GymClassDTO {
public Long id; private Long id;
public String name; private String name;
public String description; private String description;
public String instructor; private String instructor;
public LocalDateTime startTime; private LocalDateTime startTime;
public LocalDateTime endTime; private LocalDateTime endTime;
public int maxCapacity; private int maxCapacity;
public int currentBookings; private int currentBookings;
public String category; private String category;
public String imageUrl; private String imageUrl;
public GymClassDTO() {
}
public static GymClassDTO from(GymClass gymClass) { public static GymClassDTO from(GymClass gymClass) {
GymClassDTO dto = new GymClassDTO(); GymClassDTO dto = new GymClassDTO();
dto.id = gymClass.id; dto.setId(gymClass.getId());
dto.name = gymClass.name; dto.setName(gymClass.getName());
dto.description = gymClass.description; dto.setDescription(gymClass.getDescription());
dto.instructor = gymClass.instructor; dto.setInstructor(gymClass.getInstructor());
dto.startTime = gymClass.startTime; dto.setStartTime(gymClass.getStartTime());
dto.endTime = gymClass.endTime; dto.setEndTime(gymClass.getEndTime());
dto.maxCapacity = gymClass.maxCapacity; dto.setMaxCapacity(gymClass.getMaxCapacity());
dto.currentBookings = gymClass.currentBookings; dto.setCurrentBookings(gymClass.getCurrentBookings());
dto.category = gymClass.category; dto.setCategory(gymClass.getCategory());
dto.imageUrl = gymClass.imageUrl; dto.setImageUrl(gymClass.getImageUrl());
return dto; return dto;
} }
} }

View File

@ -1,25 +1,28 @@
package com.valposystems.dto; package com.valposystems.dto;
import com.valposystems.model.User; import com.valposystems.model.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO { public class UserDTO {
public Long id; private Long id;
public String name; private String name;
public String email; private String email;
public String profilePicUrl; private String profilePicUrl;
public boolean notificationsEnabled; private boolean notificationsEnabled;
public UserDTO() {
}
public static UserDTO from(User user) { public static UserDTO from(User user) {
UserDTO dto = new UserDTO(); UserDTO dto = new UserDTO();
dto.id = user.id; dto.setId(user.getId());
dto.name = user.name; dto.setName(user.getName());
dto.email = user.email; dto.setEmail(user.getEmail());
dto.profilePicUrl = user.profilePicUrl; dto.setProfilePicUrl(user.getProfilePicUrl());
dto.notificationsEnabled = user.notificationsEnabled; dto.setNotificationsEnabled(user.isNotificationsEnabled());
return dto; return dto;
} }
} }

View File

@ -1,30 +1,33 @@
package com.valposystems.model; package com.valposystems.model;
import io.quarkus.hibernate.orm.panache.PanacheEntity; import jakarta.persistence.*;
import jakarta.persistence.Entity; import lombok.AllArgsConstructor;
import jakarta.persistence.ManyToOne; import lombok.Data;
import jakarta.persistence.Table; import lombok.NoArgsConstructor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@Entity @Entity
@Table(name = "bookings") @Table(name = "bookings")
public class Booking extends PanacheEntity { @Data
@NoArgsConstructor
@AllArgsConstructor
public class Booking {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne @ManyToOne
public User user; private User user;
@ManyToOne @ManyToOne
public GymClass gymClass; private GymClass gymClass;
public LocalDateTime bookingDate; private LocalDateTime bookingDate;
public String status; // 'confirmed', 'cancelled', 'pending' private String status; // 'confirmed', 'cancelled', 'pending'
// Constructor vacío requerido por JPA
public Booking() {
}
// Constructor para inicialización más sencilla
public Booking(User user, GymClass gymClass, LocalDateTime bookingDate, String status) { public Booking(User user, GymClass gymClass, LocalDateTime bookingDate, String status) {
this.user = user; this.user = user;
this.gymClass = gymClass; this.gymClass = gymClass;

View File

@ -1,41 +1,45 @@
package com.valposystems.model; package com.valposystems.model;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import jakarta.persistence.Column; import jakarta.persistence.*;
import jakarta.persistence.Entity; import lombok.AllArgsConstructor;
import jakarta.persistence.Table; import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@Entity @Entity
@Table(name = "gym_classes") @Table(name = "gym_classes")
public class GymClass extends PanacheEntity { @Data
@NoArgsConstructor
@AllArgsConstructor
public class GymClass {
public String name; @Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public String description; private String name;
public String instructor; private String description;
public LocalDateTime startTime; private String instructor;
public LocalDateTime endTime; private LocalDateTime startTime;
public int maxCapacity; private LocalDateTime endTime;
public int currentBookings; private int maxCapacity;
public String category; private int currentBookings;
public String imageUrl; private String category;
// Constructor vacío requerido por JPA private String imageUrl;
public GymClass() {
}
// Constructor para inicialización más sencilla
public GymClass(String name, String description, String instructor, public GymClass(String name, String description, String instructor,
LocalDateTime startTime, LocalDateTime endTime, LocalDateTime startTime, LocalDateTime endTime,
int maxCapacity, int currentBookings, int maxCapacity, int currentBookings,
String category, String imageUrl) { String category, String imageUrl) {
this.name = name; this.name = name;
this.description = description; this.description = description;
this.instructor = instructor; this.instructor = instructor;

View File

@ -1,30 +1,32 @@
package com.valposystems.model; package com.valposystems.model;
import io.quarkus.hibernate.orm.panache.PanacheEntity; import jakarta.persistence.*;
import jakarta.persistence.Column; import lombok.AllArgsConstructor;
import jakarta.persistence.Entity; import lombok.Data;
import jakarta.persistence.Table; import lombok.NoArgsConstructor;
@Entity @Entity
@Table(name = "users") @Table(name = "users")
public class User extends PanacheEntity { @Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
public String name; @Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@Column(unique = true) @Column(unique = true)
public String email; private String email;
public String password; private String password;
public String profilePicUrl; private String profilePicUrl;
public boolean notificationsEnabled; private boolean notificationsEnabled;
// Constructor vacío requerido por JPA
public User() {
}
// Constructor para inicialización más sencilla
public User(String name, String email, String password, String profilePicUrl, boolean notificationsEnabled) { public User(String name, String email, String password, String profilePicUrl, boolean notificationsEnabled) {
this.name = name; this.name = name;
this.email = email; this.email = email;

View File

@ -0,0 +1,12 @@
package com.valposystems.repository;
import com.valposystems.model.Booking;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface BookingRepository extends JpaRepository<Booking, Long> {
List<Booking> findByUserId(Long userId);
}

View File

@ -0,0 +1,9 @@
package com.valposystems.repository;
import com.valposystems.model.GymClass;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface GymClassRepository extends JpaRepository<GymClass, Long> {
}

View File

@ -0,0 +1,13 @@
package com.valposystems.repository;
import com.valposystems.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
boolean existsByEmail(String email);
Optional<User> findByEmail(String email);
}

View File

@ -1,75 +0,0 @@
package com.valposystems.resource;
import com.valposystems.dto.BookingDTO;
import com.valposystems.service.BookingService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.util.List;
@ApplicationScoped
@Path("/api/bookings")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class BookingResource {
@Inject
BookingService bookingService;
@GET
@Transactional
public Response getAllBookings() {
try {
List<BookingDTO> bookings = bookingService.getAllBookings();
return Response.ok(bookings).build();
} catch (Exception e) {
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
@GET
@Path("/user/{userId}")
@Transactional
public Response getBookingsByUserId(@PathParam("userId") Long userId) {
try {
List<BookingDTO> bookings = bookingService.getBookingsByUserId(userId);
return Response.ok(bookings).build();
} catch (Exception e) {
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
@POST
@Transactional
public Response createBooking(BookingDTO dto) {
try {
BookingDTO created = bookingService.createBooking(dto);
if (created == null) {
return Response.status(Response.Status.CONFLICT)
.entity("{\"message\": \"No hay plazas disponibles o el usuario/clase no existe\"}").build();
}
return Response.status(Response.Status.CREATED).entity(created).build();
} catch (Exception e) {
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
@PUT
@Path("/{id}/cancel")
@Transactional
public Response cancelBooking(@PathParam("id") Long id) {
try {
BookingDTO cancelled = bookingService.cancelBooking(id);
if (cancelled == null) {
return Response.status(Response.Status.NOT_FOUND)
.entity("{\"message\": \"La reserva no existe o no está en estado confirmado\"}").build();
}
return Response.ok(cancelled).build();
} catch (Exception e) {
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
}

View File

@ -1,88 +0,0 @@
package com.valposystems.resource;
import com.valposystems.dto.GymClassDTO;
import com.valposystems.service.GymClassService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.util.List;
@ApplicationScoped
@Path("/api/classes")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class GymClassResource {
@Inject
GymClassService gymClassService;
@GET
@Transactional
public Response getAllClasses() {
try {
List<GymClassDTO> classes = gymClassService.getAllClasses();
return Response.ok(classes).build();
} catch (Exception e) {
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
@GET
@Path("/{id}")
@Transactional
public Response getClassById(@PathParam("id") Long id) {
try {
GymClassDTO gymClass = gymClassService.getClassById(id);
if (gymClass == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return Response.ok(gymClass).build();
} catch (Exception e) {
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
@POST
@Transactional
public Response createClass(GymClassDTO dto) {
try {
GymClassDTO created = gymClassService.createClass(dto);
return Response.status(Response.Status.CREATED).entity(created).build();
} catch (Exception e) {
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
@PUT
@Path("/{id}")
@Transactional
public Response updateClass(@PathParam("id") Long id, GymClassDTO dto) {
try {
GymClassDTO updated = gymClassService.updateClass(id, dto);
if (updated == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return Response.ok(updated).build();
} catch (Exception e) {
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
@DELETE
@Path("/{id}")
@Transactional
public Response deleteClass(@PathParam("id") Long id) {
try {
boolean deleted = gymClassService.deleteClass(id);
if (!deleted) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return Response.noContent().build();
} catch (Exception e) {
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
}

View File

@ -1,102 +0,0 @@
package com.valposystems.resource;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;
import org.jboss.logging.Logger;
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@ApplicationScoped
@Path("/api/upload")
public class UploadResource {
private static final Logger LOG = Logger.getLogger(UploadResource.class);
private static final String UPLOAD_DIR = "uploads";
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public Response uploadFile(MultipartFormDataInput input) {
try {
LOG.info("Recibiendo solicitud de carga de archivo");
// Obtener los InputPart del mapa (no directamente InputStream)
Map<String, List<InputPart>> formDataMap = input.getFormDataMap();
List<InputPart> inputParts = formDataMap.get("file");
if (inputParts == null || inputParts.isEmpty()) {
LOG.warn("No se ha proporcionado ningún archivo");
return Response.status(Response.Status.BAD_REQUEST)
.entity("{\"error\":\"No file uploaded\"}").build();
}
// Obtener el InputPart y convertirlo a InputStream
InputPart inputPart = inputParts.get(0);
InputStream fileInputStream = inputPart.getBody(InputStream.class, null);
// Crear directorio si no existe
File directory = new File(UPLOAD_DIR);
if (!directory.exists()) {
directory.mkdirs();
LOG.info("Directorio de subida creado: " + directory.getAbsolutePath());
}
// Obtener información del archivo
MultivaluedMap<String, String> headers = inputPart.getHeaders();
String fileName = UUID.randomUUID().toString() + getFileExtension(headers);
String filePath = UPLOAD_DIR + "/" + fileName;
LOG.info("Guardando archivo como: " + filePath);
// Guardar archivo
Files.copy(
fileInputStream,
Paths.get(filePath),
StandardCopyOption.REPLACE_EXISTING
);
// Devolver URL del archivo subido
String fileUrl = "/uploads/" + fileName;
LOG.info("Archivo subido exitosamente. URL: " + fileUrl);
return Response.ok("{\"url\":\"" + fileUrl + "\"}").build();
} catch (IOException e) {
LOG.error("Error al subir archivo", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("{\"error\":\"" + e.getMessage() + "\"}").build();
}
}
private String getFileExtension(MultivaluedMap<String, String> headers) {
String contentDisposition = headers.getFirst("Content-Disposition");
if (contentDisposition != null) {
for (String part : contentDisposition.split(";")) {
if (part.trim().startsWith("filename")) {
String fileName = part.substring(part.indexOf('=') + 1).trim().replace("\"", "");
int dot = fileName.lastIndexOf('.');
if (dot > 0) {
return fileName.substring(dot);
}
break;
}
}
}
return ".jpg";
}
}

View File

@ -1,88 +0,0 @@
package com.valposystems.resource;
import com.valposystems.dto.UserDTO;
import com.valposystems.service.UserService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.jboss.logging.Logger;
import java.util.List;
@ApplicationScoped
@Path("/api/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource {
private static final Logger LOG = Logger.getLogger(UserResource.class);
@Inject
UserService userService;
@GET
@Transactional
public Response getAllUsers() {
try {
LOG.info("Obteniendo todos los usuarios");
List<UserDTO> users = userService.getAllUsers();
return Response.ok(users).build();
} catch (Exception e) {
LOG.error("Error al obtener usuarios", e);
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
@GET
@Path("/{id}")
@Transactional
public Response getUserById(@PathParam("id") Long id) {
try {
LOG.info("Obteniendo usuario con ID: " + id);
UserDTO user = userService.getUserById(id);
if (user == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return Response.ok(user).build();
} catch (Exception e) {
LOG.error("Error al obtener usuario con ID: " + id, e);
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
@POST
@Transactional
public Response createUser(UserDTO dto) {
try {
LOG.info("Creando nuevo usuario: " + dto.email);
UserDTO created = userService.createUser(dto);
if (created == null) {
return Response.status(Response.Status.CONFLICT)
.entity("{\"message\": \"Ya existe un usuario con ese email\"}").build();
}
return Response.status(Response.Status.CREATED).entity(created).build();
} catch (Exception e) {
LOG.error("Error al crear usuario", e);
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
@PUT
@Path("/{id}")
@Transactional
public Response updateUser(@PathParam("id") Long id, UserDTO dto) {
try {
LOG.info("Actualizando usuario con ID: " + id);
UserDTO updated = userService.updateUser(id, dto);
if (updated == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return Response.ok(updated).build();
} catch (Exception e) {
LOG.error("Error al actualizar usuario con ID: " + id, e);
return Response.serverError().entity("Error: " + e.getMessage()).build();
}
}
}

View File

@ -4,76 +4,97 @@ import com.valposystems.dto.BookingDTO;
import com.valposystems.model.Booking; import com.valposystems.model.Booking;
import com.valposystems.model.GymClass; import com.valposystems.model.GymClass;
import com.valposystems.model.User; import com.valposystems.model.User;
import jakarta.enterprise.context.ApplicationScoped; import com.valposystems.repository.BookingRepository;
import jakarta.transaction.Transactional; import com.valposystems.repository.GymClassRepository;
import com.valposystems.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ApplicationScoped @Service
public class BookingService { public class BookingService {
private final BookingRepository bookingRepository;
private final UserRepository userRepository;
private final GymClassRepository gymClassRepository;
@Autowired
public BookingService(
BookingRepository bookingRepository,
UserRepository userRepository,
GymClassRepository gymClassRepository) {
this.bookingRepository = bookingRepository;
this.userRepository = userRepository;
this.gymClassRepository = gymClassRepository;
}
public List<BookingDTO> getAllBookings() { public List<BookingDTO> getAllBookings() {
return Booking.listAll().stream() return bookingRepository.findAll().stream()
.map(b -> BookingDTO.from((Booking) b)) .map(BookingDTO::from)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public List<BookingDTO> getBookingsByUserId(Long userId) { public List<BookingDTO> getBookingsByUserId(Long userId) {
List<Booking> bookings = Booking.list("user.id", userId); return bookingRepository.findByUserId(userId).stream()
return bookings.stream() .map(BookingDTO::from)
.map(booking -> BookingDTO.from(booking))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Transactional @Transactional
public BookingDTO createBooking(BookingDTO dto) { public BookingDTO createBooking(BookingDTO dto) {
User user = User.findById(dto.userId); User user = userRepository.findById(dto.getUserId()).orElse(null);
GymClass gymClass = GymClass.findById(dto.classId); GymClass gymClass = gymClassRepository.findById(dto.getClassId()).orElse(null);
if (user == null || gymClass == null) { if (user == null || gymClass == null) {
return null; return null;
} }
// Verificar disponibilidad // Check availability
if (gymClass.currentBookings >= gymClass.maxCapacity) { if (gymClass.getCurrentBookings() >= gymClass.getMaxCapacity()) {
return null; return null;
} }
// Crear la reserva // Create booking
Booking booking = new Booking(); Booking booking = new Booking();
booking.user = user; booking.setUser(user);
booking.gymClass = gymClass; booking.setGymClass(gymClass);
booking.bookingDate = LocalDateTime.now(); booking.setBookingDate(LocalDateTime.now());
booking.status = "confirmed"; booking.setStatus("confirmed");
// Actualizar contador de la clase // Update class counter
gymClass.currentBookings++; gymClass.setCurrentBookings(gymClass.getCurrentBookings() + 1);
gymClassRepository.save(gymClass);
booking.persist();
booking = bookingRepository.save(booking);
return BookingDTO.from(booking); return BookingDTO.from(booking);
} }
@Transactional @Transactional
public BookingDTO cancelBooking(Long id) { public BookingDTO cancelBooking(Long id) {
Booking booking = Booking.findById(id); Booking booking = bookingRepository.findById(id).orElse(null);
if (booking == null) { if (booking == null) {
return null; return null;
} }
// Solo se pueden cancelar reservas confirmadas // Only confirmed bookings can be cancelled
if (!booking.status.equals("confirmed")) { if (!"confirmed".equals(booking.getStatus())) {
return null; return null;
} }
booking.status = "cancelled"; booking.setStatus("cancelled");
// Actualizar contador de la clase // Update class counter
GymClass gymClass = booking.gymClass; GymClass gymClass = booking.getGymClass();
gymClass.currentBookings--; gymClass.setCurrentBookings(gymClass.getCurrentBookings() - 1);
gymClassRepository.save(gymClass);
booking = bookingRepository.save(booking);
return BookingDTO.from(booking); return BookingDTO.from(booking);
} }
} }

View File

@ -2,75 +2,78 @@ package com.valposystems.service;
import com.valposystems.dto.GymClassDTO; import com.valposystems.dto.GymClassDTO;
import com.valposystems.model.GymClass; import com.valposystems.model.GymClass;
import jakarta.enterprise.context.ApplicationScoped; import com.valposystems.repository.GymClassRepository;
import jakarta.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ApplicationScoped @Service
public class GymClassService { public class GymClassService {
private final GymClassRepository gymClassRepository;
@Autowired
public GymClassService(GymClassRepository gymClassRepository) {
this.gymClassRepository = gymClassRepository;
}
public List<GymClassDTO> getAllClasses() { public List<GymClassDTO> getAllClasses() {
return GymClass.listAll().stream() return gymClassRepository.findAll().stream()
.map(c -> GymClassDTO.from((GymClass) c)) .map(GymClassDTO::from)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public GymClassDTO getClassById(Long id) { public GymClassDTO getClassById(Long id) {
GymClass gymClass = GymClass.findById(id); return gymClassRepository.findById(id)
if (gymClass == null) { .map(GymClassDTO::from)
return null; .orElse(null);
}
return GymClassDTO.from(gymClass);
} }
@Transactional @Transactional
public GymClassDTO createClass(GymClassDTO dto) { public GymClassDTO createClass(GymClassDTO dto) {
GymClass gymClass = new GymClass(); GymClass gymClass = new GymClass();
gymClass.name = dto.name; gymClass.setName(dto.getName());
gymClass.description = dto.description; gymClass.setDescription(dto.getDescription());
gymClass.instructor = dto.instructor; gymClass.setInstructor(dto.getInstructor());
gymClass.startTime = dto.startTime; gymClass.setStartTime(dto.getStartTime());
gymClass.endTime = dto.endTime; gymClass.setEndTime(dto.getEndTime());
gymClass.maxCapacity = dto.maxCapacity; gymClass.setMaxCapacity(dto.getMaxCapacity());
gymClass.currentBookings = dto.currentBookings; gymClass.setCurrentBookings(dto.getCurrentBookings());
gymClass.category = dto.category; gymClass.setCategory(dto.getCategory());
gymClass.imageUrl = dto.imageUrl; gymClass.setImageUrl(dto.getImageUrl());
gymClass.persist(); gymClass = gymClassRepository.save(gymClass);
return GymClassDTO.from(gymClass); return GymClassDTO.from(gymClass);
} }
@Transactional @Transactional
public GymClassDTO updateClass(Long id, GymClassDTO dto) { public GymClassDTO updateClass(Long id, GymClassDTO dto) {
GymClass gymClass = GymClass.findById(id); return gymClassRepository.findById(id)
if (gymClass == null) { .map(gymClass -> {
return null; gymClass.setName(dto.getName());
} gymClass.setDescription(dto.getDescription());
gymClass.setInstructor(dto.getInstructor());
gymClass.name = dto.name; gymClass.setStartTime(dto.getStartTime());
gymClass.description = dto.description; gymClass.setEndTime(dto.getEndTime());
gymClass.instructor = dto.instructor; gymClass.setMaxCapacity(dto.getMaxCapacity());
gymClass.startTime = dto.startTime; gymClass.setCurrentBookings(dto.getCurrentBookings());
gymClass.endTime = dto.endTime; gymClass.setCategory(dto.getCategory());
gymClass.maxCapacity = dto.maxCapacity; gymClass.setImageUrl(dto.getImageUrl());
gymClass.currentBookings = dto.currentBookings; return GymClassDTO.from(gymClassRepository.save(gymClass));
gymClass.category = dto.category; })
gymClass.imageUrl = dto.imageUrl; .orElse(null);
return GymClassDTO.from(gymClass);
} }
@Transactional @Transactional
public boolean deleteClass(Long id) { public boolean deleteClass(Long id) {
GymClass gymClass = GymClass.findById(id); if (gymClassRepository.existsById(id)) {
if (gymClass == null) { gymClassRepository.deleteById(id);
return false; return true;
} }
return false;
gymClass.delete();
return true;
} }
} }

View File

@ -2,59 +2,64 @@ package com.valposystems.service;
import com.valposystems.dto.UserDTO; import com.valposystems.dto.UserDTO;
import com.valposystems.model.User; import com.valposystems.model.User;
import jakarta.enterprise.context.ApplicationScoped; import com.valposystems.repository.UserRepository;
import jakarta.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ApplicationScoped @Service
public class UserService { public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public List<UserDTO> getAllUsers() { public List<UserDTO> getAllUsers() {
return User.listAll().stream() return userRepository.findAll().stream()
.map(u -> UserDTO.from((User) u)) .map(UserDTO::from)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public UserDTO getUserById(Long id) { public UserDTO getUserById(Long id) {
User user = User.findById(id); return userRepository.findById(id)
if (user == null) { .map(UserDTO::from)
return null; .orElse(null);
}
return UserDTO.from(user);
} }
@Transactional @Transactional
public UserDTO createUser(UserDTO dto) { public UserDTO createUser(UserDTO dto) {
// Verificar si ya existe un usuario con ese email // Check if a user with that email already exists
if (User.count("email", dto.email) > 0) { if (userRepository.existsByEmail(dto.getEmail())) {
return null; return null;
} }
User user = new User(); User user = new User();
user.name = dto.name; user.setName(dto.getName());
user.email = dto.email; user.setEmail(dto.getEmail());
user.password = "password123"; // En una app real, esto se encriptaría user.setPassword("password123"); // In a real app, this would be encrypted
user.profilePicUrl = dto.profilePicUrl; user.setProfilePicUrl(dto.getProfilePicUrl());
user.notificationsEnabled = dto.notificationsEnabled; user.setNotificationsEnabled(dto.isNotificationsEnabled());
user.persist(); user = userRepository.save(user);
return UserDTO.from(user); return UserDTO.from(user);
} }
@Transactional @Transactional
public UserDTO updateUser(Long id, UserDTO dto) { public UserDTO updateUser(Long id, UserDTO dto) {
User user = User.findById(id); return userRepository.findById(id)
if (user == null) { .map(user -> {
return null; user.setName(dto.getName());
} user.setProfilePicUrl(dto.getProfilePicUrl());
user.setNotificationsEnabled(dto.isNotificationsEnabled());
user.name = dto.name; return UserDTO.from(userRepository.save(user));
user.profilePicUrl = dto.profilePicUrl; })
user.notificationsEnabled = dto.notificationsEnabled; .orElse(null);
return UserDTO.from(user);
} }
} }

View File

@ -2,108 +2,121 @@ package com.valposystems.util;
import com.valposystems.model.GymClass; import com.valposystems.model.GymClass;
import com.valposystems.model.User; import com.valposystems.model.User;
import io.quarkus.runtime.StartupEvent; import com.valposystems.repository.GymClassRepository;
import jakarta.enterprise.context.ApplicationScoped; import com.valposystems.repository.UserRepository;
import jakarta.enterprise.event.Observes; import org.slf4j.Logger;
import jakarta.transaction.Transactional; import org.slf4j.LoggerFactory;
import org.jboss.logging.Logger; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ApplicationScoped @Component
public class DataLoader { public class DataLoader implements CommandLineRunner {
private static final Logger LOG = Logger.getLogger(DataLoader.class); private static final Logger logger = LoggerFactory.getLogger(DataLoader.class);
private final UserRepository userRepository;
private final GymClassRepository gymClassRepository;
@Autowired
public DataLoader(UserRepository userRepository, GymClassRepository gymClassRepository) {
this.userRepository = userRepository;
this.gymClassRepository = gymClassRepository;
}
@Override
@Transactional @Transactional
public void loadData(@Observes StartupEvent evt) { public void run(String... args) {
LOG.info("Verificando si es necesario cargar datos iniciales..."); logger.info("Checking if initial data needs to be loaded...");
// Verificar si ya hay datos // Check if data already exists
if (GymClass.count() > 0 || User.count() > 0) { if (gymClassRepository.count() > 0 || userRepository.count() > 0) {
LOG.info("Ya existen datos en la base de datos, no se cargarán datos iniciales"); logger.info("Data already exists in the database, will not load initial data");
return; return;
} }
LOG.info("Cargando datos iniciales..."); logger.info("Loading initial data...");
// Crear usuario demo // Create demo user
User demoUser = new User( User demoUser = new User(
"Usuario Demo", "Demo User",
"usuario@ejemplo.com", "user@example.com",
"password123", "password123",
"/uploads/default-avatar.jpg", "/uploads/default-avatar.jpg",
true true
); );
demoUser.persist(); userRepository.save(demoUser);
LOG.info("Usuario demo creado con ID: " + demoUser.id); logger.info("Demo user created with ID: {}", demoUser.getId());
// Crear clases de ejemplo // Create example classes
GymClass yoga = new GymClass( GymClass yoga = new GymClass(
"Yoga", "Yoga",
"Clase de yoga para todos los niveles", "Yoga class for all levels",
"María López", "María López",
LocalDateTime.now().plusDays(1).withHour(8).withMinute(0), LocalDateTime.now().plusDays(1).withHour(8).withMinute(0),
LocalDateTime.now().plusDays(1).withHour(9).withMinute(0), LocalDateTime.now().plusDays(1).withHour(9).withMinute(0),
15, 15,
8, 8,
"Mente y Cuerpo", "Mind and Body",
"/uploads/yoga.png" "/uploads/yoga.png"
); );
yoga.persist(); gymClassRepository.save(yoga);
GymClass spinning = new GymClass( GymClass spinning = new GymClass(
"Spinning", "Spinning",
"Clase de alta intensidad de ciclismo estático", "High intensity static cycling class",
"Juan Pérez", "Juan Pérez",
LocalDateTime.now().plusDays(1).withHour(10).withMinute(0), LocalDateTime.now().plusDays(1).withHour(10).withMinute(0),
LocalDateTime.now().plusDays(1).withHour(11).withMinute(0), LocalDateTime.now().plusDays(1).withHour(11).withMinute(0),
20, 20,
15, 15,
"Cardiovascular", "Cardio",
"/uploads/spinning.png" "/uploads/spinning.png"
); );
spinning.persist(); gymClassRepository.save(spinning);
GymClass pilates = new GymClass( GymClass pilates = new GymClass(
"Pilates", "Pilates",
"Fortalecimiento de core y flexibilidad", "Core strength and flexibility",
"Ana García", "Ana García",
LocalDateTime.now().plusDays(1).withHour(16).withMinute(0), LocalDateTime.now().plusDays(1).withHour(16).withMinute(0),
LocalDateTime.now().plusDays(1).withHour(17).withMinute(0), LocalDateTime.now().plusDays(1).withHour(17).withMinute(0),
12, 12,
5, 5,
"Mente y Cuerpo", "Mind and Body",
"/uploads/pilates.png" "/uploads/pilates.png"
); );
pilates.persist(); gymClassRepository.save(pilates);
GymClass zumba = new GymClass( GymClass zumba = new GymClass(
"Zumba", "Zumba",
"Baile y ejercicio cardiovascular", "Dance and cardiovascular exercise",
"Carlos Martínez", "Carlos Martínez",
LocalDateTime.now().plusDays(2).withHour(18).withMinute(0), LocalDateTime.now().plusDays(2).withHour(18).withMinute(0),
LocalDateTime.now().plusDays(2).withHour(19).withMinute(0), LocalDateTime.now().plusDays(2).withHour(19).withMinute(0),
25, 25,
18, 18,
"Baile", "Dance",
"/uploads/zumba.png" "/uploads/zumba.png"
); );
zumba.persist(); gymClassRepository.save(zumba);
GymClass crossfit = new GymClass( GymClass crossfit = new GymClass(
"CrossFit", "CrossFit",
"Entrenamiento funcional de alta intensidad", "High intensity functional training",
"Roberto Sánchez", "Roberto Sánchez",
LocalDateTime.now().plusDays(2).withHour(9).withMinute(0), LocalDateTime.now().plusDays(2).withHour(9).withMinute(0),
LocalDateTime.now().plusDays(2).withHour(10).withMinute(0), LocalDateTime.now().plusDays(2).withHour(10).withMinute(0),
15, 15,
12, 12,
"Fuerza", "Strength",
"/uploads/crossfit.png" "/uploads/crossfit.png"
); );
crossfit.persist(); gymClassRepository.save(crossfit);
LOG.info("Se han cargado " + GymClass.count() + " clases de ejemplo"); logger.info("Loaded {} example classes", gymClassRepository.count());
} }
} }

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
version="3.0" bean-discovery-mode="all">
</beans>

View File

@ -0,0 +1,13 @@
# Production profile configuration
spring.datasource.url=${SPRING_DATASOURCE_URL:jdbc:postgresql://db:5432/gymdb}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME:postgres}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD:postgres}
spring.datasource.driver-class-name=org.postgresql.Driver
# JPA/Hibernate
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=false
# Server
server.port=8080
server.address=0.0.0.0

View File

@ -1,40 +0,0 @@
# Configuración de la base de datos
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=${DB_USERNAME}
quarkus.datasource.password=${DB_PASSWORD}
quarkus.datasource.jdbc.url=jdbc:postgresql://${POSTGRESSHOST}:${POSTGRESSPORT}/{POSTGRESSDATABASE}
# Configuración de Hibernate ORM
quarkus.hibernate-orm.database.generation=update
quarkus.hibernate-orm.log.sql=true
quarkus.hibernate-orm.jdbc.statement-batch-size=20
# Configuración CORS para permitir peticiones desde nuestra app Ionic
quarkus.http.cors=true
quarkus.http.cors.origins=*
quarkus.http.cors.methods=GET,POST,PUT,DELETE,OPTIONS
quarkus.http.cors.headers=Content-Type,Authorization
quarkus.http.cors.exposed-headers=Content-Disposition
quarkus.http.cors.access-control-max-age=24H
# Configuración para archivos estáticos
quarkus.http.body.uploads-directory=uploads
quarkus.http.body.handle-file-uploads=true
quarkus.http.static.path=/uploads
quarkus.http.static.dir=uploads
# Configuración de logging
quarkus.log.console.enable=true
quarkus.log.console.format=%d{HH:mm:ss} %-5p [%c{2.}] (%t) %s%e%n
quarkus.log.console.level=INFO
quarkus.log.category."org.hibernate".level=INFO
quarkus.log.category."io.quarkus.arc".level=INFO
# Configuración de JSON binding
quarkus.jackson.write-dates-as-timestamps=false
quarkus.jackson.fail-on-unknown-properties=false
# Configuración CDI
quarkus.arc.remove-unused-beans=false
# Server host

View File

@ -1,41 +1,41 @@
# Configuración de la base de datos # Database Configuration
quarkus.datasource.db-kind=postgresql spring.datasource.url=jdbc:postgresql://localhost:5432/gymdb
quarkus.datasource.username=postgres spring.datasource.username=postgres
quarkus.datasource.password=postgres spring.datasource.password=postgres
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/gymdb spring.datasource.driver-class-name=org.postgresql.Driver
# Configuración de Hibernate ORM # JPA / Hibernate
quarkus.hibernate-orm.database.generation=update spring.jpa.hibernate.ddl-auto=update
quarkus.hibernate-orm.log.sql=true spring.jpa.show-sql=true
quarkus.hibernate-orm.jdbc.statement-batch-size=20 spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.jdbc.batch_size=20
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
# Configuración CORS para permitir peticiones desde nuestra app Ionic # Web
quarkus.http.cors=true spring.servlet.multipart.max-file-size=10MB
quarkus.http.cors.origins=* spring.servlet.multipart.max-request-size=10MB
quarkus.http.cors.methods=GET,POST,PUT,DELETE,OPTIONS
quarkus.http.cors.headers=Content-Type,Authorization
quarkus.http.cors.exposed-headers=Content-Disposition
quarkus.http.cors.access-control-max-age=24H
# Configuración para archivos estáticos # File storage
quarkus.http.body.uploads-directory=uploads app.upload.dir=uploads
quarkus.http.body.handle-file-uploads=true spring.web.resources.static-locations=file:uploads/
quarkus.http.static.path=/uploads
quarkus.http.static.dir=uploads
# Configuración de logging # Jackson JSON
quarkus.log.console.enable=true spring.jackson.serialization.write-dates-as-timestamps=false
quarkus.log.console.format=%d{HH:mm:ss} %-5p [%c{2.}] (%t) %s%e%n spring.jackson.deserialization.fail-on-unknown-properties=false
quarkus.log.console.level=INFO
quarkus.log.category."org.hibernate".level=INFO
quarkus.log.category."io.quarkus.arc".level=INFO
# Configuración de JSON binding # Logging
quarkus.jackson.write-dates-as-timestamps=false logging.level.root=INFO
quarkus.jackson.fail-on-unknown-properties=false logging.level.org.hibernate=INFO
logging.level.org.springframework.web=INFO
logging.pattern.console=%d{HH:mm:ss} %-5level [%logger{36}] - %msg%n
# Configuración CDI # Server
quarkus.arc.remove-unused-beans=false server.port=8080
server.address=0.0.0.0
# Server host # CORS
quarkus.http.host=0.0.0.0 spring.web.cors.allowed-origins=*
spring.web.cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS
spring.web.cors.allowed-headers=Content-Type,Authorization
spring.web.cors.exposed-headers=Content-Disposition
spring.web.cors.max-age=3600

View File

@ -1,6 +0,0 @@
-- This file allow to write SQL commands that will be emitted in test and dev.
-- The commands are commented as their support depends of the database
-- insert into myentity (id, field) values(1, 'field-1');
-- insert into myentity (id, field) values(2, 'field-2');
-- insert into myentity (id, field) values(3, 'field-3');
-- alter sequence myentity_seq restart with 4;

View File

@ -1,8 +0,0 @@
package com.valposystems;
import io.quarkus.test.junit.QuarkusIntegrationTest;
@QuarkusIntegrationTest
class GreetingResourceIT extends GreetingResourceTest {
// Execute the same tests but in packaged mode.
}

View File

@ -1,20 +0,0 @@
package com.valposystems;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
class GreetingResourceTest {
@Test
void testHelloEndpoint() {
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("Hello RESTEasy"));
}
}