importacion de app de github KevinOlarte1(User)
This commit is contained in:
commit
4121c7b930
|
|
@ -0,0 +1,11 @@
|
||||||
|
#Database configuration
|
||||||
|
SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/resident
|
||||||
|
SPRING_DATASOURCE_USERNAME=
|
||||||
|
SPRING_DATASOURCE_PASSWORD=
|
||||||
|
|
||||||
|
#JWT secret Key
|
||||||
|
JWT_SECRET_KEY=VGhpcyBpcyBhIHZlcnkgc2VjdXJlIHNlY3JldCBrZXkgZm9yIEpXVC4uLg==
|
||||||
|
|
||||||
|
#Mail properties
|
||||||
|
SUPPORT_EMAIL=ktrabajo870@gmail.com
|
||||||
|
APP_PASSWORD=bhqu vpzu oxuy lntp
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
/mvnw text eol=lf
|
||||||
|
*.cmd text eol=crlf
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
wrapperVersion=3.3.2
|
||||||
|
distributionType=only-script
|
||||||
|
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Proyecto Fundación Residencia Benissa
|
||||||
|
|
||||||
|
### Parte Backend de la aplicación, API REST.
|
||||||
|
|
@ -0,0 +1,259 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Apache Maven Wrapper startup batch script, version 3.3.2
|
||||||
|
#
|
||||||
|
# Optional ENV vars
|
||||||
|
# -----------------
|
||||||
|
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
|
||||||
|
# MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
set -euf
|
||||||
|
[ "${MVNW_VERBOSE-}" != debug ] || set -x
|
||||||
|
|
||||||
|
# OS specific support.
|
||||||
|
native_path() { printf %s\\n "$1"; }
|
||||||
|
case "$(uname)" in
|
||||||
|
CYGWIN* | MINGW*)
|
||||||
|
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
|
||||||
|
native_path() { cygpath --path --windows "$1"; }
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# set JAVACMD and JAVACCMD
|
||||||
|
set_java_home() {
|
||||||
|
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
|
||||||
|
if [ -n "${JAVA_HOME-}" ]; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
JAVACCMD="$JAVA_HOME/jre/sh/javac"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
JAVACCMD="$JAVA_HOME/bin/javac"
|
||||||
|
|
||||||
|
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
|
||||||
|
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
|
||||||
|
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v java
|
||||||
|
)" || :
|
||||||
|
JAVACCMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v javac
|
||||||
|
)" || :
|
||||||
|
|
||||||
|
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
|
||||||
|
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# hash string like Java String::hashCode
|
||||||
|
hash_string() {
|
||||||
|
str="${1:-}" h=0
|
||||||
|
while [ -n "$str" ]; do
|
||||||
|
char="${str%"${str#?}"}"
|
||||||
|
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
|
||||||
|
str="${str#?}"
|
||||||
|
done
|
||||||
|
printf %x\\n $h
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose() { :; }
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf %s\\n "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
trim() {
|
||||||
|
# MWRAPPER-139:
|
||||||
|
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
||||||
|
# Needed for removing poorly interpreted newline sequences when running in more
|
||||||
|
# exotic environments such as mingw bash on Windows.
|
||||||
|
printf "%s" "${1}" | tr -d '[:space:]'
|
||||||
|
}
|
||||||
|
|
||||||
|
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
while IFS="=" read -r key value; do
|
||||||
|
case "${key-}" in
|
||||||
|
distributionUrl) distributionUrl=$(trim "${value-}") ;;
|
||||||
|
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
|
||||||
|
esac
|
||||||
|
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
|
||||||
|
case "${distributionUrl##*/}" in
|
||||||
|
maven-mvnd-*bin.*)
|
||||||
|
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
|
||||||
|
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
|
||||||
|
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
|
||||||
|
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
|
||||||
|
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
|
||||||
|
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
|
||||||
|
*)
|
||||||
|
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
|
||||||
|
distributionPlatform=linux-amd64
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
|
||||||
|
;;
|
||||||
|
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
|
||||||
|
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
distributionUrlNameMain="${distributionUrlName%.*}"
|
||||||
|
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
|
||||||
|
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
|
||||||
|
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
|
||||||
|
|
||||||
|
exec_maven() {
|
||||||
|
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
|
||||||
|
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -d "$MAVEN_HOME" ]; then
|
||||||
|
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
exec_maven "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${distributionUrl-}" in
|
||||||
|
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
|
||||||
|
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
|
||||||
|
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
|
||||||
|
trap clean HUP INT TERM EXIT
|
||||||
|
else
|
||||||
|
die "cannot create temp dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p -- "${MAVEN_HOME%/*}"
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
verbose "Downloading from: $distributionUrl"
|
||||||
|
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
# select .zip or .tar.gz
|
||||||
|
if ! command -v unzip >/dev/null; then
|
||||||
|
distributionUrl="${distributionUrl%.zip}.tar.gz"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# verbose opt
|
||||||
|
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
|
||||||
|
|
||||||
|
# normalize http auth
|
||||||
|
case "${MVNW_PASSWORD:+has-password}" in
|
||||||
|
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
|
||||||
|
verbose "Found wget ... using wget"
|
||||||
|
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
|
||||||
|
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
|
||||||
|
verbose "Found curl ... using curl"
|
||||||
|
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
|
||||||
|
elif set_java_home; then
|
||||||
|
verbose "Falling back to use Java to download"
|
||||||
|
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
|
||||||
|
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
cat >"$javaSource" <<-END
|
||||||
|
public class Downloader extends java.net.Authenticator
|
||||||
|
{
|
||||||
|
protected java.net.PasswordAuthentication getPasswordAuthentication()
|
||||||
|
{
|
||||||
|
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
|
||||||
|
}
|
||||||
|
public static void main( String[] args ) throws Exception
|
||||||
|
{
|
||||||
|
setDefault( new Downloader() );
|
||||||
|
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END
|
||||||
|
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
|
||||||
|
verbose " - Compiling Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
|
||||||
|
verbose " - Running Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
if [ -n "${distributionSha256Sum-}" ]; then
|
||||||
|
distributionSha256Result=false
|
||||||
|
if [ "$MVN_CMD" = mvnd.sh ]; then
|
||||||
|
echo "Checksum validation is not supported for maven-mvnd." >&2
|
||||||
|
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
elif command -v sha256sum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
elif command -v shasum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
||||||
|
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ $distributionSha256Result = false ]; then
|
||||||
|
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
|
||||||
|
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
if command -v unzip >/dev/null; then
|
||||||
|
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
|
||||||
|
else
|
||||||
|
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
|
||||||
|
fi
|
||||||
|
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
|
||||||
|
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
|
||||||
|
|
||||||
|
clean || :
|
||||||
|
exec_maven "$@"
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
<# : batch portion
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
@REM or more contributor license agreements. See the NOTICE file
|
||||||
|
@REM distributed with this work for additional information
|
||||||
|
@REM regarding copyright ownership. The ASF licenses this file
|
||||||
|
@REM to you under the Apache License, Version 2.0 (the
|
||||||
|
@REM "License"); you may not use this file except in compliance
|
||||||
|
@REM with the License. You may obtain a copy of the License at
|
||||||
|
@REM
|
||||||
|
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@REM
|
||||||
|
@REM Unless required by applicable law or agreed to in writing,
|
||||||
|
@REM software distributed under the License is distributed on an
|
||||||
|
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
@REM KIND, either express or implied. See the License for the
|
||||||
|
@REM specific language governing permissions and limitations
|
||||||
|
@REM under the License.
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Apache Maven Wrapper startup batch script, version 3.3.2
|
||||||
|
@REM
|
||||||
|
@REM Optional ENV vars
|
||||||
|
@REM MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
|
||||||
|
@SET __MVNW_CMD__=
|
||||||
|
@SET __MVNW_ERROR__=
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
||||||
|
@SET PSModulePath=
|
||||||
|
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
||||||
|
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
||||||
|
)
|
||||||
|
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=
|
||||||
|
@SET __MVNW_ARG0_NAME__=
|
||||||
|
@SET MVNW_USERNAME=
|
||||||
|
@SET MVNW_PASSWORD=
|
||||||
|
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
|
||||||
|
@echo Cannot start maven from wrapper >&2 && exit /b 1
|
||||||
|
@GOTO :EOF
|
||||||
|
: end batch / begin powershell #>
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
if ($env:MVNW_VERBOSE -eq "true") {
|
||||||
|
$VerbosePreference = "Continue"
|
||||||
|
}
|
||||||
|
|
||||||
|
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
||||||
|
if (!$distributionUrl) {
|
||||||
|
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
|
||||||
|
"maven-mvnd-*" {
|
||||||
|
$USE_MVND = $true
|
||||||
|
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
|
||||||
|
$MVN_CMD = "mvnd.cmd"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
$USE_MVND = $false
|
||||||
|
$MVN_CMD = $script -replace '^mvnw','mvn'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
if ($env:MVNW_REPOURL) {
|
||||||
|
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
|
||||||
|
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
|
||||||
|
}
|
||||||
|
$distributionUrlName = $distributionUrl -replace '^.*/',''
|
||||||
|
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
|
||||||
|
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
|
||||||
|
if ($env:MAVEN_USER_HOME) {
|
||||||
|
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
|
||||||
|
}
|
||||||
|
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
|
||||||
|
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
|
||||||
|
|
||||||
|
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
|
||||||
|
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
exit $?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
|
||||||
|
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
|
||||||
|
}
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
|
||||||
|
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
|
||||||
|
trap {
|
||||||
|
if ($TMP_DOWNLOAD_DIR.Exists) {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
Write-Verbose "Downloading from: $distributionUrl"
|
||||||
|
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
$webclient = New-Object System.Net.WebClient
|
||||||
|
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
||||||
|
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
|
||||||
|
}
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
||||||
|
if ($distributionSha256Sum) {
|
||||||
|
if ($USE_MVND) {
|
||||||
|
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
||||||
|
}
|
||||||
|
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
|
||||||
|
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
|
||||||
|
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
|
||||||
|
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
|
||||||
|
try {
|
||||||
|
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
|
||||||
|
} catch {
|
||||||
|
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
|
||||||
|
Write-Error "fail to move MAVEN_HOME"
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.4.4</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.kevinolarte</groupId>
|
||||||
|
<artifactId>resibenissa</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>resibenissa</name>
|
||||||
|
<description>Demo project for Spring Boot</description>
|
||||||
|
<url/>
|
||||||
|
<licenses>
|
||||||
|
<license/>
|
||||||
|
</licenses>
|
||||||
|
<developers>
|
||||||
|
<developer/>
|
||||||
|
</developers>
|
||||||
|
<scm>
|
||||||
|
<connection/>
|
||||||
|
<developerConnection/>
|
||||||
|
<tag/>
|
||||||
|
<url/>
|
||||||
|
</scm>
|
||||||
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-mail</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-api</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-impl</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-jackson</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.librepdf</groupId>
|
||||||
|
<artifactId>openpdf</artifactId>
|
||||||
|
<version>1.3.30</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.datafaker</groupId>
|
||||||
|
<artifactId>datafaker</artifactId>
|
||||||
|
<version>2.1.0</version> <!-- Puedes cambiar por la última disponible -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<exclude>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.kevinolarte.resibenissa;
|
||||||
|
|
||||||
|
public class LogContext {
|
||||||
|
private static final ThreadLocal<Long> currentLogId = new ThreadLocal<>();
|
||||||
|
|
||||||
|
public static void setCurrentLogId(Long id) {
|
||||||
|
currentLogId.set(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long getCurrentLogId() {
|
||||||
|
return currentLogId.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clear() {
|
||||||
|
currentLogId.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.kevinolarte.resibenissa;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class ResibenissaApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(ResibenissaApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
package com.kevinolarte.resibenissa.config;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.UserRepository;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuración de seguridad de la aplicación.
|
||||||
|
* <p>
|
||||||
|
* Define los beans necesarios para la autenticación de usuarios,
|
||||||
|
* incluyendo el codificador de contraseñas, el proveedor de autenticación
|
||||||
|
* y el servicio de obtención de detalles de usuario.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AplicationConfiguration {
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve un UserDetailsService que busca usuarios por email en la base de datos.
|
||||||
|
*
|
||||||
|
* @return Implementación de UserDetailsService personalizada.
|
||||||
|
* @throws UsernameNotFoundException si el usuario no existe.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
UserDetailsService userDetailsService(){
|
||||||
|
return email -> {
|
||||||
|
User user = userRepository.findByEmail(email);
|
||||||
|
if(user == null){
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_INVALIDO);
|
||||||
|
}
|
||||||
|
if (user.isBaja()){
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_BAJA);
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@Bean
|
||||||
|
BCryptPasswordEncoder passwordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
AuthenticationManager authenticationManager(AuthenticationConfiguration config)throws Exception {
|
||||||
|
return config.getAuthenticationManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea un bean de {@link AuthenticationProvider} personalizado que usa
|
||||||
|
* el {@link UserDetailsService} y el codificador de contraseñas definidos.
|
||||||
|
*
|
||||||
|
* @return el proveedor de autenticación configurado.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
AuthenticationProvider authenticationProvider() {
|
||||||
|
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
|
||||||
|
|
||||||
|
authProvider.setUserDetailsService(userDetailsService());
|
||||||
|
authProvider.setPasswordEncoder(passwordEncoder());
|
||||||
|
|
||||||
|
return authProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.kevinolarte.resibenissa.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clase de configuración que contiene valores por defecto utilizados en la aplicación.
|
||||||
|
* <p>
|
||||||
|
* Estos valores suelen emplearse para inicializar entidades, usuarios de sistema, o
|
||||||
|
* como fallback en lógica que requiere datos por omisión.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p><b>Nota:</b> Estas constantes no deberían modificarse dinámicamente durante la ejecución.</p>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
public class Conf {
|
||||||
|
public static final Long idResidenciaDefault = 1L;
|
||||||
|
public static final Long idUsuarioDefault = 1L;
|
||||||
|
public static final String emailDefault = "default@default.com";
|
||||||
|
public static final String PATH_PUBLIC_AUTH= "/auth/";
|
||||||
|
public static final String PATH_PUBLIC_SWAGGER = "/swagger-ui/";
|
||||||
|
public static final String PATH_PUBLIC_RESI_GET = "/resi/getAll";
|
||||||
|
public static final String PATH_PUBLIC_RESI_CONTROLLER = "/public/";
|
||||||
|
|
||||||
|
@Value("${upload.dir}")
|
||||||
|
public static String imageResource;
|
||||||
|
public static final String imageDefault = "defaultPerfil.png";
|
||||||
|
|
||||||
|
public static final int POS_ESTADO_ABIERTO = 0;
|
||||||
|
public static final int POS_ESTADO_CERRADO = 1;
|
||||||
|
public static final int POS_ESTADO_EN_CURSO = 2;
|
||||||
|
public static final int POS_ESTADO_FINALIZADA = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.kevinolarte.resibenissa.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuración global de CORS para permitir acceso desde el frontend.
|
||||||
|
* Esto permite que navegadores puedan hacer peticiones a la API desde dominios distintos.
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class CorsConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebMvcConfigurer corsConfigurer() {
|
||||||
|
return new WebMvcConfigurer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
|
registry.addMapping("/**")
|
||||||
|
.allowedOrigins(
|
||||||
|
"http://localhost:5500",
|
||||||
|
"http://127.0.0.1:5500"
|
||||||
|
)
|
||||||
|
.allowedMethods("*")
|
||||||
|
.allowedHeaders("*")
|
||||||
|
.allowCredentials(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.kevinolarte.resibenissa.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.mail.javamail.JavaMailSender;
|
||||||
|
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuración del servicio de envío de correos electrónicos.
|
||||||
|
* <p>
|
||||||
|
* Esta clase define un {@link JavaMailSender} que se configura automáticamente
|
||||||
|
* con los datos definidos en el archivo {@code application.properties} o {@code application.yml}.
|
||||||
|
* Utiliza los servidores de Gmail como proveedor SMTP.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Las credenciales y configuraciones sensibles se inyectan desde las propiedades:
|
||||||
|
* <ul>
|
||||||
|
* <li><code>spring.mail.username</code></li>
|
||||||
|
* <li><code>spring.mail.password</code></li>
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return Bean de {@link JavaMailSender} listo para ser inyectado y utilizado en servicios.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class EmailConfiguration {
|
||||||
|
@Value("${spring.mail.username}")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Value("${spring.mail.password}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea e inicializa el {@link JavaMailSender} con configuración para SMTP (Gmail).
|
||||||
|
*
|
||||||
|
* @return Instancia de {@link JavaMailSender} configurada.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public JavaMailSender javaMailSender() {
|
||||||
|
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
|
||||||
|
mailSender.setHost("smtp.gmail.com");
|
||||||
|
mailSender.setPort(587);
|
||||||
|
mailSender.setUsername(username);
|
||||||
|
mailSender.setPassword(password);
|
||||||
|
|
||||||
|
Properties props = mailSender.getJavaMailProperties();
|
||||||
|
props.put("mail.transport.protocol", "smtp");
|
||||||
|
props.put("mail.smtp.auth", "true");
|
||||||
|
props.put("mail.smtp.starttls.enable", "true");
|
||||||
|
props.put("mail.debug", "true");
|
||||||
|
|
||||||
|
return mailSender;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
package com.kevinolarte.resibenissa.config;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.JwtService;
|
||||||
|
import com.kevinolarte.resibenissa.services.LoggerService;
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filtro de autenticación que intercepta todas las peticiones HTTP y verifica si contienen
|
||||||
|
* un token JWT válido en la cabecera {@code Authorization}.
|
||||||
|
* <p>
|
||||||
|
* Si el token es válido, autentica al usuario y lo registra en el {@link SecurityContextHolder}.
|
||||||
|
* En caso de error, delega la excepción al {@link HandlerExceptionResolver} para devolver
|
||||||
|
* una respuesta estructurada.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Este filtro se ejecuta una sola vez por petición, al extender de {@link OncePerRequestFilter}.
|
||||||
|
*
|
||||||
|
* @author Kevin
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
private final JwtService jwtService;
|
||||||
|
private final UserDetailsService userDetailsService;
|
||||||
|
private final HandlerExceptionResolver handlerExceptionResolver;
|
||||||
|
private final LoggerService loggerService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lógica principal del filtro. Verifica si la petición contiene un token JWT válido
|
||||||
|
* y, si es así, autentica al usuario en el contexto de seguridad de Spring.
|
||||||
|
*
|
||||||
|
* @param request Petición HTTP entrante.
|
||||||
|
* @param response Respuesta HTTP saliente.
|
||||||
|
* @param filterChain Cadena de filtros que se continúa tras el procesamiento.
|
||||||
|
* @throws ServletException si ocurre un error en el filtro.
|
||||||
|
* @throws IOException si ocurre un error de entrada/salida.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(
|
||||||
|
@NonNull HttpServletRequest request,
|
||||||
|
@NonNull HttpServletResponse response,
|
||||||
|
@NonNull FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
final String authHeader = request.getHeader("Authorization");
|
||||||
|
String endpoint = request.getRequestURI();
|
||||||
|
String metodo = request.getMethod();
|
||||||
|
|
||||||
|
|
||||||
|
// Aquí puedes añadir más lógica para determinar el usuario autenticado
|
||||||
|
String descripcion = "Acceso a endpoint";
|
||||||
|
|
||||||
|
loggerService.registrarLog(endpoint, metodo, descripcion);
|
||||||
|
|
||||||
|
|
||||||
|
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||||
|
handlerExceptionResolver.resolveException(
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
null,
|
||||||
|
new ApiException(new ResiException(ApiErrorCode.ENDPOINT_PROTEGIDO), "Falta el token de autorización.")
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String jwt = authHeader.substring(7);
|
||||||
|
final String userEmail = jwtService.extrtractEmail(jwt);
|
||||||
|
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
|
if (userEmail != null && authentication == null) {
|
||||||
|
UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail);
|
||||||
|
|
||||||
|
if (jwtService.isTokenValid(jwt, userDetails)) {
|
||||||
|
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
|
||||||
|
userDetails,
|
||||||
|
null,
|
||||||
|
userDetails.getAuthorities()
|
||||||
|
);
|
||||||
|
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String uri = request.getRequestURI();
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (uri.startsWith("/admin/resi") && auth != null && auth.isAuthenticated()) {
|
||||||
|
boolean isAdmin = auth.getAuthorities().stream()
|
||||||
|
.anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));
|
||||||
|
|
||||||
|
if (!isAdmin) {
|
||||||
|
handlerExceptionResolver.resolveException(
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
null,
|
||||||
|
new ApiException(new ResiException(ApiErrorCode.ENDPOINT_PROTEGIDO), "Falta el token de autorización.")
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
} catch(Exception e){
|
||||||
|
handlerExceptionResolver.resolveException(request, response, null, new ApiException(new ResiException(ApiErrorCode.ENDPOINT_PROTEGIDO), e.getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldNotFilter(HttpServletRequest request) {
|
||||||
|
String path = request.getRequestURI();
|
||||||
|
System.out.println("URI: " + path);
|
||||||
|
return path.startsWith(Conf.PATH_PUBLIC_SWAGGER)
|
||||||
|
|| path.startsWith(Conf.PATH_PUBLIC_AUTH)
|
||||||
|
|| path.startsWith(Conf.PATH_PUBLIC_RESI_GET)
|
||||||
|
|| path.startsWith(Conf.PATH_PUBLIC_RESI_CONTROLLER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
package com.kevinolarte.resibenissa.config;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clase de configuración de seguridad para la API.
|
||||||
|
* <p>
|
||||||
|
* Define la cadena de filtros de seguridad, política de sesiones,
|
||||||
|
* rutas públicas y configuración CORS para permitir solicitudes seguras desde el frontend.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Esta configuración se basa en JWT y es stateless (sin sesiones de servidor).
|
||||||
|
*
|
||||||
|
* @author Kevin
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SecurityConfiguration {
|
||||||
|
|
||||||
|
private final AuthenticationProvider authenticationProvider;
|
||||||
|
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configura la cadena de filtros de seguridad para la aplicación.
|
||||||
|
* <p>
|
||||||
|
* - Desactiva CSRF.<br>
|
||||||
|
* - Permite acceso libre a rutas que comienzan con {@code /auth/**}.<br>
|
||||||
|
* - Requiere autenticación para cualquier otra petición.<br>
|
||||||
|
* - Aplica política de sesión stateless (usada con JWT).<br>
|
||||||
|
* - Agrega el filtro personalizado para validar JWT antes de {@link UsernamePasswordAuthenticationFilter}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param http Objeto {@link HttpSecurity} para construir la configuración.
|
||||||
|
* @return Cadena de filtros de seguridad {@link SecurityFilterChain} configurada.
|
||||||
|
* @throws Exception Si ocurre un error en la construcción de la cadena.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.csrf(AbstractHttpConfigurer::disable)
|
||||||
|
.authorizeHttpRequests(authorize -> authorize
|
||||||
|
|
||||||
|
.requestMatchers(Conf.PATH_PUBLIC_AUTH + "**").permitAll()
|
||||||
|
.requestMatchers(Conf.PATH_PUBLIC_SWAGGER + "**").permitAll()
|
||||||
|
.requestMatchers(Conf.PATH_PUBLIC_RESI_CONTROLLER + "**").permitAll()
|
||||||
|
.requestMatchers(Conf.PATH_PUBLIC_RESI_GET).permitAll()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
)
|
||||||
|
.sessionManagement(session -> session
|
||||||
|
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
|
.authenticationProvider(authenticationProvider)
|
||||||
|
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CorsConfigurationSource corsConfigurationSource(){
|
||||||
|
CorsConfiguration configuration = new CorsConfiguration();
|
||||||
|
configuration.setAllowedOrigins(List.of("http://localhost:8080"));
|
||||||
|
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
|
||||||
|
configuration.setAllowedHeaders(List.of("Authorization","Content-Type"));
|
||||||
|
|
||||||
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
|
source.registerCorsConfiguration("/**", configuration);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,194 @@
|
||||||
|
package com.kevinolarte.resibenissa.config;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.moduloOrgSalida.EventoSalidaDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.moduloOrgSalida.ParticipanteDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.modulojuego.RegistroJuegoDto;
|
||||||
|
import com.kevinolarte.resibenissa.enums.Role;
|
||||||
|
import com.kevinolarte.resibenissa.enums.moduloOrgSalida.EstadoSalida;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.Dificultad;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residente;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloOrgSalida.EventoSalida;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloOrgSalida.Participante;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloWallet.Wallet;
|
||||||
|
import com.kevinolarte.resibenissa.models.modulojuego.Juego;
|
||||||
|
import com.kevinolarte.resibenissa.models.modulojuego.RegistroJuego;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.ResidenciaRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.ResidenteRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.UserRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.moduloOrgSalida.EventoSalidaRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.moduloOrgSalida.ParticipanteRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.moduloWallet.WalletRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.modulojuego.JuegoRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.modulojuego.RegistroJuegoRepository;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import net.datafaker.Faker;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class StartupDataLoader {
|
||||||
|
|
||||||
|
private final ResidenciaRepository residenciaRepository;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
private final ResidenteRepository residenteRepository;
|
||||||
|
private final JuegoRepository juegoRepository;
|
||||||
|
private final RegistroJuegoRepository registroJuegoRepository;
|
||||||
|
private final EventoSalidaRepository eventoSalidaRepository;
|
||||||
|
private final ParticipanteRepository participanteRepository;
|
||||||
|
private final BCryptPasswordEncoder passwordEncoder;
|
||||||
|
private final WalletRepository walletRepository;
|
||||||
|
private final Faker faker = new Faker();
|
||||||
|
private final Set<String> dniGenerados = new HashSet<>();
|
||||||
|
private final Set<String> emailsGenerados = new HashSet<>();
|
||||||
|
private final Random random = new Random();
|
||||||
|
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
Residencia residenciaAdmin = residenciaRepository.save(new Residencia("Residencia Admin", "resiAdmin@gmail.com"));
|
||||||
|
User user = new User("Kevin", "olarte", "dafault@gmail.com", passwordEncoder.encode("default"), Role.ADMIN);
|
||||||
|
user.setResidencia(residenciaAdmin);
|
||||||
|
user.setEnabled(true);
|
||||||
|
user = userRepository.save(user);
|
||||||
|
// Cargar datos de prueba al iniciar la aplicación
|
||||||
|
cargarDatosPrueba();
|
||||||
|
cargarJuegosPrueba();
|
||||||
|
cargarRegistrosJuegosPrueba();
|
||||||
|
cargarEventosSalidaPrueba();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cargarRegistrosJuegosPrueba() {
|
||||||
|
List<Residente> residentes = residenteRepository.findAll();
|
||||||
|
List<Juego> juegos = juegoRepository.findAll();
|
||||||
|
List<User> user = userRepository.findAll();
|
||||||
|
if (residentes.isEmpty() || juegos.isEmpty()) {
|
||||||
|
System.out.println("⚠️ No hay residentes o juegos cargados en la base de datos.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Residente residente : residentes) {
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
RegistroJuego registro = new RegistroJuego();
|
||||||
|
registro.setResidente(residente);
|
||||||
|
registro.setJuego(juegos.get(random.nextInt(juegos.size())));
|
||||||
|
registro.setFecha(LocalDateTime.now().minusDays(random.nextInt(30)));
|
||||||
|
registro.setNum(random.nextInt(10)); // Fallos entre 0 y 9
|
||||||
|
registro.setDuracion(30 + random.nextDouble() * 90); // Entre 30 y 120 segundos
|
||||||
|
registro.setDificultad(Dificultad.values()[random.nextInt(Dificultad.values().length)]);
|
||||||
|
registro.setObservacion("Prueba generada automáticamente");
|
||||||
|
registro.setUsuario(user.get(0));
|
||||||
|
registroJuegoRepository.save(registro);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cargarJuegosPrueba() {
|
||||||
|
Juego juego1 = new Juego("Seguir la línea");
|
||||||
|
Juego juego2 = new Juego("Memory");
|
||||||
|
Juego juego3 = new Juego("Bongo");
|
||||||
|
|
||||||
|
juegoRepository.save(juego1);
|
||||||
|
juegoRepository.save(juego2);
|
||||||
|
juegoRepository.save(juego3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cargarEventosSalidaPrueba() {
|
||||||
|
List<Residencia> residencias = residenciaRepository.findAll();
|
||||||
|
|
||||||
|
for (Residencia residencia : residencias) {
|
||||||
|
// 1 evento esta mañana
|
||||||
|
eventoSalidaRepository.save(crearEvento(residencia, LocalDateTime.now().with(LocalTime.of(10, 0))));
|
||||||
|
|
||||||
|
// 2 eventos pasado mañana
|
||||||
|
eventoSalidaRepository.save(crearEvento(residencia, LocalDateTime.now().plusDays(2).with(LocalTime.of(9 + random.nextInt(3), 0))));
|
||||||
|
eventoSalidaRepository.save(crearEvento(residencia, LocalDateTime.now().plusDays(2).with(LocalTime.of(14 + random.nextInt(3), 0))));
|
||||||
|
|
||||||
|
// 2 eventos la semana que viene
|
||||||
|
eventoSalidaRepository.save(crearEvento(residencia, LocalDateTime.now().plusDays(7).with(LocalTime.of(10, 0))));
|
||||||
|
eventoSalidaRepository.save(crearEvento(residencia, LocalDateTime.now().plusDays(8).with(LocalTime.of(17, 30))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private EventoSalida crearEvento(Residencia residencia, LocalDateTime fecha) {
|
||||||
|
EventoSalida evento = new EventoSalida();
|
||||||
|
evento.setNombre(faker.funnyName().name());
|
||||||
|
evento.setDescripcion(faker.lorem().sentence(10));
|
||||||
|
evento.setFechaInicio(fecha);
|
||||||
|
evento.setEstado(EstadoSalida.ABIERTO); // Ajusta si usas otro valor por defecto
|
||||||
|
evento.setResidencia(residencia);
|
||||||
|
return evento;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cargarDatosPrueba() {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
String ciudad = faker.address().cityName().replaceAll("[^A-Za-z]", "");
|
||||||
|
String emailResidencia = generarEmailUnico("residencia" + ciudad.toLowerCase());
|
||||||
|
|
||||||
|
Residencia residencia = new Residencia();
|
||||||
|
residencia.setNombre("Residencia " + ciudad);
|
||||||
|
residencia.setEmail(emailResidencia);
|
||||||
|
residenciaRepository.save(residencia);
|
||||||
|
User user = new User();
|
||||||
|
user.setNombre("Admin " + ciudad);
|
||||||
|
user.setApellido("Administrador " + ciudad);
|
||||||
|
user.setEnabled(true);
|
||||||
|
user.setEmail("admin@" + ciudad.toLowerCase() + ".com");
|
||||||
|
user.setPassword(passwordEncoder.encode("admin123"));
|
||||||
|
user.setResidencia(residencia);
|
||||||
|
user.setRole(Role.NORMAL);
|
||||||
|
userRepository.save(user);
|
||||||
|
|
||||||
|
|
||||||
|
for (int j = 0; j < 30; j++) {
|
||||||
|
String nombre = faker.name().firstName();
|
||||||
|
String apellido = faker.name().lastName();
|
||||||
|
LocalDate nacimiento = faker.date().birthday(65, 95).toLocalDateTime().toLocalDate();
|
||||||
|
String dni = generarDniUnico();
|
||||||
|
String familiar1 = generarEmailUnico(faker.name().firstName());
|
||||||
|
String familiar2 = null;
|
||||||
|
|
||||||
|
Residente residente = new Residente(nombre, apellido, nacimiento, dni, familiar1, familiar2);
|
||||||
|
residente.setResidencia(residencia);
|
||||||
|
residenteRepository.save(residente);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generarDniUnico() {
|
||||||
|
String dni;
|
||||||
|
do {
|
||||||
|
// DNI español típico: 8 números + letra final (omitimos la letra final para cumplir tu validador de 8)
|
||||||
|
dni = String.format("%08d", faker.number().numberBetween(10000000, 99999999));
|
||||||
|
} while (!dniGenerados.add(dni));
|
||||||
|
return dni;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String generarEmailUnico(String base) {
|
||||||
|
String email;
|
||||||
|
int intento = 0;
|
||||||
|
do {
|
||||||
|
email = base + (intento == 0 ? "" : intento) + "@resisuite.com";
|
||||||
|
intento++;
|
||||||
|
} while (!emailsGenerados.add(email));
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.kevinolarte.resibenissa.config;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.config.interceptor.ControllerLoggerInterceptor;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class WebConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
private final ControllerLoggerInterceptor controllerLoggerInterceptor;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(controllerLoggerInterceptor)
|
||||||
|
.addPathPatterns("/**"); // Intercepta todos los endpoints
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.kevinolarte.resibenissa.config.interceptor;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.LogContext;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.LoggerService;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ControllerLoggerInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
private final LoggerService loggerService;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
|
if (!(handler instanceof HandlerMethod)) return true;
|
||||||
|
|
||||||
|
String endpoint = request.getRequestURI();
|
||||||
|
String metodo = request.getMethod();
|
||||||
|
|
||||||
|
|
||||||
|
// Aquí puedes añadir más lógica para determinar el usuario autenticado
|
||||||
|
String descripcion = "Acceso a endpoint";
|
||||||
|
|
||||||
|
loggerService.registrarLog(endpoint, metodo, descripcion);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||||
|
System.out.println("Interceptor afterCompletion called");
|
||||||
|
LogContext.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.auth.LoginUserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.auth.RegisterUserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.auth.VerifyUserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.UserResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.LoginResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.services.AuthenticationService;
|
||||||
|
import com.kevinolarte.resibenissa.services.JwtService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST para la creacion de usuarios
|
||||||
|
* <p>
|
||||||
|
* Expone endpoints relacionados con el registro, inicio de sesión,
|
||||||
|
* verificación de cuenta por correo y reenvío de códigos de verificación.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Todas las rutas están bajo el prefijo <code>/auth</code>.
|
||||||
|
*
|
||||||
|
* @author Kevin
|
||||||
|
*/
|
||||||
|
@RequestMapping("/auth")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AuthenticationController {
|
||||||
|
private final JwtService jwtService;
|
||||||
|
private final AuthenticationService authenticationService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registra un nuevo usuario en el sistema.
|
||||||
|
* <p>
|
||||||
|
* El usuario creado se guarda con estado "no activado" hasta que complete
|
||||||
|
* el proceso de verificación vía código enviado al correo.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param registerUserDto Datos necesarios para registrar al usuario.
|
||||||
|
* @return {@link ResponseEntity} con los datos del usuario registrado.
|
||||||
|
*/
|
||||||
|
@PostMapping("/signup")
|
||||||
|
public ResponseEntity<UserResponseDto> register(@RequestBody RegisterUserDto registerUserDto){
|
||||||
|
UserResponseDto user;
|
||||||
|
try{
|
||||||
|
user = authenticationService.singUp(registerUserDto);
|
||||||
|
} catch (ResiException e){
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok(user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autentica a un usuario existente y devuelve un token JWT válido.
|
||||||
|
*
|
||||||
|
* @param loginUserDto DTO con email y contraseña.
|
||||||
|
* @return {@link ResponseEntity} con el token JWT y su tiempo de expiración.
|
||||||
|
*/
|
||||||
|
@PostMapping("/login")
|
||||||
|
public ResponseEntity<LoginResponseDto> authenticate(@RequestBody LoginUserDto loginUserDto){
|
||||||
|
LoginResponseDto loginResponse;
|
||||||
|
try{
|
||||||
|
User userauthentication = authenticationService.authenticate(loginUserDto);
|
||||||
|
String token = jwtService.generateToken(userauthentication);
|
||||||
|
loginResponse = new LoginResponseDto(
|
||||||
|
token,
|
||||||
|
jwtService.getExpirationTime(),
|
||||||
|
userauthentication
|
||||||
|
);
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(loginResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica un usuario usando el código enviado por correo.
|
||||||
|
*
|
||||||
|
* @param verifyUserDto DTO con email y código de verificación.
|
||||||
|
* @return {@link ResponseEntity} con mensaje de éxito.
|
||||||
|
*/
|
||||||
|
@PostMapping("/verify")
|
||||||
|
public ResponseEntity<String> verifyUser(@RequestBody VerifyUserDto verifyUserDto){
|
||||||
|
try{
|
||||||
|
authenticationService.verifyUser(verifyUserDto);
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok("AcountVerfied");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reenvía un nuevo código de verificación al correo indicado.
|
||||||
|
*
|
||||||
|
* @param email Dirección de correo del usuario.
|
||||||
|
* @return {@link ResponseEntity} con mensaje de confirmación.
|
||||||
|
*/
|
||||||
|
@PostMapping("/resend")
|
||||||
|
public ResponseEntity<String> resendVerificationCode(@RequestParam String email ){
|
||||||
|
try{
|
||||||
|
authenticationService.resendVerificationCode(email);
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok("Verification Code Resent");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.services.JwtService;
|
||||||
|
import com.kevinolarte.resibenissa.services.moduloOrgSalida.ParticipanteService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST para manejar operaciones públicas relacionadas con participantes en eventos.
|
||||||
|
* Permite confirmar o denegar permisos de participantes en eventos de una residencia.
|
||||||
|
* <P>
|
||||||
|
* URL Base: {@code /public}
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RequestMapping("/public")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class PublicController {
|
||||||
|
|
||||||
|
private final JwtService jwtService;
|
||||||
|
private final ParticipanteService participanteService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Endpoint para confirmar el permiso de un participante en un evento.
|
||||||
|
* @param token Token JWT que contiene la información del participante, evento y residencia.
|
||||||
|
* @return ResponseEntity con un mensaje de éxito o error.
|
||||||
|
*/
|
||||||
|
@GetMapping("/allowParticipante")
|
||||||
|
public ResponseEntity<String> confirmarPermiso(@RequestParam String token) {
|
||||||
|
try {
|
||||||
|
Long idParticipante = Long.parseLong(jwtService.extractClaim(token, claims -> claims.get("idParticipante").toString()));
|
||||||
|
Long idEvento = Long.parseLong(jwtService.extractClaim(token, claims -> claims.get("idEvento").toString()));
|
||||||
|
Long idResidencia = Long.parseLong(jwtService.extractClaim(token, claims -> claims.get("idResidencia").toString()));
|
||||||
|
|
||||||
|
participanteService.allow(idResidencia, idEvento, idParticipante);
|
||||||
|
return ResponseEntity.ok("✅ Permiso registrado correctamente.");
|
||||||
|
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.ENDPOINT_PROTEGIDO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Endpoint para confirmar la denegación de un participante en un evento.
|
||||||
|
* @param token Token JWT que contiene la información del participante, evento y residencia.
|
||||||
|
* @return ResponseEntity con un mensaje de éxito o error.
|
||||||
|
*/
|
||||||
|
@GetMapping("/denyParticipante")
|
||||||
|
public ResponseEntity<String> confirmarDenegacion(@RequestParam String token) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
Long idParticipante = Long.parseLong(jwtService.extractClaim(token, claims -> claims.get("idParticipante").toString()));
|
||||||
|
Long idEvento = Long.parseLong(jwtService.extractClaim(token, claims -> claims.get("idEvento").toString()));
|
||||||
|
Long idResidencia = Long.parseLong(jwtService.extractClaim(token, claims -> claims.get("idResidencia").toString()));
|
||||||
|
participanteService.deny(idResidencia, idEvento, idParticipante);
|
||||||
|
return ResponseEntity.ok("✅ Denegación registrada correctamente.");
|
||||||
|
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.ENDPOINT_PROTEGIDO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,308 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.moduloOrgSalida.evento;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.moduloOrgSalida.EventoSalidaDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.moduloOrgSalida.EventoSalidaResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.enums.moduloOrgSalida.EstadoSalida;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.moduloOrgSalida.EventoSalidaService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST para gestionar los eventos de salida de una residencia.
|
||||||
|
* <p>
|
||||||
|
* Permite crear, actualizar, eliminar, consultar y listar eventos de salida
|
||||||
|
* asociados a una residencia específica.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* URL base: /admin/resi
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/admin/resi")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class EventoSalidaAdminController {
|
||||||
|
|
||||||
|
public final EventoSalidaService eventoSalidaService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea un nuevo evento de salida en una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia donde se creará el evento de salida.
|
||||||
|
* @param input DTO que contiene los datos del evento de salida a crear.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida creado.ç
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("/{idResidencia}/evento/add")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> add(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestBody EventoSalidaDto input) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED)
|
||||||
|
.body(eventoSalidaService.add(input, idResidencia));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene los datos de un evento de salida específico.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia a la que pertenece el evento de salida.
|
||||||
|
* @param idEventoSalida ID del evento de salida a consultar.
|
||||||
|
* @return {@link ResponseEntity} con los datos del evento de salida encontrado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idResidencia}/evento/{idEventoSalida}/get")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> getEventoSalida(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEventoSalida) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.get(idEventoSalida, idResidencia));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de eventos de salida con filtros dinámicos.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia (obligatorio)
|
||||||
|
* @param fecha Fecha exacta del evento
|
||||||
|
* @param minFecha Fecha mínima del evento (rango)
|
||||||
|
* @param maxFecha Fecha máxima del evento (rango)
|
||||||
|
* @param estado Estado del evento (PENDIENTE, REALIZADA, CANCELADA...)
|
||||||
|
* @param idResidente Filtra eventos que contengan al residente con este ID
|
||||||
|
* @param idParticipante Filtra eventos que contengan al participante con este ID
|
||||||
|
* @param minRH Mínimo número de participantes con recursos humanos
|
||||||
|
* @param maxRH Máximo número de participantes con recursos humanos
|
||||||
|
* @param minRM Mínimo número de participantes con recursos materiales
|
||||||
|
* @param maxRM Máximo número de participantes con recursos materiales
|
||||||
|
* @return Lista de eventos de salida que cumplen los filtros
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idResidencia}/evento/getAll")
|
||||||
|
public ResponseEntity<List<EventoSalidaResponseDto>> getAllEventosSalida(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestParam(required = false) LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha,
|
||||||
|
@RequestParam(required = false) EstadoSalida estado,
|
||||||
|
@RequestParam(required = false) Long idResidente,
|
||||||
|
@RequestParam(required = false) Long idParticipante,
|
||||||
|
@RequestParam(required = false) Integer minRH,
|
||||||
|
@RequestParam(required = false) Integer maxRH,
|
||||||
|
@RequestParam(required = false) Integer minRM,
|
||||||
|
@RequestParam(required = false) Integer maxRM) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.getAll(
|
||||||
|
idResidencia, fecha, minFecha, maxFecha, estado,
|
||||||
|
idResidente, idParticipante, minRH, maxRH, minRM, maxRM));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de eventos de salida con filtros dinámicos.
|
||||||
|
*
|
||||||
|
* @param fecha Fecha exacta del evento
|
||||||
|
* @param minFecha Fecha mínima del evento (rango)
|
||||||
|
* @param maxFecha Fecha máxima del evento (rango)
|
||||||
|
* @param estado Estado del evento (PENDIENTE, REALIZADA, CANCELADA...)
|
||||||
|
* @param idResidente Filtra eventos que contengan al residente con este ID
|
||||||
|
* @param idParticipante Filtra eventos que contengan al participante con este ID
|
||||||
|
* @param minRH Mínimo número de participantes con recursos humanos
|
||||||
|
* @param maxRH Máximo número de participantes con recursos humanos
|
||||||
|
* @param minRM Mínimo número de participantes con recursos materiales
|
||||||
|
* @param maxRM Máximo número de participantes con recursos materiales
|
||||||
|
* @return Lista de eventos de salida que cumplen los filtros
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/evento/getAll")
|
||||||
|
public ResponseEntity<List<EventoSalidaResponseDto>> getAllEventosSalidaSinResidencia(
|
||||||
|
@RequestParam(required = false) LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha,
|
||||||
|
@RequestParam(required = false) EstadoSalida estado,
|
||||||
|
@RequestParam(required = false) Long idResidente,
|
||||||
|
@RequestParam(required = false) Long idParticipante,
|
||||||
|
@RequestParam(required = false) Integer minRH,
|
||||||
|
@RequestParam(required = false) Integer maxRH,
|
||||||
|
@RequestParam(required = false) Integer minRM,
|
||||||
|
@RequestParam(required = false) Integer maxRM) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.getAll(
|
||||||
|
fecha, minFecha, maxFecha, estado,
|
||||||
|
idResidente, idParticipante, minRH, maxRH, minRM, maxRM));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina un evento de salida de una residencia.
|
||||||
|
* <p>
|
||||||
|
* La eliminación incluye también a todos los participantes asociados al evento.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia a la que pertenece el evento de salida.
|
||||||
|
* @param idEventoSalida ID del evento de salida a eliminar.
|
||||||
|
* @return {@link ResponseEntity} sin contenido si la eliminación fue exitosa.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{idResidencia}/evento/{idEventoSalida}/delete")
|
||||||
|
public ResponseEntity<Void> delete(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEventoSalida) {
|
||||||
|
try {
|
||||||
|
eventoSalidaService.delete(idEventoSalida, idResidencia);
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia el nombre de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia a la que pertenece el evento de salida.
|
||||||
|
* @param idEventoSalida ID del evento de salida a actualizar.
|
||||||
|
* @param nombre Nuevo nombre del evento de salida.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidencia}/evento/{idEventoSalida}/changeNombre")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> changeNombre(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEventoSalida,
|
||||||
|
@RequestParam String nombre) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.changeNombre(idEventoSalida, nombre, idResidencia));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia la descripción de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia a la que pertenece el evento de salida.
|
||||||
|
* @param idEventoSalida ID del evento de salida a actualizar.
|
||||||
|
* @param descripcion Nueva descripción del evento de salida.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidencia}/evento/{idEventoSalida}/changeDescripcion")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> changeDescripcion(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEventoSalida,
|
||||||
|
@RequestParam String descripcion) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.changeDescripcion(idEventoSalida, descripcion, idResidencia));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia la fecha de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia a la que pertenece el evento de salida.
|
||||||
|
* @param idEventoSalida ID del evento de salida a actualizar.
|
||||||
|
* @param fecha Nueva fecha del evento de salida.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidencia}/evento/{idEventoSalida}/changeFecha")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> changeFecha(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEventoSalida,
|
||||||
|
@RequestParam LocalDateTime fecha) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.changeFecha(idEventoSalida, fecha, idResidencia));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia el estado de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia a la que pertenece el evento de salida.
|
||||||
|
* @param idEventoSalida ID del evento de salida a actualizar.
|
||||||
|
* @param estado Nuevo estado del evento de salida.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidencia}/evento/{idEventoSalida}/changeEstado")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> changeEstado(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEventoSalida,
|
||||||
|
@RequestParam EstadoSalida estado) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.changeEstado(idEventoSalida, estado, idResidencia));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza los datos de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia a la que pertenece el evento de salida.
|
||||||
|
* @param idEventoSalida ID del evento de salida a actualizar.
|
||||||
|
* @param input DTO con los nuevos datos del evento de salida.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidencia}/evento/{idEventoSalida}/update")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> update(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEventoSalida,
|
||||||
|
@RequestBody EventoSalidaDto input) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.update(input, idResidencia, idEventoSalida));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,261 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.moduloOrgSalida.evento;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.moduloOrgSalida.EventoSalidaDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.moduloOrgSalida.EventoSalidaResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.enums.moduloOrgSalida.EstadoSalida;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.moduloOrgSalida.EventoSalidaService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST para gestionar los eventos de salida de una residencia.
|
||||||
|
* <p>
|
||||||
|
* Permite crear, actualizar, eliminar, consultar y listar eventos de salida
|
||||||
|
* asociados a una residencia específica.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* URL base: /resi/evento
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/resi/evento")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class EventoSalidaController {
|
||||||
|
|
||||||
|
private final EventoSalidaService eventoSalidaService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea un nuevo evento de salida en una residencia.
|
||||||
|
*
|
||||||
|
* @param input DTO que contiene los datos del evento de salida a crear.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida creado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("/add")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> add(@RequestBody EventoSalidaDto input) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED)
|
||||||
|
.body(eventoSalidaService.add(input, currentUser.getResidencia().getId()));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene los datos de un evento de salida específico.
|
||||||
|
*
|
||||||
|
* @param idEventoSalida ID del evento de salida a consultar.
|
||||||
|
* @return {@link ResponseEntity} con los datos del evento de salida encontrado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idEventoSalida}/get")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> getEventoSalida(@PathVariable Long idEventoSalida) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.get(idEventoSalida, currentUser.getResidencia().getId()));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de eventos de salida filtrados por varios parámetros.
|
||||||
|
*
|
||||||
|
* @param fecha Fecha específica del evento de salida.
|
||||||
|
* @param minFecha Fecha mínima del evento de salida.
|
||||||
|
* @param maxFecha Fecha máxima del evento de salida.
|
||||||
|
* @param estado Estado del evento de salida.
|
||||||
|
* @param idResidente ID del residente asociado al evento de salida.
|
||||||
|
* @param idParticipante ID del participante asociado al evento de salida.
|
||||||
|
* @param minRH Mínimo rango horario del evento de salida.
|
||||||
|
* @param maxRH Máximo rango horario del evento de salida.
|
||||||
|
* @param minRM Mínimo rango de minutos del evento de salida.
|
||||||
|
* @param maxRM Máximo rango de minutos del evento de salida.
|
||||||
|
* @return {@link ResponseEntity} con la lista de eventos de salida encontrados.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll")
|
||||||
|
public ResponseEntity<List<EventoSalidaResponseDto>> getAllEventosSalida(
|
||||||
|
@RequestParam(required = false) LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha,
|
||||||
|
@RequestParam(required = false) EstadoSalida estado,
|
||||||
|
@RequestParam(required = false) Long idResidente,
|
||||||
|
@RequestParam(required = false) Long idParticipante,
|
||||||
|
@RequestParam(required = false) Integer minRH,
|
||||||
|
@RequestParam(required = false) Integer maxRH,
|
||||||
|
@RequestParam(required = false) Integer minRM,
|
||||||
|
@RequestParam(required = false) Integer maxRM) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.getAll(
|
||||||
|
currentUser.getResidencia().getId(),
|
||||||
|
fecha, minFecha, maxFecha, estado,
|
||||||
|
idResidente, idParticipante, minRH, maxRH, minRM, maxRM));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina un evento de salida de una residencia.
|
||||||
|
* <p>
|
||||||
|
* La eliminación incluye también a todos los participantes asociados al evento.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param idEventoSalida ID del evento de salida a eliminar.
|
||||||
|
* @return {@link ResponseEntity} con estado NO_CONTENT si la eliminación fue exitosa.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{idEventoSalida}/delete")
|
||||||
|
public ResponseEntity<Void> delete(@PathVariable Long idEventoSalida) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
eventoSalidaService.delete(idEventoSalida, currentUser.getResidencia().getId());
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia el nombre de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idEventoSalida ID del evento de salida a actualizar.
|
||||||
|
* @param nombre Nuevo nombre del evento de salida.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idEventoSalida}/changeNombre")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> changeNombre(
|
||||||
|
@PathVariable Long idEventoSalida,
|
||||||
|
@RequestParam String nombre) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.changeNombre(idEventoSalida, nombre, currentUser.getResidencia().getId()));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia la descripción de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idEventoSalida ID del evento de salida a actualizar.
|
||||||
|
* @param descripcion Nueva descripción del evento de salida.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idEventoSalida}/changeDescripcion")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> changeDescripcion(
|
||||||
|
@PathVariable Long idEventoSalida,
|
||||||
|
@RequestParam String descripcion) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.changeDescripcion(idEventoSalida, descripcion, currentUser.getResidencia().getId()));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia la fecha de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idEventoSalida ID del evento de salida a actualizar.
|
||||||
|
* @param fecha Nueva fecha del evento de salida.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idEventoSalida}/ChangeFecha")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> changeFecha(
|
||||||
|
@PathVariable Long idEventoSalida,
|
||||||
|
@RequestParam LocalDateTime fecha) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.changeFecha(idEventoSalida, fecha, currentUser.getResidencia().getId()));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia el estado de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idEventoSalida ID del evento de salida a actualizar.
|
||||||
|
* @param estado Nuevo estado del evento de salida.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idEventoSalida}/changeEstado")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> changeEstado(
|
||||||
|
@PathVariable Long idEventoSalida,
|
||||||
|
@RequestParam EstadoSalida estado) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.changeEstado(idEventoSalida, estado, currentUser.getResidencia().getId()));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza los datos de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idEventoSalida ID del evento de salida a actualizar.
|
||||||
|
* @param input DTO con los nuevos datos del evento de salida.
|
||||||
|
* @return {@link ResponseEntity} con el evento de salida actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idEventoSalida}/update")
|
||||||
|
public ResponseEntity<EventoSalidaResponseDto> update(
|
||||||
|
@PathVariable Long idEventoSalida,
|
||||||
|
@RequestBody EventoSalidaDto input) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(eventoSalidaService.update(input, currentUser.getResidencia().getId(), idEventoSalida));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,297 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.moduloOrgSalida.participante;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.moduloOrgSalida.ParticipanteDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.moduloOrgSalida.ParticipanteResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.moduloOrgSalida.ParticipanteService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST para gestionar los participantes de un evento de salida en una residencia.
|
||||||
|
* <p>
|
||||||
|
* Permite agregar, consultar, actualizar, eliminar y listar participantes asociados
|
||||||
|
* a un evento específico dentro de una residencia.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* URL Base: {@code /admin/resi/{idResidencia}/evento/{idEvento}/participante}
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/admin/resi/{idResidencia}/evento/{idEvento}/participante")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ParticipanteAdminController {
|
||||||
|
|
||||||
|
private final ParticipanteService participanteService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registra un nuevo participante en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia donde se registra el participante.
|
||||||
|
* @param idEvento ID del evento de salida al que se registra el participante.
|
||||||
|
* @param participanteDto DTO con los datos del participante a registrar.
|
||||||
|
* @return {@link ResponseEntity} con el participante creado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("/add")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> add(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEvento,
|
||||||
|
@RequestBody ParticipanteDto participanteDto) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED)
|
||||||
|
.body(participanteService.add(participanteDto, idEvento, idResidencia));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene los datos de un participante específico en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia donde se encuentra el evento.
|
||||||
|
* @param idEvento ID del evento de salida al que pertenece el participante.
|
||||||
|
* @param idParticipante ID del participante a consultar.
|
||||||
|
* @return {@link ResponseEntity} con los datos del participante encontrado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("{idParticipante}/get")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> get(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(participanteService.get(idResidencia, idEvento, idParticipante));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de todos los participantes de un evento de salida, con opciones de filtrado.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia donde se encuentra el evento.
|
||||||
|
* @param idEvento ID del evento de salida del que se obtienen los participantes.
|
||||||
|
* @param idResidente ID del residente (opcional) para filtrar por residente específico.
|
||||||
|
* @param rM Recurso material (opcional) para filtrar por recurso material.
|
||||||
|
* @param rH Recurso humano (opcional) para filtrar por recurso humano.
|
||||||
|
* @param minEdad Edad mínima del participante (opcional).
|
||||||
|
* @param maxEdad Edad máxima del participante (opcional).
|
||||||
|
* @param preOpinion Filtra por participantes con opinión previa (opcional).
|
||||||
|
* @param postOpinion Filtra por participantes con opinión posterior (opcional).
|
||||||
|
* @param asistenciPermitida Filtra por participantes con asistencia permitida (opcional).
|
||||||
|
* @return {@link ResponseEntity} con la lista de participantes encontrados.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll")
|
||||||
|
public ResponseEntity<List<ParticipanteResponseDto>> getAllParticipantes(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEvento,
|
||||||
|
@RequestParam(required = false) Long idResidente,
|
||||||
|
@RequestParam(required = false) Boolean rM,
|
||||||
|
@RequestParam(required = false) Boolean rH,
|
||||||
|
@RequestParam(required = false) Integer minEdad,
|
||||||
|
@RequestParam(required = false) Integer maxEdad,
|
||||||
|
@RequestParam(required = false) Boolean preOpinion,
|
||||||
|
@RequestParam(required = false) Boolean postOpinion,
|
||||||
|
@RequestParam(required = false) Boolean asistenciPermitida) {
|
||||||
|
try {
|
||||||
|
List<ParticipanteResponseDto> result = participanteService.getAll(
|
||||||
|
idResidencia, idEvento, idResidente, rM, rH, minEdad, maxEdad, preOpinion, postOpinion, asistenciPermitida
|
||||||
|
);
|
||||||
|
return ResponseEntity.ok(result);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina un participante de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante a eliminar.
|
||||||
|
* @param idResidencia ID de la residencia donde se encuentra el evento.
|
||||||
|
* @param idEvento ID del evento de salida del que se elimina el participante.
|
||||||
|
* @return {@link ResponseEntity} con el estado de la operación.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{idParticipante}/delete")
|
||||||
|
public ResponseEntity<Void> deleteParticipante(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante) {
|
||||||
|
try {
|
||||||
|
participanteService.deleteParticipante(idResidencia, idEvento, idParticipante);
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza los datos de un participante existente en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante a actualizar.
|
||||||
|
* @param idResidencia ID de la residencia donde se encuentra el evento.
|
||||||
|
* @param idEvento ID del evento de salida al que pertenece el participante.
|
||||||
|
* @param participanteDto DTO con los nuevos datos del participante.
|
||||||
|
* @return {@link ResponseEntity} con el participante actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idParticipante}/update")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> update(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante,
|
||||||
|
@RequestBody ParticipanteDto participanteDto) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(participanteService.update(participanteDto, idResidencia, idEvento, idParticipante));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Añade una opinión previa de un participante en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante al que se le añade la opinión.
|
||||||
|
* @param preOpinion Opinión previa del participante.
|
||||||
|
* @return {@link ResponseEntity} con el participante actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idParticipante}/addPreOpinion")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> addPreOpinion(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante,
|
||||||
|
@RequestParam String preOpinion) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(participanteService.addPreOpinion(idResidencia, idEvento, idParticipante, preOpinion));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Agrega una opinión posterior a la participación de un residente en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante al que se le agregará la opinión.
|
||||||
|
* @param idResidencia ID de la residencia donde se encuentra el evento.
|
||||||
|
* @param idEvento ID del evento de salida al que pertenece el participante.
|
||||||
|
* @param postOpinion Opinión posterior a la participación.
|
||||||
|
* @return {@link ResponseEntity} con el participante actualizado.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idParticipante}/addPostOpinion")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> addPostOpinion(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante,
|
||||||
|
@RequestParam String postOpinion) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(participanteService.addPostOpinion(idResidencia, idEvento, idParticipante, postOpinion));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia los recursos asignados a un participante en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante a actualizar.
|
||||||
|
* @param idResidencia ID de la residencia donde se encuentra el evento.
|
||||||
|
* @param idEvento ID del evento de salida al que pertenece el participante.
|
||||||
|
* @param rH Recurso humano (opcional).
|
||||||
|
* @param rM Recurso material (opcional).
|
||||||
|
* @return {@link ResponseEntity} con el participante actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idParticipante}/changeRecursos")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> changeRecursos(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante,
|
||||||
|
@RequestParam(required = false) Boolean rH,
|
||||||
|
@RequestParam(required = false) Boolean rM) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(participanteService.changeRecursos(idResidencia, idEvento, idParticipante, rH, rM));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acepta la participación un participante en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante a aceptar.
|
||||||
|
* @param idResidencia ID de la residencia donde se encuentra el evento.
|
||||||
|
* @param idEvento ID del evento de salida al que pertenece el participante.
|
||||||
|
* @return {@link ResponseEntity} con el participante aceptado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("/{idParticipante}/allow")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> allow(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(participanteService.allow(idResidencia, idEvento, idParticipante));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deniega la participación de un residente en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante a denegar.
|
||||||
|
* @param idResidencia ID de la residencia donde se encuentra el evento.
|
||||||
|
* @param idEvento ID del evento de salida al que pertenece el participante.
|
||||||
|
* @return {@link ResponseEntity} con el participante actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("/{idParticipante}/deny")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> deny(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(participanteService.deny(idResidencia, idEvento, idParticipante));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,278 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.moduloOrgSalida.participante;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.moduloOrgSalida.ParticipanteDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.moduloOrgSalida.ParticipanteResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.EmailService;
|
||||||
|
import com.kevinolarte.resibenissa.services.moduloOrgSalida.ParticipanteService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST para gestionar los participantes de un evento de salida en una residencia.
|
||||||
|
* <p>
|
||||||
|
* Permite agregar, consultar, actualizar, eliminar y listar participantes asociados
|
||||||
|
* a un evento específico dentro de una residencia.
|
||||||
|
* </p>
|
||||||
|
* URL base: /resi/evento/{idEvento}/participante
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/resi/evento/{idEvento}/participante")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ParticipanteController {
|
||||||
|
|
||||||
|
private final ParticipanteService participanteService;
|
||||||
|
private final EmailService emailService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registra un nuevo participante en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param participanteDto DTO con los datos del participante a registrar.
|
||||||
|
* @return {@link ResponseEntity} con el participante creado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("/add")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> add(@PathVariable Long idEvento,
|
||||||
|
@RequestBody ParticipanteDto participanteDto) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
ParticipanteResponseDto dto = participanteService.add(participanteDto, idEvento, currentUser.getResidencia().getId());
|
||||||
|
emailService.sendNotificationParticipante(dto);
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(dto);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene los datos de un participante específico en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante a consultar.
|
||||||
|
* @return {@link ResponseEntity} con los datos del participante encontrado.
|
||||||
|
*/
|
||||||
|
@GetMapping("{idParticipante}/get")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> get(@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
|
||||||
|
return ResponseEntity.ok(participanteService.get(currentUser.getResidencia().getId(), idEvento, idParticipante));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los participantes de un evento de salida, con filtros opcionales.
|
||||||
|
*
|
||||||
|
* @param idEvento ID del evento del que se obtienen los participantes.
|
||||||
|
* @param idResidente ID del residente (opcional).
|
||||||
|
* @param rM Recurso material (opcional).
|
||||||
|
* @param rH Recurso humano (opcional).
|
||||||
|
* @param minEdad Edad mínima del participante (opcional).
|
||||||
|
* @param maxEdad Edad máxima del participante (opcional).
|
||||||
|
* @param preOpinion Si se filtran por opinión previa (opcional).
|
||||||
|
* @param postOpinion Si se filtran por opinión posterior (opcional).
|
||||||
|
* @param asistenciPermitida Si se filtran por asistencia permitida (opcional).
|
||||||
|
* @return {@link ResponseEntity} con la lista de participantes filtrados.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll")
|
||||||
|
public ResponseEntity<List<ParticipanteResponseDto>> getAllParticipantes(
|
||||||
|
@PathVariable Long idEvento,
|
||||||
|
@RequestParam(required = false) Long idResidente,
|
||||||
|
@RequestParam(required = false) Boolean rM,
|
||||||
|
@RequestParam(required = false) Boolean rH,
|
||||||
|
@RequestParam(required = false) Integer minEdad,
|
||||||
|
@RequestParam(required = false) Integer maxEdad,
|
||||||
|
@RequestParam(required = false) Boolean preOpinion,
|
||||||
|
@RequestParam(required = false) Boolean postOpinion,
|
||||||
|
@RequestParam(required = false) Boolean asistenciPermitida) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(participanteService.getAll(currentUser.getResidencia().getId(), idEvento, idResidente, rM, rH, minEdad, maxEdad, preOpinion, postOpinion, asistenciPermitida));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina un participante de un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante a eliminar.
|
||||||
|
* @return {@link ResponseEntity} sin contenido si la eliminación fue exitosa.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{idParticipante}/delete")
|
||||||
|
public ResponseEntity<Void> deleteParticipante(@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
participanteService.deleteParticipante(currentUser.getResidencia().getId(), idEvento, idParticipante);
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Añade una opinión previa de un participante en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante al que se le añade la opinión.
|
||||||
|
* @param preOpinion Opinión previa del participante.
|
||||||
|
* @return {@link ResponseEntity} con el participante actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idParticipante}/addPreOpinion")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> addPreOpinion(@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante,
|
||||||
|
@RequestParam String preOpinion) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
|
||||||
|
return ResponseEntity.ok(participanteService.addPreOpinion(currentUser.getResidencia().getId(), idEvento, idParticipante, preOpinion));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Agrega una opinión posterior a la participación de un residente en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante al que se le agregará la opinión.
|
||||||
|
* @param postOpinion Opinión posterior a la participación.
|
||||||
|
* @return {@link ResponseEntity} con el participante actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idParticipante}/addPostOpinion")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> addPostOpinion(@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante,
|
||||||
|
@RequestParam String postOpinion) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
|
||||||
|
return ResponseEntity.ok(participanteService.addPostOpinion(currentUser.getResidencia().getId(), idEvento, idParticipante, postOpinion));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia los recursos asignados a un participante en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante a actualizar.
|
||||||
|
* @param rH Recurso humano (opcional).
|
||||||
|
* @param rM Recurso material (opcional).
|
||||||
|
* @return {@link ResponseEntity} con el participante actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idParticipante}/changeRecursos")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> changeRecursos(@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante,
|
||||||
|
@RequestParam(required = false) Boolean rH,
|
||||||
|
@RequestParam(required = false) Boolean rM) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
|
||||||
|
return ResponseEntity.ok(participanteService.changeRecursos(currentUser.getResidencia().getId(), idEvento, idParticipante, rH, rM));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acepta la participación un participante en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante a aceptar.
|
||||||
|
* @return {@link ResponseEntity} con el participante aceptado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("/{idParticipante}/allow")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> allow(@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(participanteService.allow(currentUser.getResidencia().getId(), idEvento, idParticipante));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deniega la participación de un residente en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante a denegar.
|
||||||
|
* @return {@link ResponseEntity} con el participante actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("/{idParticipante}/deny")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> deny(@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
|
||||||
|
return ResponseEntity.ok(participanteService.deny(currentUser.getResidencia().getId(), idEvento, idParticipante));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza los datos de un participante existente en un evento de salida.
|
||||||
|
*
|
||||||
|
* @param idParticipante ID del participante a actualizar.
|
||||||
|
* @param participanteDto DTO con los nuevos datos del participante.
|
||||||
|
* @return {@link ResponseEntity} con el participante actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idParticipante}/update")
|
||||||
|
public ResponseEntity<ParticipanteResponseDto> update(@PathVariable Long idEvento,
|
||||||
|
@PathVariable Long idParticipante,
|
||||||
|
@RequestBody ParticipanteDto participanteDto) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
|
||||||
|
return ResponseEntity.ok(participanteService.update(participanteDto, currentUser.getResidencia().getId(), idEvento, idParticipante));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.moduloWallet;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.modeloWallet.MovimientoRequestDTO;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.moduloWallet.WalletService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/admin/resi/{idResidencia}/resi/{idResidente}/wallet")
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class WalletAdminController {
|
||||||
|
|
||||||
|
private final WalletService walletService;
|
||||||
|
|
||||||
|
@GetMapping("/informe")
|
||||||
|
public ResponseEntity<byte[]> getInforme(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idResidente) {
|
||||||
|
|
||||||
|
try{
|
||||||
|
byte[] pdf = walletService.getInforme(idResidencia, idResidente);
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=informe_wallet_" + idResidente + ".pdf")
|
||||||
|
.contentType(MediaType.APPLICATION_PDF)
|
||||||
|
.body(pdf);
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@PostMapping("/deposit")
|
||||||
|
public ResponseEntity<String> deposit(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idResidente,
|
||||||
|
@RequestBody MovimientoRequestDTO input) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
walletService.deposit(idResidencia, idResidente, input);
|
||||||
|
return ResponseEntity.ok("Deposit successful");
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/retire")
|
||||||
|
public ResponseEntity<String> retire(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idResidente,
|
||||||
|
@RequestBody MovimientoRequestDTO input) {
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
walletService.retire(idResidencia, idResidente, input);
|
||||||
|
return ResponseEntity.ok("Retire successful");
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getSaldo")
|
||||||
|
public ResponseEntity<Double> getSaldo(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idResidente) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
Double saldo = walletService.getSaldo(idResidencia, idResidente);
|
||||||
|
return ResponseEntity.ok(saldo);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.moduloWallet;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.modeloWallet.MovimientoRequestDTO;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.moduloWallet.WalletService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
|
||||||
|
@RequestMapping("/resi/resident/{idResidente}/wallet")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class WalletController {
|
||||||
|
private final WalletService walletService;
|
||||||
|
|
||||||
|
@GetMapping("/informe")
|
||||||
|
public ResponseEntity<byte[]> getInforme(
|
||||||
|
@PathVariable Long idResidente) {
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
|
||||||
|
try{
|
||||||
|
byte[] pdf = walletService.getInforme(currentUser.getResidencia().getId(), idResidente);
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=informe_wallet_" + currentUser.getId() + ".pdf")
|
||||||
|
.contentType(MediaType.APPLICATION_PDF)
|
||||||
|
.body(pdf);
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deposit")
|
||||||
|
public ResponseEntity<String> deposit(
|
||||||
|
@PathVariable Long idResidente,
|
||||||
|
@RequestBody MovimientoRequestDTO input) {
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
try {
|
||||||
|
walletService.deposit(currentUser.getResidencia().getId(), idResidente, input);
|
||||||
|
return ResponseEntity.ok("Deposit successful");
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/retire")
|
||||||
|
public ResponseEntity<String> retire(
|
||||||
|
@PathVariable Long idResidente,
|
||||||
|
@RequestBody MovimientoRequestDTO input) {
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
try {
|
||||||
|
walletService.retire(currentUser.getResidencia().getId(), idResidente, input);
|
||||||
|
return ResponseEntity.ok("Retire successful");
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getSaldo")
|
||||||
|
public ResponseEntity<Double> getSaldo(
|
||||||
|
@PathVariable Long idResidente) {
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
try {
|
||||||
|
Double saldo = walletService.getSaldo(currentUser.getResidencia().getId(), idResidente);
|
||||||
|
return ResponseEntity.ok(saldo);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.modulojuego.juego;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.modulojuego.JuegoDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.modulojuego.JuegoResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.Dificultad;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.TipoAgrupacion;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.modulojuego.RegistroJuegoRepository;
|
||||||
|
import com.kevinolarte.resibenissa.services.modulojuego.JuegoService;
|
||||||
|
import com.kevinolarte.resibenissa.services.modulojuego.RegistroJuegoService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST que gestiona las operaciones relacionadas con los juegos en una residencia.
|
||||||
|
* <p>
|
||||||
|
* Permite registrar, consultar, listar, actualizar y eliminar juegos asociados a una residencia.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Ruta base: <b>/admin/resi/juego</b>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/admin/resi/juego")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class JuegoAdminController {
|
||||||
|
private final JuegoService juegoService;
|
||||||
|
private final RegistroJuegoRepository registroJuegoRepository;
|
||||||
|
private final RegistroJuegoService registroJuegoService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registra un nuevo juego asociado a una residencia.
|
||||||
|
*
|
||||||
|
* @param juegoDto Datos del juego a registrar.
|
||||||
|
* @return {@link ResponseEntity} con los datos del juego creado y estado 201 CREATED.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("/add")
|
||||||
|
public ResponseEntity<JuegoResponseDto> add(@RequestBody JuegoDto juegoDto) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(juegoService.save(juegoDto));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene los datos de un juego específico en una residencia.
|
||||||
|
* @param idJuego ID del juego a consultar.
|
||||||
|
* @return {@link ResponseEntity} con los datos del juego solicitado y estado 200 OK.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idJuego}/get")
|
||||||
|
public ResponseEntity<JuegoResponseDto> get(@PathVariable Long idJuego) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(juegoService.get(idJuego));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de todos los juegos registrados en una residencia.
|
||||||
|
*
|
||||||
|
* @param nombreJuego Nombre del juego para filtrar (opcional).
|
||||||
|
* @param maxRegistros Indica si se debe limitar la cantidad de registros devueltos (opcional).
|
||||||
|
* @return {@link ResponseEntity} con la lista de juegos y estado 200 OK.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll")
|
||||||
|
public ResponseEntity<?> getAll(
|
||||||
|
@RequestParam(required = false) String nombreJuego,
|
||||||
|
@RequestParam(required = false) Boolean maxRegistros) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(juegoService.getAll(nombreJuego, maxRegistros));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina un juego de una residencia si no tiene referencias dependientes.
|
||||||
|
*
|
||||||
|
* @param idJuego ID del juego a eliminar.
|
||||||
|
* @return {@link ResponseEntity} con estado 204 NO CONTENT si la eliminación es exitosa.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud o si el juego no puede ser eliminado.
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{idJuego}/delete")
|
||||||
|
public ResponseEntity<Void> delete(@PathVariable Long idJuego) {
|
||||||
|
try {
|
||||||
|
juegoService.delete(idJuego);
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO),e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza los datos de un juego ya registrado en una residencia.
|
||||||
|
*
|
||||||
|
* @param idJuego ID del juego a actualizar.
|
||||||
|
* @param juegoDto Datos nuevos del juego.
|
||||||
|
* @return {@link ResponseEntity} con los datos del juego actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud o si el juego no puede ser actualizado.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idJuego}/update")
|
||||||
|
public ResponseEntity<JuegoResponseDto> update(
|
||||||
|
@PathVariable Long idJuego,
|
||||||
|
@RequestBody JuegoDto juegoDto) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(juegoService.update(idJuego, juegoDto));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e,e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO),e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.modulojuego.juego;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.modulojuego.JuegoResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.Dificultad;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.TipoAgrupacion;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.modulojuego.JuegoService;
|
||||||
|
import com.kevinolarte.resibenissa.services.modulojuego.RegistroJuegoService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST que gestiona las operaciones relacionadas con los juegos en una residencia.
|
||||||
|
* <p>
|
||||||
|
* Permite registrar, consultar, listar, actualizar y eliminar juegos asociados a una residencia.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Ruta base: <b>/resi/juego</b>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/resi/juego")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class JuegoController {
|
||||||
|
private final JuegoService juegoService;
|
||||||
|
private final RegistroJuegoService registroJuegoService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene los datos de un juego específico dentro de una residencia.
|
||||||
|
*
|
||||||
|
* @param idJuego ID del juego a consultar.
|
||||||
|
* @return {@link ResponseEntity} con los datos del juego solicitado.
|
||||||
|
* @throws ResiException si ocurre un error al obtener el juego.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idJuego}/get")
|
||||||
|
public ResponseEntity<JuegoResponseDto> get(
|
||||||
|
@PathVariable Long idJuego) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
JuegoResponseDto juego;
|
||||||
|
try {
|
||||||
|
juego = juegoService.get(idJuego);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(juego);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de juegos de una residencia, con filtros opcionales por nombre y cantidad máxima.
|
||||||
|
*
|
||||||
|
* @param nombreJuego Filtro por nombre del juego (opcional).
|
||||||
|
* @param maxRegistros Si es {@code true}, limita los resultados a un número máximo (definido en servicio).
|
||||||
|
* @return {@link ResponseEntity} con la lista de juegos.
|
||||||
|
* @throws ApiException si ocurre un error al obtener los juegos.g
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll")
|
||||||
|
public ResponseEntity<List<JuegoResponseDto>> getAll(
|
||||||
|
@RequestParam(required = false) String nombreJuego,
|
||||||
|
@RequestParam(required = false) Boolean maxRegistros) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
List<JuegoResponseDto> juegos;
|
||||||
|
try {
|
||||||
|
juegos = juegoService.getAll(nombreJuego, maxRegistros);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(juegos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,352 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.modulojuego.registroJuego;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.modulojuego.RegistroJuegoDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.modulojuego.RegistroJuegoResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.Dificultad;
|
||||||
|
import com.kevinolarte.resibenissa.enums.Filtrado.RegistroJuegoFiltrado;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.TipoAgrupacion;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.modulojuego.RegistroJuegoService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.print.attribute.standard.Media;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST para gestionar los registros de juegos jugados por los residentes.
|
||||||
|
* <p>
|
||||||
|
* Permite agregar nuevos registros, consultar estadísticas con múltiples filtros,
|
||||||
|
* actualizar observaciones y eliminar registros específicos.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* URL base: <code>admin/resi</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/admin/resi")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RegistroJuegoAdminController {
|
||||||
|
|
||||||
|
private final RegistroJuegoService registroJuegoService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea un nuevo registro de juego para un residente en una residencia y juego específicos.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idJuego ID del juego.
|
||||||
|
* @param registroJuegoDto Datos del registro a guardar.
|
||||||
|
* @return El registro de juego creado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("{idResidencia}/registro/add")
|
||||||
|
public ResponseEntity<RegistroJuegoResponseDto> add(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestParam Long idJuego,
|
||||||
|
@RequestBody RegistroJuegoDto registroJuegoDto) {
|
||||||
|
try {
|
||||||
|
RegistroJuegoResponseDto registroJuego = registroJuegoService.add(idResidencia, idJuego, registroJuegoDto);
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(registroJuego);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene un registro de juego específico mediante su ID.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idRegistroJuego ID del registro de juego.
|
||||||
|
* @return El registro de juego solicitado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idResidencia}/registro/{idRegistroJuego}/get")
|
||||||
|
public ResponseEntity<RegistroJuegoResponseDto> get(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idRegistroJuego) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(registroJuegoService.get(idResidencia, idRegistroJuego));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de registros de juego filtrados por varios parámetros.
|
||||||
|
* @param idJuego ID del juego.
|
||||||
|
* @param dificultad Dificultad del juego (opcional).
|
||||||
|
* @param edad Edad del residente (opcional).
|
||||||
|
* @param minEdad Edad mínima del residente (opcional).
|
||||||
|
* @param maxEdad Edad máxima del residente (opcional).
|
||||||
|
* @param idResidente ID del residente (opcional).
|
||||||
|
* @param fecha Fecha del registro (opcional).
|
||||||
|
* @param minFecha Fecha mínima del registro (opcional).
|
||||||
|
* @param maxFecha Fecha máxima del registro (opcional).
|
||||||
|
* @param promedio true si se desea obtener el promedio de los registros, false en caso contrario.
|
||||||
|
* @param masPromedio true si se desea obtener los registros con puntajes superiores al promedio, false en caso contrario.
|
||||||
|
* @param menosPromedio true si se desea obtener los registros con puntajes inferiores al promedio, false en caso contrario.
|
||||||
|
* @return Lista de registros de juego filtrados.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/registro/getAll")
|
||||||
|
public ResponseEntity<List<RegistroJuegoResponseDto>> getAll(
|
||||||
|
@RequestParam(required = false) Long idJuego,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Integer edad,
|
||||||
|
@RequestParam(required = false) Integer minEdad,
|
||||||
|
@RequestParam(required = false) Integer maxEdad,
|
||||||
|
@RequestParam(required = false) Long idResidente,
|
||||||
|
@RequestParam(required = false) LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha,
|
||||||
|
@RequestParam(required = false) boolean promedio,
|
||||||
|
@RequestParam(required = false) boolean masPromedio,
|
||||||
|
@RequestParam(required = false) boolean menosPromedio,
|
||||||
|
@RequestParam(required = false) RegistroJuegoFiltrado filtrado,
|
||||||
|
@RequestParam(required = false) Boolean comentado) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(registroJuegoService.getAll(
|
||||||
|
idJuego, dificultad, edad, minEdad, maxEdad,
|
||||||
|
idResidente, fecha, minFecha, maxFecha,
|
||||||
|
promedio, masPromedio, menosPromedio,
|
||||||
|
filtrado, comentado));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de registros de juego filtrados por varios parámetros de una residencia especifica
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idJuego ID del juego.
|
||||||
|
* @param dificultad Dificultad del juego (opcional).
|
||||||
|
* @param edad Edad del residente (opcional).
|
||||||
|
* @param minEdad Edad mínima del residente (opcional).
|
||||||
|
* @param maxEdad Edad máxima del residente (opcional).
|
||||||
|
* @param idResidente ID del residente (opcional).
|
||||||
|
* @param fecha Fecha del registro (opcional).
|
||||||
|
* @param minFecha Fecha mínima del registro (opcional).
|
||||||
|
* @param maxFecha Fecha máxima del registro (opcional).
|
||||||
|
* @param promedio true si se desea obtener el promedio de los registros, false en caso contrario.
|
||||||
|
* @param masPromedio true si se desea obtener los registros con puntajes superiores al promedio, false en caso contrario.
|
||||||
|
* @param menosPromedio true si se desea obtener los registros con puntajes inferiores al promedio, false en caso contrario.
|
||||||
|
* @return Lista de registros de juego filtrados.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idResidencia}/registro/getAll")
|
||||||
|
public ResponseEntity<List<RegistroJuegoResponseDto>> getAll(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestParam(required = false) Long idJuego,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Integer edad,
|
||||||
|
@RequestParam(required = false) Integer minEdad,
|
||||||
|
@RequestParam(required = false) Integer maxEdad,
|
||||||
|
@RequestParam(required = false) Long idResidente,
|
||||||
|
@RequestParam(required = false) LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha,
|
||||||
|
@RequestParam(required = false) boolean promedio,
|
||||||
|
@RequestParam(required = false) boolean masPromedio,
|
||||||
|
@RequestParam(required = false) boolean menosPromedio,
|
||||||
|
@RequestParam(required = false) RegistroJuegoFiltrado filtrado,
|
||||||
|
@RequestParam(required = false) Boolean comentado) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(registroJuegoService.getAll(
|
||||||
|
idResidencia, idJuego, dificultad, edad, minEdad, maxEdad,
|
||||||
|
idResidente, fecha, minFecha, maxFecha,
|
||||||
|
promedio, masPromedio, menosPromedio,
|
||||||
|
filtrado, comentado));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza un registro de juego existente añadiendo o modificando una observación.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia donde se encuentra el registro.
|
||||||
|
* @param idRegistroJuego ID del registro a actualizar.
|
||||||
|
* @param registroJuegoDto DTO con los nuevos datos (principalmente observación).
|
||||||
|
* @return Registro de juego actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidencia}/registro/{idRegistroJuego}/addComment")
|
||||||
|
public ResponseEntity<RegistroJuegoResponseDto> update(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idRegistroJuego,
|
||||||
|
@RequestBody RegistroJuegoDto registroJuegoDto) {
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(registroJuegoService.update(idResidencia, idRegistroJuego, registroJuegoDto));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina un registro de juego específico.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia donde se encuentra el registro.
|
||||||
|
* @param idRegistroJuego ID del registro a eliminar.
|
||||||
|
* @return Respuesta sin contenido si la eliminación fue exitosa.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{idResidencia}/registro/{idRegistroJuego}/delete")
|
||||||
|
public ResponseEntity<Void> delete(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idRegistroJuego) {
|
||||||
|
try {
|
||||||
|
registroJuegoService.delete(idResidencia, idRegistroJuego);
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{idResidencia}/registro/media-duracion")
|
||||||
|
public ResponseEntity<List<MediaRegistroDTO>> getMediaDuracionPorResidencia(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestParam(required = false, defaultValue = "DIARIO") TipoAgrupacion tipo,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
|
||||||
|
|
||||||
|
try{
|
||||||
|
List<MediaRegistroDTO> medias = registroJuegoService.getMediaDuracionPorResidencia(idResidencia, tipo, dificultad, idJuego);
|
||||||
|
return ResponseEntity.ok(medias);
|
||||||
|
}catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{idResidencia}/registro/media-num")
|
||||||
|
public ResponseEntity<List<MediaRegistroDTO>> getMediaErroresPorResidencia(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestParam(required = false, defaultValue = "DIARIO") TipoAgrupacion tipo,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<MediaRegistroDTO> medias = registroJuegoService.getMediaErroresPorResidencia(idResidencia, tipo, dificultad, idJuego);
|
||||||
|
return ResponseEntity.ok(medias);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("{idResidencia}/registro/resident/{idResidente}/media-duracion")
|
||||||
|
public ResponseEntity<List<MediaRegistroDTO>> getMediaDuracionPorResidente(@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idResidente,
|
||||||
|
@RequestParam(required = false, defaultValue = "DIARIO") TipoAgrupacion tipo,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
try {
|
||||||
|
List<MediaRegistroDTO> medias = registroJuegoService.getMediaDuracion(idResidencia, idResidente, tipo, dificultad, idJuego);
|
||||||
|
return ResponseEntity.ok(medias);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("{idResidencia}/registro/resident/{idResidente}/media-num")
|
||||||
|
public ResponseEntity<List<MediaRegistroDTO>> getMediaNumPorResidente(@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idResidente,
|
||||||
|
@RequestParam(required = false, defaultValue = "DIARIO") TipoAgrupacion tipo,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
try {
|
||||||
|
List<MediaRegistroDTO> medias = registroJuegoService.getMediaErrores(idResidencia, idResidente, tipo, dificultad, idJuego);
|
||||||
|
return ResponseEntity.ok(medias);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Endpoint global que calcula el promedio de duración de los registros de juego
|
||||||
|
* agrupados por día, mes o año, para todos los registros del sistema.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Permite filtrar opcionalmente por:
|
||||||
|
* <ul>
|
||||||
|
* <li><b>Dificultad</b> del juego (FACIL, MEDIO, DIFICIL)</li>
|
||||||
|
* <li><b>ID del juego</b> específico</li>
|
||||||
|
* </ul>
|
||||||
|
* Si no se proporciona ningún filtro, se devolverá la media de duración de todos los juegos y dificultades del sistema.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param tipo Tipo de agrupación temporal: DIARIO (por defecto), MENSUAL o ANUAL.
|
||||||
|
* @param dificultad Nivel de dificultad del juego a filtrar (opcional).
|
||||||
|
* @param idJuego ID del juego a filtrar (opcional).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} que contienen el agrupamiento temporal (día, mes o año),
|
||||||
|
* el promedio de duración y el número de registros correspondientes.
|
||||||
|
*/
|
||||||
|
@GetMapping("/registro/media-duracion")
|
||||||
|
public ResponseEntity<List<MediaRegistroDTO>> getMediaDuracionPorResidencia(
|
||||||
|
@RequestParam(required = false, defaultValue = "DIARIO") TipoAgrupacion tipo,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
|
||||||
|
|
||||||
|
try{
|
||||||
|
List<MediaRegistroDTO> medias = registroJuegoService.getMediaDuracionGlobal(tipo, dificultad, idJuego);
|
||||||
|
return ResponseEntity.ok(medias);
|
||||||
|
}catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/registro/media-num")
|
||||||
|
public ResponseEntity<List<MediaRegistroDTO>> getMediaErroresPorResidencia(
|
||||||
|
@RequestParam(required = false, defaultValue = "DIARIO") TipoAgrupacion tipo,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<MediaRegistroDTO> medias = registroJuegoService.getMediaErroresGlobal(tipo, dificultad, idJuego);
|
||||||
|
return ResponseEntity.ok(medias);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,251 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.modulojuego.registroJuego;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.modulojuego.RegistroJuegoDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.modulojuego.RegistroJuegoResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.Dificultad;
|
||||||
|
import com.kevinolarte.resibenissa.enums.Filtrado.RegistroJuegoFiltrado;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.TipoAgrupacion;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.modulojuego.RegistroJuegoService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST para gestionar los registros de juegos jugados por los residentes.
|
||||||
|
* <p>
|
||||||
|
* Permite agregar nuevos registros, consultar estadísticas con múltiples filtros,
|
||||||
|
* actualizar observaciones y eliminar registros específicos.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Todas las rutas expuestas están bajo el prefijo <code>/resi/registro</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/resi/registro")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RegistroJuegoController {
|
||||||
|
|
||||||
|
private final RegistroJuegoService registroJuegoService;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea un nuevo registro de juego para un residente en una residencia y juego específicos.
|
||||||
|
*
|
||||||
|
* @param idJuego ID del juego.
|
||||||
|
* @param registroJuegoDto Datos del registro a guardar.
|
||||||
|
* @return El registro de juego creado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("/juego/{idJuego}/add")
|
||||||
|
public ResponseEntity<RegistroJuegoResponseDto> add(
|
||||||
|
@PathVariable Long idJuego,
|
||||||
|
@RequestBody RegistroJuegoDto registroJuegoDto) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
registroJuegoDto.setIdUsuario(currentUser.getId());
|
||||||
|
RegistroJuegoResponseDto registroJuego = registroJuegoService.add(currentUser.getResidencia().getId(), idJuego, registroJuegoDto);
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(registroJuego);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene un registro de juego específico mediante su ID.
|
||||||
|
*
|
||||||
|
*@param idRegistroJuego ID del registro de juego.
|
||||||
|
* @return El registro de juego solicitado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idRegistroJuego}/get")
|
||||||
|
public ResponseEntity<RegistroJuegoResponseDto> get(@PathVariable Long idRegistroJuego) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(registroJuegoService.get(currentUser.getResidencia().getId(), idRegistroJuego));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de registros de juego filtrados por varios parámetros.
|
||||||
|
* @param idJuego ID del juego.
|
||||||
|
* @param edad Edad del residente (opcional).
|
||||||
|
* @param minEdad Edad mínima del residente (opcional).
|
||||||
|
* @param maxEdad Edad máxima del residente (opcional).
|
||||||
|
* @param idResidente ID del residente (opcional).
|
||||||
|
* @param fecha Fecha del registro (opcional).
|
||||||
|
* @param minFecha Fecha mínima del registro (opcional).
|
||||||
|
* @param maxFecha Fecha máxima del registro (opcional).
|
||||||
|
* @param promedio true si se desea obtener el promedio de los registros, false en caso contrario.
|
||||||
|
* @param masPromedio true si se desea obtener los registros con puntajes superiores al promedio, false en caso contrario.
|
||||||
|
* @param menosPromedio true si se desea obtener los registros con puntajes inferiores al promedio, false en caso contrario.
|
||||||
|
* @param dificultad Dificultad del juego (opcional).
|
||||||
|
* @return Lista de registros de juego filtrados.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll")
|
||||||
|
public ResponseEntity<List<RegistroJuegoResponseDto>> getAll(
|
||||||
|
@RequestParam(required = false) Long idJuego,
|
||||||
|
@RequestParam(required = false) Long idResidente,
|
||||||
|
@RequestParam(required = false) Integer edad,
|
||||||
|
@RequestParam(required = false) Integer minEdad,
|
||||||
|
@RequestParam(required = false) Integer maxEdad,
|
||||||
|
@RequestParam(required = false) LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha,
|
||||||
|
@RequestParam(required = false) boolean promedio,
|
||||||
|
@RequestParam(required = false) boolean masPromedio,
|
||||||
|
@RequestParam(required = false) boolean menosPromedio,
|
||||||
|
@RequestParam(required = false) RegistroJuegoFiltrado filtrado,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Boolean comentado) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(
|
||||||
|
registroJuegoService.getAll(
|
||||||
|
currentUser.getResidencia().getId(),
|
||||||
|
idJuego, dificultad, edad, minEdad, maxEdad,
|
||||||
|
idResidente, fecha, minFecha, maxFecha,
|
||||||
|
promedio, masPromedio, menosPromedio, filtrado, comentado
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza un registro de juego existente añadiendo o modificando una observación.
|
||||||
|
*
|
||||||
|
* @param idRegistroJuego ID del registro a actualizar.
|
||||||
|
* @param registroJuegoDto DTO con los nuevos datos (principalmente observación).
|
||||||
|
* @return Registro de juego actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idRegistroJuego}/addComment")
|
||||||
|
public ResponseEntity<RegistroJuegoResponseDto> update(
|
||||||
|
@PathVariable Long idRegistroJuego,
|
||||||
|
@RequestBody RegistroJuegoDto registroJuegoDto) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
return ResponseEntity.ok(registroJuegoService.update(currentUser.getResidencia().getId(), idRegistroJuego, registroJuegoDto));
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina un registro de juego específico.
|
||||||
|
*
|
||||||
|
* @param idRegistroJuego ID del registro a eliminar.
|
||||||
|
* @return Respuesta sin contenido si la eliminación fue exitosa.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{idRegistroJuego}/delete")
|
||||||
|
public ResponseEntity<Void> delete(@PathVariable Long idRegistroJuego) {
|
||||||
|
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
try {
|
||||||
|
registroJuegoService.delete(currentUser.getResidencia().getId(), idRegistroJuego);
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/media-duracion")
|
||||||
|
public ResponseEntity<List<MediaRegistroDTO>> getMediaDuracionPorResidencia(
|
||||||
|
@RequestParam(required = false, defaultValue = "DIARIO") TipoAgrupacion tipo,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
|
||||||
|
try{
|
||||||
|
List<MediaRegistroDTO> medias = registroJuegoService.getMediaDuracionPorResidencia(currentUser.getResidencia().getId(), tipo, dificultad, idJuego);
|
||||||
|
return ResponseEntity.ok(medias);
|
||||||
|
}catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/media-num")
|
||||||
|
public ResponseEntity<List<MediaRegistroDTO>> getMediaErroresPorResidencia(
|
||||||
|
@RequestParam(required = false, defaultValue = "DIARIO") TipoAgrupacion tipo,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<MediaRegistroDTO> medias = registroJuegoService.getMediaErroresPorResidencia(currentUser.getResidencia().getId(), tipo, dificultad, idJuego);
|
||||||
|
return ResponseEntity.ok(medias);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/resident/{idResidente}/media-duracion")
|
||||||
|
public ResponseEntity<List<MediaRegistroDTO>> getMediaDuracion(
|
||||||
|
@PathVariable Long idResidente,
|
||||||
|
@RequestParam(required = false, defaultValue = "DIARIO") TipoAgrupacion tipo,
|
||||||
|
@RequestParam(required = false) Dificultad dificultad,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
|
||||||
|
List<MediaRegistroDTO> medias;
|
||||||
|
try {
|
||||||
|
medias = registroJuegoService.getMediaDuracion(currentUser.getResidencia().getId(), idResidente, tipo, dificultad, idJuego);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok(medias);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.residencia;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.ResidenciaDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.ResidenciaPublicResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.ResidenciaResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import com.kevinolarte.resibenissa.services.ResidenciaService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador que expone endpoints REST para gestionar entidades {@link Residencia}.
|
||||||
|
* <p>
|
||||||
|
* Permite crear nuevas residencias, obtenerlas por ID y eliminarlas.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* URL Base: {@code /admin/resi}
|
||||||
|
*
|
||||||
|
* Autor: Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/admin/resi/")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ResidenciaAdminController {
|
||||||
|
|
||||||
|
private final ResidenciaService residenciaService;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea una nueva residencia.
|
||||||
|
*
|
||||||
|
* @param residenciaDto DTO con los datos de la residencia a crear.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 201 Created} y el DTO de la residencia creada.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud.
|
||||||
|
*/
|
||||||
|
@PostMapping("/add")
|
||||||
|
public ResponseEntity<ResidenciaResponseDto> add(
|
||||||
|
@RequestBody ResidenciaDto residenciaDto) {
|
||||||
|
ResidenciaResponseDto residencia;
|
||||||
|
try {
|
||||||
|
residencia = residenciaService.add(residenciaDto);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
// Manejo de excepciones específicas de la aplicación
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Manejo de excepciones genéricas
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(residencia);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una residencia por su ID.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia a recuperar.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 200 OK} y el DTO de la residencia encontrada.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idResidencia}/get")
|
||||||
|
public ResponseEntity<ResidenciaResponseDto> get(
|
||||||
|
@PathVariable Long idResidencia) {
|
||||||
|
ResidenciaResponseDto residencia;
|
||||||
|
try {
|
||||||
|
residencia = residenciaService.get(idResidencia);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
// Manejo de excepciones específicas de la aplicación
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Manejo de excepciones genéricas
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residencia);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todas las residencias.
|
||||||
|
*
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 200 OK} y una lista de DTOs de residencias.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener las residencias.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll")
|
||||||
|
public ResponseEntity<List<ResidenciaPublicResponseDto>> getAll() {
|
||||||
|
List<ResidenciaPublicResponseDto> residencias;
|
||||||
|
try {
|
||||||
|
residencias = residenciaService.getAll();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Manejo de excepciones genéricas
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residencias);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los que estan de baja
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 200 OK} y una lista de DTOs de residencias.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener las residencias.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll/baja")
|
||||||
|
public ResponseEntity<List<ResidenciaPublicResponseDto>> getAllBaja() {
|
||||||
|
List<ResidenciaPublicResponseDto> residencias;
|
||||||
|
try {
|
||||||
|
residencias = residenciaService.getAllBaja();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Manejo de excepciones genéricas
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residencias);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina una residencia por su ID.
|
||||||
|
*
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 204 No Content} si la eliminación fue exitosa.
|
||||||
|
* @param idResidencia ID de la residencia a eliminar.
|
||||||
|
* @throws ApiException si ocurre un error al intentar eliminar la residencia.
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{idResidencia}/delete")
|
||||||
|
public ResponseEntity<Void> remove(
|
||||||
|
@PathVariable Long idResidencia) {
|
||||||
|
try {
|
||||||
|
residenciaService.deleteFisico(idResidencia);
|
||||||
|
}catch (ResiException e) {
|
||||||
|
// Manejo de excepciones específicas de la aplicación
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Manejo de excepciones genéricas
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina una residencia de forma lógica. Dandolo de baja.
|
||||||
|
*
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 204 No Content} si la eliminación fue exitosa.
|
||||||
|
* @param idResidencia ID de la residencia a dar de baja.
|
||||||
|
* @throws ApiException si ocurre un error al intentar eliminar la residencia.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidencia}/baja")
|
||||||
|
public ResponseEntity<Void> baja(
|
||||||
|
@PathVariable Long idResidencia) {
|
||||||
|
try {
|
||||||
|
residenciaService.deleteLogico(idResidencia);
|
||||||
|
}catch (ResiException e) {
|
||||||
|
// Manejo de excepciones específicas de la aplicación
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Manejo de excepciones genéricas
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.residencia;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.ResidenciaDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.ResidenciaPublicResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.ResidenciaResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.ResidenciaService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador que expone endpoints REST para gestionar entidades {@link Residencia}.
|
||||||
|
* <p>
|
||||||
|
* Permite crear nuevas residencias, obtenerlas por ID y eliminarlas.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* URL Base: {@code /resi}
|
||||||
|
*
|
||||||
|
* Autor: Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/resi")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ResidenciaController {
|
||||||
|
|
||||||
|
private final ResidenciaService residenciaService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una residencia por su ID.
|
||||||
|
*
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 200 OK} y el DTO de la residencia encontrada.
|
||||||
|
* @throws ResiException si ocurre un error al obtener la residencia.
|
||||||
|
*/
|
||||||
|
@GetMapping("/get")
|
||||||
|
public ResponseEntity<ResidenciaResponseDto> get() {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
ResidenciaResponseDto residencia;
|
||||||
|
try{
|
||||||
|
residencia = residenciaService.get(currentUser.getResidencia().getId());
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residencia);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todas las residencias.
|
||||||
|
*
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 200 OK} y una lista de DTOs de residencias.
|
||||||
|
* @throws ApiException si ocurre un error al obtener las residencias.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll")
|
||||||
|
public ResponseEntity<List<ResidenciaPublicResponseDto>> getAll() {
|
||||||
|
List<ResidenciaPublicResponseDto> residencias;
|
||||||
|
try{
|
||||||
|
residencias = residenciaService.getAll();
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residencias);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,315 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.residente;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.ResidenteDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.moduloReporting.EmailRequestDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.ResidenteResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO;
|
||||||
|
import com.kevinolarte.resibenissa.enums.Filtrado.ResidenteFiltrado;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.Dificultad;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.TipoAgrupacion;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.ResidenteService;
|
||||||
|
import com.kevinolarte.resibenissa.services.modulojuego.RegistroJuegoService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST para la administración de residentes dentro de una residencia.
|
||||||
|
* <p>
|
||||||
|
* Permite registrar, consultar, actualizar, eliminar y listar residentes
|
||||||
|
* aplicando filtros opcionales, tanto a nivel de una residencia específica como global.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* URL base: {@code /admin/resi}
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/admin/resi/")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ResidenteAdminController {
|
||||||
|
private final ResidenteService residenteService;
|
||||||
|
private final RegistroJuegoService registroJuegoService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registra un nuevo residente dentro de una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param residenteDto DTO con los datos del residente a crear.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 201 Created} y el residente creado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud, como campos obligatorios faltantes
|
||||||
|
*/
|
||||||
|
@PostMapping("/{idResidencia}/resident/add")
|
||||||
|
public ResponseEntity<ResidenteResponseDto> add(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestBody ResidenteDto residenteDto){
|
||||||
|
ResidenteResponseDto residenteResponseDto;
|
||||||
|
try{
|
||||||
|
residenteResponseDto = residenteService.add(idResidencia, residenteDto);
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(residenteResponseDto);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene los detalles de un residente específico dentro de una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 200 OK} y los datos del residente.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud, como campos obligatorios faltantes
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idResidencia}/resident/{idResidente}/get")
|
||||||
|
public ResponseEntity<ResidenteResponseDto> get(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idResidente) {
|
||||||
|
|
||||||
|
ResidenteResponseDto residenteResponseDto;
|
||||||
|
try {
|
||||||
|
residenteResponseDto = residenteService.get(idResidencia, idResidente);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residenteResponseDto);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lista todos los residentes de una residencia, aplicando filtros opcionales.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param fechaNacimiento Fecha exacta de nacimiento.
|
||||||
|
* @param minFNac Fecha mínima de nacimiento.
|
||||||
|
* @param maxFNac Fecha máxima de nacimiento.
|
||||||
|
* @param maxAge Edad máxima.
|
||||||
|
* @param minAge Edad mínima.
|
||||||
|
* @param idJuego ID de juego asociado (opcional).
|
||||||
|
* @param idEvento ID de evento asociado (opcional).
|
||||||
|
* @return {@link ResponseEntity} con la lista de residentes filtrados.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud, como campos obligatorios faltantes
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idResidencia}/resident/getAll")
|
||||||
|
public ResponseEntity<List<ResidenteResponseDto>> getAll(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestParam(required = false) LocalDate fechaNacimiento,
|
||||||
|
@RequestParam(required = false) LocalDate minFNac,
|
||||||
|
@RequestParam(required = false) LocalDate maxFNac,
|
||||||
|
@RequestParam(required = false) Integer maxAge,
|
||||||
|
@RequestParam(required = false) Integer minAge,
|
||||||
|
@RequestParam(required = false) Long idJuego,
|
||||||
|
@RequestParam(required = false) Long idEvento,
|
||||||
|
@RequestParam(required = false)ResidenteFiltrado filtrado) {
|
||||||
|
|
||||||
|
List<ResidenteResponseDto> residentes;
|
||||||
|
try {
|
||||||
|
residentes = residenteService.getAll(idResidencia, fechaNacimiento, minFNac, maxFNac, maxAge, minAge, idJuego, idEvento, filtrado);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residentes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lista todos los residentes en el sistema, sin filtrar por residencia.
|
||||||
|
*
|
||||||
|
* @param fechaNacimiento Fecha exacta de nacimiento.
|
||||||
|
* @param minFNac Fecha mínima de nacimiento.
|
||||||
|
* @param maxFNac Fecha máxima de nacimiento.
|
||||||
|
* @param maxAge Edad máxima.
|
||||||
|
* @param minAge Edad mínima.
|
||||||
|
* @param idJuego ID de juego asociado (opcional).
|
||||||
|
* @param idEvento ID de evento asociado (opcional).
|
||||||
|
* @return {@link ResponseEntity} con la lista global de residentes filtrados.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud, como campos obligatorios faltantes
|
||||||
|
*/
|
||||||
|
@GetMapping("/resident/getAll")
|
||||||
|
public ResponseEntity<List<ResidenteResponseDto>> getAll(
|
||||||
|
@RequestParam(required = false) LocalDate fechaNacimiento,
|
||||||
|
@RequestParam(required = false) LocalDate minFNac,
|
||||||
|
@RequestParam(required = false) LocalDate maxFNac,
|
||||||
|
@RequestParam(required = false) Integer maxAge,
|
||||||
|
@RequestParam(required = false) Integer minAge,
|
||||||
|
@RequestParam(required = false) Long idJuego,
|
||||||
|
@RequestParam(required = false) Long idEvento,
|
||||||
|
@RequestParam(required = false) ResidenteFiltrado filtrado) {
|
||||||
|
List<ResidenteResponseDto> residentes;
|
||||||
|
try {
|
||||||
|
residentes = residenteService.getAll(fechaNacimiento, minFNac, maxFNac, maxAge, minAge, idJuego, idEvento, filtrado);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residentes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lista todos los residentes dados de baja dentro de una residencia, filtrando opcionalmente por fecha.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param fecha Fecha exacta de baja (opcional).
|
||||||
|
* @param minFecha Fecha mínima de baja (opcional).
|
||||||
|
* @param maxFecha Fecha máxima de baja (opcional).
|
||||||
|
* @return {@link ResponseEntity} con la lista de residentes dados de baja.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud, como campos obligatorios faltantes
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idResidencia}/resident/getAll/bajas")
|
||||||
|
public ResponseEntity<List<ResidenteResponseDto>> getAllBajas(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestParam(required = false) LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha){
|
||||||
|
List<ResidenteResponseDto> residentes;
|
||||||
|
try{
|
||||||
|
residentes = residenteService.getAllBajas(idResidencia, fecha, minFecha, maxFecha);
|
||||||
|
}catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residentes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lista todos los residentes dados de baja del sistema (sin filtro de residencia).
|
||||||
|
*
|
||||||
|
* @param fecha Fecha exacta de baja (opcional).
|
||||||
|
* @param minFecha Fecha mínima de baja (opcional).
|
||||||
|
* @param maxFecha Fecha máxima de baja (opcional).
|
||||||
|
* @return {@link ResponseEntity} con la lista global de residentes dados de baja.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud, como campos obligatorios faltantes
|
||||||
|
*/
|
||||||
|
@GetMapping("/resident/getAll/bajas")
|
||||||
|
public ResponseEntity<List<ResidenteResponseDto>> getAllBajas(
|
||||||
|
@RequestParam(required = false) LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha){
|
||||||
|
List<ResidenteResponseDto> residentes;
|
||||||
|
try {
|
||||||
|
residentes = residenteService.getAllBajas(fecha, minFecha, maxFecha);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residentes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina físicamente un residente de una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 204 No Content} si la eliminación fue exitosa.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud, como campos obligatorios faltantes
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{idResidencia}/resident/{idResidente}/delete")
|
||||||
|
public ResponseEntity<Void> delete(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idResidente) {
|
||||||
|
|
||||||
|
try{
|
||||||
|
residenteService.deleteFisico(idResidencia,idResidente);
|
||||||
|
}catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marca lógicamente como dado de baja a un residente (sin eliminarlo físicamente).
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 204 No Content} si se realizó correctamente.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud, como campos obligatorios faltantes
|
||||||
|
*/
|
||||||
|
@PatchMapping("{idResidencia}/resident/{idResidente}/baja")
|
||||||
|
public ResponseEntity<Void> deleteLogico(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idResidente) {
|
||||||
|
try{
|
||||||
|
residenteService.deleteLogico(idResidencia,idResidente);
|
||||||
|
|
||||||
|
}catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza parcialmente los datos de un residente dentro de una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idResidente ID del residente a actualizar.
|
||||||
|
* @param residenteDto DTO con los datos a actualizar.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 200 OK} y el residente actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al procesar la solicitud, como campos obligatorios faltantes
|
||||||
|
*/
|
||||||
|
@PatchMapping("{idResidencia}/resident/{idResidente}/update")
|
||||||
|
public ResponseEntity<ResidenteResponseDto> update(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idResidente,
|
||||||
|
@RequestBody ResidenteDto residenteDto) {
|
||||||
|
ResidenteResponseDto residenteResponseDto;
|
||||||
|
try {
|
||||||
|
residenteResponseDto = residenteService.update(idResidencia, idResidente, residenteDto);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residenteResponseDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envía un correo electrónico a un familiar de un residente.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @param emailRequestDto DTO con los datos del correo a enviar.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 204 No Content} si el envío fue exitoso.
|
||||||
|
*/
|
||||||
|
@PostMapping("/{idResidencia}/resident/{idResidente}/sendEmailFamily")
|
||||||
|
public ResponseEntity<Void> sendEmailFamily(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idResidente,
|
||||||
|
@RequestBody EmailRequestDto emailRequestDto) {
|
||||||
|
try{
|
||||||
|
residenteService.sendEmailFamiliar(idResidencia, idResidente, emailRequestDto);
|
||||||
|
|
||||||
|
}catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,267 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.residente;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.config.Conf;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.ResidenteDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.moduloReporting.EmailRequestDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.ResidenteResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO;
|
||||||
|
import com.kevinolarte.resibenissa.enums.Filtrado.ResidenteFiltrado;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.Dificultad;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.TipoAgrupacion;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.ResidenteService;
|
||||||
|
import com.kevinolarte.resibenissa.services.modulojuego.RegistroJuegoService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST que gestiona las operaciones relacionadas con los residentes de una residencia.
|
||||||
|
* <p>
|
||||||
|
* Permite registrar, consultar, actualizar, listar y dar de baja residentes.
|
||||||
|
* Todas las operaciones se contextualizan dentro de la residencia del usuario autenticado.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* URL base: {@code /resi/resident}
|
||||||
|
*
|
||||||
|
* Autor: Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/resi/resident")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ResidenteController {
|
||||||
|
|
||||||
|
private final ResidenteService residenteService;
|
||||||
|
private final RegistroJuegoService registroJuegoService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registra un nuevo residente en la residencia del usuario autenticado.
|
||||||
|
*
|
||||||
|
* @param residenteDto DTO con los datos del nuevo residente.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 201 Created} y el residente creado.
|
||||||
|
* @throws ApiException si ocurre un error durante el proceso de registro.
|
||||||
|
*/
|
||||||
|
@PostMapping("/add")
|
||||||
|
public ResponseEntity<ResidenteResponseDto> add(
|
||||||
|
@RequestBody ResidenteDto residenteDto){
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
|
||||||
|
ResidenteResponseDto residenteResponseDto;
|
||||||
|
try {
|
||||||
|
residenteResponseDto = residenteService.add(currentUser.getResidencia().getId(), residenteDto);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(residenteResponseDto);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene los detalles de un residente específico perteneciente a la misma residencia que el usuario autenticado.
|
||||||
|
*
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 200 OK} y el residente encontrado.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener el residente.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idResidente}/get")
|
||||||
|
public ResponseEntity<ResidenteResponseDto> get(
|
||||||
|
@PathVariable Long idResidente) {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
|
||||||
|
ResidenteResponseDto residenteResponseDto;
|
||||||
|
try {
|
||||||
|
residenteResponseDto = residenteService.get(currentUser.getResidencia().getId(), idResidente);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residenteResponseDto);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lista todos los residentes de la residencia del usuario autenticado, con múltiples filtros opcionales.
|
||||||
|
*
|
||||||
|
* @param fechaNacimiento Fecha exacta de nacimiento.
|
||||||
|
* @param minFNac Fecha mínima de nacimiento.
|
||||||
|
* @param maxFNac Fecha máxima de nacimiento.
|
||||||
|
* @param maxAge Edad máxima.
|
||||||
|
* @param minAge Edad mínima.
|
||||||
|
* @param idJuego ID de juego asociado (opcional).
|
||||||
|
* @param idEvento ID de evento asociado (opcional).
|
||||||
|
* @return {@link ResponseEntity} con la lista de residentes filtrados.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener los residentes.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll")
|
||||||
|
public ResponseEntity<List<ResidenteResponseDto>> getAll(
|
||||||
|
@RequestParam(required = false) LocalDate fechaNacimiento,
|
||||||
|
@RequestParam(required = false) LocalDate minFNac,
|
||||||
|
@RequestParam(required = false) LocalDate maxFNac,
|
||||||
|
@RequestParam(required = false) Integer maxAge,
|
||||||
|
@RequestParam(required = false) Integer minAge,
|
||||||
|
@RequestParam(required = false) Long idJuego,
|
||||||
|
@RequestParam(required = false) Long idEvento,
|
||||||
|
@RequestParam(required = false)ResidenteFiltrado filtrado) {
|
||||||
|
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
|
||||||
|
List<ResidenteResponseDto> residentes;
|
||||||
|
try{
|
||||||
|
residentes = residenteService.getAll(currentUser.getResidencia().getId(),fechaNacimiento, minFNac, maxFNac, maxAge, minAge, idJuego, idEvento, filtrado);
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residentes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lista todos los residentes dados de baja en la residencia del usuario autenticado,
|
||||||
|
* con posibilidad de filtrar por fechas.
|
||||||
|
*
|
||||||
|
* @param fecha Fecha exacta de baja (opcional).
|
||||||
|
* @param minFecha Fecha mínima de baja (opcional).
|
||||||
|
* @param maxFecha Fecha máxima de baja (opcional).
|
||||||
|
* @return {@link ResponseEntity} con la lista de residentes dados de baja.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener los residentes dados de baja.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll/bajas")
|
||||||
|
public ResponseEntity<List<ResidenteResponseDto>> getAllBajas(
|
||||||
|
@RequestParam(required = false) LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha){
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
List<ResidenteResponseDto> residentesBajas;
|
||||||
|
try {
|
||||||
|
residentesBajas = residenteService.getAllBajas(currentUser.getResidencia().getId(),fecha, minFecha, maxFecha);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residentesBajas);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marca lógicamente como dado de baja a un residente (no lo elimina físicamente).
|
||||||
|
*
|
||||||
|
* @param idResidente ID del residente a dar de baja.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 204 No Content} si se realizó correctamente.
|
||||||
|
* @throws ApiException si ocurre un error al intentar dar de baja al residente.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidente}/baja")
|
||||||
|
public ResponseEntity<Void> deleteLogico(
|
||||||
|
@PathVariable Long idResidente) {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
try{
|
||||||
|
residenteService.deleteLogico(currentUser.getResidencia().getId(),idResidente);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza parcialmente los datos de un residente específico.
|
||||||
|
*
|
||||||
|
* @param idResidente ID del residente a actualizar.
|
||||||
|
* @param residenteDto DTO con los nuevos datos del residente.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 200 OK} y el residente actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al intentar actualizar el residente.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidente}/update")
|
||||||
|
public ResponseEntity<ResidenteResponseDto> update(
|
||||||
|
@PathVariable Long idResidente,
|
||||||
|
@RequestBody ResidenteDto residenteDto) {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
ResidenteResponseDto residenteResponseDto;
|
||||||
|
try {
|
||||||
|
residenteResponseDto = residenteService.update(currentUser.getResidencia().getId(), idResidente, residenteDto);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO),currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(residenteResponseDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envía un correo electrónico a un familiar de un residente específico.
|
||||||
|
*
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @param emailRequestDto DTO con los detalles del correo electrónico.
|
||||||
|
* @return {@link ResponseEntity} con estado {@code 204 No Content} si se envió correctamente.
|
||||||
|
*/
|
||||||
|
@PostMapping("/{idResidente}/sendEmailFamily")
|
||||||
|
public ResponseEntity<Void> sendEmailFamily(
|
||||||
|
@PathVariable Long idResidente,
|
||||||
|
@RequestBody EmailRequestDto emailRequestDto) {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
try{
|
||||||
|
residenteService.sendEmailFamiliar(currentUser.getResidencia().getId(), idResidente, emailRequestDto);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Descarga la imagen por defecto del usuario.
|
||||||
|
*
|
||||||
|
* @return Recurso de imagen por defecto como archivo adjunto.
|
||||||
|
*/
|
||||||
|
@GetMapping("/defualtImage")
|
||||||
|
public ResponseEntity<Resource> downloadImage(){
|
||||||
|
Resource resource = residenteService.getImage(Conf.imageDefault);
|
||||||
|
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
|
||||||
|
.body(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,342 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.user;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.UserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.auth.ChangePasswordUserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.UserResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.services.UserService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST para la administración de usuarios dentro de una residencia.
|
||||||
|
*
|
||||||
|
* Proporciona operaciones para registrar, consultar, actualizar, desactivar
|
||||||
|
* y eliminar usuarios. Admite filtros por estado, juego asociado y fecha de baja.
|
||||||
|
*
|
||||||
|
* URL base: {@code /admin/resi}
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/admin/resi")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class UserAdminController {
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registra un nuevo usuario en una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param userDto Datos del usuario a registrar.
|
||||||
|
* @return Usuario creado.
|
||||||
|
* @throws ApiException si ocurre un error durante el registro.
|
||||||
|
*/
|
||||||
|
@PostMapping("{idResidencia}/user/add")
|
||||||
|
public ResponseEntity<UserResponseDto> addUser(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestBody UserDto userDto) {
|
||||||
|
|
||||||
|
UserResponseDto user;
|
||||||
|
|
||||||
|
try {
|
||||||
|
user = userService.add(idResidencia, userDto);
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene un usuario por su ID dentro de una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idUser ID del usuario.
|
||||||
|
* @return Datos del usuario.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener el usuario.
|
||||||
|
*/
|
||||||
|
@GetMapping("{idResidencia}/user/{idUser}/get")
|
||||||
|
public ResponseEntity<UserResponseDto> get(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idUser) {
|
||||||
|
UserResponseDto user;
|
||||||
|
try {
|
||||||
|
user = userService.get(idResidencia, idUser);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene un usuario por su email dentro de una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param email Email del usuario.
|
||||||
|
* @return Datos del usuario.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener el usuario.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idResidencia}/user/get")
|
||||||
|
public ResponseEntity<UserResponseDto> get(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestParam(required = true) String email) {
|
||||||
|
|
||||||
|
UserResponseDto user;
|
||||||
|
try {
|
||||||
|
user = userService.get(idResidencia, email);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de usuarios filtrada por estado y/o juego dentro de una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param enabled Filtro por estado habilitado (opcional).
|
||||||
|
* @param idJuego Filtro por ID de juego (opcional).
|
||||||
|
* @return Lista de usuarios.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener los usuarios.
|
||||||
|
*/
|
||||||
|
@GetMapping("{idResidencia}/user/getAll")
|
||||||
|
public ResponseEntity<List<UserResponseDto>> getAll(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestParam(required = false) Boolean enabled,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
|
||||||
|
List<UserResponseDto> user;
|
||||||
|
try {
|
||||||
|
user = userService.getAll(idResidencia, enabled, idJuego);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los usuarios, con filtros por estado y/o juego (sin filtrar por residencia).
|
||||||
|
*
|
||||||
|
* @param enabled Filtro por estado habilitado (opcional).
|
||||||
|
* @param idJuego Filtro por ID de juego (opcional).
|
||||||
|
* @return Lista de usuarios.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener los usuarios.
|
||||||
|
*/
|
||||||
|
@GetMapping("/user/getAll")
|
||||||
|
public ResponseEntity<List<UserResponseDto>> getAll(
|
||||||
|
@RequestParam(required = false) Boolean enabled,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
|
||||||
|
List<UserResponseDto> user;
|
||||||
|
try {
|
||||||
|
user = userService.getAll(enabled, idJuego);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de usuarios dados de baja en una residencia, con filtros de fecha.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param fecha Fecha exacta de baja (opcional).
|
||||||
|
* @param minFecha Fecha mínima de baja (opcional).
|
||||||
|
* @param maxFecha Fecha máxima de baja (opcional).
|
||||||
|
* @return Lista de usuarios dados de baja.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener los usuarios dados de baja.
|
||||||
|
*/
|
||||||
|
@GetMapping("{idResidencia}/user/getAll/bajas")
|
||||||
|
public ResponseEntity<List<UserResponseDto>> getAllBajas(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@RequestParam(required = false)LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha){
|
||||||
|
|
||||||
|
List<UserResponseDto> user;
|
||||||
|
try {
|
||||||
|
user = userService.getAllBajas(idResidencia, fecha, minFecha, maxFecha);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los usuarios dados de baja (sin filtrar por residencia).
|
||||||
|
*
|
||||||
|
* @param fecha Fecha exacta de baja (opcional).
|
||||||
|
* @param minFecha Fecha mínima de baja (opcional).
|
||||||
|
* @param maxFecha Fecha máxima de baja (opcional).
|
||||||
|
* @return Lista de usuarios dados de baja.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener los usuarios dados de baja.
|
||||||
|
*/
|
||||||
|
@GetMapping("/user/getAll/bajas")
|
||||||
|
public ResponseEntity<List<UserResponseDto>> getAllBajas(
|
||||||
|
@RequestParam(required = false)LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha){
|
||||||
|
|
||||||
|
List<UserResponseDto> user;
|
||||||
|
try {
|
||||||
|
user = userService.getAllBajas(fecha, minFecha, maxFecha);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina físicamente un usuario de una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idUser ID del usuario.
|
||||||
|
* @return HTTP 204 si se elimina correctamente.
|
||||||
|
* @throws ApiException si ocurre un error al intentar eliminar el usuario.
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{idResidencia}/user/{idUser}/delete")
|
||||||
|
public ResponseEntity<Void> delete(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idUser) {
|
||||||
|
try{
|
||||||
|
userService.deleteFisico(idResidencia,idUser);
|
||||||
|
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina las referencias del usuario a registros dependientes (sin eliminar el usuario).
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idUser ID del usuario.
|
||||||
|
* @return HTTP 204 si se eliminan correctamente las referencias.
|
||||||
|
* @throws ApiException si ocurre un error al intentar eliminar las referencias.
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{idResidencia}/{idUser}/delete/referencies")
|
||||||
|
public ResponseEntity<Void> deleteReferencies(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idUser) {
|
||||||
|
|
||||||
|
try{
|
||||||
|
userService.deleteReferencies(idResidencia, idUser);
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza los datos de un usuario.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idUser ID del usuario.
|
||||||
|
* @param userDto Nuevos datos del usuario.
|
||||||
|
* @return Usuario actualizado.
|
||||||
|
* @throws ApiException si ocurre un error al intentar actualizar el usuario.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidencia}/user/{idUser}/update")
|
||||||
|
public ResponseEntity<UserResponseDto> update(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idUser,
|
||||||
|
@RequestBody UserDto userDto) {
|
||||||
|
|
||||||
|
UserResponseDto user;
|
||||||
|
try {
|
||||||
|
user = userService.update(idResidencia, idUser, userDto);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia la contraseña de un usuario validando la anterior.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia a la que pertenece el usuario.
|
||||||
|
* @param idUser ID del usuario.
|
||||||
|
* @param changePasswordUserDto DTO con la contraseña actual y la nueva.
|
||||||
|
* @return {@link ResponseEntity} con los datos del usuario tras el cambio.
|
||||||
|
* * @throws ApiException si ocurre un error al intentar cambiar la contraseña.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidencia}/user/{idUser}/update/changePassword")
|
||||||
|
public ResponseEntity<UserResponseDto> changePassword(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idUser,
|
||||||
|
@RequestBody ChangePasswordUserDto changePasswordUserDto) {
|
||||||
|
|
||||||
|
UserResponseDto userResponseDto;
|
||||||
|
try {
|
||||||
|
userResponseDto = userService.updatePassword(idResidencia, idUser, changePasswordUserDto);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(userResponseDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marca un usuario como dado de baja (borrado lógico).
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idUser ID del usuario.
|
||||||
|
* @return HTTP 204 si se desactiva correctamente.
|
||||||
|
* @throws ApiException si ocurre un error al intentar dar de baja al usuario.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/{idResidencia}/user/{idUser}/baja")
|
||||||
|
public ResponseEntity<Void> baja(
|
||||||
|
@PathVariable Long idResidencia,
|
||||||
|
@PathVariable Long idUser) {
|
||||||
|
try{
|
||||||
|
userService.deleteLogico(idResidencia, idUser);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,226 @@
|
||||||
|
package com.kevinolarte.resibenissa.controllers.user;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.config.Conf;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.UserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.auth.ChangePasswordUserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.UserResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiException;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.services.UserService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlador REST para gestionar las operaciones relacionadas con los usuarios.
|
||||||
|
* Expone endpoints para obtener, actualizar y dar de baja usuarios dentro de una residencia.
|
||||||
|
* <p>
|
||||||
|
* URL Base: {@code /resi/user}
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RequestMapping("/resi/user")
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene la información del usuario actualmente autenticado.
|
||||||
|
*
|
||||||
|
* @return DTO con los datos del usuario autenticado.
|
||||||
|
*/
|
||||||
|
@GetMapping("/me")
|
||||||
|
public ResponseEntity<UserResponseDto> getMe() {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
|
||||||
|
return ResponseEntity.ok(new UserResponseDto(currentUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene la información de un usuario específico por su ID, perteneciente a la misma residencia del usuario autenticado.
|
||||||
|
*
|
||||||
|
* @param idUser ID del usuario a consultar.
|
||||||
|
* @return DTO con los datos del usuario.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener el usuario.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{idUser}/get")
|
||||||
|
public ResponseEntity<UserResponseDto> get(
|
||||||
|
@PathVariable Long idUser) {
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
UserResponseDto userResponseDto;
|
||||||
|
try{
|
||||||
|
userResponseDto = userService.get(currentUser.getResidencia().getId(), idUser);
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(userResponseDto);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los usuarios filtrando opcionalmente por si están habilitados y
|
||||||
|
* por ID de juego que han registrado partidas.
|
||||||
|
*
|
||||||
|
* @param enabled Filtro opcional para usuarios habilitados.
|
||||||
|
* @param idJuego Filtro opcional por ID de juego.
|
||||||
|
* @return Lista de DTOs con los datos de los usuarios.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener los usuarios.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll")
|
||||||
|
public ResponseEntity<List<UserResponseDto>> getAll(
|
||||||
|
@RequestParam(required = false) Boolean enabled,
|
||||||
|
@RequestParam(required = false) Long idJuego) {
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
List<UserResponseDto> userResponseDtos;
|
||||||
|
try {
|
||||||
|
userResponseDtos = userService.getAll(currentUser.getResidencia().getId(), enabled, idJuego);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(userResponseDtos);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los usuarios dados de baja, filtrando opcionalmente por fechas.
|
||||||
|
*
|
||||||
|
* @param fecha Fecha exacta de baja.
|
||||||
|
* @param minFecha Fecha mínima de baja.
|
||||||
|
* @param maxFecha Fecha máxima de baja.
|
||||||
|
* @return Lista de usuarios dados de baja en el rango indicado.
|
||||||
|
* @throws ApiException si ocurre un error al intentar obtener los usuarios dados de baja.
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAll/bajas")
|
||||||
|
public ResponseEntity<List<UserResponseDto>> getAllBajas(
|
||||||
|
@RequestParam(required = false) LocalDate fecha,
|
||||||
|
@RequestParam(required = false) LocalDate minFecha,
|
||||||
|
@RequestParam(required = false) LocalDate maxFecha){
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
List<UserResponseDto> userResponseDtos;
|
||||||
|
try {
|
||||||
|
userResponseDtos = userService.getAllBajas(currentUser.getResidencia().getId(), fecha, minFecha, maxFecha);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(userResponseDtos);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Descarga la imagen por defecto del usuario.
|
||||||
|
*
|
||||||
|
* @return Recurso de imagen por defecto como archivo adjunto.
|
||||||
|
*/
|
||||||
|
@GetMapping("/defualtImage")
|
||||||
|
public ResponseEntity<Resource> downloadImage(){
|
||||||
|
Resource resource = userService.getImage(Conf.imageDefault);
|
||||||
|
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
|
||||||
|
.body(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza los datos personales del usuario autenticado.
|
||||||
|
*
|
||||||
|
* @param userDto Objeto DTO con los nuevos datos del usuario.
|
||||||
|
* @return DTO actualizado con la información del usuario.
|
||||||
|
* @throws ApiException si ocurre un error al intentar actualizar los datos del usuario.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/update")
|
||||||
|
public ResponseEntity<UserResponseDto> update(
|
||||||
|
@RequestBody UserDto userDto) {
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
UserResponseDto userResponseDto;
|
||||||
|
try {
|
||||||
|
userResponseDto = userService.update(currentUser.getResidencia().getId(), currentUser.getId(), userDto);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok(userResponseDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia la contraseña del usuario autenticado.
|
||||||
|
*
|
||||||
|
* @param changePasswordUserDto DTO con la contraseña antigua y la nueva.
|
||||||
|
* @return DTO actualizado del usuario tras el cambio de contraseña.
|
||||||
|
* @throws ApiException si ocurre un error al intentar cambiar la contraseña.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/update/changePassword")
|
||||||
|
public ResponseEntity<UserResponseDto> changePassword(
|
||||||
|
@RequestBody ChangePasswordUserDto changePasswordUserDto) {
|
||||||
|
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
UserResponseDto userResponseDto;
|
||||||
|
try {
|
||||||
|
userResponseDto = userService.updatePassword(currentUser.getResidencia().getId(), currentUser.getId(), changePasswordUserDto);
|
||||||
|
} catch (ResiException e) {
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e){
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(userResponseDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marca lógicamente como dado de baja al usuario.
|
||||||
|
*
|
||||||
|
* @return Respuesta sin contenido (HTTP 204) si se realiza correctamente.
|
||||||
|
* @throws ApiException si ocurre un error al intentar dar de baja al usuario.
|
||||||
|
*/
|
||||||
|
@PatchMapping("/baja")
|
||||||
|
public ResponseEntity<Void> baja() {
|
||||||
|
System.out.println("baja");
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
User currentUser = (User) auth.getPrincipal();
|
||||||
|
try {
|
||||||
|
userService.deleteLogico(currentUser.getResidencia().getId(), currentUser.getId());
|
||||||
|
}catch (ResiException e){
|
||||||
|
throw new ApiException(e, currentUser);
|
||||||
|
} catch (Exception e){
|
||||||
|
throw new ApiException(new ResiException(ApiErrorCode.PROBLEMA_INTERNO), currentUser, e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objeto de transferencia de datos (DTO) utilizado para crear o actualizar una residencia.
|
||||||
|
* <p>
|
||||||
|
* Contiene los datos básicos necesarios para registrar una residencia en el sistema,
|
||||||
|
* como su nombre y correo electrónico de contacto.
|
||||||
|
* <p>
|
||||||
|
* No contiene lógica de negocio ni persistencia.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ResidenciaDto {
|
||||||
|
|
||||||
|
private String nombre;
|
||||||
|
private String email;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objeto de transferencia de datos (DTO) utilizado para crear o actualizar residentes.
|
||||||
|
* <p>
|
||||||
|
* Contiene los datos personales básicos necesarios para registrar un residente
|
||||||
|
* y asociarlo a una residencia existente.
|
||||||
|
* <p>
|
||||||
|
* No contiene lógica de negocio ni anotaciones de persistencia.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ResidenteDto {
|
||||||
|
|
||||||
|
private String nombre;
|
||||||
|
private String apellido;
|
||||||
|
|
||||||
|
private LocalDate fechaNacimiento;
|
||||||
|
private String documentoIdentidad;
|
||||||
|
private String familiar1;
|
||||||
|
private String familiar2;
|
||||||
|
private Integer year;
|
||||||
|
private Integer month;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objeto de transferencia de datos (DTO) utilizado para crear o actualizar usuarios.
|
||||||
|
* <p>
|
||||||
|
* Contiene los campos necesarios para registrar un nuevo usuario en el sistema.
|
||||||
|
* No debe contener lógica de negocio ni anotaciones de persistencia.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class UserDto {
|
||||||
|
private String nombre;
|
||||||
|
private String apellido;
|
||||||
|
private String email;
|
||||||
|
private String password;
|
||||||
|
private Long idResidencia;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in.auth;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
public class ChangePasswordUserDto {
|
||||||
|
private String oldPassword;
|
||||||
|
private String newPassword;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in.auth;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objeto de transferecia de datos (DTO) utilizado para logearse y obtener el token de un usario activado anteriormente.
|
||||||
|
* <p>
|
||||||
|
* Este DTO permite obtener acceso a los demas endPoint porque se usara para crear un token. A partir de los parametros que tiene.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class LoginUserDto {
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in.auth;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objecto de transferencia de datos (DTO) utilizado para registrar por primera vez un usuaario.
|
||||||
|
* <p>
|
||||||
|
* Este DTO permite asociar un nuevo usuario a una residencia especifica,
|
||||||
|
* enviando unicamente los siguentes parametros.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class RegisterUserDto {
|
||||||
|
|
||||||
|
private String nombre;
|
||||||
|
private String apellido;
|
||||||
|
private String email;
|
||||||
|
private String password;
|
||||||
|
private Long idResidencia;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in.auth;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objecto de transferencia de datos (DTO) utilizado para verificar el usuario creado anteriormente
|
||||||
|
* <p>
|
||||||
|
* Este DTO permite actibar el usuario creado anteriormete, con solo pasando
|
||||||
|
* los siguientes parametros.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class VerifyUserDto {
|
||||||
|
private String email;
|
||||||
|
private String verificationCode;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in.modeloWallet;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class MovimientoRequestDTO {
|
||||||
|
private double cantidad;
|
||||||
|
private String concepto; // opcional, se puede usar "Depósito manual" por defecto si es null
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in.moduloOrgSalida;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.enums.moduloOrgSalida.EstadoSalida;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO para representar un evento de salida.
|
||||||
|
*<p>
|
||||||
|
* Esta clase contiene información básica sobre un evento de salida, incluyendo su ID,
|
||||||
|
* nombre, descripción, fecha y estado.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class EventoSalidaDto {
|
||||||
|
private String nombre;
|
||||||
|
private String descripcion;
|
||||||
|
private LocalDateTime fecha;
|
||||||
|
private EstadoSalida estado;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in.moduloOrgSalida;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objeto de transferencia de datos (DTO) utilizado para representar la asistencia de un residente a una salida.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Esta clase encapsula la información necesaria para identificar al residente y el evento de salida
|
||||||
|
* al que asistió, así como su estado de asistencia.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ParticipanteDto {
|
||||||
|
private Long idResidente;
|
||||||
|
private Boolean recursosHumanos;
|
||||||
|
private Boolean recursosMateriales;
|
||||||
|
private String preOpinion;
|
||||||
|
private String postOpinion;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in.moduloReporting;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class EmailRequestDto {
|
||||||
|
private String subject;
|
||||||
|
private String body;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in.modulojuego;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objeto de transferencia de datos (DTO) utilizado para crear o actualizar un juego.
|
||||||
|
* <p>
|
||||||
|
* Este DTO permite asociar un nuevo juego a una residencia específica,
|
||||||
|
* enviando únicamente el nombre del juego y el ID de la residencia.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class JuegoDto {
|
||||||
|
private String nombre;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.in.modulojuego;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.Dificultad;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objeto de transferencia de datos (DTO) utilizado para registrar una partida de juego
|
||||||
|
* realizada por un residente en una residencia específica.
|
||||||
|
* <p>
|
||||||
|
* Incluye los datos mínimos necesarios para asociar el registro con el juego y la residencia,
|
||||||
|
* así como la información del desempeño durante la sesión.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class RegistroJuegoDto {
|
||||||
|
|
||||||
|
private Long idJuego;
|
||||||
|
private Long idResidente;
|
||||||
|
private Long idUsuario;
|
||||||
|
private Integer num;
|
||||||
|
private Double duracion;
|
||||||
|
private Dificultad dificultad;
|
||||||
|
private String observacion;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "RegistroJuegoDto{" +
|
||||||
|
"idJuego=" + idJuego +
|
||||||
|
", idResidente=" + idResidente +
|
||||||
|
", idUsuario=" + idUsuario +
|
||||||
|
", fallos=" + num +
|
||||||
|
", duracion=" + duracion +
|
||||||
|
", dificultad=" + dificultad +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.out;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO de salida utilizado como respuesta al iniciar sesión.
|
||||||
|
* <p>
|
||||||
|
* Contiene el token JWT generado para el usuario autenticado, así como el tiempo
|
||||||
|
* de expiración en milisegundos, indicando cuánto tiempo es válido el token.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Este DTO es devuelto por el endpoint de autenticación {@code /auth/login}.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class LoginResponseDto {
|
||||||
|
private String token;
|
||||||
|
private Long expiresIn;
|
||||||
|
private Long idUser;
|
||||||
|
private Long idResidencia;
|
||||||
|
|
||||||
|
public LoginResponseDto(String token, long expiresIn, User user) {
|
||||||
|
this.token = token;
|
||||||
|
this.expiresIn = expiresIn;
|
||||||
|
this.idUser = user.getId();
|
||||||
|
this.idResidencia = user.getResidencia().getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.out;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
|
||||||
|
public class ResidenciaPublicResponseDto {
|
||||||
|
public Long id;
|
||||||
|
public String nombre;
|
||||||
|
public String email;
|
||||||
|
|
||||||
|
public ResidenciaPublicResponseDto(Residencia residencia) {
|
||||||
|
this.id = residencia.getId();
|
||||||
|
this.nombre = residencia.getNombre();
|
||||||
|
this.email = residencia.getEmail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.out;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residente;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
/**
|
||||||
|
* DTO de salida que representa la información pública de una residencia.
|
||||||
|
* <p>
|
||||||
|
* Esta clase se utiliza para enviar al cliente los datos esenciales de una residencia,
|
||||||
|
* incluyendo su nombre, email y los identificadores de usuarios y residentes asociados.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Se construye a partir de una instancia de {@link Residencia}, mapeando únicamente los IDs
|
||||||
|
* de las relaciones con usuarios y residentes para evitar sobrecarga de datos en la respuesta.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ResidenciaResponseDto {
|
||||||
|
private Long id;
|
||||||
|
private String nombre;
|
||||||
|
private String email;
|
||||||
|
private List<Long> usuarios;
|
||||||
|
private List<Long> residentes;
|
||||||
|
|
||||||
|
public ResidenciaResponseDto(Residencia residencia) {
|
||||||
|
this.id = residencia.getId();
|
||||||
|
this.nombre = residencia.getNombre();
|
||||||
|
this.email = residencia.getEmail();
|
||||||
|
|
||||||
|
this.usuarios = residencia.getUsuarios()
|
||||||
|
.stream()
|
||||||
|
.map(User::getId)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
this.residentes = residencia.getResidentes()
|
||||||
|
.stream()
|
||||||
|
.map(Residente::getId)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.out;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.Residente;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO de salida que representa los datos públicos de un residente.
|
||||||
|
* <p>
|
||||||
|
* Esta clase se utiliza para enviar al cliente información relevante sobre
|
||||||
|
* un residente sin exponer detalles internos del modelo ni relaciones sensibles.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Contiene campos como el ID, nombre completo, fecha de nacimiento y la residencia asociada.
|
||||||
|
*
|
||||||
|
* @author Kevin Olate
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ResidenteResponseDto {
|
||||||
|
private Long id;
|
||||||
|
private String nombre;
|
||||||
|
private String apellido;
|
||||||
|
private LocalDate fechaNacimiento;
|
||||||
|
private String documentoIdentidad;
|
||||||
|
private String familiar1;
|
||||||
|
private String familiar2;
|
||||||
|
private Long idResidencia;
|
||||||
|
private Boolean baja;
|
||||||
|
|
||||||
|
public ResidenteResponseDto(Residente residente) {
|
||||||
|
this.id = residente.getId();
|
||||||
|
this.nombre = residente.getNombre();
|
||||||
|
this.apellido = residente.getApellido();
|
||||||
|
this.fechaNacimiento = residente.getFechaNacimiento();
|
||||||
|
this.idResidencia = residente.getResidencia().getId();
|
||||||
|
this.documentoIdentidad = residente.getDocuemntoIdentidad();
|
||||||
|
this.baja = residente.isBaja();
|
||||||
|
this.familiar1 = residente.getFamiliar1();
|
||||||
|
this.familiar2 = residente.getFamiliar2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.out;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO de salida para representar los datos públicos de un usuario del sistema.
|
||||||
|
* <p>
|
||||||
|
* Esta clase se utiliza para devolver información básica del usuario en las respuestas
|
||||||
|
* de la API, sin incluir detalles sensibles como contraseñas o tokens de autenticación.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Contiene datos como el ID del usuario, nombre, email, estado de activación y la residencia asociada.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class UserResponseDto {
|
||||||
|
private Long id;
|
||||||
|
private String nombre;
|
||||||
|
private String apellido;
|
||||||
|
private String email;
|
||||||
|
private String verificationCode;
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
private Long idResidencia;
|
||||||
|
private String fotoPerfil;
|
||||||
|
private boolean baja;
|
||||||
|
|
||||||
|
|
||||||
|
public UserResponseDto(User user) {
|
||||||
|
this.id = user.getId();
|
||||||
|
this.nombre = user.getNombre();
|
||||||
|
this.apellido = user.getApellido();
|
||||||
|
this.email = user.getEmail();
|
||||||
|
this.enabled = user.isEnabled();
|
||||||
|
this.idResidencia = user.getResidencia().getId();
|
||||||
|
this.fotoPerfil = user.getFotoPerfil();
|
||||||
|
this.verificationCode = user.getVerificationCode();
|
||||||
|
this.baja = user.isBaja();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.out.moduloOrgSalida;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.enums.moduloOrgSalida.EstadoSalida;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloOrgSalida.EventoSalida;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloOrgSalida.Participante;
|
||||||
|
import jdk.jfr.Event;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO de salida que representa los datos públicos de un evento de salida.
|
||||||
|
* <p>
|
||||||
|
* Esta clase se utiliza para enviar al cliente información relevante sobre
|
||||||
|
* un evento de salida sin exponer detalles internos del modelo ni relaciones sensibles.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Contiene campos como el ID, nombre, descripción, fecha de inicio, estado y lista de participantes.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class EventoSalidaResponseDto {
|
||||||
|
private Long id;
|
||||||
|
private String nombre;
|
||||||
|
private String descripcion;
|
||||||
|
private LocalDateTime fechaInicio;
|
||||||
|
private EstadoSalida estado;
|
||||||
|
private List<Long> participantes;
|
||||||
|
private Long idResidencia;
|
||||||
|
|
||||||
|
public EventoSalidaResponseDto(EventoSalida e) {
|
||||||
|
this.id = e.getId();
|
||||||
|
this.nombre = e.getNombre();
|
||||||
|
this.descripcion = e.getDescripcion();
|
||||||
|
this.fechaInicio = e.getFechaInicio();
|
||||||
|
this.estado = e.getEstado();
|
||||||
|
this.participantes = e.getParticipantes().stream()
|
||||||
|
.map(Participante::getId)
|
||||||
|
.toList();
|
||||||
|
this.idResidencia = e.getResidencia().getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.out.moduloOrgSalida;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloOrgSalida.Participante;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Objeto de transferencia de datos (DTO) utilizado para representar la respuesta de un participante en un evento de salida.
|
||||||
|
* <p>
|
||||||
|
* Este DTO contiene información sobre el participante, incluyendo su ID, el ID del residente, el ID del evento de salida,
|
||||||
|
* si asistió al evento y sus opiniones antes y después del evento.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ParticipanteResponseDto {
|
||||||
|
private Long id;
|
||||||
|
private Long idResidente;
|
||||||
|
private Long idEvento;
|
||||||
|
private boolean recursosHumanos;
|
||||||
|
private boolean recursosMateriales;
|
||||||
|
private boolean asistenciaPermitida;
|
||||||
|
private String preOpinion;
|
||||||
|
private String postOpinion;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
private Long idResidencia;
|
||||||
|
@JsonIgnore
|
||||||
|
private String familiar1;
|
||||||
|
@JsonIgnore
|
||||||
|
private String familiar2;
|
||||||
|
|
||||||
|
public ParticipanteResponseDto(Participante participante) {
|
||||||
|
this.id = participante.getId();
|
||||||
|
this.idResidente = participante.getResidente().getId();
|
||||||
|
this.idEvento = participante.getEvento().getId();
|
||||||
|
this.recursosHumanos = participante.isRecursosHumanos();
|
||||||
|
this.recursosMateriales = participante.isRecursosMateriales();
|
||||||
|
this.preOpinion = participante.getPreOpinion();
|
||||||
|
this.postOpinion = participante.getPostOpinion();
|
||||||
|
this.asistenciaPermitida = participante.isAsistenciaPermitida();
|
||||||
|
this.idResidencia = participante.getResidente().getResidencia().getId();
|
||||||
|
this.familiar1 = participante.getResidente().getFamiliar1();
|
||||||
|
this.familiar2 = participante.getResidente().getFamiliar2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.out.modulojuego;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.modulojuego.Juego;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO de salida que representa los datos públicos de un juego registrado.
|
||||||
|
* <p>
|
||||||
|
* Esta clase es utilizada para enviar al cliente información sobre un juego,
|
||||||
|
* como su identificador, nombre y la residencia a la que pertenece.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Se construye a partir de una entidad {@link Juego}.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class JuegoResponseDto {
|
||||||
|
private Long id;
|
||||||
|
private String nombre;
|
||||||
|
|
||||||
|
public JuegoResponseDto(Juego juego){
|
||||||
|
this.id = juego.getId();
|
||||||
|
this.nombre = juego.getNombre();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.out.modulojuego;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class MediaRegistroDTO {
|
||||||
|
private String agrupacion;
|
||||||
|
private Double promedio;
|
||||||
|
private Long total;
|
||||||
|
|
||||||
|
|
||||||
|
public MediaRegistroDTO(String agrupacion, Double promedio, Long total) {
|
||||||
|
this.agrupacion = agrupacion;
|
||||||
|
this.promedio = promedio;
|
||||||
|
this.total = total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.kevinolarte.resibenissa.dto.out.modulojuego;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.modulojuego.RegistroJuego;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.Dificultad;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO de salida que representa un registro del uso de un juego por parte de un residente.
|
||||||
|
* <p>
|
||||||
|
* Este DTO se utiliza para enviar al cliente información sobre una sesión de juego,
|
||||||
|
* incluyendo detalles como duración, dificultad, número de errores y fecha de ejecución.
|
||||||
|
* También identifica al residente, al juego y al usuario (trabajador) que registró la partida.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Si el usuario asociado a la partida es nulo, el campo {@code idUsario} se establece en {@code null}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class RegistroJuegoResponseDto {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private Long idResidente;
|
||||||
|
private Long idJuego;
|
||||||
|
private Long idUsuario;
|
||||||
|
private Integer num;
|
||||||
|
private Double duracion;
|
||||||
|
private Dificultad dificultad;
|
||||||
|
private LocalDateTime fecha;
|
||||||
|
private String observacion;
|
||||||
|
|
||||||
|
public RegistroJuegoResponseDto(RegistroJuego registroJuego) {
|
||||||
|
this.id = registroJuego.getId();
|
||||||
|
this.idResidente = registroJuego.getResidente().getId();
|
||||||
|
this.idJuego = registroJuego.getJuego().getId();
|
||||||
|
this.idUsuario = registroJuego.getUsuario() == null? null : registroJuego.getUsuario().getId();
|
||||||
|
this.num = registroJuego.getNum();
|
||||||
|
this.duracion = registroJuego.getDuracion();
|
||||||
|
this.dificultad = registroJuego.getDificultad();
|
||||||
|
this.fecha = registroJuego.getFecha();
|
||||||
|
this.observacion = registroJuego.getObservacion() == null ? null : registroJuego.getObservacion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.kevinolarte.resibenissa.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum CategoriaLog {
|
||||||
|
DEBUG_INSERT(3L), DEBUG_UPDATE(4L), DEBUG_DELETE(5L), DEBUG_SELECT(6L),
|
||||||
|
ERROR_INSERT(7L), ERROR_UPDATE(8L), ERROR_DELETE(9L), ERROR_SELECT(10L);
|
||||||
|
private final Long valor;
|
||||||
|
CategoriaLog(Long valor) {
|
||||||
|
this.valor = valor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.kevinolarte.resibenissa.enums.Filtrado;
|
||||||
|
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
|
||||||
|
public enum RegistroJuegoFiltrado {
|
||||||
|
FECHA_ASC("fecha", Sort.Direction.ASC),
|
||||||
|
FECHA_DESC("fecha", Sort.Direction.DESC),
|
||||||
|
NUM_ASC("num", Sort.Direction.ASC),
|
||||||
|
NUM_DESC("num", Sort.Direction.DESC),
|
||||||
|
DURACION_ASC("duracion", Sort.Direction.ASC),
|
||||||
|
DURACION_DESC("duracion", Sort.Direction.DESC);
|
||||||
|
|
||||||
|
private final String campo;
|
||||||
|
private final Sort.Direction direccion;
|
||||||
|
|
||||||
|
RegistroJuegoFiltrado(String campo, Sort.Direction direccion) {
|
||||||
|
this.campo = campo;
|
||||||
|
this.direccion = direccion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sort toSort() {
|
||||||
|
return Sort.by(direccion, campo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.kevinolarte.resibenissa.enums.Filtrado;
|
||||||
|
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
|
||||||
|
public enum ResidenteFiltrado {
|
||||||
|
FECHA_NAC_ASC("fechaNacimiento", Sort.Direction.ASC),
|
||||||
|
FECHA_NAC_DESC("fechaNacimiento", Sort.Direction.DESC),
|
||||||
|
NOMBRE_ASC("nombre", Sort.Direction.ASC),
|
||||||
|
NOMBRE_DESC("nombre", Sort.Direction.DESC),
|
||||||
|
APELLIDO_ASC("apellido", Sort.Direction.ASC),
|
||||||
|
APELLIDO_DESC("apellido", Sort.Direction.DESC);
|
||||||
|
|
||||||
|
private final String campo;
|
||||||
|
private final Sort.Direction direccion;
|
||||||
|
|
||||||
|
ResidenteFiltrado(String campo, Sort.Direction direccion) {
|
||||||
|
this.campo = campo;
|
||||||
|
this.direccion = direccion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sort toSort() {
|
||||||
|
return Sort.by(direccion, campo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.kevinolarte.resibenissa.enums;
|
||||||
|
|
||||||
|
public enum Role {
|
||||||
|
ADMIN, NORMAL, SENDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.kevinolarte.resibenissa.enums.moduloOrgSalida;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeración que representa los posibles estados de una salida.
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum EstadoSalida {
|
||||||
|
ABIERTO(0), CERRADO(1), EN_CURSO(2), FINALIZADA(3);
|
||||||
|
|
||||||
|
|
||||||
|
private final int estado;
|
||||||
|
|
||||||
|
EstadoSalida(int estado) {
|
||||||
|
this.estado = estado;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.kevinolarte.resibenissa.enums.moduloWallet;
|
||||||
|
|
||||||
|
public enum TipoMovimiento {
|
||||||
|
IN, OUT;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.kevinolarte.resibenissa.enums.modulojuego;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum que representa la dificultad de una partida.
|
||||||
|
* <p>
|
||||||
|
* La interpretación de la dificultad depende del tipo de juego:
|
||||||
|
* <ul>
|
||||||
|
* <li>En juegos tipo A, determina el modo de juego (p. ej. memoria, parejas, secuencia).</li>
|
||||||
|
* <li>En juegos tipo B, define la complejidad de las reglas (p. ej. número de cartas, tiempo disponible).</li>
|
||||||
|
* </ul>
|
||||||
|
* Es responsabilidad del juego interpretar estos valores adecuadamente.
|
||||||
|
*
|
||||||
|
* author Kevin Olarte
|
||||||
|
*/
|
||||||
|
public enum Dificultad {
|
||||||
|
DIFICULTAD1, DIFICULTAD2, DIFICULTAD3;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.kevinolarte.resibenissa.enums.modulojuego;
|
||||||
|
|
||||||
|
public enum TipoAgrupacion {
|
||||||
|
DIARIO,
|
||||||
|
MENSUAL,
|
||||||
|
ANUAL;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
package com.kevinolarte.resibenissa.exceptions;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeración que define los distintos códigos de error personalizados utilizados en la API.
|
||||||
|
* <p>
|
||||||
|
* Cada valor del enum representa un tipo específico de error que puede ocurrir en la lógica
|
||||||
|
* de negocio de la aplicación. Cada error contiene:
|
||||||
|
* <ul>
|
||||||
|
* <li>Un código numérico interno único para facilitar el rastreo.</li>
|
||||||
|
* <li>Un mensaje amigable que puede mostrarse al usuario.</li>
|
||||||
|
* <li>Un {@link HttpStatus} que será devuelto como código HTTP en la respuesta.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>Esta clase se utiliza junto a {@link ResiException} para lanzar errores consistentes.</p>
|
||||||
|
*
|
||||||
|
* @see ResiException
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum ApiErrorCode {
|
||||||
|
|
||||||
|
CAMPOS_OBLIGATORIOS(1001, "Faltan campos obligatorios", HttpStatus.BAD_REQUEST),
|
||||||
|
CORREO_INVALIDO(1002, "Email invalid", HttpStatus.NOT_ACCEPTABLE),
|
||||||
|
CORREO_DUPLICADO(1003, "Email ya existente", HttpStatus.CONFLICT),
|
||||||
|
NOMBRE_DUPLICADO(1004, "Nombre ya existente", HttpStatus.CONFLICT),
|
||||||
|
FECHA_INVALIDO(1005, "Fecha invalida", HttpStatus.NOT_ACCEPTABLE),
|
||||||
|
RESIDENCIA_INVALIDO(1006, "Residencia invalida", HttpStatus.NOT_FOUND),
|
||||||
|
VALORES_NEGATIVOS(1007,"No puede ser negativos los valores", HttpStatus.NOT_ACCEPTABLE),
|
||||||
|
JUEGO_INVALIDO(1008, "Juego invalido", HttpStatus.NOT_FOUND),
|
||||||
|
RESIDENTE_INVALIDO(1009, "Residente invalido", HttpStatus.NOT_FOUND),
|
||||||
|
USUARIO_INVALIDO(1010, "Usuario invalido", HttpStatus.NOT_FOUND),
|
||||||
|
CONFLICTO_REFERENCIAS(1011, "Problemas con las referencias de las entidades, no corresponden a las mismas", HttpStatus.CONFLICT),
|
||||||
|
REGISTRO_JUEGO_INVALIDO(1012,"Registro juego invalido" , HttpStatus.NOT_FOUND ),
|
||||||
|
REFERENCIAS_DEPENDIENTES(1013, "Esta entidad tiene referencias asociadas que dependen de el", HttpStatus.CONFLICT),
|
||||||
|
USER_EXIST(1014, "Usuario ya existente" , HttpStatus.CONFLICT ),
|
||||||
|
USER_NO_ACTIVADO(1015,"Usuario no activado" , HttpStatus.NOT_ACCEPTABLE ),
|
||||||
|
CODIGO_EXPIRADO(1016,"El codigo de verificacion a caducado" , HttpStatus.GONE ),
|
||||||
|
CODIGO_INVALIDO(1017,"El codigo de verificacion no es valdio" , HttpStatus.NOT_ACCEPTABLE ),
|
||||||
|
USER_YA_ACTIVADO(1018,"El usuario ya activado" , HttpStatus.CONFLICT ),
|
||||||
|
ERROR_MAIL_SENDER(1019,"Error enviando el correo" , HttpStatus.BAD_REQUEST ),
|
||||||
|
ENDPOINT_PROTEGIDO(1020, "Tiene que tener permiso para acceder aqui", HttpStatus.METHOD_NOT_ALLOWED),
|
||||||
|
PROBLEMAS_CON_FILE(1021,"A surgido un problema con la imagen" , HttpStatus.INTERNAL_SERVER_ERROR ),
|
||||||
|
PARTICIPANTE_YA_REGISTRADO(1022,"Este residente ya participa en otro evento ese mismo dia" ,HttpStatus.NOT_ACCEPTABLE),
|
||||||
|
EVENTO_SALIDA_INVALIDO(1023,"EventoSalida invalida" ,HttpStatus.NOT_FOUND),
|
||||||
|
EVENTO_SALIDA_NO_DISPONIBLE(1024, "No se puede hacer nada con este evento ciertos problemas", HttpStatus.BAD_REQUEST),
|
||||||
|
PARTICIPANTE_INVALIDO(1025, "Participante invalido" , HttpStatus.NOT_FOUND),
|
||||||
|
PARTICIPANTE_INMUTABLE(1026, "No se puede hacer esta operacion con el participante porque ahora mismo es inmutable", HttpStatus.NOT_ACCEPTABLE),
|
||||||
|
DOCUMENTO_INVALIDO(1027,"El docuemnto de identidad no tiene el formato correcto" ,HttpStatus.NOT_ACCEPTABLE),
|
||||||
|
DOCUMENTO_DUPLICADO(1028,"El docuemnto de identidad debe ser unico" ,HttpStatus.CONFLICT ),
|
||||||
|
CONTRASENA_INCORRECTA(1029,"Contraseña no valida" , HttpStatus.NOT_ACCEPTABLE ),
|
||||||
|
RESIDENTE_BAJA(1028, "Este residente ya esta dado de baja", HttpStatus.NOT_ACCEPTABLE ),
|
||||||
|
RANGO_EDAD_INVALIDO(1029, "Rango de edad inadecuado" , HttpStatus.NOT_ACCEPTABLE ),
|
||||||
|
USUARIO_BAJA(1030, "Usuario dado de baja", HttpStatus.NOT_ACCEPTABLE),
|
||||||
|
RESIDENCIA_BAJA(1031, "Residencia dado de baja", HttpStatus.NOT_ACCEPTABLE),
|
||||||
|
ESTADO_INVALIDO(1032, "Este estado no se puede cambiar por el otro, sigue la secuencia.",HttpStatus.NOT_ACCEPTABLE),
|
||||||
|
PROBLEMA_INTERNO(5000, "Error interno del servidor", HttpStatus.INTERNAL_SERVER_ERROR),
|
||||||
|
WALLET_NO_ENCONTRADA(1033,"Wallet no encontrada" , HttpStatus.NOT_FOUND ),
|
||||||
|
MONTO_INVALIDO(1034,"El monto seleccionado no es valido" , HttpStatus.NOT_ACCEPTABLE ),
|
||||||
|
SALDO_INSUFICIENTE(1035, "No tiene suficiente saldo", HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
|
||||||
|
|
||||||
|
private final int code;
|
||||||
|
private final String message;
|
||||||
|
private final HttpStatus httpStatus;
|
||||||
|
|
||||||
|
ApiErrorCode(int code, String message, HttpStatus httpStatus) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
this.httpStatus = httpStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.kevinolarte.resibenissa.exceptions;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ApiException extends RuntimeException {
|
||||||
|
private ResiException resiException;
|
||||||
|
private String mensaje;
|
||||||
|
|
||||||
|
public ApiException(ResiException resiException, User user) {
|
||||||
|
super(resiException.getMessage());
|
||||||
|
this.resiException = resiException;
|
||||||
|
this.mensaje = resiException.getMessage() + " - Usuario: " + user.getUsername();
|
||||||
|
}
|
||||||
|
public ApiException(ResiException resiException, User user, String mensaje) {
|
||||||
|
super(resiException.getMessage());
|
||||||
|
this.resiException = resiException;
|
||||||
|
this.mensaje = mensaje + " - Usuario: " + user.getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApiException(ResiException resiException, String mensaje) {
|
||||||
|
super(resiException.getMessage());
|
||||||
|
this.resiException = resiException;
|
||||||
|
this.mensaje = mensaje;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.kevinolarte.resibenissa.exceptions;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO de salida que representa la respuesta de error estándar en la API.
|
||||||
|
* <p>
|
||||||
|
* Esta clase encapsula toda la información relevante cuando ocurre una {@link ResiException}
|
||||||
|
* y se desea devolver una respuesta estructurada al cliente.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Contiene:
|
||||||
|
* <ul>
|
||||||
|
* <li>Mensaje de error amigable.</li>
|
||||||
|
* <li>Código de error interno (definido en {@link ApiErrorCode}).</li>
|
||||||
|
* <li>Estado HTTP correspondiente.</li>
|
||||||
|
* <li>Fecha y hora del error.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* Este DTO es ideal para ser devuelto por un {@code @ControllerAdvice}.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ErrorResponseDto {
|
||||||
|
|
||||||
|
private String mensaje;
|
||||||
|
|
||||||
|
private int codigo; // Código del enum
|
||||||
|
|
||||||
|
private int status; // Código HTTP
|
||||||
|
|
||||||
|
private String timestamp;
|
||||||
|
|
||||||
|
public ErrorResponseDto(ResiException ex) {
|
||||||
|
this.mensaje = ex.getErrorCode().getMessage();
|
||||||
|
this.codigo = ex.getErrorCode().getCode();
|
||||||
|
this.status = ex.getHttpStatus().value();
|
||||||
|
this.timestamp = LocalDateTime.now().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.kevinolarte.resibenissa.exceptions;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.services.LoggerService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manejador global de excepciones para la API REST.
|
||||||
|
* <p>
|
||||||
|
* Captura y transforma excepciones de tipo {@link ResiException} en una respuesta estructurada
|
||||||
|
* de tipo {@link ErrorResponseDto}, con el código, mensaje y estado HTTP correspondiente.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Esta clase garantiza respuestas consistentes en todos los endpoints ante errores controlados.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@RestControllerAdvice
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
private LoggerService loggerService;
|
||||||
|
/**
|
||||||
|
* Maneja cualquier excepción de tipo {@link ResiException} lanzada en los controladores.
|
||||||
|
*
|
||||||
|
* @param ex Excepción personalizada que contiene el código de error y estado HTTP.
|
||||||
|
* @return {@link ResponseEntity} con el cuerpo {@link ErrorResponseDto} y el código HTTP correspondiente.
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(ApiException.class)
|
||||||
|
public ResponseEntity<ErrorResponseDto> handleApiException(ApiException ex) {
|
||||||
|
loggerService.registrarLogError(ex.getMensaje());
|
||||||
|
ErrorResponseDto error =
|
||||||
|
new ErrorResponseDto(ex.getResiException());
|
||||||
|
return ResponseEntity.status(ex.getResiException().getHttpStatus()).body(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package com.kevinolarte.resibenissa.exceptions;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Excepción personalizada para representar errores controlados en la lógica de negocio de la aplicación.
|
||||||
|
* <p>
|
||||||
|
* Esta excepción encapsula un {@link ApiErrorCode}, el cual contiene:
|
||||||
|
* <ul>
|
||||||
|
* <li>Un mensaje de error legible.</li>
|
||||||
|
* <li>Un código HTTP asociado.</li>
|
||||||
|
* <li>Un código interno único para identificar el tipo de error.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* Al lanzar esta excepción, los controladores o filtros pueden capturarla y devolver una respuesta estructurada
|
||||||
|
* al cliente con la información correspondiente.
|
||||||
|
*
|
||||||
|
* @see ApiErrorCode
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class ResiException extends RuntimeException{
|
||||||
|
|
||||||
|
private final ApiErrorCode errorCode;
|
||||||
|
|
||||||
|
public ResiException(ApiErrorCode errorCode) {
|
||||||
|
super(errorCode.getMessage());
|
||||||
|
this.errorCode = errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatusCode() {
|
||||||
|
return errorCode.getHttpStatus().value();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpStatus getHttpStatus() {
|
||||||
|
return errorCode.getHttpStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.kevinolarte.resibenissa.models;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modelo que representa un registro de acción en el sistema.
|
||||||
|
* <p>
|
||||||
|
* Esta clase almacena información sobre acciones realizadas por los usuarios,
|
||||||
|
* incluyendo el nombre de la acción, una descripción, el correo del usuario que la realizó,ç
|
||||||
|
* y la fecha de la acción.
|
||||||
|
* <p>
|
||||||
|
* @Author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "logger")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Logger {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String endpoint;
|
||||||
|
private String metodo;
|
||||||
|
|
||||||
|
@Column(length = 1000)
|
||||||
|
private String descripcion;
|
||||||
|
private LocalDateTime fecha;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "id_padre")
|
||||||
|
private Logger padre;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "padre", cascade = CascadeType.ALL)
|
||||||
|
private List<Logger> hijos = new ArrayList<>();
|
||||||
|
|
||||||
|
// Constructores
|
||||||
|
public Logger() {}
|
||||||
|
|
||||||
|
public Logger(String endpoint, String metodo, String descripcion) {
|
||||||
|
this.endpoint = endpoint;
|
||||||
|
this.metodo = metodo;
|
||||||
|
this.descripcion = descripcion;
|
||||||
|
this.fecha = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters y setters
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package com.kevinolarte.resibenissa.models;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloOrgSalida.EventoSalida;
|
||||||
|
import com.kevinolarte.resibenissa.models.modulojuego.Juego;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entidad que representa una residencia en la base de datos.
|
||||||
|
* <p>
|
||||||
|
* Cada residencia tiene un identificador, un nombre único y un correo electrónico.
|
||||||
|
* Está relacionada con múltiples usuarios del sistema (como cuidadores o administradores),
|
||||||
|
* así como con los residentes (personas mayores) que viven en ella.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "residencias")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Residencia {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de la residencia. Debe ser único.
|
||||||
|
*/
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String nombre;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correo electrónico de contacto de la residencia. También debe ser único.
|
||||||
|
*/
|
||||||
|
@Column(unique = true, nullable = false)
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usuarios asociados a esta residencia (por ejemplo, personal que la gestiona).
|
||||||
|
* Relación uno a muchos.
|
||||||
|
*/
|
||||||
|
@OneToMany(mappedBy = "residencia", cascade = CascadeType.ALL)
|
||||||
|
@JsonIgnore
|
||||||
|
private Set<User> usuarios = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Residentes (personas mayores) que viven en esta residencia.
|
||||||
|
* Relación uno a muchos.
|
||||||
|
*/
|
||||||
|
@OneToMany(mappedBy = "residencia", cascade = CascadeType.ALL)
|
||||||
|
@JsonIgnore
|
||||||
|
private Set<Residente> residentes = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eventos que tienen implementados en esta residencia
|
||||||
|
* Relacion uno a muchos
|
||||||
|
*/
|
||||||
|
@OneToMany(mappedBy = "residencia", cascade = CascadeType.ALL)
|
||||||
|
@JsonIgnore
|
||||||
|
private Set<EventoSalida> eventos = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
private boolean baja;
|
||||||
|
private LocalDateTime fechaBaja;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Residencia(String nombre, String email) {
|
||||||
|
this.nombre = nombre;
|
||||||
|
this.email = email;
|
||||||
|
this.baja = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Residencia() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
package com.kevinolarte.resibenissa.models;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloOrgSalida.Participante;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloWallet.Wallet;
|
||||||
|
import com.kevinolarte.resibenissa.models.modulojuego.RegistroJuego;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entidad que representa a un residente (persona mayor) de una residencia.
|
||||||
|
* <p>
|
||||||
|
* A diferencia de {@link User}, los residentes no se autentican en el sistema.
|
||||||
|
* Esta clase almacena datos personales y permite vincular al residente con su residencia,
|
||||||
|
* así como con registros de actividades (como juegos, entrenos, etc).
|
||||||
|
* <p>
|
||||||
|
* Esta entidad es gestionada por usuarios autenticados del sistema.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "residentes")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Residente {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String nombre;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String apellido;
|
||||||
|
|
||||||
|
@Column(name = "fecha_nacimiento",nullable = false)
|
||||||
|
private LocalDate fechaNacimiento;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* documento de identidad del residente.
|
||||||
|
* DNI o NIE.
|
||||||
|
*/
|
||||||
|
@Column(name = "documento_identidad", nullable = false, unique = true)
|
||||||
|
private String docuemntoIdentidad;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String familiar1;
|
||||||
|
|
||||||
|
private String familiar2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relación con la residencia donde vive este residente.
|
||||||
|
* Múltiples residentes pueden estar en una misma residencia.
|
||||||
|
*/
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "fk_residencia", nullable = false)
|
||||||
|
private Residencia residencia;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registros de juegos realizados por este residente.
|
||||||
|
* Relación uno a muchos.
|
||||||
|
*/
|
||||||
|
@OneToMany(mappedBy = "residente", cascade = CascadeType.REMOVE)
|
||||||
|
@JsonIgnore
|
||||||
|
private Set<RegistroJuego> registros = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conjunto de veces que participa el resudente a las excuirsiones.
|
||||||
|
*/
|
||||||
|
@OneToMany(mappedBy = "residente", cascade = CascadeType.ALL)
|
||||||
|
@JsonIgnore
|
||||||
|
private Set<Participante> participantes = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
@OneToOne(mappedBy = "residente", cascade = CascadeType.ALL)
|
||||||
|
@JsonIgnore
|
||||||
|
private Wallet wallet;
|
||||||
|
|
||||||
|
private boolean baja;
|
||||||
|
private LocalDateTime fechaBaja;
|
||||||
|
|
||||||
|
public Residente(String nombre, String apellido, LocalDate fechaNacimiento, String documentoIdentidad, String familiar1, String familiar2) {
|
||||||
|
this.nombre = nombre;
|
||||||
|
this.apellido = apellido;
|
||||||
|
this.fechaNacimiento = fechaNacimiento;
|
||||||
|
this.docuemntoIdentidad = documentoIdentidad;
|
||||||
|
this.baja = false;
|
||||||
|
this.familiar1 = familiar1;
|
||||||
|
this.familiar2 = familiar2;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Residente(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,180 @@
|
||||||
|
package com.kevinolarte.resibenissa.models;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.kevinolarte.resibenissa.enums.Role;
|
||||||
|
import com.kevinolarte.resibenissa.models.modulojuego.RegistroJuego;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entidad que representa un usuario del sistema.
|
||||||
|
* <p>
|
||||||
|
* Implementa la interfaz {@link UserDetails} de Spring Security para integrarse
|
||||||
|
* con el sistema de autenticación.
|
||||||
|
* Cada usuario está asociado a una residencia.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "usuarios")
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
public class User implements UserDetails {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String nombre;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String apellido;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correo electrónico del usuario, usado como username para iniciar sesión.
|
||||||
|
* Debe ser único en el sistema.
|
||||||
|
*/
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Código de verificación utilizado en el proceso de activación de la cuenta.
|
||||||
|
*/
|
||||||
|
@Column(name = "verification_code")
|
||||||
|
private String verificationCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fecha y hora de expiración del código de verificación.
|
||||||
|
*/
|
||||||
|
@Column(name = "verification_expiration")
|
||||||
|
private LocalDateTime verificationExpiration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indica si el usuario está habilitado para acceder al sistema.
|
||||||
|
*/
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ruta de la foto de perfil.
|
||||||
|
*/
|
||||||
|
@Column(name = "foto_perfil")
|
||||||
|
private String fotoPerfil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Roles o permisos del usuario. En este caso no se están usando, se devuelve una lista vacía.
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
private boolean accountNonExpired;
|
||||||
|
@JsonIgnore
|
||||||
|
private boolean credentialsNonExpired;
|
||||||
|
@JsonIgnore
|
||||||
|
private boolean accountNonLocked;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relación con la residencia a la que pertenece el usuario.
|
||||||
|
* Varios usuarios pueden estar asociados a la misma residencia.
|
||||||
|
*/
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "fk_residencia", nullable = false)
|
||||||
|
@JsonIgnore
|
||||||
|
private Residencia residencia;
|
||||||
|
|
||||||
|
private boolean baja;
|
||||||
|
private LocalDateTime fechaBaja;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relacion con los registros de los juegos que son los que se encargan de asignar el jugador.
|
||||||
|
* Para llevar un mayor control.
|
||||||
|
* <p>
|
||||||
|
* Este ususario puede tener varios registros.
|
||||||
|
*/
|
||||||
|
@OneToMany(mappedBy = "usuario")
|
||||||
|
@JsonIgnore
|
||||||
|
private Set<RegistroJuego> registroJuegos = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
private Role role;
|
||||||
|
|
||||||
|
public User() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public User(String nombre, String apellido, String email, String password){
|
||||||
|
this.nombre = nombre;
|
||||||
|
this.apellido = apellido;
|
||||||
|
this.email = email;
|
||||||
|
this.password = password;
|
||||||
|
this.baja = false;
|
||||||
|
this.role = Role.NORMAL;
|
||||||
|
|
||||||
|
}
|
||||||
|
public User(String nombre, String apellido, String email, String password, Role role){
|
||||||
|
this.nombre = nombre;
|
||||||
|
this.apellido = apellido;
|
||||||
|
this.email = email;
|
||||||
|
this.password = password;
|
||||||
|
this.baja = false;
|
||||||
|
this.role = role;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
|
if (role != null) {
|
||||||
|
return List.of(new SimpleGrantedAuthority("ROLE_" + role));
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPassword(){
|
||||||
|
return this.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsername() {
|
||||||
|
return this.email; // el correo es usado como nombre de usuario
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonExpired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonLocked() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCredentialsNonExpired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return this.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{" +
|
||||||
|
"nombre='" + nombre + '\'' +
|
||||||
|
", id=" + id +
|
||||||
|
", email='" + email + '\'' +
|
||||||
|
", apellido='" + apellido + '\'' +
|
||||||
|
", password='" + password + '\'' +
|
||||||
|
", residencia=" + residencia.getId() +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
package com.kevinolarte.resibenissa.models.moduloOrgSalida;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.moduloOrgSalida.EventoSalidaDto;
|
||||||
|
import com.kevinolarte.resibenissa.enums.moduloOrgSalida.EstadoSalida;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representa un evento de salida organizado en el sistema.
|
||||||
|
* <p>
|
||||||
|
* Cada salida contiene información sobre su nombre, descripción, fecha de inicio y estado.
|
||||||
|
* También mantiene una lista de residentes que participan en ella.
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "eventos")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class EventoSalida {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre del evento de salida.
|
||||||
|
*/
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String nombre;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Descripción del evento, explicando de qué trata o qué actividades incluye.
|
||||||
|
*/
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String descripcion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fecha en la que se realizará el evento de salida.
|
||||||
|
*/
|
||||||
|
@Column(nullable = false)
|
||||||
|
private LocalDateTime fechaInicio;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estado actual del evento de salida.
|
||||||
|
* <p>
|
||||||
|
* Puede ser uno de los valores definidos en el enum {@link EstadoSalida}, como por ejemplo: PENDIENTE, REALIZADA, CANCELADA.
|
||||||
|
*/
|
||||||
|
@Column(nullable = false)
|
||||||
|
private EstadoSalida estado;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conjunto de participantes que asisten a esta salida.
|
||||||
|
* <p>
|
||||||
|
* Relación uno-a-muchos con {@link Participante}, donde esta salida es la referencia inversa.
|
||||||
|
* <p>
|
||||||
|
* Se ignora en la serialización JSON para evitar bucles y sobrecarga de datos innecesarios.
|
||||||
|
*/
|
||||||
|
@OneToMany(mappedBy = "evento", cascade = CascadeType.REMOVE)
|
||||||
|
@JsonIgnore
|
||||||
|
private Set<Participante> participantes = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relación con la residencia donde pueden tener varias salidas.
|
||||||
|
* Múltiples Eventos pueden estar en una misma residencia.
|
||||||
|
*/
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "fk_residencia")
|
||||||
|
private Residencia residencia;
|
||||||
|
|
||||||
|
public EventoSalida(EventoSalidaDto e) {
|
||||||
|
this.nombre = e.getNombre();
|
||||||
|
this.descripcion = e.getDescripcion();
|
||||||
|
this.fechaInicio = e.getFecha();
|
||||||
|
this.estado = EstadoSalida.ABIERTO;
|
||||||
|
}
|
||||||
|
public EventoSalida() {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
package com.kevinolarte.resibenissa.models.moduloOrgSalida;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.moduloOrgSalida.ParticipanteDto;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residente;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representa la participación de un residente en un evento de salida.
|
||||||
|
* <p>
|
||||||
|
* Esta entidad contiene información sobre el residente que participa, la salida a la que asiste
|
||||||
|
* y otros datos como si necesita ayuda y sus opiniones antes y después del evento.
|
||||||
|
* <p>
|
||||||
|
* Se asegura que no pueda existir más de un participante con la misma combinación
|
||||||
|
* de {@code fk_salida} y {@code fk_residente}, garantizando que un residente no se registre
|
||||||
|
* dos veces en la misma salida.
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(
|
||||||
|
name = "participantes",
|
||||||
|
uniqueConstraints = {
|
||||||
|
@UniqueConstraint(columnNames = {"fk_evento", "fk_residente"})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
public class Participante {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evento de salida en el que participa el residente.
|
||||||
|
* <p>
|
||||||
|
* Relación muchos-a-uno con {@link EventoSalida}.
|
||||||
|
* Esta relación es ignorada en la serialización JSON para evitar bucles.
|
||||||
|
*/
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "fk_evento", nullable = false)
|
||||||
|
@JsonIgnore
|
||||||
|
private EventoSalida evento;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Residente que participa en la salida.
|
||||||
|
* <p>
|
||||||
|
* Relación muchos-a-uno con {@link Residente}.
|
||||||
|
* Esta relación es ignorada en la serialización JSON para evitar bucles.
|
||||||
|
*/
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "fk_residente", nullable = false)
|
||||||
|
@JsonIgnore
|
||||||
|
private Residente residente;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indica si el residente requiere ayuda durante la salida.
|
||||||
|
*/
|
||||||
|
@Column(nullable = false)
|
||||||
|
private boolean recursosHumanos;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private boolean recursosMateriales;
|
||||||
|
|
||||||
|
private boolean asistenciaPermitida;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opinión del residente antes de asistir a la salida (opcional).
|
||||||
|
*/
|
||||||
|
private String preOpinion;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opinión del residente después de asistir a la salida (opcional).
|
||||||
|
*/
|
||||||
|
private String postOpinion;
|
||||||
|
|
||||||
|
|
||||||
|
private boolean baja;
|
||||||
|
private LocalDateTime fechaBaja;
|
||||||
|
|
||||||
|
|
||||||
|
public Participante() {
|
||||||
|
this.recursosHumanos = false;
|
||||||
|
this.recursosMateriales = false;
|
||||||
|
this.preOpinion = "";
|
||||||
|
this.postOpinion = "";
|
||||||
|
this.baja = false;
|
||||||
|
this.asistenciaPermitida = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.kevinolarte.resibenissa.models.moduloWallet;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.enums.moduloWallet.TipoMovimiento;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
public class MovimientoWallet {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "fk_wallet", nullable = false)
|
||||||
|
private Wallet wallet;
|
||||||
|
|
||||||
|
private Double cantidad;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private TipoMovimiento tipo; // IN / OUT
|
||||||
|
|
||||||
|
private String concepto;
|
||||||
|
|
||||||
|
private LocalDateTime fecha;
|
||||||
|
|
||||||
|
public MovimientoWallet() {
|
||||||
|
// Constructor por defecto
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.kevinolarte.resibenissa.models.moduloWallet;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.Residente;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Wallet {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "fk_residente", unique = true)
|
||||||
|
private Residente residente;
|
||||||
|
|
||||||
|
private Double saldoTotal;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "wallet", cascade = CascadeType.ALL)
|
||||||
|
private Set<MovimientoWallet> movimientos = new LinkedHashSet<>();
|
||||||
|
public Wallet() {
|
||||||
|
this.saldoTotal = 0.0;
|
||||||
|
this.movimientos = new LinkedHashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Wallet{" +
|
||||||
|
"id=" + id +
|
||||||
|
", residente=" + residente +
|
||||||
|
", saldoTotal=" + saldoTotal +
|
||||||
|
", movimientos=" + movimientos +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.kevinolarte.resibenissa.models.modulojuego;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entidad que representa un juego disponible en una residencia.
|
||||||
|
* <p>
|
||||||
|
* Cada juego tiene un nombre único dentro de su residencia.
|
||||||
|
* Está asociado a múltiples registros que indican cuándo y cómo fue jugado por los residentes.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(
|
||||||
|
name = "juegos"
|
||||||
|
|
||||||
|
)
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Juego {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre del juego. Debe ser único dentro de cada residencia.
|
||||||
|
*/
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String nombre;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registros de uso de este juego por parte de residentes.
|
||||||
|
*/
|
||||||
|
@OneToMany(mappedBy = "juego", cascade = CascadeType.REMOVE)
|
||||||
|
@JsonIgnore
|
||||||
|
private Set<RegistroJuego> registro = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
public Juego(String nombre){
|
||||||
|
this.nombre = nombre;
|
||||||
|
}
|
||||||
|
public Juego(){}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Juego{" +
|
||||||
|
"id=" + id +
|
||||||
|
", nombre='" + nombre + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
package com.kevinolarte.resibenissa.models.modulojuego;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.modulojuego.RegistroJuegoDto;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.Dificultad;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residente;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entidad que representa un registro del uso de un juego por parte de un residente.
|
||||||
|
* <p>
|
||||||
|
* Cada vez que un residente juega, se guarda un registro con la fecha, la duración
|
||||||
|
* del juego y el número de fallos cometidos.
|
||||||
|
* Este historial puede ser usado para analizar la evolución cognitiva o motriz del residente.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "registros_juegos")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class RegistroJuego {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Residente que ha jugado.
|
||||||
|
*/
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
@JoinColumn(name = "fk_residente")
|
||||||
|
private Residente residente;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Juego que fue utilizado.
|
||||||
|
*/
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
@JoinColumn(name = "fk_juego")
|
||||||
|
private Juego juego;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trabajador que registra la partida.
|
||||||
|
*/
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "fk_usuario")
|
||||||
|
private User usuario;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fecha en la que se jugó.
|
||||||
|
*/
|
||||||
|
@Column(nullable = false)
|
||||||
|
private LocalDateTime fecha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Número de fallos cometidos por el residente durante el juego.
|
||||||
|
*/
|
||||||
|
private Integer num;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duración del juego en segundos (o minutos, según convención del sistema).
|
||||||
|
*/
|
||||||
|
@Column(nullable = false)
|
||||||
|
private Double duracion;
|
||||||
|
|
||||||
|
private Dificultad dificultad;
|
||||||
|
private String observacion;
|
||||||
|
|
||||||
|
public RegistroJuego(RegistroJuegoDto input) {
|
||||||
|
this.num = input.getNum();
|
||||||
|
this.duracion = input.getDuracion();
|
||||||
|
this.fecha = LocalDateTime.now();
|
||||||
|
this.dificultad = input.getDificultad();
|
||||||
|
this.observacion = "";
|
||||||
|
}
|
||||||
|
public RegistroJuego(RegistroJuegoDto input, LocalDateTime fecha) {
|
||||||
|
this.num = input.getNum();
|
||||||
|
this.duracion = input.getDuracion();
|
||||||
|
this.fecha = fecha;
|
||||||
|
this.dificultad = input.getDificultad();
|
||||||
|
this.observacion = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegistroJuego() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.kevinolarte.resibenissa.repositories;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.Logger;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface LoggerRepository extends JpaRepository<Logger, Long> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.kevinolarte.resibenissa.repositories;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repositorio para acceder y gestionar entidades {@link Residencia}.
|
||||||
|
* <p>
|
||||||
|
* Proporciona métodos personalizados para buscar residencias por nombre o correo electrónico,
|
||||||
|
* además de los métodos estándar de {@link JpaRepository}.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface ResidenciaRepository extends JpaRepository<Residencia, Long> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Busca una residencia por su correo electrónico.
|
||||||
|
*
|
||||||
|
* @param email Correo electrónico de la residencia.
|
||||||
|
* @return Un Optional con la residencia si se encuentra.
|
||||||
|
*/
|
||||||
|
Optional<Residencia> findByEmail(String email);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Busca una residencia por su nombre.
|
||||||
|
*
|
||||||
|
* @param nombre Nombre de la residencia.
|
||||||
|
* @return Un Optional con la residencia si se encuentra.
|
||||||
|
*/
|
||||||
|
Optional<Residencia> findByNombre(String nombre);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Busca residencias que estén marcadas como dadas de baja.
|
||||||
|
*
|
||||||
|
* @return Lista de residencias que tienen el campo baja en true.
|
||||||
|
*/
|
||||||
|
List<Residencia> findByBajaTrue();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.kevinolarte.resibenissa.repositories;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residente;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repositorio para acceder y gestionar entidades {@link Residente}.
|
||||||
|
* <p>
|
||||||
|
* Permite realizar operaciones CRUD y buscar residentes por su residencia.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface ResidenteRepository extends JpaRepository<Residente, Long>, JpaSpecificationExecutor<Residente>{
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Busca residentes por su documento de identidad.
|
||||||
|
* @param docuemntoIdentidad Documento de identidad del residente.
|
||||||
|
* @return residente que coincide con el documento de identidad proporcionado.
|
||||||
|
*/
|
||||||
|
Residente findByDocuemntoIdentidad(String docuemntoIdentidad);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.kevinolarte.resibenissa.repositories;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repositorio para gestionar entidades {@link User}.
|
||||||
|
* <p>
|
||||||
|
* Proporciona métodos personalizados para buscar usuarios por correo electrónico
|
||||||
|
* o por la residencia a la que pertenecen, además de los métodos básicos de {@link JpaRepository}.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Busca un usuario por su correo electrónico.
|
||||||
|
*
|
||||||
|
* @param email Correo electrónico del usuario a buscar.
|
||||||
|
* @return Usuario encontrado o {@code null} si no existe.
|
||||||
|
*/
|
||||||
|
User findByEmail(String email);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.kevinolarte.resibenissa.repositories.moduloOrgSalida;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.enums.moduloOrgSalida.EstadoSalida;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloOrgSalida.EventoSalida;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface EventoSalidaRepository extends JpaRepository<EventoSalida, Long>, JpaSpecificationExecutor<EventoSalida> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exsite un nombre igual en la misma residencia
|
||||||
|
*/
|
||||||
|
boolean existsByNombreAndResidenciaId(String nombre, Long residenciaId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina todos los eventos de salida asociados a una residencia.
|
||||||
|
* @param idResidencia ID de la residencia cuyos eventos de salida
|
||||||
|
*/
|
||||||
|
@Modifying
|
||||||
|
@Transactional
|
||||||
|
@Query("DELETE FROM EventoSalida p WHERE p.residencia.id = :idResidencia")
|
||||||
|
void deleteAllByResidenciaId(@Param("idResidencia") Long idResidencia);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene el evento de salida por su nombre y id de residencia perteneciente.
|
||||||
|
* @param nombre Nombre del evento de salida a buscar.
|
||||||
|
* @param residenciaId ID de la residencia a la que pertenece el evento de salida.
|
||||||
|
* @return EventoSalida si se encuentra, null en caso contrario.
|
||||||
|
*/
|
||||||
|
EventoSalida findByNombreAndResidencia_Id(String nombre, Long residenciaId);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
package com.kevinolarte.resibenissa.repositories.moduloOrgSalida;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.Residente;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloOrgSalida.EventoSalida;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloOrgSalida.Participante;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ParticipanteRepository extends JpaRepository<Participante, Long>, JpaSpecificationExecutor<Participante> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica si un residente esta inscrito el otro evento a partir del idEvento
|
||||||
|
* @param idResidente ID del residente
|
||||||
|
* @param idEvento ID del evento actual
|
||||||
|
* @return true si el residente está inscrito en otro evento el mismo día, false en caso contrario
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT COUNT(p) > 0
|
||||||
|
FROM Participante p
|
||||||
|
WHERE p.residente.id = :idResidente
|
||||||
|
AND p.evento.fechaInicio = (
|
||||||
|
SELECT s.fechaInicio
|
||||||
|
FROM EventoSalida s
|
||||||
|
WHERE s.id = :idEvento
|
||||||
|
)
|
||||||
|
AND p.evento.id <> :idEvento
|
||||||
|
""")
|
||||||
|
boolean existsByResidenteInOtherEventoSameDay(
|
||||||
|
@Param("idResidente") Long idResidente,
|
||||||
|
@Param("idEvento") Long idEvento
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica si un residente está inscrito en un evento específico.
|
||||||
|
*
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @param idEvento ID del evento.
|
||||||
|
* @return true si el residente está inscrito en el evento, false en caso contrario.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT COUNT(p) > 0
|
||||||
|
FROM Participante p
|
||||||
|
WHERE p.residente.id = :idResidente
|
||||||
|
AND p.evento.id = :idEvento
|
||||||
|
AND p.baja = false
|
||||||
|
""")
|
||||||
|
boolean isResidenteInscritoEnEvento(Long idResidente, Long idEvento);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina todos los participantes asociados a una residencia específica.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
*/
|
||||||
|
@Modifying
|
||||||
|
@Transactional
|
||||||
|
@Query("DELETE FROM Participante p WHERE p.residente.residencia.id = :idResidencia")
|
||||||
|
void deleteAllByResidenciaId(@Param("idResidencia") Long idResidencia);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.kevinolarte.resibenissa.repositories.moduloWallet;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloWallet.MovimientoWallet;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloWallet.Wallet;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface MovimientoWalletRepository extends JpaRepository<MovimientoWallet, Long> {
|
||||||
|
List<MovimientoWallet> findByWallet(Wallet wallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.kevinolarte.resibenissa.repositories.moduloWallet;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloWallet.Wallet;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface WalletRepository extends JpaRepository<Wallet, Long> {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.kevinolarte.resibenissa.repositories.modulojuego;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import com.kevinolarte.resibenissa.models.modulojuego.Juego;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repositorio para acceder y gestionar entidades de tipo {@link Juego}.
|
||||||
|
* <p>
|
||||||
|
* Extiende {@link JpaRepository} para aprovechar métodos CRUD y de paginación,
|
||||||
|
* y define métodos personalizados para búsquedas por nombre y residencia.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface JuegoRepository extends JpaRepository<Juego, Long> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Busca si existe juegos por su nombre, ignorando mayúsculas y minúsculas.
|
||||||
|
* @param nombre Nombre del juego a buscar.
|
||||||
|
* @return Lista de juegos que coinciden con el nombre dado.
|
||||||
|
*/
|
||||||
|
boolean existsByNombreIgnoreCase(String nombre);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Busca juegos cuyo nombre contenga una cadena específica, ignorando mayúsculas y minúsculas.
|
||||||
|
* @param nombre Cadena a buscar en el nombre del juego.
|
||||||
|
* @return Lista de juegos que contienen la cadena en su nombre.
|
||||||
|
*/
|
||||||
|
List<Juego> findByNombreContainingIgnoreCase(String nombre);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,647 @@
|
||||||
|
package com.kevinolarte.resibenissa.repositories.modulojuego;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO;
|
||||||
|
import com.kevinolarte.resibenissa.enums.modulojuego.Dificultad;
|
||||||
|
import com.kevinolarte.resibenissa.models.modulojuego.Juego;
|
||||||
|
import com.kevinolarte.resibenissa.models.modulojuego.RegistroJuego;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repositorio para acceder y gestionar registros de juegos ({@link RegistroJuego}).
|
||||||
|
* <p>
|
||||||
|
* Permite obtener estadísticas o historiales de juegos filtrando por residencia,
|
||||||
|
* por juego, por residente o por fecha.
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface RegistroJuegoRepository extends JpaRepository<RegistroJuego, Long>, JpaSpecificationExecutor<RegistroJuego> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio diario de duración de los registros de juego de un residente específico.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Se agrupan los registros por día (formato YYYY-MM-DD), y se calcula la duración media y el total de registros
|
||||||
|
* por cada día. Permite filtrar por dificultad y por un juego concreto (ambos opcionales).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param idResidente ID del residente a analizar.
|
||||||
|
* @param dificultad Nivel de dificultad a filtrar (opcional, puede ser {@code null}).
|
||||||
|
* @param idJuego ID del juego a filtrar (opcional, puede ser {@code null} para incluir todos).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} con fecha (día), duración media y cantidad de registros por día.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM-DD'), AVG(r.duracion), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.id = :idResidente
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionDiaria(@Param("idResidente") Long idResidente,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio mensual de duración de los registros de juego de un residente específico.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Agrupa por mes (formato YYYY-MM), mostrando duración media y número de registros por cada mes.
|
||||||
|
* Se puede filtrar por dificultad y juego (ambos opcionales).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @param dificultad Dificultad del juego (opcional).
|
||||||
|
* @param idJuego ID del juego a filtrar (opcional, puede ser {@code null} para todos los juegos).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} con la media mensual de duración y el total de registros.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM'), AVG(r.duracion), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.id = :idResidente
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionMensual(@Param("idResidente") Long idResidente,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio anual de duración de los registros de juego de un residente específico.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Agrupa por año (YYYY) y devuelve la duración media y el total de registros de cada año.
|
||||||
|
* Se puede aplicar filtro por dificultad y juego.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param idResidente ID del residente cuyos registros se agrupan.
|
||||||
|
* @param dificultad Dificultad del juego (opcional).
|
||||||
|
* @param idJuego ID del juego a filtrar (opcional, puede ser {@code null}).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} con año, duración media y conteo de registros por año.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(CAST(EXTRACT(YEAR FROM r.fecha) AS string), AVG(r.duracion), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.id = :idResidente
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
ORDER BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionAnual(@Param("idResidente") Long idResidente,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio diario de errores cometidos por un residente específico.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Agrupa los registros por día (formato YYYY-MM-DD), y calcula el promedio de errores (`num`)
|
||||||
|
* y el total de registros por día. Permite filtrar por dificultad y juego de forma opcional.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param idResidente ID del residente a analizar.
|
||||||
|
* @param dificultad Nivel de dificultad del juego (opcional).
|
||||||
|
* @param idJuego ID del juego a filtrar (opcional, {@code null} para incluir todos).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} con fecha (día), promedio de errores y número total de registros por día.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM-DD'), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.id = :idResidente
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresDiario(@Param("idResidente") Long idResidente,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio mensual de errores cometidos por un residente específico.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Agrupa por mes (formato YYYY-MM), y devuelve el promedio de errores (`num`)
|
||||||
|
* junto con el total de registros por cada mes. Se puede filtrar por dificultad y juego.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @param dificultad Dificultad del juego (opcional).
|
||||||
|
* @param idJuego ID del juego a filtrar (opcional, {@code null} para incluir todos).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} con promedio mensual de errores y conteo de registros.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM'), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.id = :idResidente
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresMensual(@Param("idResidente") Long idResidente,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio anual de errores cometidos por un residente específico.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Agrupa por año (YYYY), devolviendo el promedio de errores (`num`)
|
||||||
|
* y el total de registros por cada año. Admite filtros opcionales por dificultad y juego.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param idResidente ID del residente cuyos registros se analizarán.
|
||||||
|
* @param dificultad Nivel de dificultad (opcional).
|
||||||
|
* @param idJuego ID del juego (opcional, {@code null} para todos los juegos).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} con año, promedio de errores y total de registros por año.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(CAST(EXTRACT(YEAR FROM r.fecha) AS string), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.id = :idResidente
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
ORDER BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresAnual(@Param("idResidente") Long idResidente,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio mensual de duración de los juegos jugados por todos los residentes
|
||||||
|
* de una residencia, con opción de filtrar por dificultad.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes serán considerados.
|
||||||
|
* @param dificultad Dificultad específica a filtrar (puede ser null para ignorar el filtro).
|
||||||
|
* @param idJuego ID del juego a filtrar (puede ser null para ignorar el filtro).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada elemento representa un mes y su promedio de duración.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM'), AVG(r.duracion), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionResidenciaMensual(@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio anual de duración de los juegos jugados por todos los residentes
|
||||||
|
* de una residencia, con opción de filtrar por dificultad.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes serán considerados.
|
||||||
|
* @param dificultad Dificultad específica a filtrar (puede ser null para ignorar el filtro).
|
||||||
|
* @param idJuego ID del juego a filtrar (puede ser null para ignorar el filtro).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada elemento representa un año y su promedio de duración.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(CAST(EXTRACT(YEAR FROM r.fecha) AS string), AVG(r.duracion), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
ORDER BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionResidenciaAnual(@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio diario de errores cometidos en los juegos por todos los residentes
|
||||||
|
* de una residencia específica, con opción de filtrar por dificultad.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes se van a considerar.
|
||||||
|
* @param dificultad Dificultad de los juegos a filtrar (si es null, se consideran todas las dificultades).
|
||||||
|
* @param idJuego ID del juego a filtrar (puede ser null para ignorar el filtro).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada elemento representa un día y el promedio de errores cometidos.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM-DD'), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresResidenciaDiaria(@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio diario de duración de los juegos jugados por todos los residentes
|
||||||
|
* de una residencia, con opción de filtrar por dificultad.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes serán considerados.
|
||||||
|
* @param idJuego ID del juego a filtrar (puede ser null para ignorar el filtro).
|
||||||
|
* @param dificultad Dificultad específica a filtrar (puede ser null para ignorar el filtro).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada elemento representa un día y su promedio de duración.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM-DD'), AVG(r.duracion), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionResidenciaDiaria(@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio mensual de errores cometidos en los juegos por todos los residentes
|
||||||
|
* de una residencia específica, con opción de filtrar por dificultad.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes se van a considerar.
|
||||||
|
* @param dificultad Dificultad de los juegos a filtrar (si es null, se consideran todas las dificultades).
|
||||||
|
* @param idJuego ID del juego a filtrar (puede ser null para ignorar el filtro).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada elemento representa un mes y el promedio de errores cometidos.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM'), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresResidenciaMensual(@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio anual de errores cometidos en los juegos por todos los residentes
|
||||||
|
* de una residencia específica, con opción de filtrar por dificultad.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes se van a considerar.
|
||||||
|
* @param dificultad Dificultad de los juegos a filtrar (si es null, se consideran todas las dificultades).
|
||||||
|
* @param idJuego ID del juego a filtrar (puede ser null para ignorar el filtro).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada elemento representa un año y el promedio de errores cometidos.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(CAST(EXTRACT(YEAR FROM r.fecha) AS string), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
ORDER BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresResidenciaAnual(@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio diario de errores a nivel global,
|
||||||
|
* con posibilidad de filtrar por dificultad y juego.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(
|
||||||
|
TO_CHAR(r.fecha, 'YYYY-MM-DD'),
|
||||||
|
AVG(r.num),
|
||||||
|
COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresGlobalDiaria(@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio mensual de errores a nivel global,
|
||||||
|
* con posibilidad de filtrar por dificultad y juego.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(
|
||||||
|
TO_CHAR(r.fecha, 'YYYY-MM'),
|
||||||
|
AVG(r.num),
|
||||||
|
COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresGlobalMensual(@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio anual de errores a nivel global,
|
||||||
|
* con posibilidad de filtrar por dificultad y juego.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(
|
||||||
|
CAST(EXTRACT(YEAR FROM r.fecha) AS string),
|
||||||
|
AVG(r.num),
|
||||||
|
COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
ORDER BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresGlobalAnual(@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula la media diaria de duración de juegos a nivel global,
|
||||||
|
* con posibilidad de filtrar por dificultad y juego.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(
|
||||||
|
TO_CHAR(r.fecha, 'YYYY-MM-DD'),
|
||||||
|
AVG(r.duracion),
|
||||||
|
COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionGlobalDiaria(@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula la media mensual de duración de juegos a nivel global,
|
||||||
|
* con posibilidad de filtrar por dificultad y juego.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(
|
||||||
|
TO_CHAR(r.fecha, 'YYYY-MM'),
|
||||||
|
AVG(r.duracion),
|
||||||
|
COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionGlobalMensual(@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula la media anual de duración de juegos a nivel global,
|
||||||
|
* con posibilidad de filtrar por dificultad y juego.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(
|
||||||
|
CAST(EXTRACT(YEAR FROM r.fecha) AS string),
|
||||||
|
AVG(r.duracion),
|
||||||
|
COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
AND (:idJuego IS NULL OR r.juego.id = :idJuego)
|
||||||
|
GROUP BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
ORDER BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionGlobalAnual(@Param("dificultad") Dificultad dificultad,
|
||||||
|
@Param("idJuego") Long idJuego);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio diario de errores en los juegos jugados por todos los residentes para un juego específico.
|
||||||
|
*
|
||||||
|
* @param idJuego ID del juego a analizar.
|
||||||
|
* @param dificultad Dificultad a filtrar (puede ser null para incluir todas).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} agrupada por día.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM-DD'), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresPorJuegoDiaria(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio mensual de errores para un juego específico.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM'), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresPorJuegoMensual(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio anual de errores para un juego específico.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(CAST(EXTRACT(YEAR FROM r.fecha) AS string), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
ORDER BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresPorJuegoAnual(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio diario de duración de un juego específico.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM-DD'), AVG(r.duracion),COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionPorJuegoDiaria(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio mensual de duración de un juego específico.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM'), AVG(r.duracion), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionPorJuegoMensual(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio anual de duración de un juego específico.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(CAST(EXTRACT(YEAR FROM r.fecha) AS string), AVG(r.duracion), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
ORDER BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionPorJuegoAnual(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio diario de duración del juego especificado,
|
||||||
|
* considerando únicamente los registros pertenecientes a los residentes de una residencia específica.
|
||||||
|
*
|
||||||
|
* @param idJuego ID del juego cuyos registros se analizarán.
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes serán tenidos en cuenta.
|
||||||
|
* @param dificultad Nivel de dificultad a filtrar (opcional, puede ser null para incluir todas).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada entrada representa un día con el promedio de duración.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM-DD'), AVG(r.duracion),COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionPorJuegoYResidenciaDiaria(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio mensual de duración del juego especificado,
|
||||||
|
* considerando únicamente los registros pertenecientes a los residentes de una residencia específica.
|
||||||
|
*
|
||||||
|
* @param idJuego ID del juego cuyos registros se analizarán.
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes serán tenidos en cuenta.
|
||||||
|
* @param dificultad Nivel de dificultad a filtrar (opcional, puede ser null para incluir todas).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada entrada representa un mes con el promedio de duración.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM'), AVG(r.duracion), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionPorJuegoYResidenciaMensual(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio anual de duración del juego especificado,
|
||||||
|
* considerando únicamente los registros pertenecientes a los residentes de una residencia específica.
|
||||||
|
*
|
||||||
|
* @param idJuego ID del juego cuyos registros se analizarán.
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes serán tenidos en cuenta.
|
||||||
|
* @param dificultad Nivel de dificultad a filtrar (opcional, puede ser null para incluir todas).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada entrada representa un año con el promedio de duración.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(CAST(EXTRACT(YEAR FROM r.fecha) AS string), AVG(r.duracion), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
ORDER BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaDuracionPorJuegoYResidenciaAnual(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio diario de errores del juego especificado,
|
||||||
|
* considerando únicamente los registros pertenecientes a los residentes de una residencia específica.
|
||||||
|
*
|
||||||
|
* @param idJuego ID del juego cuyos registros se analizarán.
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes serán tenidos en cuenta.
|
||||||
|
* @param dificultad Nivel de dificultad a filtrar (opcional, puede ser null para incluir todas).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada entrada representa un día con el promedio de errores.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM-DD'), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM-DD')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresPorJuegoYResidenciaDiaria(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio mensual de errores del juego especificado,
|
||||||
|
* considerando únicamente los registros pertenecientes a los residentes de una residencia específica.
|
||||||
|
*
|
||||||
|
* @param idJuego ID del juego cuyos registros se analizarán.
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes serán tenidos en cuenta.
|
||||||
|
* @param dificultad Nivel de dificultad a filtrar (opcional, puede ser null para incluir todas).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada entrada representa un mes con el promedio de errores.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(TO_CHAR(r.fecha, 'YYYY-MM'), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
ORDER BY TO_CHAR(r.fecha, 'YYYY-MM')
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresPorJuegoYResidenciaMensual(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el promedio anual de errores del juego especificado,
|
||||||
|
* considerando únicamente los registros pertenecientes a los residentes de una residencia específica.
|
||||||
|
*
|
||||||
|
* @param idJuego ID del juego cuyos registros se analizarán.
|
||||||
|
* @param idResidencia ID de la residencia cuyos residentes serán tenidos en cuenta.
|
||||||
|
* @param dificultad Nivel de dificultad a filtrar (opcional, puede ser null para incluir todas).
|
||||||
|
* @return Lista de {@link MediaRegistroDTO} donde cada entrada representa un año con el promedio de errores.
|
||||||
|
*/
|
||||||
|
@Query("""
|
||||||
|
SELECT new com.kevinolarte.resibenissa.dto.out.modulojuego.MediaRegistroDTO(CAST(EXTRACT(YEAR FROM r.fecha) AS string), AVG(r.num), COUNT(r))
|
||||||
|
FROM RegistroJuego r
|
||||||
|
WHERE r.juego.id = :idJuego AND r.residente.residencia.id = :idResidencia
|
||||||
|
AND (:dificultad IS NULL OR r.dificultad = :dificultad)
|
||||||
|
GROUP BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
ORDER BY EXTRACT(YEAR FROM r.fecha)
|
||||||
|
""")
|
||||||
|
List<MediaRegistroDTO> getMediaErroresPorJuegoYResidenciaAnual(@Param("idJuego") Long idJuego,
|
||||||
|
@Param("idResidencia") Long idResidencia,
|
||||||
|
@Param("dificultad") Dificultad dificultad);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,257 @@
|
||||||
|
package com.kevinolarte.resibenissa.services;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.config.Conf;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.auth.LoginUserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.auth.RegisterUserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.auth.VerifyUserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.UserResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.UserRepository;
|
||||||
|
import jakarta.mail.MessagingException;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Servicio encargado de gestionar la autenticación y verificación de usuarios.
|
||||||
|
* <p>
|
||||||
|
* Incluye el registro de nuevos usuarios, generación y envío de códigos de verificación por correo electrónico,
|
||||||
|
* autenticación mediante email y contraseña, y validación del código de activación.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Este servicio utiliza:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link PasswordEncoder} para cifrar contraseñas.</li>
|
||||||
|
* <li>{@link AuthenticationManager} para autenticación en Spring Security.</li>
|
||||||
|
* <li>{@link EmailService} para el envío de correos electrónicos.</li>
|
||||||
|
* <li>{@link ResidenciaService} para validar residencias al registrar usuarios.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AuthenticationService {
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final AuthenticationManager authenticationManager;
|
||||||
|
private final EmailService emailService;
|
||||||
|
private final ResidenciaService residenciaService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registra un nuevo usuario si no existe previamente.
|
||||||
|
* <p>
|
||||||
|
* Genera un código de verificación y lo envía por correo electrónico.
|
||||||
|
* El usuario se crea con estado desactivado hasta completar la verificación.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param input DTO con los datos del usuario a registrar.
|
||||||
|
* @return DTO con los datos del usuario creado.
|
||||||
|
* @throws ResiException si el email es inválido, ya existe, o la residencia no es válida.
|
||||||
|
*/
|
||||||
|
public UserResponseDto singUp(RegisterUserDto input){
|
||||||
|
if (input.getEmail() == null || input.getEmail().trim().isEmpty() || input.getPassword() == null || input.getPassword().trim().isEmpty()
|
||||||
|
|| input.getIdResidencia() == null || input.getNombre() == null || input.getNombre().trim().isEmpty() || input.getApellido() == null || input.getApellido().trim().isEmpty()){
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
input.setEmail(input.getEmail().trim().toLowerCase());
|
||||||
|
if (!EmailService.isEmailValid(input.getEmail())){
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Miramos si ese usuario y residencia existen
|
||||||
|
User userTest = userRepository.findByEmail(input.getEmail());
|
||||||
|
Residencia residenciaTest = residenciaService.getResidencia(input.getIdResidencia());
|
||||||
|
if(userTest != null){
|
||||||
|
if (userTest.isBaja())
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_BAJA);
|
||||||
|
throw new ResiException(ApiErrorCode.USER_EXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (residenciaTest.isBaja())
|
||||||
|
throw new ResiException(ApiErrorCode.RESIDENCIA_BAJA);
|
||||||
|
|
||||||
|
User user = new User(input.getNombre(), input.getApellido(),input.getEmail(), passwordEncoder.encode(input.getPassword()));
|
||||||
|
user.setVerificationCode(generateVerificationCode());
|
||||||
|
System.out.println(user.getVerificationCode());
|
||||||
|
user.setVerificationExpiration(LocalDateTime.now().plusMinutes(15));
|
||||||
|
user.setEnabled(false);
|
||||||
|
sendVerificationEmail(user);
|
||||||
|
user.setResidencia(residenciaTest);
|
||||||
|
user.setFotoPerfil("/uploads/" + Conf.imageDefault);
|
||||||
|
User savedUser = userRepository.save(user);
|
||||||
|
|
||||||
|
return new UserResponseDto(savedUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autentica un usuario existente mediante email y contraseña.
|
||||||
|
*
|
||||||
|
* @param input DTO con credenciales de acceso.
|
||||||
|
* @return El objeto {@link User} autenticado.
|
||||||
|
* @throws ResiException si el usuario no existe o no está activado.
|
||||||
|
*/
|
||||||
|
public User authenticate(LoginUserDto input){
|
||||||
|
if (input.getEmail() == null || input.getEmail().trim().isEmpty() || input.getPassword() == null || input.getPassword().trim().isEmpty()){
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
input.setEmail(input.getEmail().trim().toLowerCase());
|
||||||
|
if (!EmailService.isEmailValid(input.getEmail())){
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Ver si ese usuario existe o no
|
||||||
|
User user = userRepository.findByEmail(input.getEmail());
|
||||||
|
|
||||||
|
if (user == null){
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Ver si esta activado
|
||||||
|
if(!user.isEnabled()){
|
||||||
|
throw new ResiException(ApiErrorCode.USER_NO_ACTIVADO);
|
||||||
|
}
|
||||||
|
//Ver si esta de baja
|
||||||
|
if(user.isBaja()){
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_BAJA);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Autehnticamos
|
||||||
|
try{
|
||||||
|
authenticationManager.authenticate(
|
||||||
|
new UsernamePasswordAuthenticationToken(
|
||||||
|
input.getEmail(),
|
||||||
|
input.getPassword()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}catch (AuthenticationException e){
|
||||||
|
throw new ResiException(ApiErrorCode.CONTRASENA_INCORRECTA);
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica el código enviado por correo y activa la cuenta del usuario.
|
||||||
|
*
|
||||||
|
* @param input DTO que contiene el email y el código de verificación.
|
||||||
|
* @throws ResiException si el código está expirado, es inválido, o el usuario no existe.
|
||||||
|
*/
|
||||||
|
public void verifyUser(VerifyUserDto input){
|
||||||
|
if (input.getEmail() == null || input.getEmail().trim().isEmpty() || input.getVerificationCode() == null || input.getVerificationCode().trim().isEmpty()){
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
User user = userRepository.findByEmail(input.getEmail());
|
||||||
|
if(user != null){
|
||||||
|
|
||||||
|
if (user.isBaja()) {
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_BAJA);
|
||||||
|
}
|
||||||
|
if (user.isEnabled()) {
|
||||||
|
throw new ResiException(ApiErrorCode.USER_YA_ACTIVADO);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(user.getVerificationExpiration().isBefore(LocalDateTime.now())){
|
||||||
|
throw new ResiException(ApiErrorCode.CODIGO_EXPIRADO);
|
||||||
|
}
|
||||||
|
if (user.getVerificationCode().equals(input.getVerificationCode())){
|
||||||
|
user.setEnabled(true);
|
||||||
|
user.setVerificationCode(null);
|
||||||
|
user.setVerificationExpiration(null);
|
||||||
|
userRepository.save(user); //CUIDADO!!!
|
||||||
|
}else{
|
||||||
|
throw new ResiException(ApiErrorCode.CODIGO_INVALIDO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_INVALIDO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reenvía un nuevo código de verificación por correo si el usuario aún no está activado.
|
||||||
|
*
|
||||||
|
* @param email Dirección de correo del usuario.
|
||||||
|
* @throws ResiException si el usuario no existe o ya está activado.
|
||||||
|
*/
|
||||||
|
public void resendVerificationCode(String email){
|
||||||
|
if (email == null || email.trim().isEmpty()){
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
email = email.trim().toLowerCase();
|
||||||
|
if (!EmailService.isEmailValid(email)){
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_INVALIDO);
|
||||||
|
}
|
||||||
|
User user = userRepository.findByEmail(email);
|
||||||
|
|
||||||
|
if(user != null){
|
||||||
|
if (user.isBaja()) {
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_BAJA);
|
||||||
|
}
|
||||||
|
if (user.isEnabled()){
|
||||||
|
throw new ResiException(ApiErrorCode.USER_YA_ACTIVADO);
|
||||||
|
}
|
||||||
|
user.setVerificationCode(generateVerificationCode());
|
||||||
|
user.setVerificationExpiration(LocalDateTime.now().plusHours(1));
|
||||||
|
sendVerificationEmail(user);
|
||||||
|
userRepository.save(user);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_INVALIDO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genera un código de verificación de 6 dígitos.
|
||||||
|
*
|
||||||
|
* @return Código de verificación como String.
|
||||||
|
*/
|
||||||
|
public String generateVerificationCode(){
|
||||||
|
Random random = new Random();
|
||||||
|
int code = random.nextInt(900000) + 100000;
|
||||||
|
return String.valueOf(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envía un correo con el código de verificación al usuario.
|
||||||
|
*
|
||||||
|
* @param user Usuario al que se le enviará el correo.
|
||||||
|
* @throws ResiException si ocurre un error al enviar el correo.
|
||||||
|
*/
|
||||||
|
public void sendVerificationEmail(User user){
|
||||||
|
String subject = "Account verification";
|
||||||
|
String verificationCode = user.getVerificationCode();
|
||||||
|
String htmlMessage = "<html>"
|
||||||
|
+ "<body style=\"font-family: Arial, sans-serif;\">"
|
||||||
|
+ "<div style=\"background-color: #f5f5f5; padding: 20px;\">"
|
||||||
|
+ "<h2 style=\"color: #333;\">Welcome to our app!</h2>"
|
||||||
|
+ "<p style=\"font-size: 16px;\">Please enter the verification code below to continue:</p>"
|
||||||
|
+ "<div style=\"background-color: #fff; padding: 20px; border-radius: 5px; box-shadow: 0 0 10px rgba(0,0,0,0.1);\">"
|
||||||
|
+ "<h3 style=\"color: #333;\">Verification Code:</h3>"
|
||||||
|
+ "<p style=\"font-size: 18px; font-weight: bold; color: #007bff;\">" + verificationCode + "</p>"
|
||||||
|
+ "</div>"
|
||||||
|
+ "</div>"
|
||||||
|
+ "</body>"
|
||||||
|
+ "</html>";
|
||||||
|
try{
|
||||||
|
emailService.sendEmail(user.getEmail(), subject, htmlMessage);
|
||||||
|
}catch (MessagingException e){
|
||||||
|
throw new ResiException(ApiErrorCode.ERROR_MAIL_SENDER);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
package com.kevinolarte.resibenissa.services;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.moduloOrgSalida.ParticipanteResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residente;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.ResidenteRepository;
|
||||||
|
import jakarta.mail.MessagingException;
|
||||||
|
import jakarta.mail.internet.MimeMessage;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.mail.javamail.JavaMailSender;
|
||||||
|
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Servicio encargado del envío de correos electrónicos dentro de la aplicación.
|
||||||
|
* <p>
|
||||||
|
* Este servicio utiliza {@link JavaMailSender} para construir y enviar correos
|
||||||
|
* en formato HTML. También incluye una utilidad para validar la estructura de
|
||||||
|
* direcciones de correo electrónico.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Requiere configuración previa en {@code application.properties} o {@code application.yml}
|
||||||
|
* con los datos del servidor SMTP (por ejemplo, Gmail).
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class EmailService {
|
||||||
|
|
||||||
|
private final ResidenteRepository residenteRepository;
|
||||||
|
private JavaMailSender mailSender;
|
||||||
|
private JwtService jwtService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica si una dirección de correo electrónico tiene un formato válido.
|
||||||
|
* <p>
|
||||||
|
* La validación se realiza mediante una expresión regular que comprueba la estructura estándar de emails.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param email Dirección de correo electrónico a validar.
|
||||||
|
* @return {@code true} si el formato del email es válido, {@code false} en caso contrario.
|
||||||
|
*/
|
||||||
|
public static boolean isEmailValid(String email) {
|
||||||
|
String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
|
||||||
|
return email != null && email.matches(emailRegex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envía un correo electrónico de verificación en formato HTML.
|
||||||
|
* <p>
|
||||||
|
* Construye el mensaje a partir de los parámetros recibidos y lo envía utilizando el {@link JavaMailSender}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param to Dirección de correo del destinatario.
|
||||||
|
* @param subject Asunto del correo.
|
||||||
|
* @param text Cuerpo del mensaje en formato HTML.
|
||||||
|
* @throws MessagingException si ocurre un error al crear o enviar el mensaje.
|
||||||
|
*/
|
||||||
|
public void sendEmail(String to, String subject, String text) throws MessagingException {
|
||||||
|
|
||||||
|
MimeMessage message = mailSender.createMimeMessage();
|
||||||
|
|
||||||
|
|
||||||
|
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||||
|
|
||||||
|
helper.setTo(to);
|
||||||
|
helper.setSubject(subject);
|
||||||
|
helper.setText(text, true);
|
||||||
|
|
||||||
|
mailSender.send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envía una notificación por correo electrónico a los familiares de un participante
|
||||||
|
* para solicitar permiso para una excursión.
|
||||||
|
* <p>
|
||||||
|
* Genera un token JWT con información del participante y construye URLs para permitir o rechazar la solicitud.
|
||||||
|
* Reemplaza los placeholders en una plantilla HTML y envía el correo a los familiares.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param participanteDto DTO que contiene la información del participante.
|
||||||
|
*/
|
||||||
|
public void sendNotificationParticipante(ParticipanteResponseDto participanteDto) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
Map<String, Object> claims = new HashMap<>();
|
||||||
|
claims.put("idParticipante", participanteDto.getId());
|
||||||
|
claims.put("idEvento", participanteDto.getIdEvento());
|
||||||
|
claims.put("idResidencia", participanteDto.getIdResidencia());
|
||||||
|
|
||||||
|
String token = jwtService.generateTokenConExpiracionCustomClaims(claims, Duration.ofMinutes(30));
|
||||||
|
System.out.println("Token: " + token);
|
||||||
|
// Construir URLs
|
||||||
|
String urlPermitir = "http://localhost:8080/public/allowParticipante?token=" + token;
|
||||||
|
String urlRechazar = "http://localhost:8080/public/denyParticipante?token=" + token;
|
||||||
|
|
||||||
|
// Leer la plantilla HTML desde resources/templates
|
||||||
|
Path htmlPath = Paths.get("src/main/resources/templates/permiso-excursion.html");
|
||||||
|
String html = Files.readString(htmlPath);
|
||||||
|
Residente residente = residenteRepository.findById(participanteDto.getIdResidente())
|
||||||
|
.orElseThrow(() -> new ResiException(ApiErrorCode.RESIDENTE_INVALIDO));
|
||||||
|
|
||||||
|
// Reemplazar los placeholders
|
||||||
|
html = html.replace("{{nombreFamiliar}}", "Familiar")
|
||||||
|
.replace("{{nombreResidente}}", "Residente " + residente.getNombre() + " " + residente.getApellido())
|
||||||
|
.replace("{{nombreExcursion}}", "Excursión especial")
|
||||||
|
.replace("{{fecha}}", LocalDate.now().plusDays(7).toString()) // ejemplo de fecha
|
||||||
|
.replace("{{urlPermitir}}", urlPermitir)
|
||||||
|
.replace("{{urlRechazar}}", urlRechazar);
|
||||||
|
|
||||||
|
|
||||||
|
sendEmail(participanteDto.getFamiliar1(), "Permiso para excursión", html);
|
||||||
|
if (participanteDto.getFamiliar2() != null) {
|
||||||
|
sendEmail(participanteDto.getFamiliar2(), "Permiso para excursión", html);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ResiException(ApiErrorCode.ERROR_MAIL_SENDER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,211 @@
|
||||||
|
package com.kevinolarte.resibenissa.services;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import io.jsonwebtoken.io.Decoders;
|
||||||
|
import io.jsonwebtoken.security.Keys;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.security.Key;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Servicio encargado de la generación, validación y extracción de información de tokens JWT.
|
||||||
|
* <p>
|
||||||
|
* Utiliza la clave secreta configurada en las propiedades de la aplicación y respeta el tiempo
|
||||||
|
* de expiración establecido para los tokens. Este servicio también añade el email como un claim
|
||||||
|
* adicional en los tokens generados.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* El campo {@code sub} del token corresponde al {@code username}, pero en esta aplicación se trabaja principalmente con {@code email}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class JwtService {
|
||||||
|
@Value("${security.jwt.secret-key}")
|
||||||
|
private String secretKey;
|
||||||
|
|
||||||
|
@Value("${security.jwt.expiration-time}")
|
||||||
|
private long jwtExpiration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extrae el nombre de usuario (username/subject) del token JWT.
|
||||||
|
*
|
||||||
|
* @param token Token JWT.
|
||||||
|
* @return Nombre de usuario extraído del token.
|
||||||
|
*/
|
||||||
|
public String extractUsername(String token) {
|
||||||
|
return extractClaim(token, Claims::getSubject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extrae un claim personalizado del token, utilizando una función de resolución.
|
||||||
|
*
|
||||||
|
* @param token Token JWT.
|
||||||
|
* @param claimsResolver Función que define qué claim se desea extraer.
|
||||||
|
* @return Valor del claim.
|
||||||
|
* @param <T> Tipo del claim.
|
||||||
|
*/
|
||||||
|
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver){
|
||||||
|
final Claims claims = extractAllClaims(token);
|
||||||
|
return claimsResolver.apply(claims);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genera un token JWT para un usuario, sin claims adicionales.
|
||||||
|
*
|
||||||
|
* @param userDetails Usuario autenticado.
|
||||||
|
* @return Token JWT generado.
|
||||||
|
*/
|
||||||
|
public String generateToken(UserDetails userDetails) {
|
||||||
|
|
||||||
|
return generateToken(new HashMap<>(), userDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genera un token JWT con claims personalizados y el correo del usuario.
|
||||||
|
*
|
||||||
|
* @param extraClaims Claims adicionales a incluir en el token.
|
||||||
|
* @param userDetails Usuario autenticado.
|
||||||
|
* @return Token JWT generado.
|
||||||
|
*/
|
||||||
|
public String generateToken(Map<String, Object> extraClaims, UserDetails userDetails) {
|
||||||
|
|
||||||
|
if (userDetails instanceof User user) {
|
||||||
|
extraClaims.put("email", user.getEmail());
|
||||||
|
}
|
||||||
|
return buildToken(extraClaims, userDetails, jwtExpiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genera un token JWT con claims personalizados y una duración específica.
|
||||||
|
*
|
||||||
|
* @param extraClaims Claims adicionales a incluir en el token.
|
||||||
|
* @param duration Duración del token.
|
||||||
|
* @return Token JWT generado.
|
||||||
|
*/
|
||||||
|
public String generateTokenConExpiracionCustomClaims(Map<String, Object> extraClaims, Duration duration) {
|
||||||
|
return Jwts.builder()
|
||||||
|
.setClaims(extraClaims)
|
||||||
|
.setIssuedAt(new Date(System.currentTimeMillis()))
|
||||||
|
.setExpiration(new Date(System.currentTimeMillis() + duration.toMillis()))
|
||||||
|
.signWith(getSingKey(), SignatureAlgorithm.HS256)
|
||||||
|
.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve el tiempo de expiración configurado para los tokens (en milisegundos).
|
||||||
|
*
|
||||||
|
* @return Tiempo de expiración en milisegundos.
|
||||||
|
*/
|
||||||
|
public long getExpirationTime() {
|
||||||
|
return this.jwtExpiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construye el token JWT firmándolo con la clave secreta.
|
||||||
|
*
|
||||||
|
* @param extraClaims Claims adicionales.
|
||||||
|
* @param userDetails Datos del usuario.
|
||||||
|
* @param expirationTime Tiempo de expiración en milisegundos.
|
||||||
|
* @return Token JWT generado.
|
||||||
|
*/
|
||||||
|
private String buildToken(
|
||||||
|
Map<String, Object> extraClaims,
|
||||||
|
UserDetails userDetails,
|
||||||
|
long expirationTime) {
|
||||||
|
|
||||||
|
return Jwts
|
||||||
|
.builder()
|
||||||
|
.setClaims(extraClaims)
|
||||||
|
.setSubject(userDetails.getUsername())
|
||||||
|
.setIssuedAt(new Date(System.currentTimeMillis()))
|
||||||
|
.setExpiration(new Date(System.currentTimeMillis() + expirationTime))
|
||||||
|
.signWith(getSingKey(), SignatureAlgorithm.HS256)
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extrae el claim personalizado {@code email} del token.
|
||||||
|
*
|
||||||
|
* @param token Token JWT.
|
||||||
|
* @return Email del usuario.
|
||||||
|
*/
|
||||||
|
public String extrtractEmail(String token) {
|
||||||
|
//Del extra claim que pusimos.
|
||||||
|
return extractAllClaims(token).get("email", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica si un token es válido para un usuario dado.
|
||||||
|
*
|
||||||
|
* @param token Token JWT.
|
||||||
|
* @param userDetails Usuario autenticado.
|
||||||
|
* @return {@code true} si el token es válido y no ha expirado.
|
||||||
|
*/
|
||||||
|
public boolean isTokenValid(String token, UserDetails userDetails) {
|
||||||
|
|
||||||
|
final String username = extractUsername(token);
|
||||||
|
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica si el token ya ha expirado.
|
||||||
|
*
|
||||||
|
* @param token Token JWT.
|
||||||
|
* @return {@code true} si el token está expirado.
|
||||||
|
*/
|
||||||
|
private boolean isTokenExpired(String token) {
|
||||||
|
return extractExpiration(token).before(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extrae la fecha de expiración del token.
|
||||||
|
*
|
||||||
|
* @param token Token JWT.
|
||||||
|
* @return Fecha de expiración.
|
||||||
|
*/
|
||||||
|
private Date extractExpiration(String token) {
|
||||||
|
return extractClaim(token, Claims::getExpiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extrae todos los claims del token.
|
||||||
|
*
|
||||||
|
* @param token Token JWT.
|
||||||
|
* @return Todos los claims contenidos en el token.
|
||||||
|
*/
|
||||||
|
private Claims extractAllClaims(String token) {
|
||||||
|
return Jwts
|
||||||
|
.parserBuilder()
|
||||||
|
.setSigningKey(getSingKey())
|
||||||
|
.build()
|
||||||
|
.parseClaimsJws(token)
|
||||||
|
.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene la clave secreta firmada a partir del string base64 en la configuración.
|
||||||
|
*
|
||||||
|
* @return Clave HMAC SHA válida para firmar/verificar JWT.
|
||||||
|
*/
|
||||||
|
private Key getSingKey() {
|
||||||
|
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
|
||||||
|
return Keys.hmacShaKeyFor(keyBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.kevinolarte.resibenissa.services;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.LogContext;
|
||||||
|
import com.kevinolarte.resibenissa.enums.CategoriaLog;
|
||||||
|
import com.kevinolarte.resibenissa.models.Logger;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.LoggerRepository;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.java.Log;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class LoggerService {
|
||||||
|
|
||||||
|
private final LoggerRepository loggerRepository;
|
||||||
|
|
||||||
|
public LoggerService(LoggerRepository loggerRepository) {
|
||||||
|
this.loggerRepository = loggerRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registrarLog(String endpoint, String metodo, String descripcion) {
|
||||||
|
Logger log = new Logger(
|
||||||
|
endpoint,
|
||||||
|
metodo,
|
||||||
|
descripcion
|
||||||
|
);
|
||||||
|
Logger saved = loggerRepository.save(log);
|
||||||
|
LogContext.setCurrentLogId(saved.getId());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registrarLogError(String descripcion) {
|
||||||
|
Logger log = new Logger(null, null, descripcion);
|
||||||
|
|
||||||
|
Long logId = LogContext.getCurrentLogId();
|
||||||
|
if (logId != null) {
|
||||||
|
loggerRepository.findById(logId).ifPresent(log::setPadre);
|
||||||
|
}
|
||||||
|
|
||||||
|
loggerRepository.save(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
package com.kevinolarte.resibenissa.services;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.ResidenciaDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.ResidenciaPublicResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.ResidenciaResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.ResidenciaRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.ResidenteRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.moduloOrgSalida.EventoSalidaRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.moduloOrgSalida.ParticipanteRepository;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Servicio que gestiona la lógica de negocio relacionada con entidades {@link Residencia}.
|
||||||
|
* <p>
|
||||||
|
* Permite crear, obtener, buscar por ID y eliminar residencias.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author : Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ResidenciaService {
|
||||||
|
|
||||||
|
private final ResidenciaRepository residenciaRepository;
|
||||||
|
private final BCryptPasswordEncoder passwordEncoder;
|
||||||
|
private final ResidenteRepository residenteRepository;
|
||||||
|
private final ParticipanteRepository participanteRepository;
|
||||||
|
private final EventoSalidaRepository eventoSalidaRepository;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea una nueva residencia en el sistema a partir de los datos recibidos.
|
||||||
|
* <p>
|
||||||
|
* Valida que el nombre y correo no estén vacíos, que el correo tenga un formato válido,
|
||||||
|
* y que tanto el nombre como el correo no estén ya registrados.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param input DTO que contiene el nombre y correo de la residencia.
|
||||||
|
* @return {@link ResidenciaResponseDto} de la residencia creada.
|
||||||
|
* @throws ResiException en caso de errores de validación o duplicados.
|
||||||
|
*/
|
||||||
|
public ResidenciaResponseDto add(ResidenciaDto input) throws RuntimeException{
|
||||||
|
if (input.getNombre() == null || input.getEmail() == null
|
||||||
|
|| input.getNombre().trim().isEmpty() || input.getEmail().trim().isEmpty()){
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validar formato del correo electrónico
|
||||||
|
input.setEmail(input.getEmail().toLowerCase().trim());
|
||||||
|
if (!EmailService.isEmailValid(input.getEmail())){
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comprobar si ya existe una residencia con ese correo o nombre
|
||||||
|
Optional<Residencia> residenciaTmp = residenciaRepository.findByEmail(input.getEmail());
|
||||||
|
Optional<Residencia> residenciaTmp2 = residenciaRepository.findByNombre(input.getNombre());
|
||||||
|
if(residenciaTmp.isPresent()){
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_DUPLICADO);
|
||||||
|
}
|
||||||
|
if(residenciaTmp2.isPresent()){
|
||||||
|
throw new ResiException(ApiErrorCode.NOMBRE_DUPLICADO);
|
||||||
|
}
|
||||||
|
|
||||||
|
Residencia residencia = new Residencia(input.getNombre(), input.getEmail());
|
||||||
|
return new ResidenciaResponseDto(residenciaRepository.save(residencia));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una residencia a partir de su ID validando su existencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia a recuperar.
|
||||||
|
* @return {@link ResidenciaResponseDto} de la residencia encontrada.
|
||||||
|
* @throws ResiException si el ID es nulo o no existe una residencia con ese ID.
|
||||||
|
*/
|
||||||
|
public ResidenciaResponseDto get(Long idResidencia) {
|
||||||
|
Residencia resi;
|
||||||
|
|
||||||
|
// Comprobar si el ID de residencia es nulo
|
||||||
|
if (idResidencia == null)
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
else
|
||||||
|
resi = residenciaRepository.findById(idResidencia)
|
||||||
|
.orElseThrow(() -> new ResiException(ApiErrorCode.RESIDENCIA_INVALIDO));
|
||||||
|
|
||||||
|
|
||||||
|
return new ResidenciaResponseDto(resi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de todas las residencias en el sistema. con solo el nombre , correo e id.
|
||||||
|
* @return Lista de residencias públicas.
|
||||||
|
*/
|
||||||
|
public List<ResidenciaPublicResponseDto> getAll() {
|
||||||
|
return residenciaRepository.findAll()
|
||||||
|
.stream().map(ResidenciaPublicResponseDto::new)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de todas las residencias que están marcadas como inactivas (baja).
|
||||||
|
* @return Lista de residencias inactivas.
|
||||||
|
*/
|
||||||
|
public List<ResidenciaPublicResponseDto> getAllBaja() {
|
||||||
|
return residenciaRepository.findByBajaTrue().stream().map(ResidenciaPublicResponseDto::new).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina una residencia a partir de su ID.
|
||||||
|
* <p>
|
||||||
|
* Si no se encuentra la residencia, lanza una excepción.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia a eliminar.
|
||||||
|
* @throws ResiException si no se encuentra la residencia especificada.
|
||||||
|
*/
|
||||||
|
public void deleteFisico(Long idResidencia) {
|
||||||
|
Residencia residenciaTmp = residenciaRepository.findById(idResidencia).orElse(null);
|
||||||
|
|
||||||
|
if(residenciaTmp == null){
|
||||||
|
throw new ResiException(ApiErrorCode.RESIDENCIA_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
residenciaRepository.delete(residenciaTmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina una residencia de forma lógica, marcando su estado como inactivo.
|
||||||
|
* @param id ID de la residencia a eliminar.
|
||||||
|
* @throws ResiException si no se encuentra la residencia.
|
||||||
|
*/
|
||||||
|
public void deleteLogico(Long id) {
|
||||||
|
Residencia residencia = residenciaRepository.findById(id).orElse(null);
|
||||||
|
if (residencia == null) {
|
||||||
|
throw new ResiException(ApiErrorCode.RESIDENCIA_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
residencia.setBaja(true);
|
||||||
|
residencia.setFechaBaja(LocalDateTime.now());
|
||||||
|
residencia.setEmail(passwordEncoder.encode(residencia.getEmail()));
|
||||||
|
|
||||||
|
// Cambiar el estado de los residentes a inactivos
|
||||||
|
residencia.getResidentes().forEach(residente -> {
|
||||||
|
ResidenteService.darBajaUser(residente, passwordEncoder);
|
||||||
|
residenteRepository.save(residente);
|
||||||
|
});
|
||||||
|
// Cambiar el estado de los usuarios a inactivos
|
||||||
|
residencia.getUsuarios().forEach(usuario -> {
|
||||||
|
usuario.setBaja(true);
|
||||||
|
usuario.setFechaBaja(LocalDateTime.now());
|
||||||
|
usuario.setPassword(passwordEncoder.encode(usuario.getPassword()));
|
||||||
|
});
|
||||||
|
|
||||||
|
participanteRepository.deleteAllByResidenciaId(residencia.getId());
|
||||||
|
eventoSalidaRepository.deleteAllByResidenciaId(residencia.getId());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
residenciaRepository.save(residencia);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Busca una residencia por su ID.
|
||||||
|
*
|
||||||
|
* @param id ID de la residencia.
|
||||||
|
* @return {@link Residencia} encontrada.
|
||||||
|
* @throws ResiException si no se encuentra la residencia.
|
||||||
|
*/
|
||||||
|
public Residencia getResidencia(Long id){
|
||||||
|
return residenciaRepository.findById(id).orElseThrow(() -> new ResiException(ApiErrorCode.RESIDENCIA_INVALIDO));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,440 @@
|
||||||
|
package com.kevinolarte.resibenissa.services;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.config.Conf;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.ResidenteDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.moduloReporting.EmailRequestDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.ResidenteResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.enums.Filtrado.ResidenteFiltrado;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residente;
|
||||||
|
import com.kevinolarte.resibenissa.models.moduloWallet.Wallet;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.ResidenteRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.moduloOrgSalida.ParticipanteRepository;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.moduloWallet.WalletRepository;
|
||||||
|
import com.kevinolarte.resibenissa.services.moduloWallet.WalletService;
|
||||||
|
import com.kevinolarte.resibenissa.specifications.ResidenteSpecification;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.UrlResource;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Servicio encargado de gestionar la lógica de negocio relacionada con los residentes.
|
||||||
|
* <p>
|
||||||
|
* Permite registrar, consultar, actualizar y eliminar residentes asociados a residencias.
|
||||||
|
* También permite aplicar filtros básicos sobre los residentes.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author : Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ResidenteService {
|
||||||
|
private final ResidenteRepository residenteRepository;
|
||||||
|
private final ResidenciaService residenciaService;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final ParticipanteRepository participanteRepository;
|
||||||
|
private final EmailService emailService;
|
||||||
|
private final WalletRepository walletRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registra un nuevo residente asociado a una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param input DTO con los datos del residente.
|
||||||
|
* @return DTO del residente creado.
|
||||||
|
* @throws ResiException en caso de datos inválidos o duplicidad de documento.
|
||||||
|
*/
|
||||||
|
public ResidenteResponseDto add(Long idResidencia, ResidenteDto input) throws ResiException {
|
||||||
|
if (input.getNombre() == null || input.getApellido() == null || input.getFechaNacimiento() == null || input.getDocumentoIdentidad() == null ||
|
||||||
|
input.getNombre().trim().isEmpty() || input.getApellido().trim().isEmpty() || input.getDocumentoIdentidad().trim().isEmpty() || idResidencia == null ||
|
||||||
|
input.getFamiliar1() == null || input.getFamiliar1().trim().isEmpty()) {
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validar el formato del documento de identidad
|
||||||
|
input.setDocumentoIdentidad(input.getDocumentoIdentidad().trim().toUpperCase());
|
||||||
|
if (input.getDocumentoIdentidad().length() != 8) {
|
||||||
|
throw new ResiException(ApiErrorCode.DOCUMENTO_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Validar correo familiar 1
|
||||||
|
if (!EmailService.isEmailValid(input.getFamiliar1().toLowerCase().trim())){
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_INVALIDO);
|
||||||
|
}
|
||||||
|
//Validar correo familiar 2
|
||||||
|
if (input.getFamiliar2() != null && !input.getFamiliar2().trim().isEmpty())
|
||||||
|
if (!EmailService.isEmailValid(input.getFamiliar2().toLowerCase().trim()))
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_INVALIDO);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Validar que la fecha de nacimiento no sea futura
|
||||||
|
if (input.getFechaNacimiento().isAfter(LocalDate.now())) {
|
||||||
|
throw new ResiException(ApiErrorCode.FECHA_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validar que la residencia existe
|
||||||
|
Residencia residencia = residenciaService.getResidencia(idResidencia);
|
||||||
|
|
||||||
|
// Validar que no existe otro residente con el mismo documento de identidad en cualquier residencia
|
||||||
|
Residente residenteDup = residenteRepository.findByDocuemntoIdentidad(input.getDocumentoIdentidad());
|
||||||
|
if (residenteDup != null) {
|
||||||
|
throw new ResiException(ApiErrorCode.DOCUMENTO_DUPLICADO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear el nuevo residente
|
||||||
|
Residente residente = new Residente(input.getNombre(), input.getApellido(), input.getFechaNacimiento(), input.getDocumentoIdentidad(), input.getFamiliar1(), input.getFamiliar2());
|
||||||
|
residente.setResidencia(residencia);
|
||||||
|
Residente residenteSaved = residenteRepository.save(residente);
|
||||||
|
Wallet wallet = new Wallet();
|
||||||
|
wallet.setResidente(residenteSaved);
|
||||||
|
wallet = walletRepository.save(wallet);
|
||||||
|
System.out.println(wallet);
|
||||||
|
residenteSaved.setWallet(wallet);
|
||||||
|
|
||||||
|
|
||||||
|
return new ResidenteResponseDto(residenteRepository.save(residenteSaved));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene un residente asegurando su pertenencia a una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @return DTO del residente encontrado.
|
||||||
|
* @throws ResiException si el residente no existe o no pertenece a la residencia.
|
||||||
|
*/
|
||||||
|
public ResidenteResponseDto get(Long idResidencia, Long idResidente) {
|
||||||
|
|
||||||
|
Residente residenteTmp = getResidente(idResidencia, idResidente);
|
||||||
|
|
||||||
|
return new ResidenteResponseDto(residenteTmp);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los residentes de todas residencias con filtros opcionales.
|
||||||
|
* @param fechaNacimiento Fecha exacta de nacimiento (opcional).
|
||||||
|
* @param minFNac Fecha mínima de nacimiento (opcional).
|
||||||
|
* @param maxFNac Fecha máxima de nacimiento (opcional).
|
||||||
|
* @param maxAge Edad máxima (opcional).
|
||||||
|
* @param minAge Edad mínima (opcional).
|
||||||
|
* @param idJuego ID de juego asociado (opcional).
|
||||||
|
* @param idEvento ID de evento asociado (opcional).
|
||||||
|
* @return Lista de residentes filtrados.
|
||||||
|
* @throws ResiException si la residencia no existe.
|
||||||
|
*/
|
||||||
|
public List<ResidenteResponseDto> getAll(LocalDate fechaNacimiento, LocalDate minFNac, LocalDate maxFNac, Integer maxAge, Integer minAge, Long idJuego, Long idEvento, ResidenteFiltrado filtrado) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Specification<Residente> spec = ResidenteSpecification.withFilters(null, fechaNacimiento, minFNac, maxFNac, maxAge, minAge, idJuego, idEvento);
|
||||||
|
|
||||||
|
Sort sort = (filtrado != null) ? filtrado.toSort() : Sort.by(Sort.Direction.ASC, "apellido");
|
||||||
|
List<Residente> residentes = residenteRepository.findAll(spec, sort);
|
||||||
|
|
||||||
|
|
||||||
|
return residentes.stream().map(ResidenteResponseDto::new).collect(Collectors.toList());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los residentes de una residencia con filtros opcionales.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param fechaNacimiento Fecha exacta de nacimiento (opcional).
|
||||||
|
* @param minFNac Fecha mínima de nacimiento (opcional).
|
||||||
|
* @param maxFNac Fecha máxima de nacimiento (opcional).
|
||||||
|
* @param maxAge Edad máxima (opcional).
|
||||||
|
* @param minAge Edad mínima (opcional).
|
||||||
|
* @param idJuego ID de juego asociado (opcional).
|
||||||
|
* @param idEvento ID de evento asociado (opcional).
|
||||||
|
* @return Lista de residentes filtrados.
|
||||||
|
* @throws ResiException si la residencia no existe o el ID es nulo.
|
||||||
|
*/
|
||||||
|
public List<ResidenteResponseDto> getAll(Long idResidencia, LocalDate fechaNacimiento, LocalDate minFNac, LocalDate maxFNac, Integer maxAge, Integer minAge, Long idJuego, Long idEvento, ResidenteFiltrado filtrado) {
|
||||||
|
if (idResidencia == null) {
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
// Validar que la residencia existe
|
||||||
|
Residencia residencia = residenciaService.getResidencia(idResidencia);
|
||||||
|
|
||||||
|
Specification<Residente> spec = ResidenteSpecification.withFilters(idResidencia, fechaNacimiento, minFNac, maxFNac, maxAge, minAge, idJuego, idEvento);
|
||||||
|
|
||||||
|
Sort sort = (filtrado != null) ? filtrado.toSort() : Sort.by(Sort.Direction.ASC, "apellido");
|
||||||
|
List<Residente> residentes = residenteRepository.findAll(spec, sort);
|
||||||
|
|
||||||
|
|
||||||
|
return residentes.stream().map(ResidenteResponseDto::new).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los residentes dados de baja en una residencia, con filtros de fecha.
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param fecha Fecha exacta de baja (opcional).
|
||||||
|
* @param minFecha Fecha mínima de baja (opcional).
|
||||||
|
* @param maxFecha Fecha máxima de baja (opcional).
|
||||||
|
* @return Lista de residentes dados de baja.
|
||||||
|
* @throws ResiException si la residencia no existe o el ID es nulo.
|
||||||
|
*/
|
||||||
|
public List<ResidenteResponseDto> getAllBajas(Long idResidencia, LocalDate fecha, LocalDate minFecha, LocalDate maxFecha) {
|
||||||
|
if (idResidencia == null){
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Residente> lista = residenteRepository.findAll(ResidenteSpecification.withFiltersBaja(fecha, minFecha, maxFecha, idResidencia));
|
||||||
|
|
||||||
|
return lista.stream().map(ResidenteResponseDto::new).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los residentes dados de baja en el sistema, sin filtrar por residencia.
|
||||||
|
* @param fecha Fecha exacta de baja (opcional).
|
||||||
|
* @param minFecha Fecha mínima de baja (opcional).
|
||||||
|
* @param maxFecha Fecha máxima de baja (opcional).
|
||||||
|
* @return Lista de residentes dados de baja.
|
||||||
|
* @throws ResiException si la residencia no existe o el ID es nulo.
|
||||||
|
*/
|
||||||
|
public List<ResidenteResponseDto> getAllBajas( LocalDate fecha, LocalDate minFecha, LocalDate maxFecha) {
|
||||||
|
List<Residente> lista = residenteRepository.findAll(ResidenteSpecification.withFiltersBaja(fecha, minFecha, maxFecha, null));
|
||||||
|
|
||||||
|
return lista.stream().map(ResidenteResponseDto::new).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina un residente asegurando su pertenencia a una residencia.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @throws ResiException si no existe el residente o no pertenece a la residencia.
|
||||||
|
*/
|
||||||
|
public void deleteFisico(Long idResidencia, Long idResidente) {
|
||||||
|
Residente residenteTmp = getResidente(idResidencia, idResidente);
|
||||||
|
// Eliminar el residente
|
||||||
|
residenteRepository.delete(residenteTmp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina un residente de forma lógica, marcándolo como dado de baja.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @throws ResiException si el residente no existe o ya está dado de baja.
|
||||||
|
*/
|
||||||
|
public void deleteLogico(Long idResidencia, Long idResidente) {
|
||||||
|
// Validar que el residente existe
|
||||||
|
Residente residenteUpdatable = getResidente(idResidencia, idResidente);
|
||||||
|
|
||||||
|
//Dar de baja al residente
|
||||||
|
if (residenteUpdatable.isBaja())
|
||||||
|
throw new ResiException(ApiErrorCode.RESIDENTE_BAJA);
|
||||||
|
|
||||||
|
darBajaUser(residenteUpdatable, passwordEncoder);
|
||||||
|
participanteRepository.deleteAll(residenteUpdatable.getParticipantes());
|
||||||
|
residenteRepository.save(residenteUpdatable);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza los datos de un residente.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @param input DTO con los nuevos datos a actualizar.
|
||||||
|
* @return DTO del residente actualizado.
|
||||||
|
* @throws ResiException si los datos son inválidos o se detecta duplicidad de documento.
|
||||||
|
*/
|
||||||
|
public ResidenteResponseDto update(Long idResidencia, Long idResidente, ResidenteDto input) {
|
||||||
|
if (idResidencia == null || idResidente == null) {
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
// Validar que el residente existe
|
||||||
|
Residente residenteUpdatable = getResidente(idResidencia, idResidente);
|
||||||
|
|
||||||
|
//Comprobar si el residente ya se ha dado de baja
|
||||||
|
if (residenteUpdatable.isBaja()) {
|
||||||
|
throw new ResiException(ApiErrorCode.RESIDENTE_BAJA);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Si ha añadido algun campo en el input para actualizar
|
||||||
|
if (input != null) {
|
||||||
|
// Validar el formato del documento de identidad
|
||||||
|
if (input.getDocumentoIdentidad() != null) {
|
||||||
|
input.setDocumentoIdentidad(input.getDocumentoIdentidad().trim().toUpperCase());
|
||||||
|
if (input.getDocumentoIdentidad().length() != 8) {
|
||||||
|
throw new ResiException(ApiErrorCode.DOCUMENTO_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comprobar si ya existe otro residente con el mismo documento de identidad
|
||||||
|
Residente residenteDup = residenteRepository.findByDocuemntoIdentidad(input.getDocumentoIdentidad());
|
||||||
|
if (residenteDup != null) {
|
||||||
|
if (!Objects.equals(residenteDup.getId(), idResidente)) {
|
||||||
|
throw new ResiException(ApiErrorCode.DOCUMENTO_DUPLICADO);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else
|
||||||
|
residenteUpdatable.setDocuemntoIdentidad(input.getDocumentoIdentidad());
|
||||||
|
}
|
||||||
|
if (input.getFechaNacimiento() != null) {
|
||||||
|
// Validar que la fecha de nacimiento no sea futura
|
||||||
|
if (input.getFechaNacimiento().isAfter(LocalDate.now())) {
|
||||||
|
throw new ResiException(ApiErrorCode.FECHA_INVALIDO);
|
||||||
|
}
|
||||||
|
residenteUpdatable.setFechaNacimiento(input.getFechaNacimiento());
|
||||||
|
}
|
||||||
|
if (input.getNombre() != null && !input.getNombre().trim().isEmpty()) {
|
||||||
|
residenteUpdatable.setNombre(input.getNombre());
|
||||||
|
}
|
||||||
|
if (input.getApellido() != null && !input.getApellido().trim().isEmpty()) {
|
||||||
|
residenteUpdatable.setApellido(input.getApellido());
|
||||||
|
}
|
||||||
|
if (input.getFamiliar1() != null && !input.getFamiliar1().trim().isEmpty()) {
|
||||||
|
//Validar correo familiar 1
|
||||||
|
if (!EmailService.isEmailValid(input.getFamiliar1().toLowerCase().trim())) {
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_INVALIDO);
|
||||||
|
}
|
||||||
|
residenteUpdatable.setFamiliar1(input.getFamiliar1());
|
||||||
|
}
|
||||||
|
if (input.getFamiliar2() != null && !input.getFamiliar2().trim().isEmpty()) {
|
||||||
|
//Validar correo familiar 2
|
||||||
|
if (!EmailService.isEmailValid(input.getFamiliar2().toLowerCase().trim())) {
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_INVALIDO);
|
||||||
|
}
|
||||||
|
residenteUpdatable.setFamiliar2(input.getFamiliar2());
|
||||||
|
}
|
||||||
|
// Guardar los cambios
|
||||||
|
residenteUpdatable = residenteRepository.save(residenteUpdatable);
|
||||||
|
}
|
||||||
|
return new ResidenteResponseDto(residenteUpdatable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envía un correo electrónico a los familiares de un residente.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @param input DTO con el asunto y cuerpo del correo.
|
||||||
|
* @throws ResiException si el residente no existe o no tiene familiares asociados.
|
||||||
|
*/
|
||||||
|
public void sendEmailFamiliar(Long idResidencia, Long idResidente, EmailRequestDto input) {
|
||||||
|
|
||||||
|
// Validar que el residente existe
|
||||||
|
Residente residenteTmp = getResidente(idResidencia, idResidente);
|
||||||
|
|
||||||
|
if (input == null || input.getSubject() == null || input.getBody() == null ||
|
||||||
|
input.getSubject().trim().isEmpty() || input.getBody().trim().isEmpty()) {
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
//Enviar correo al familiar
|
||||||
|
try{
|
||||||
|
emailService.sendEmail(residenteTmp.getFamiliar1(), input.getSubject(), input.getBody());
|
||||||
|
if(residenteTmp.getFamiliar2() != null)
|
||||||
|
emailService.sendEmail(residenteTmp.getFamiliar2(), input.getSubject(), input.getBody());
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ResiException(ApiErrorCode.ERROR_MAIL_SENDER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marca un residente como dado de baja.
|
||||||
|
* @param residenteUpdatable Residente a actualizar.
|
||||||
|
* @param passwordEncoder Codificador de contraseñas.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static void darBajaUser(Residente residenteUpdatable, PasswordEncoder passwordEncoder) {
|
||||||
|
residenteUpdatable.setBaja(true);
|
||||||
|
residenteUpdatable.setFechaBaja(LocalDateTime.now());
|
||||||
|
residenteUpdatable.setDocuemntoIdentidad(passwordEncoder.encode(residenteUpdatable.getDocuemntoIdentidad()));
|
||||||
|
residenteUpdatable.setFamiliar1(passwordEncoder.encode(residenteUpdatable.getFamiliar1()));
|
||||||
|
if (residenteUpdatable.getFamiliar2() != null && !residenteUpdatable.getFamiliar2().trim().isEmpty())
|
||||||
|
residenteUpdatable.setFamiliar2(passwordEncoder.encode(residenteUpdatable.getFamiliar2()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene un residente y valida que pertenece a la residencia especificada.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idResidente ID del residente.
|
||||||
|
* @return Residente encontrado.
|
||||||
|
* @throws ResiException si no existe o no pertenece a la residencia.
|
||||||
|
*/
|
||||||
|
public Residente getResidente(Long idResidencia, Long idResidente) {
|
||||||
|
if (idResidencia == null || idResidente == null) {
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validar que el residente existe
|
||||||
|
Residente residenteTmp = residenteRepository.findById(idResidente).orElse(null);
|
||||||
|
if (residenteTmp == null) {
|
||||||
|
throw new ResiException(ApiErrorCode.RESIDENTE_INVALIDO);
|
||||||
|
}
|
||||||
|
//Comrpobar que el residente pertenece a la residencia
|
||||||
|
if (!Objects.equals(residenteTmp.getResidencia().getId(), idResidencia)) {
|
||||||
|
throw new ResiException(ApiErrorCode.RESIDENTE_INVALIDO);
|
||||||
|
}
|
||||||
|
return residenteTmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una imagen como recurso desde el sistema de archivos.
|
||||||
|
* @param filename Nombre del archivo solicitado (actualmente no se utiliza, se carga siempre la imagen por defecto).
|
||||||
|
* @return {@link Resource} que representa la imagen cargada desde el sistema de archivos.
|
||||||
|
* @throws ResiException si el archivo no existe o no puede accederse.
|
||||||
|
*/
|
||||||
|
public Resource getImage(String filename) {
|
||||||
|
|
||||||
|
Path filePath = Paths.get("src/main/resources/static/uploads").resolve(Conf.imageDefault).normalize();
|
||||||
|
Resource resource;
|
||||||
|
try{
|
||||||
|
resource = new UrlResource(filePath.toUri());
|
||||||
|
if (!resource.exists()) {
|
||||||
|
throw new ResiException(ApiErrorCode.PROBLEMAS_CON_FILE);
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ResiException(ApiErrorCode.PROBLEMAS_CON_FILE);
|
||||||
|
}
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,416 @@
|
||||||
|
package com.kevinolarte.resibenissa.services;
|
||||||
|
|
||||||
|
import com.kevinolarte.resibenissa.config.Conf;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.UserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.in.auth.ChangePasswordUserDto;
|
||||||
|
import com.kevinolarte.resibenissa.dto.out.UserResponseDto;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ApiErrorCode;
|
||||||
|
import com.kevinolarte.resibenissa.exceptions.ResiException;
|
||||||
|
import com.kevinolarte.resibenissa.models.Residencia;
|
||||||
|
import com.kevinolarte.resibenissa.models.modulojuego.RegistroJuego;
|
||||||
|
import com.kevinolarte.resibenissa.models.User;
|
||||||
|
import com.kevinolarte.resibenissa.repositories.UserRepository;
|
||||||
|
import com.kevinolarte.resibenissa.specifications.UserSpecification;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.UrlResource;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Servicio que gestiona la lógica relacionada con los usuarios del sistema.
|
||||||
|
* <p>
|
||||||
|
* Permite registrar, consultar, actualizar, eliminar y dar de baja usuarios,
|
||||||
|
* así como aplicar filtros personalizados en las búsquedas.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Kevin Olarte
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class UserService {
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
private final ResidenciaService residenciaService;
|
||||||
|
private final BCryptPasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guarda un nuevo usuario en la base de datos.
|
||||||
|
* @param idResidencia ID de la residencia a la que pertenece el usuario.
|
||||||
|
* @param input Datos del usuario a guardar.
|
||||||
|
* @return DTO con los datos del usuario guardado.
|
||||||
|
* @throws ResiException si los datos son inválidos o el usuario ya existe.
|
||||||
|
*/
|
||||||
|
public UserResponseDto add(Long idResidencia, UserDto input) {
|
||||||
|
if (input.getEmail() == null || input.getEmail().trim().isEmpty() || input.getPassword() == null || input.getPassword().trim().isEmpty()
|
||||||
|
|| input.getIdResidencia() == null || input.getNombre() == null || input.getNombre().trim().isEmpty() || input.getApellido() == null || input.getApellido().trim().isEmpty()){
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
input.setEmail(input.getEmail().trim().toLowerCase());
|
||||||
|
if (!EmailService.isEmailValid(input.getEmail())){
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Miramos si ese usuario y residencia existen
|
||||||
|
User userTest = userRepository.findByEmail(input.getEmail());
|
||||||
|
Residencia residenciaTest = residenciaService.getResidencia(input.getIdResidencia());
|
||||||
|
if(userTest != null){
|
||||||
|
if (userTest.isBaja())
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_BAJA);
|
||||||
|
throw new ResiException(ApiErrorCode.USER_EXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (residenciaTest.isBaja())
|
||||||
|
throw new ResiException(ApiErrorCode.RESIDENCIA_BAJA);
|
||||||
|
|
||||||
|
User user = new User(input.getNombre(), input.getApellido(),input.getEmail(), passwordEncoder.encode(input.getPassword()));
|
||||||
|
user.setResidencia(residenciaTest);
|
||||||
|
//TODO: VERIFICACION CON CODIGO PERO FASE DESAROLLOO, AUN NO.
|
||||||
|
user.setEnabled(true);
|
||||||
|
user.setFotoPerfil("/uploads/" + Conf.imageDefault);
|
||||||
|
User savedUser = userRepository.save(user);
|
||||||
|
return new UserResponseDto(savedUser);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene un usuario por su ID dentro de una residencia específica.
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idUser ID del usuario.
|
||||||
|
* @return DTO con los datos del usuario.
|
||||||
|
* @throws ResiException si el ID de residencia o usuario es nulo, o si el usuario no pertenece a la residencia.
|
||||||
|
*/
|
||||||
|
public UserResponseDto get(Long idResidencia, Long idUser) {
|
||||||
|
User userTmp = getUsuario(idResidencia, idUser);
|
||||||
|
// Si todo es correcto, devolver el usuario
|
||||||
|
return new UserResponseDto(userTmp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene un usuario por su email dentro de una residencia específica.
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param email Email del usuario.
|
||||||
|
* @return DTO con los datos del usuario.
|
||||||
|
* @throws ResiException si el ID de residencia o email es nulo, o si el usuario no pertenece a la residencia.
|
||||||
|
*/
|
||||||
|
public UserResponseDto get(Long idResidencia, String email){
|
||||||
|
if (idResidencia == null || email == null){
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Validar si existe ese usuario
|
||||||
|
User user = userRepository.findByEmail(email);
|
||||||
|
if (user == null){
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Validar si pertenece a esa residencia
|
||||||
|
if (user.getResidencia() == null || !user.getResidencia().getId().equals(idResidencia)) {
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si todo es correcto, devolver el usuario
|
||||||
|
return new UserResponseDto(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una imagen como recurso desde el sistema de archivos.
|
||||||
|
* @param filename Nombre del archivo solicitado (actualmente no se utiliza, se carga siempre la imagen por defecto).
|
||||||
|
* @return {@link Resource} que representa la imagen cargada desde el sistema de archivos.
|
||||||
|
* @throws ResiException si el archivo no existe o no puede accederse.
|
||||||
|
*/
|
||||||
|
public Resource getImage(String filename) {
|
||||||
|
|
||||||
|
Path filePath = Paths.get("src/main/resources/static/uploads").resolve(Conf.imageDefault).normalize();
|
||||||
|
Resource resource;
|
||||||
|
try{
|
||||||
|
resource = new UrlResource(filePath.toUri());
|
||||||
|
if (!resource.exists()) {
|
||||||
|
throw new ResiException(ApiErrorCode.PROBLEMAS_CON_FILE);
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new ResiException(ApiErrorCode.PROBLEMAS_CON_FILE);
|
||||||
|
}
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de todos los usuarios asociados a una residencia con filtros opcionales.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param enabled Estado habilitado para filtrar (opcional).
|
||||||
|
* @param idJuego ID del juego para filtrar (opcional).
|
||||||
|
* @return Lista de usuarios que cumplen con los filtros aplicados.
|
||||||
|
* @throws ResiException si la residencia no existe o el ID es nulo.
|
||||||
|
*/
|
||||||
|
public List<UserResponseDto> getAll(Long idResidencia, Boolean enabled, Long idJuego){
|
||||||
|
if (idResidencia == null){
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<User> list = userRepository.findAll(UserSpecification.withFilters(enabled,idResidencia, idJuego));
|
||||||
|
|
||||||
|
return list.stream().map(UserResponseDto::new).toList();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de todos los usuarios con filtros opcionales.
|
||||||
|
*
|
||||||
|
* @param enabled Estado habilitado para filtrar (opcional).
|
||||||
|
* @param idJuego ID del juego para filtrar (opcional).
|
||||||
|
* @return Lista de usuarios que cumplen con los filtros aplicados.
|
||||||
|
* @throws ResiException si la residencia no existe o el ID es nulo.
|
||||||
|
*/
|
||||||
|
public List<UserResponseDto> getAll(Boolean enabled, Long idJuego) {
|
||||||
|
|
||||||
|
List<User> list = userRepository.findAll(UserSpecification.withFilters(enabled,null, idJuego));
|
||||||
|
|
||||||
|
return list.stream().map(UserResponseDto::new).toList();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de usuarios dados de baja en una residencia específica.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @return Lista de usuarios dados de baja en la residencia.
|
||||||
|
* @throws ResiException si la residencia no existe o el ID es nulo.
|
||||||
|
*/
|
||||||
|
public List<UserResponseDto> getAllBajas(Long idResidencia, LocalDate fecha, LocalDate minFecha, LocalDate maxFecha) {
|
||||||
|
if (idResidencia == null) throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
|
||||||
|
List<User> list = userRepository.findAll(UserSpecification.withFiltersBaja(fecha,minFecha, maxFecha, idResidencia));
|
||||||
|
|
||||||
|
|
||||||
|
return list.stream().map(UserResponseDto::new).toList();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una lista de usuarios dados de baja.
|
||||||
|
*
|
||||||
|
* @param fecha Fecha exacta de baja (opcional).
|
||||||
|
* @param minFecha Fecha mínima de baja (opcional).
|
||||||
|
* @param maxFecha Fecha máxima de baja (opcional).
|
||||||
|
* @return Lista de usuarios dados de baja en la residencia.
|
||||||
|
* @throws ResiException si la residencia no existe o el ID es nulo.
|
||||||
|
*/
|
||||||
|
public List<UserResponseDto> getAllBajas(LocalDate fecha, LocalDate minFecha, LocalDate maxFecha) {
|
||||||
|
|
||||||
|
List<User> list = userRepository.findAll(UserSpecification.withFiltersBaja(fecha,minFecha, maxFecha, null));
|
||||||
|
|
||||||
|
return list.stream().map(UserResponseDto::new).toList();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina físicamente un usuario si no tiene registros dependientes.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idUser ID del usuario.
|
||||||
|
* @throws ResiException si el usuario tiene registros de juego asociados.
|
||||||
|
*/
|
||||||
|
public void deleteFisico(Long idResidencia, Long idUser) {
|
||||||
|
User userTmp = getUsuario(idResidencia, idUser);
|
||||||
|
|
||||||
|
// Comprobar juegos asociados
|
||||||
|
if (userTmp.getRegistroJuegos() != null && !userTmp.getRegistroJuegos().isEmpty()){
|
||||||
|
throw new ResiException(ApiErrorCode.REFERENCIAS_DEPENDIENTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
userRepository.delete(userTmp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marca lógicamente como dado de baja a un usuario.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idUser ID del usuario.
|
||||||
|
* @throws ResiException si el usuario no existe, no pertenece a la residencia o ya está dado de baja.
|
||||||
|
*/
|
||||||
|
public void deleteLogico(Long idResidencia, Long idUser) {
|
||||||
|
if (idResidencia == null || idUser == null){
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
//Verificamos si existe el usuario
|
||||||
|
User user = userRepository.findById(idUser).orElse(null);
|
||||||
|
if (user == null){
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_INVALIDO);
|
||||||
|
}
|
||||||
|
//Validamos si pertenece a la residencia
|
||||||
|
if (!user.getResidencia().getId().equals(idResidencia)){
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Validamos si el usuario ya esta de baja
|
||||||
|
if (user.isBaja()){
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_BAJA);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Dar de baja
|
||||||
|
user.setBaja(true);
|
||||||
|
user.setEmail(passwordEncoder.encode(user.getEmail()));
|
||||||
|
user.setFechaBaja(LocalDateTime.now());
|
||||||
|
userRepository.save(user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desvincula registros de juego del usuario sin eliminar al usuario.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia del usuario.
|
||||||
|
* @param idUser ID del usuario al que se le eliminarán las referencias.
|
||||||
|
* @throws ResiException en caso de error
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void deleteReferencies(Long idResidencia, Long idUser) {
|
||||||
|
if (idResidencia == null || idUser == null) {
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
User userTmp = userRepository.findById(idUser)
|
||||||
|
.orElseThrow(() -> new ResiException(ApiErrorCode.USUARIO_INVALIDO));
|
||||||
|
//Validar si pertenece a esa residencia
|
||||||
|
if (!userTmp.getResidencia().getId().equals(idResidencia)) {
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_INVALIDO);
|
||||||
|
}
|
||||||
|
// Desvincular el usuario de todos los registros de juego
|
||||||
|
for(RegistroJuego reg : userTmp.getRegistroJuegos()){
|
||||||
|
reg.setUsuario(null);
|
||||||
|
}
|
||||||
|
userTmp.setRegistroJuegos(new LinkedHashSet<>());
|
||||||
|
userRepository.save(userTmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza los datos de un usuario existente.
|
||||||
|
* <p>
|
||||||
|
* Este método permite modificar nombre, apellido y correo electrónico del usuario,
|
||||||
|
* con validaciones para cada uno. El correo debe ser válido y no estar ya registrado.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idUser ID del usuario a actualizar.
|
||||||
|
* @param input Datos nuevos del usuario.
|
||||||
|
* @return DTO con los datos del usuario actualizado.
|
||||||
|
* @throws ResiException si los datos son inválidos o el usuario no pertenece a la residencia.
|
||||||
|
*/
|
||||||
|
public UserResponseDto update(Long idResidencia, Long idUser, UserDto input) {
|
||||||
|
User userTmp = getUsuario(idResidencia, idUser);
|
||||||
|
//Comprobar si elm usuario esta de baja
|
||||||
|
if (userTmp.isBaja()) {
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_BAJA);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input != null){
|
||||||
|
//Validar si el nombre es valido
|
||||||
|
if (input.getNombre() != null && !input.getNombre().isEmpty()) {
|
||||||
|
userTmp.setNombre(input.getNombre().trim());
|
||||||
|
}
|
||||||
|
//Validar si el apellido es valido
|
||||||
|
if (input.getApellido() != null && !input.getApellido().isEmpty()) {
|
||||||
|
userTmp.setApellido(input.getApellido().trim());
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//Validar si el email es valido
|
||||||
|
input.setEmail(input.getEmail().trim().toLowerCase());
|
||||||
|
if (EmailService.isEmailValid(input.getEmail())) {
|
||||||
|
//Validar si el email ya existe
|
||||||
|
if (userRepository.findByEmail(input.getEmail()) != null) {
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_DUPLICADO);
|
||||||
|
}
|
||||||
|
userTmp.setEmail(input.getEmail());
|
||||||
|
} else {
|
||||||
|
throw new ResiException(ApiErrorCode.CORREO_INVALIDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return new UserResponseDto(userRepository.save(userTmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia la contraseña de un usuario, validando su contraseña actual.
|
||||||
|
*
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idUser ID del usuario.
|
||||||
|
* @param input Objeto con la contraseña actual y la nueva.
|
||||||
|
* @return DTO con los datos del usuario actualizado.
|
||||||
|
* @throws ResiException si los datos son inválidos o la contraseña actual no coincide.
|
||||||
|
*/
|
||||||
|
public UserResponseDto updatePassword(Long idResidencia, Long idUser, ChangePasswordUserDto input) {
|
||||||
|
if (idResidencia == null || idUser == null || input == null ||
|
||||||
|
input.getOldPassword() == null || input.getNewPassword() == null) {
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
//Validar si existe ese usuario
|
||||||
|
User userTmp = userRepository.findById(idUser)
|
||||||
|
.orElseThrow(() -> new ResiException(ApiErrorCode.USUARIO_INVALIDO));
|
||||||
|
//Validar si pertenece a esa residencia
|
||||||
|
if (!userTmp.getResidencia().getId().equals(idResidencia)) {
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_INVALIDO);
|
||||||
|
}
|
||||||
|
//Comprobar si elm usuario esta de baja
|
||||||
|
if (userTmp.isBaja()) {
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_BAJA);
|
||||||
|
}
|
||||||
|
//Validar si la contraseña es correcta
|
||||||
|
if (!passwordEncoder.matches(input.getOldPassword(), userTmp.getPassword())) {
|
||||||
|
throw new ResiException(ApiErrorCode.CONTRASENA_INCORRECTA); // Asegúrate de definir este código si no existe
|
||||||
|
}
|
||||||
|
|
||||||
|
userTmp.setPassword(passwordEncoder.encode(input.getNewPassword()));
|
||||||
|
|
||||||
|
return new UserResponseDto(userRepository.save(userTmp));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene un usuario por su ID y valida que pertenezca a la residencia indicada.
|
||||||
|
* @param idResidencia ID de la residencia.
|
||||||
|
* @param idUsuario ID del usuario.
|
||||||
|
* @return DTO del usuario solicitado.
|
||||||
|
* @throws ResiException si el ID es nulo, el usuario no existe o no pertenece a la residencia.
|
||||||
|
*/
|
||||||
|
public User getUsuario(Long idResidencia, Long idUsuario) {
|
||||||
|
if (idResidencia == null || idUsuario == null) {
|
||||||
|
throw new ResiException(ApiErrorCode.CAMPOS_OBLIGATORIOS);
|
||||||
|
}
|
||||||
|
//validar si existe ese usuario
|
||||||
|
User userTmp = userRepository.findById(idUsuario)
|
||||||
|
.orElseThrow(() -> new ResiException(ApiErrorCode.USUARIO_INVALIDO));
|
||||||
|
|
||||||
|
//Validar si pertenece a esa residencia
|
||||||
|
if (userTmp.getResidencia() == null || !userTmp.getResidencia().getId().equals(idResidencia)) {
|
||||||
|
throw new ResiException(ApiErrorCode.USUARIO_INVALIDO);
|
||||||
|
}
|
||||||
|
return userTmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue