🗑️ Remove old backend folder
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- backend/.gitignore +0 -62
- backend/.mvn/wrapper/maven-wrapper.properties +0 -3
- backend/Dockerfile +0 -28
- backend/mvnw +0 -295
- backend/mvnw.cmd +0 -189
- backend/pom.xml +0 -108
- backend/src/main/java/com/locallend/locallend/LocallendApplication.java +0 -13
- backend/src/main/java/com/locallend/locallend/config/CategoryDataInitializer.java +0 -81
- backend/src/main/java/com/locallend/locallend/config/CloudinaryConfig.java +0 -38
- backend/src/main/java/com/locallend/locallend/config/CorsConfig.java +0 -63
- backend/src/main/java/com/locallend/locallend/config/MongoTextIndexInitializer.java +0 -41
- backend/src/main/java/com/locallend/locallend/config/SecurityConfig.java +0 -97
- backend/src/main/java/com/locallend/locallend/config/ValidationConfig.java +0 -36
- backend/src/main/java/com/locallend/locallend/controller/AuthController.java +0 -64
- backend/src/main/java/com/locallend/locallend/controller/BookingController.java +0 -261
- backend/src/main/java/com/locallend/locallend/controller/CategoryController.java +0 -287
- backend/src/main/java/com/locallend/locallend/controller/ImageController.java +0 -200
- backend/src/main/java/com/locallend/locallend/controller/ItemController.java +0 -349
- backend/src/main/java/com/locallend/locallend/controller/RatingController.java +0 -531
- backend/src/main/java/com/locallend/locallend/controller/UserController.java +0 -100
- backend/src/main/java/com/locallend/locallend/dto/CategoryDto.java +0 -106
- backend/src/main/java/com/locallend/locallend/dto/CreateCategoryRequest.java +0 -57
- backend/src/main/java/com/locallend/locallend/dto/CreateItemRequest.java +0 -49
- backend/src/main/java/com/locallend/locallend/dto/ItemDTO.java +0 -68
- backend/src/main/java/com/locallend/locallend/dto/UpdateItemRequest.java +0 -33
- backend/src/main/java/com/locallend/locallend/dto/request/BookingRequestDto.java +0 -78
- backend/src/main/java/com/locallend/locallend/dto/request/ItemRequestDto.java +0 -60
- backend/src/main/java/com/locallend/locallend/dto/request/ItemUpdateDto.java +0 -49
- backend/src/main/java/com/locallend/locallend/dto/request/RatingCreateDto.java +0 -71
- backend/src/main/java/com/locallend/locallend/dto/request/UserLoginDto.java +0 -33
- backend/src/main/java/com/locallend/locallend/dto/request/UserRegistrationDto.java +0 -71
- backend/src/main/java/com/locallend/locallend/dto/request/UserUpdateDto.java +0 -42
- backend/src/main/java/com/locallend/locallend/dto/response/BookingResponseDto.java +0 -138
- backend/src/main/java/com/locallend/locallend/dto/response/CategoryResponseDto.java +0 -36
- backend/src/main/java/com/locallend/locallend/dto/response/ItemResponseDto.java +0 -103
- backend/src/main/java/com/locallend/locallend/dto/response/ItemSummaryDto.java +0 -61
- backend/src/main/java/com/locallend/locallend/dto/response/JwtAuthResponseDto.java +0 -43
- backend/src/main/java/com/locallend/locallend/dto/response/RatingResponseDto.java +0 -89
- backend/src/main/java/com/locallend/locallend/dto/response/RatingStatsResponse.java +0 -74
- backend/src/main/java/com/locallend/locallend/dto/response/UserPublicDto.java +0 -76
- backend/src/main/java/com/locallend/locallend/dto/response/UserResponseDto.java +0 -141
- backend/src/main/java/com/locallend/locallend/exception/BookingConflictException.java +0 -37
- backend/src/main/java/com/locallend/locallend/exception/BookingNotFoundException.java +0 -32
- backend/src/main/java/com/locallend/locallend/exception/BusinessException.java +0 -11
- backend/src/main/java/com/locallend/locallend/exception/CategoryNotFoundException.java +0 -36
- backend/src/main/java/com/locallend/locallend/exception/DuplicateResourceException.java +0 -37
- backend/src/main/java/com/locallend/locallend/exception/GlobalExceptionHandler.java +0 -504
- backend/src/main/java/com/locallend/locallend/exception/InsufficientTrustScoreException.java +0 -31
- backend/src/main/java/com/locallend/locallend/exception/InvalidBookingPeriodException.java +0 -38
- backend/src/main/java/com/locallend/locallend/exception/InvalidOperationException.java +0 -30
backend/.gitignore
DELETED
|
@@ -1,62 +0,0 @@
|
|
| 1 |
-
# Maven
|
| 2 |
-
target/
|
| 3 |
-
!.mvn/wrapper/maven-wrapper.jar
|
| 4 |
-
*.original
|
| 5 |
-
|
| 6 |
-
# STS
|
| 7 |
-
.apt_generated
|
| 8 |
-
.classpath
|
| 9 |
-
.factorypath
|
| 10 |
-
.project
|
| 11 |
-
.settings
|
| 12 |
-
.springBeans
|
| 13 |
-
.sts4-cache
|
| 14 |
-
|
| 15 |
-
# IntelliJ IDEA
|
| 16 |
-
.idea
|
| 17 |
-
*.iws
|
| 18 |
-
*.iml
|
| 19 |
-
*.ipr
|
| 20 |
-
|
| 21 |
-
# NetBeans
|
| 22 |
-
/nbproject/private/
|
| 23 |
-
/nbbuild/
|
| 24 |
-
/dist/
|
| 25 |
-
/nbdist/
|
| 26 |
-
/.nb-gradle/
|
| 27 |
-
build/
|
| 28 |
-
!**/src/main/**/build/
|
| 29 |
-
!**/src/test/**/build/
|
| 30 |
-
|
| 31 |
-
# VS Code
|
| 32 |
-
.vscode/
|
| 33 |
-
|
| 34 |
-
# Environment variables
|
| 35 |
-
.env
|
| 36 |
-
.env.local
|
| 37 |
-
.env.*.local
|
| 38 |
-
|
| 39 |
-
# OS
|
| 40 |
-
.DS_Store
|
| 41 |
-
.DS_Store?
|
| 42 |
-
._*
|
| 43 |
-
.Spotlight-V100
|
| 44 |
-
.Trashes
|
| 45 |
-
ehthumbs.db
|
| 46 |
-
Thumbs.db
|
| 47 |
-
|
| 48 |
-
# Logs
|
| 49 |
-
*.log
|
| 50 |
-
logs/
|
| 51 |
-
|
| 52 |
-
# Compiled class files
|
| 53 |
-
*.class
|
| 54 |
-
|
| 55 |
-
# Package Files
|
| 56 |
-
*.jar
|
| 57 |
-
*.war
|
| 58 |
-
*.nar
|
| 59 |
-
*.ear
|
| 60 |
-
*.zip
|
| 61 |
-
*.tar.gz
|
| 62 |
-
*.rar
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/.mvn/wrapper/maven-wrapper.properties
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
wrapperVersion=3.3.4
|
| 2 |
-
distributionType=only-script
|
| 3 |
-
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
|
|
|
|
|
|
|
|
|
|
|
|
backend/Dockerfile
DELETED
|
@@ -1,28 +0,0 @@
|
|
| 1 |
-
# ===== STAGE 1: Build the app =====
|
| 2 |
-
FROM maven:3.9.6-eclipse-temurin-17 AS build
|
| 3 |
-
WORKDIR /app
|
| 4 |
-
|
| 5 |
-
# Copy pom.xml and download dependencies
|
| 6 |
-
COPY pom.xml .
|
| 7 |
-
RUN mvn dependency:go-offline -B
|
| 8 |
-
|
| 9 |
-
# Copy source and build the JAR
|
| 10 |
-
COPY src ./src
|
| 11 |
-
RUN mvn clean package -DskipTests
|
| 12 |
-
|
| 13 |
-
# ===== STAGE 2: Run the app =====
|
| 14 |
-
FROM eclipse-temurin:17-jre
|
| 15 |
-
WORKDIR /app
|
| 16 |
-
|
| 17 |
-
# Copy the JAR from build stage
|
| 18 |
-
COPY --from=build /app/target/*.jar app.jar
|
| 19 |
-
|
| 20 |
-
# Expose port
|
| 21 |
-
EXPOSE 8080
|
| 22 |
-
|
| 23 |
-
# Health check
|
| 24 |
-
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
| 25 |
-
CMD curl -f http://localhost:8080/actuator/health || exit 1
|
| 26 |
-
|
| 27 |
-
# Run the application
|
| 28 |
-
ENTRYPOINT ["java", "-jar", "app.jar"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/mvnw
DELETED
|
@@ -1,295 +0,0 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
# ----------------------------------------------------------------------------
|
| 3 |
-
# Licensed to the Apache Software Foundation (ASF) under one
|
| 4 |
-
# or more contributor license agreements. See the NOTICE file
|
| 5 |
-
# distributed with this work for additional information
|
| 6 |
-
# regarding copyright ownership. The ASF licenses this file
|
| 7 |
-
# to you under the Apache License, Version 2.0 (the
|
| 8 |
-
# "License"); you may not use this file except in compliance
|
| 9 |
-
# with the License. You may obtain a copy of the License at
|
| 10 |
-
#
|
| 11 |
-
# http://www.apache.org/licenses/LICENSE-2.0
|
| 12 |
-
#
|
| 13 |
-
# Unless required by applicable law or agreed to in writing,
|
| 14 |
-
# software distributed under the License is distributed on an
|
| 15 |
-
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 16 |
-
# KIND, either express or implied. See the License for the
|
| 17 |
-
# specific language governing permissions and limitations
|
| 18 |
-
# under the License.
|
| 19 |
-
# ----------------------------------------------------------------------------
|
| 20 |
-
|
| 21 |
-
# ----------------------------------------------------------------------------
|
| 22 |
-
# Apache Maven Wrapper startup batch script, version 3.3.4
|
| 23 |
-
#
|
| 24 |
-
# Optional ENV vars
|
| 25 |
-
# -----------------
|
| 26 |
-
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
|
| 27 |
-
# MVNW_REPOURL - repo url base for downloading maven distribution
|
| 28 |
-
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
| 29 |
-
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
|
| 30 |
-
# ----------------------------------------------------------------------------
|
| 31 |
-
|
| 32 |
-
set -euf
|
| 33 |
-
[ "${MVNW_VERBOSE-}" != debug ] || set -x
|
| 34 |
-
|
| 35 |
-
# OS specific support.
|
| 36 |
-
native_path() { printf %s\\n "$1"; }
|
| 37 |
-
case "$(uname)" in
|
| 38 |
-
CYGWIN* | MINGW*)
|
| 39 |
-
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
|
| 40 |
-
native_path() { cygpath --path --windows "$1"; }
|
| 41 |
-
;;
|
| 42 |
-
esac
|
| 43 |
-
|
| 44 |
-
# set JAVACMD and JAVACCMD
|
| 45 |
-
set_java_home() {
|
| 46 |
-
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
|
| 47 |
-
if [ -n "${JAVA_HOME-}" ]; then
|
| 48 |
-
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
|
| 49 |
-
# IBM's JDK on AIX uses strange locations for the executables
|
| 50 |
-
JAVACMD="$JAVA_HOME/jre/sh/java"
|
| 51 |
-
JAVACCMD="$JAVA_HOME/jre/sh/javac"
|
| 52 |
-
else
|
| 53 |
-
JAVACMD="$JAVA_HOME/bin/java"
|
| 54 |
-
JAVACCMD="$JAVA_HOME/bin/javac"
|
| 55 |
-
|
| 56 |
-
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
|
| 57 |
-
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
|
| 58 |
-
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
|
| 59 |
-
return 1
|
| 60 |
-
fi
|
| 61 |
-
fi
|
| 62 |
-
else
|
| 63 |
-
JAVACMD="$(
|
| 64 |
-
'set' +e
|
| 65 |
-
'unset' -f command 2>/dev/null
|
| 66 |
-
'command' -v java
|
| 67 |
-
)" || :
|
| 68 |
-
JAVACCMD="$(
|
| 69 |
-
'set' +e
|
| 70 |
-
'unset' -f command 2>/dev/null
|
| 71 |
-
'command' -v javac
|
| 72 |
-
)" || :
|
| 73 |
-
|
| 74 |
-
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
|
| 75 |
-
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
|
| 76 |
-
return 1
|
| 77 |
-
fi
|
| 78 |
-
fi
|
| 79 |
-
}
|
| 80 |
-
|
| 81 |
-
# hash string like Java String::hashCode
|
| 82 |
-
hash_string() {
|
| 83 |
-
str="${1:-}" h=0
|
| 84 |
-
while [ -n "$str" ]; do
|
| 85 |
-
char="${str%"${str#?}"}"
|
| 86 |
-
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
|
| 87 |
-
str="${str#?}"
|
| 88 |
-
done
|
| 89 |
-
printf %x\\n $h
|
| 90 |
-
}
|
| 91 |
-
|
| 92 |
-
verbose() { :; }
|
| 93 |
-
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
|
| 94 |
-
|
| 95 |
-
die() {
|
| 96 |
-
printf %s\\n "$1" >&2
|
| 97 |
-
exit 1
|
| 98 |
-
}
|
| 99 |
-
|
| 100 |
-
trim() {
|
| 101 |
-
# MWRAPPER-139:
|
| 102 |
-
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
| 103 |
-
# Needed for removing poorly interpreted newline sequences when running in more
|
| 104 |
-
# exotic environments such as mingw bash on Windows.
|
| 105 |
-
printf "%s" "${1}" | tr -d '[:space:]'
|
| 106 |
-
}
|
| 107 |
-
|
| 108 |
-
scriptDir="$(dirname "$0")"
|
| 109 |
-
scriptName="$(basename "$0")"
|
| 110 |
-
|
| 111 |
-
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
|
| 112 |
-
while IFS="=" read -r key value; do
|
| 113 |
-
case "${key-}" in
|
| 114 |
-
distributionUrl) distributionUrl=$(trim "${value-}") ;;
|
| 115 |
-
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
|
| 116 |
-
esac
|
| 117 |
-
done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
| 118 |
-
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
| 119 |
-
|
| 120 |
-
case "${distributionUrl##*/}" in
|
| 121 |
-
maven-mvnd-*bin.*)
|
| 122 |
-
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
|
| 123 |
-
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
|
| 124 |
-
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
|
| 125 |
-
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
|
| 126 |
-
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
|
| 127 |
-
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
|
| 128 |
-
*)
|
| 129 |
-
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
|
| 130 |
-
distributionPlatform=linux-amd64
|
| 131 |
-
;;
|
| 132 |
-
esac
|
| 133 |
-
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
|
| 134 |
-
;;
|
| 135 |
-
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
|
| 136 |
-
*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
|
| 137 |
-
esac
|
| 138 |
-
|
| 139 |
-
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
| 140 |
-
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
| 141 |
-
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
|
| 142 |
-
distributionUrlName="${distributionUrl##*/}"
|
| 143 |
-
distributionUrlNameMain="${distributionUrlName%.*}"
|
| 144 |
-
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
|
| 145 |
-
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
|
| 146 |
-
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
|
| 147 |
-
|
| 148 |
-
exec_maven() {
|
| 149 |
-
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
|
| 150 |
-
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
|
| 151 |
-
}
|
| 152 |
-
|
| 153 |
-
if [ -d "$MAVEN_HOME" ]; then
|
| 154 |
-
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
| 155 |
-
exec_maven "$@"
|
| 156 |
-
fi
|
| 157 |
-
|
| 158 |
-
case "${distributionUrl-}" in
|
| 159 |
-
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
|
| 160 |
-
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
|
| 161 |
-
esac
|
| 162 |
-
|
| 163 |
-
# prepare tmp dir
|
| 164 |
-
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
|
| 165 |
-
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
|
| 166 |
-
trap clean HUP INT TERM EXIT
|
| 167 |
-
else
|
| 168 |
-
die "cannot create temp dir"
|
| 169 |
-
fi
|
| 170 |
-
|
| 171 |
-
mkdir -p -- "${MAVEN_HOME%/*}"
|
| 172 |
-
|
| 173 |
-
# Download and Install Apache Maven
|
| 174 |
-
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
| 175 |
-
verbose "Downloading from: $distributionUrl"
|
| 176 |
-
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
| 177 |
-
|
| 178 |
-
# select .zip or .tar.gz
|
| 179 |
-
if ! command -v unzip >/dev/null; then
|
| 180 |
-
distributionUrl="${distributionUrl%.zip}.tar.gz"
|
| 181 |
-
distributionUrlName="${distributionUrl##*/}"
|
| 182 |
-
fi
|
| 183 |
-
|
| 184 |
-
# verbose opt
|
| 185 |
-
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
|
| 186 |
-
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
|
| 187 |
-
|
| 188 |
-
# normalize http auth
|
| 189 |
-
case "${MVNW_PASSWORD:+has-password}" in
|
| 190 |
-
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
| 191 |
-
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
| 192 |
-
esac
|
| 193 |
-
|
| 194 |
-
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
|
| 195 |
-
verbose "Found wget ... using wget"
|
| 196 |
-
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
|
| 197 |
-
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
|
| 198 |
-
verbose "Found curl ... using curl"
|
| 199 |
-
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
|
| 200 |
-
elif set_java_home; then
|
| 201 |
-
verbose "Falling back to use Java to download"
|
| 202 |
-
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
|
| 203 |
-
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
|
| 204 |
-
cat >"$javaSource" <<-END
|
| 205 |
-
public class Downloader extends java.net.Authenticator
|
| 206 |
-
{
|
| 207 |
-
protected java.net.PasswordAuthentication getPasswordAuthentication()
|
| 208 |
-
{
|
| 209 |
-
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
|
| 210 |
-
}
|
| 211 |
-
public static void main( String[] args ) throws Exception
|
| 212 |
-
{
|
| 213 |
-
setDefault( new Downloader() );
|
| 214 |
-
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
| 215 |
-
}
|
| 216 |
-
}
|
| 217 |
-
END
|
| 218 |
-
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
|
| 219 |
-
verbose " - Compiling Downloader.java ..."
|
| 220 |
-
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
|
| 221 |
-
verbose " - Running Downloader.java ..."
|
| 222 |
-
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
|
| 223 |
-
fi
|
| 224 |
-
|
| 225 |
-
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
| 226 |
-
if [ -n "${distributionSha256Sum-}" ]; then
|
| 227 |
-
distributionSha256Result=false
|
| 228 |
-
if [ "$MVN_CMD" = mvnd.sh ]; then
|
| 229 |
-
echo "Checksum validation is not supported for maven-mvnd." >&2
|
| 230 |
-
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
| 231 |
-
exit 1
|
| 232 |
-
elif command -v sha256sum >/dev/null; then
|
| 233 |
-
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then
|
| 234 |
-
distributionSha256Result=true
|
| 235 |
-
fi
|
| 236 |
-
elif command -v shasum >/dev/null; then
|
| 237 |
-
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
|
| 238 |
-
distributionSha256Result=true
|
| 239 |
-
fi
|
| 240 |
-
else
|
| 241 |
-
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
| 242 |
-
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
| 243 |
-
exit 1
|
| 244 |
-
fi
|
| 245 |
-
if [ $distributionSha256Result = false ]; then
|
| 246 |
-
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
|
| 247 |
-
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
|
| 248 |
-
exit 1
|
| 249 |
-
fi
|
| 250 |
-
fi
|
| 251 |
-
|
| 252 |
-
# unzip and move
|
| 253 |
-
if command -v unzip >/dev/null; then
|
| 254 |
-
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
|
| 255 |
-
else
|
| 256 |
-
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
|
| 257 |
-
fi
|
| 258 |
-
|
| 259 |
-
# Find the actual extracted directory name (handles snapshots where filename != directory name)
|
| 260 |
-
actualDistributionDir=""
|
| 261 |
-
|
| 262 |
-
# First try the expected directory name (for regular distributions)
|
| 263 |
-
if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then
|
| 264 |
-
if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then
|
| 265 |
-
actualDistributionDir="$distributionUrlNameMain"
|
| 266 |
-
fi
|
| 267 |
-
fi
|
| 268 |
-
|
| 269 |
-
# If not found, search for any directory with the Maven executable (for snapshots)
|
| 270 |
-
if [ -z "$actualDistributionDir" ]; then
|
| 271 |
-
# enable globbing to iterate over items
|
| 272 |
-
set +f
|
| 273 |
-
for dir in "$TMP_DOWNLOAD_DIR"/*; do
|
| 274 |
-
if [ -d "$dir" ]; then
|
| 275 |
-
if [ -f "$dir/bin/$MVN_CMD" ]; then
|
| 276 |
-
actualDistributionDir="$(basename "$dir")"
|
| 277 |
-
break
|
| 278 |
-
fi
|
| 279 |
-
fi
|
| 280 |
-
done
|
| 281 |
-
set -f
|
| 282 |
-
fi
|
| 283 |
-
|
| 284 |
-
if [ -z "$actualDistributionDir" ]; then
|
| 285 |
-
verbose "Contents of $TMP_DOWNLOAD_DIR:"
|
| 286 |
-
verbose "$(ls -la "$TMP_DOWNLOAD_DIR")"
|
| 287 |
-
die "Could not find Maven distribution directory in extracted archive"
|
| 288 |
-
fi
|
| 289 |
-
|
| 290 |
-
verbose "Found extracted Maven distribution directory: $actualDistributionDir"
|
| 291 |
-
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url"
|
| 292 |
-
mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
|
| 293 |
-
|
| 294 |
-
clean || :
|
| 295 |
-
exec_maven "$@"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/mvnw.cmd
DELETED
|
@@ -1,189 +0,0 @@
|
|
| 1 |
-
<# : batch portion
|
| 2 |
-
@REM ----------------------------------------------------------------------------
|
| 3 |
-
@REM Licensed to the Apache Software Foundation (ASF) under one
|
| 4 |
-
@REM or more contributor license agreements. See the NOTICE file
|
| 5 |
-
@REM distributed with this work for additional information
|
| 6 |
-
@REM regarding copyright ownership. The ASF licenses this file
|
| 7 |
-
@REM to you under the Apache License, Version 2.0 (the
|
| 8 |
-
@REM "License"); you may not use this file except in compliance
|
| 9 |
-
@REM with the License. You may obtain a copy of the License at
|
| 10 |
-
@REM
|
| 11 |
-
@REM http://www.apache.org/licenses/LICENSE-2.0
|
| 12 |
-
@REM
|
| 13 |
-
@REM Unless required by applicable law or agreed to in writing,
|
| 14 |
-
@REM software distributed under the License is distributed on an
|
| 15 |
-
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 16 |
-
@REM KIND, either express or implied. See the License for the
|
| 17 |
-
@REM specific language governing permissions and limitations
|
| 18 |
-
@REM under the License.
|
| 19 |
-
@REM ----------------------------------------------------------------------------
|
| 20 |
-
|
| 21 |
-
@REM ----------------------------------------------------------------------------
|
| 22 |
-
@REM Apache Maven Wrapper startup batch script, version 3.3.4
|
| 23 |
-
@REM
|
| 24 |
-
@REM Optional ENV vars
|
| 25 |
-
@REM MVNW_REPOURL - repo url base for downloading maven distribution
|
| 26 |
-
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
| 27 |
-
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
|
| 28 |
-
@REM ----------------------------------------------------------------------------
|
| 29 |
-
|
| 30 |
-
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
|
| 31 |
-
@SET __MVNW_CMD__=
|
| 32 |
-
@SET __MVNW_ERROR__=
|
| 33 |
-
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
| 34 |
-
@SET PSModulePath=
|
| 35 |
-
@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 @(
|
| 36 |
-
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
| 37 |
-
)
|
| 38 |
-
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
| 39 |
-
@SET __MVNW_PSMODULEP_SAVE=
|
| 40 |
-
@SET __MVNW_ARG0_NAME__=
|
| 41 |
-
@SET MVNW_USERNAME=
|
| 42 |
-
@SET MVNW_PASSWORD=
|
| 43 |
-
@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*)
|
| 44 |
-
@echo Cannot start maven from wrapper >&2 && exit /b 1
|
| 45 |
-
@GOTO :EOF
|
| 46 |
-
: end batch / begin powershell #>
|
| 47 |
-
|
| 48 |
-
$ErrorActionPreference = "Stop"
|
| 49 |
-
if ($env:MVNW_VERBOSE -eq "true") {
|
| 50 |
-
$VerbosePreference = "Continue"
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
| 54 |
-
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
| 55 |
-
if (!$distributionUrl) {
|
| 56 |
-
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
| 57 |
-
}
|
| 58 |
-
|
| 59 |
-
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
|
| 60 |
-
"maven-mvnd-*" {
|
| 61 |
-
$USE_MVND = $true
|
| 62 |
-
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
|
| 63 |
-
$MVN_CMD = "mvnd.cmd"
|
| 64 |
-
break
|
| 65 |
-
}
|
| 66 |
-
default {
|
| 67 |
-
$USE_MVND = $false
|
| 68 |
-
$MVN_CMD = $script -replace '^mvnw','mvn'
|
| 69 |
-
break
|
| 70 |
-
}
|
| 71 |
-
}
|
| 72 |
-
|
| 73 |
-
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
| 74 |
-
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
| 75 |
-
if ($env:MVNW_REPOURL) {
|
| 76 |
-
$MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" }
|
| 77 |
-
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')"
|
| 78 |
-
}
|
| 79 |
-
$distributionUrlName = $distributionUrl -replace '^.*/',''
|
| 80 |
-
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
|
| 81 |
-
|
| 82 |
-
$MAVEN_M2_PATH = "$HOME/.m2"
|
| 83 |
-
if ($env:MAVEN_USER_HOME) {
|
| 84 |
-
$MAVEN_M2_PATH = "$env:MAVEN_USER_HOME"
|
| 85 |
-
}
|
| 86 |
-
|
| 87 |
-
if (-not (Test-Path -Path $MAVEN_M2_PATH)) {
|
| 88 |
-
New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null
|
| 89 |
-
}
|
| 90 |
-
|
| 91 |
-
$MAVEN_WRAPPER_DISTS = $null
|
| 92 |
-
if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) {
|
| 93 |
-
$MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists"
|
| 94 |
-
} else {
|
| 95 |
-
$MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists"
|
| 96 |
-
}
|
| 97 |
-
|
| 98 |
-
$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain"
|
| 99 |
-
$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
|
| 100 |
-
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
|
| 101 |
-
|
| 102 |
-
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
|
| 103 |
-
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
| 104 |
-
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
| 105 |
-
exit $?
|
| 106 |
-
}
|
| 107 |
-
|
| 108 |
-
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
|
| 109 |
-
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
|
| 110 |
-
}
|
| 111 |
-
|
| 112 |
-
# prepare tmp dir
|
| 113 |
-
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
|
| 114 |
-
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
|
| 115 |
-
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
|
| 116 |
-
trap {
|
| 117 |
-
if ($TMP_DOWNLOAD_DIR.Exists) {
|
| 118 |
-
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
| 119 |
-
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
| 120 |
-
}
|
| 121 |
-
}
|
| 122 |
-
|
| 123 |
-
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
|
| 124 |
-
|
| 125 |
-
# Download and Install Apache Maven
|
| 126 |
-
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
| 127 |
-
Write-Verbose "Downloading from: $distributionUrl"
|
| 128 |
-
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
| 129 |
-
|
| 130 |
-
$webclient = New-Object System.Net.WebClient
|
| 131 |
-
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
| 132 |
-
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
|
| 133 |
-
}
|
| 134 |
-
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
| 135 |
-
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
| 136 |
-
|
| 137 |
-
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
| 138 |
-
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
| 139 |
-
if ($distributionSha256Sum) {
|
| 140 |
-
if ($USE_MVND) {
|
| 141 |
-
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
| 142 |
-
}
|
| 143 |
-
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
|
| 144 |
-
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
|
| 145 |
-
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."
|
| 146 |
-
}
|
| 147 |
-
}
|
| 148 |
-
|
| 149 |
-
# unzip and move
|
| 150 |
-
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
|
| 151 |
-
|
| 152 |
-
# Find the actual extracted directory name (handles snapshots where filename != directory name)
|
| 153 |
-
$actualDistributionDir = ""
|
| 154 |
-
|
| 155 |
-
# First try the expected directory name (for regular distributions)
|
| 156 |
-
$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain"
|
| 157 |
-
$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD"
|
| 158 |
-
if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) {
|
| 159 |
-
$actualDistributionDir = $distributionUrlNameMain
|
| 160 |
-
}
|
| 161 |
-
|
| 162 |
-
# If not found, search for any directory with the Maven executable (for snapshots)
|
| 163 |
-
if (!$actualDistributionDir) {
|
| 164 |
-
Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object {
|
| 165 |
-
$testPath = Join-Path $_.FullName "bin/$MVN_CMD"
|
| 166 |
-
if (Test-Path -Path $testPath -PathType Leaf) {
|
| 167 |
-
$actualDistributionDir = $_.Name
|
| 168 |
-
}
|
| 169 |
-
}
|
| 170 |
-
}
|
| 171 |
-
|
| 172 |
-
if (!$actualDistributionDir) {
|
| 173 |
-
Write-Error "Could not find Maven distribution directory in extracted archive"
|
| 174 |
-
}
|
| 175 |
-
|
| 176 |
-
Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir"
|
| 177 |
-
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null
|
| 178 |
-
try {
|
| 179 |
-
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
|
| 180 |
-
} catch {
|
| 181 |
-
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
|
| 182 |
-
Write-Error "fail to move MAVEN_HOME"
|
| 183 |
-
}
|
| 184 |
-
} finally {
|
| 185 |
-
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
| 186 |
-
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
| 187 |
-
}
|
| 188 |
-
|
| 189 |
-
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/pom.xml
DELETED
|
@@ -1,108 +0,0 @@
|
|
| 1 |
-
<?xml version="1.0" encoding="UTF-8"?>
|
| 2 |
-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
| 3 |
-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
| 4 |
-
<modelVersion>4.0.0</modelVersion>
|
| 5 |
-
<parent>
|
| 6 |
-
<groupId>org.springframework.boot</groupId>
|
| 7 |
-
<artifactId>spring-boot-starter-parent</artifactId>
|
| 8 |
-
<version>3.5.6</version>
|
| 9 |
-
<relativePath/> <!-- lookup parent from repository -->
|
| 10 |
-
</parent>
|
| 11 |
-
<groupId>com.locallend</groupId>
|
| 12 |
-
<artifactId>locallend</artifactId>
|
| 13 |
-
<version>0.0.1-SNAPSHOT</version>
|
| 14 |
-
<name>locallend</name>
|
| 15 |
-
<description>Demo project for Spring Boot</description>
|
| 16 |
-
<url/>
|
| 17 |
-
<licenses>
|
| 18 |
-
<license/>
|
| 19 |
-
</licenses>
|
| 20 |
-
<developers>
|
| 21 |
-
<developer/>
|
| 22 |
-
</developers>
|
| 23 |
-
<scm>
|
| 24 |
-
<connection/>
|
| 25 |
-
<developerConnection/>
|
| 26 |
-
<tag/>
|
| 27 |
-
<url/>
|
| 28 |
-
</scm>
|
| 29 |
-
<properties>
|
| 30 |
-
<java.version>17</java.version>
|
| 31 |
-
</properties>
|
| 32 |
-
<dependencies>
|
| 33 |
-
<dependency>
|
| 34 |
-
<groupId>org.springframework.boot</groupId>
|
| 35 |
-
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
| 36 |
-
</dependency>
|
| 37 |
-
<dependency>
|
| 38 |
-
<groupId>org.springframework.boot</groupId>
|
| 39 |
-
<artifactId>spring-boot-starter-mail</artifactId>
|
| 40 |
-
</dependency>
|
| 41 |
-
<dependency>
|
| 42 |
-
<groupId>org.springframework.boot</groupId>
|
| 43 |
-
<artifactId>spring-boot-starter-security</artifactId>
|
| 44 |
-
</dependency>
|
| 45 |
-
<dependency>
|
| 46 |
-
<groupId>org.springframework.boot</groupId>
|
| 47 |
-
<artifactId>spring-boot-starter-validation</artifactId>
|
| 48 |
-
</dependency>
|
| 49 |
-
<dependency>
|
| 50 |
-
<groupId>org.springframework.boot</groupId>
|
| 51 |
-
<artifactId>spring-boot-starter-web</artifactId>
|
| 52 |
-
</dependency>
|
| 53 |
-
|
| 54 |
-
<!-- JWT for token-based authentication -->
|
| 55 |
-
<dependency>
|
| 56 |
-
<groupId>io.jsonwebtoken</groupId>
|
| 57 |
-
<artifactId>jjwt-api</artifactId>
|
| 58 |
-
<version>0.11.5</version>
|
| 59 |
-
</dependency>
|
| 60 |
-
<dependency>
|
| 61 |
-
<groupId>io.jsonwebtoken</groupId>
|
| 62 |
-
<artifactId>jjwt-impl</artifactId>
|
| 63 |
-
<version>0.11.5</version>
|
| 64 |
-
<scope>runtime</scope>
|
| 65 |
-
</dependency>
|
| 66 |
-
<dependency>
|
| 67 |
-
<groupId>io.jsonwebtoken</groupId>
|
| 68 |
-
<artifactId>jjwt-jackson</artifactId>
|
| 69 |
-
<version>0.11.5</version>
|
| 70 |
-
<scope>runtime</scope>
|
| 71 |
-
</dependency>
|
| 72 |
-
|
| 73 |
-
<dependency>
|
| 74 |
-
<groupId>org.springframework.boot</groupId>
|
| 75 |
-
<artifactId>spring-boot-starter-test</artifactId>
|
| 76 |
-
<scope>test</scope>
|
| 77 |
-
</dependency>
|
| 78 |
-
<dependency>
|
| 79 |
-
<groupId>org.springframework.security</groupId>
|
| 80 |
-
<artifactId>spring-security-test</artifactId>
|
| 81 |
-
<scope>test</scope>
|
| 82 |
-
</dependency>
|
| 83 |
-
|
| 84 |
-
<!-- Cloudinary for image upload and management -->
|
| 85 |
-
<dependency>
|
| 86 |
-
<groupId>com.cloudinary</groupId>
|
| 87 |
-
<artifactId>cloudinary-http44</artifactId>
|
| 88 |
-
<version>1.38.0</version>
|
| 89 |
-
</dependency>
|
| 90 |
-
|
| 91 |
-
<!-- dotenv for loading .env files -->
|
| 92 |
-
<dependency>
|
| 93 |
-
<groupId>me.paulschwarz</groupId>
|
| 94 |
-
<artifactId>spring-dotenv</artifactId>
|
| 95 |
-
<version>4.0.0</version>
|
| 96 |
-
</dependency>
|
| 97 |
-
</dependencies>
|
| 98 |
-
|
| 99 |
-
<build>
|
| 100 |
-
<plugins>
|
| 101 |
-
<plugin>
|
| 102 |
-
<groupId>org.springframework.boot</groupId>
|
| 103 |
-
<artifactId>spring-boot-maven-plugin</artifactId>
|
| 104 |
-
</plugin>
|
| 105 |
-
</plugins>
|
| 106 |
-
</build>
|
| 107 |
-
|
| 108 |
-
</project>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/LocallendApplication.java
DELETED
|
@@ -1,13 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend;
|
| 2 |
-
|
| 3 |
-
import org.springframework.boot.SpringApplication;
|
| 4 |
-
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
| 5 |
-
|
| 6 |
-
@SpringBootApplication
|
| 7 |
-
public class LocallendApplication {
|
| 8 |
-
|
| 9 |
-
public static void main(String[] args) {
|
| 10 |
-
SpringApplication.run(LocallendApplication.class, args);
|
| 11 |
-
}
|
| 12 |
-
|
| 13 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/config/CategoryDataInitializer.java
DELETED
|
@@ -1,81 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.config;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.model.Category;
|
| 4 |
-
import com.locallend.locallend.repository.CategoryRepository;
|
| 5 |
-
import org.slf4j.Logger;
|
| 6 |
-
import org.slf4j.LoggerFactory;
|
| 7 |
-
import org.springframework.boot.ApplicationArguments;
|
| 8 |
-
import org.springframework.boot.ApplicationRunner;
|
| 9 |
-
import org.springframework.context.annotation.Profile;
|
| 10 |
-
import org.springframework.stereotype.Component;
|
| 11 |
-
|
| 12 |
-
import java.time.LocalDateTime;
|
| 13 |
-
import java.util.Arrays;
|
| 14 |
-
import java.util.List;
|
| 15 |
-
|
| 16 |
-
/**
|
| 17 |
-
* Initializes default categories in the database at startup.
|
| 18 |
-
* This ensures that the application has basic categories available
|
| 19 |
-
* immediately after deployment without manual intervention.
|
| 20 |
-
*/
|
| 21 |
-
@Component
|
| 22 |
-
@Profile("prod") // Only run in production profile used in docker-compose
|
| 23 |
-
public class CategoryDataInitializer implements ApplicationRunner {
|
| 24 |
-
|
| 25 |
-
private static final Logger log = LoggerFactory.getLogger(CategoryDataInitializer.class);
|
| 26 |
-
private final CategoryRepository categoryRepository;
|
| 27 |
-
|
| 28 |
-
public CategoryDataInitializer(CategoryRepository categoryRepository) {
|
| 29 |
-
this.categoryRepository = categoryRepository;
|
| 30 |
-
}
|
| 31 |
-
|
| 32 |
-
@Override
|
| 33 |
-
public void run(ApplicationArguments args) {
|
| 34 |
-
initializeDefaultCategories();
|
| 35 |
-
}
|
| 36 |
-
|
| 37 |
-
private void initializeDefaultCategories() {
|
| 38 |
-
// Check if categories already exist to avoid duplicates
|
| 39 |
-
long existingCategoryCount = categoryRepository.count();
|
| 40 |
-
if (existingCategoryCount > 0) {
|
| 41 |
-
log.info("[CategoryInit] Categories already exist ({}), skipping initialization", existingCategoryCount);
|
| 42 |
-
return;
|
| 43 |
-
}
|
| 44 |
-
|
| 45 |
-
log.info("[CategoryInit] Initializing default categories...");
|
| 46 |
-
|
| 47 |
-
List<Category> defaultCategories = Arrays.asList(
|
| 48 |
-
createCategory("Electronics", "Electronic devices, gadgets, and technology items including phones, laptops, cameras, and accessories"),
|
| 49 |
-
createCategory("Tools", "Hand tools, power tools, and equipment for construction, repair, and maintenance work"),
|
| 50 |
-
createCategory("Sports", "Sports equipment, gear, and accessories for various athletic activities and outdoor recreation"),
|
| 51 |
-
createCategory("Books", "Books, magazines, educational materials, and reading resources across all genres and topics"),
|
| 52 |
-
createCategory("Furniture", "Home and office furniture including chairs, tables, storage solutions, and decorative pieces"),
|
| 53 |
-
createCategory("Vehicles", "Cars, motorcycles, bicycles, and other transportation vehicles and related accessories"),
|
| 54 |
-
createCategory("Appliances", "Home appliances, kitchen equipment, and household electrical devices"),
|
| 55 |
-
createCategory("Others", "Miscellaneous items that don't fit into other specific categories")
|
| 56 |
-
);
|
| 57 |
-
|
| 58 |
-
try {
|
| 59 |
-
List<Category> savedCategories = categoryRepository.saveAll(defaultCategories);
|
| 60 |
-
log.info("[CategoryInit] Successfully initialized {} categories", savedCategories.size());
|
| 61 |
-
|
| 62 |
-
// Log each category for verification
|
| 63 |
-
savedCategories.forEach(category ->
|
| 64 |
-
log.info("[CategoryInit] Created category: {} (ID: {})", category.getName(), category.getId())
|
| 65 |
-
);
|
| 66 |
-
|
| 67 |
-
} catch (Exception e) {
|
| 68 |
-
log.error("[CategoryInit] Failed to initialize categories", e);
|
| 69 |
-
throw new RuntimeException("Failed to initialize default categories", e);
|
| 70 |
-
}
|
| 71 |
-
}
|
| 72 |
-
|
| 73 |
-
private Category createCategory(String name, String description) {
|
| 74 |
-
Category category = new Category();
|
| 75 |
-
category.setName(name);
|
| 76 |
-
category.setDescription(description);
|
| 77 |
-
category.setCreatedAt(LocalDateTime.now());
|
| 78 |
-
category.setUpdatedAt(LocalDateTime.now());
|
| 79 |
-
return category;
|
| 80 |
-
}
|
| 81 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/config/CloudinaryConfig.java
DELETED
|
@@ -1,38 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.config;
|
| 2 |
-
|
| 3 |
-
import com.cloudinary.Cloudinary;
|
| 4 |
-
import com.cloudinary.utils.ObjectUtils;
|
| 5 |
-
import org.springframework.beans.factory.annotation.Value;
|
| 6 |
-
import org.springframework.context.annotation.Bean;
|
| 7 |
-
import org.springframework.context.annotation.Configuration;
|
| 8 |
-
|
| 9 |
-
/**
|
| 10 |
-
* Configuration class for Cloudinary integration.
|
| 11 |
-
* Initializes Cloudinary instance with credentials from application.properties.
|
| 12 |
-
*/
|
| 13 |
-
@Configuration
|
| 14 |
-
public class CloudinaryConfig {
|
| 15 |
-
|
| 16 |
-
@Value("${cloudinary.cloud-name}")
|
| 17 |
-
private String cloudName;
|
| 18 |
-
|
| 19 |
-
@Value("${cloudinary.api-key}")
|
| 20 |
-
private String apiKey;
|
| 21 |
-
|
| 22 |
-
@Value("${cloudinary.api-secret}")
|
| 23 |
-
private String apiSecret;
|
| 24 |
-
|
| 25 |
-
/**
|
| 26 |
-
* Creates and configures a Cloudinary bean.
|
| 27 |
-
* @return Configured Cloudinary instance
|
| 28 |
-
*/
|
| 29 |
-
@Bean
|
| 30 |
-
public Cloudinary cloudinary() {
|
| 31 |
-
return new Cloudinary(ObjectUtils.asMap(
|
| 32 |
-
"cloud_name", cloudName,
|
| 33 |
-
"api_key", apiKey,
|
| 34 |
-
"api_secret", apiSecret,
|
| 35 |
-
"secure", true
|
| 36 |
-
));
|
| 37 |
-
}
|
| 38 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/config/CorsConfig.java
DELETED
|
@@ -1,63 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.config;
|
| 2 |
-
|
| 3 |
-
import org.springframework.context.annotation.Bean;
|
| 4 |
-
import org.springframework.context.annotation.Configuration;
|
| 5 |
-
import org.springframework.web.cors.CorsConfiguration;
|
| 6 |
-
import org.springframework.web.cors.CorsConfigurationSource;
|
| 7 |
-
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
| 8 |
-
|
| 9 |
-
import java.util.Arrays;
|
| 10 |
-
import java.util.List;
|
| 11 |
-
|
| 12 |
-
/**
|
| 13 |
-
* CORS (Cross-Origin Resource Sharing) configuration for the LocalLend application.
|
| 14 |
-
* Enables the frontend to communicate with the backend from different origins.
|
| 15 |
-
*/
|
| 16 |
-
@Configuration
|
| 17 |
-
public class CorsConfig {
|
| 18 |
-
|
| 19 |
-
/**
|
| 20 |
-
* CORS configuration source that defines allowed origins, methods, and headers.
|
| 21 |
-
* This enables the React frontend (localhost:5173) to communicate with the backend (localhost:8080).
|
| 22 |
-
*
|
| 23 |
-
* @return CorsConfigurationSource with appropriate CORS settings
|
| 24 |
-
*/
|
| 25 |
-
@Bean
|
| 26 |
-
public CorsConfigurationSource corsConfigurationSource() {
|
| 27 |
-
CorsConfiguration configuration = new CorsConfiguration();
|
| 28 |
-
|
| 29 |
-
// Allow requests from frontend origins
|
| 30 |
-
configuration.setAllowedOriginPatterns(Arrays.asList(
|
| 31 |
-
"http://localhost", // Production (Nginx on port 80)
|
| 32 |
-
"http://localhost:80", // Production (explicit port 80)
|
| 33 |
-
"http://localhost:3000", // Create React App default
|
| 34 |
-
"http://localhost:5173", // Vite default port
|
| 35 |
-
"http://127.0.0.1", // Production (alternative localhost)
|
| 36 |
-
"http://127.0.0.1:80", // Production (alternative localhost port 80)
|
| 37 |
-
"http://127.0.0.1:3000", // Alternative localhost
|
| 38 |
-
"http://127.0.0.1:5173", // Alternative localhost
|
| 39 |
-
"https://*.hf.space", // Hugging Face Spaces
|
| 40 |
-
"https://*.huggingface.co" // Hugging Face domain
|
| 41 |
-
));
|
| 42 |
-
|
| 43 |
-
// Allow specific HTTP methods
|
| 44 |
-
configuration.setAllowedMethods(Arrays.asList(
|
| 45 |
-
"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"
|
| 46 |
-
));
|
| 47 |
-
|
| 48 |
-
// Allow all headers (including custom headers like Authorization)
|
| 49 |
-
configuration.setAllowedHeaders(List.of("*"));
|
| 50 |
-
|
| 51 |
-
// Allow credentials (cookies, authorization headers, etc.)
|
| 52 |
-
configuration.setAllowCredentials(true);
|
| 53 |
-
|
| 54 |
-
// Cache preflight requests for 1 hour
|
| 55 |
-
configuration.setMaxAge(3600L);
|
| 56 |
-
|
| 57 |
-
// Apply this configuration to all endpoints
|
| 58 |
-
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
| 59 |
-
source.registerCorsConfiguration("/**", configuration);
|
| 60 |
-
|
| 61 |
-
return source;
|
| 62 |
-
}
|
| 63 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/config/MongoTextIndexInitializer.java
DELETED
|
@@ -1,41 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.config;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.model.Category;
|
| 4 |
-
import org.slf4j.Logger;
|
| 5 |
-
import org.slf4j.LoggerFactory;
|
| 6 |
-
import org.springframework.boot.ApplicationArguments;
|
| 7 |
-
import org.springframework.boot.ApplicationRunner;
|
| 8 |
-
import org.springframework.context.annotation.Profile;
|
| 9 |
-
import org.springframework.data.mongodb.core.MongoTemplate;
|
| 10 |
-
import org.springframework.data.mongodb.core.index.TextIndexDefinition;
|
| 11 |
-
import org.springframework.stereotype.Component;
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
/**
|
| 15 |
-
* Ensures required MongoDB text indexes exist at startup so that search endpoints work
|
| 16 |
-
* on a freshly created database without manual intervention.
|
| 17 |
-
*/
|
| 18 |
-
@Component
|
| 19 |
-
@Profile("prod") // limit to prod profile used in docker-compose
|
| 20 |
-
public class MongoTextIndexInitializer implements ApplicationRunner {
|
| 21 |
-
private static final Logger log = LoggerFactory.getLogger(MongoTextIndexInitializer.class);
|
| 22 |
-
private final MongoTemplate mongoTemplate;
|
| 23 |
-
|
| 24 |
-
public MongoTextIndexInitializer(MongoTemplate mongoTemplate) {
|
| 25 |
-
this.mongoTemplate = mongoTemplate;
|
| 26 |
-
}
|
| 27 |
-
|
| 28 |
-
@Override
|
| 29 |
-
public void run(ApplicationArguments args) {
|
| 30 |
-
ensureCategoryTextIndex();
|
| 31 |
-
}
|
| 32 |
-
|
| 33 |
-
private void ensureCategoryTextIndex() {
|
| 34 |
-
TextIndexDefinition def = new TextIndexDefinition.TextIndexDefinitionBuilder()
|
| 35 |
-
.onField("name")
|
| 36 |
-
.onField("description")
|
| 37 |
-
.build();
|
| 38 |
-
String indexName = mongoTemplate.indexOps(Category.class).createIndex(def);
|
| 39 |
-
log.info("[MongoIndex] Ensured Category text index (name='{}') on fields: name, description", indexName);
|
| 40 |
-
}
|
| 41 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/config/SecurityConfig.java
DELETED
|
@@ -1,97 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.config;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.security.JwtAuthenticationFilter;
|
| 4 |
-
import com.locallend.locallend.security.JwtTokenProvider;
|
| 5 |
-
import com.locallend.locallend.security.MongoUserDetailsService;
|
| 6 |
-
import org.springframework.context.annotation.Bean;
|
| 7 |
-
import org.springframework.context.annotation.Configuration;
|
| 8 |
-
import org.springframework.http.HttpMethod;
|
| 9 |
-
import org.springframework.security.authentication.AuthenticationManager;
|
| 10 |
-
import org.springframework.security.config.Customizer;
|
| 11 |
-
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
| 12 |
-
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
| 13 |
-
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
| 14 |
-
import org.springframework.security.config.http.SessionCreationPolicy;
|
| 15 |
-
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
| 16 |
-
import org.springframework.security.crypto.password.PasswordEncoder;
|
| 17 |
-
import org.springframework.security.web.SecurityFilterChain;
|
| 18 |
-
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
| 19 |
-
|
| 20 |
-
/**
|
| 21 |
-
* Spring Security configuration with JWT authentication.
|
| 22 |
-
* Protects endpoints while allowing public access to auth endpoints.
|
| 23 |
-
*/
|
| 24 |
-
@Configuration
|
| 25 |
-
public class SecurityConfig {
|
| 26 |
-
|
| 27 |
-
private final MongoUserDetailsService userDetailsService;
|
| 28 |
-
private final JwtTokenProvider jwtTokenProvider;
|
| 29 |
-
|
| 30 |
-
public SecurityConfig(MongoUserDetailsService userDetailsService,
|
| 31 |
-
JwtTokenProvider jwtTokenProvider) {
|
| 32 |
-
this.userDetailsService = userDetailsService;
|
| 33 |
-
this.jwtTokenProvider = jwtTokenProvider;
|
| 34 |
-
}
|
| 35 |
-
|
| 36 |
-
/**
|
| 37 |
-
* Password encoder bean using BCrypt.
|
| 38 |
-
* @return BCryptPasswordEncoder instance
|
| 39 |
-
*/
|
| 40 |
-
@Bean
|
| 41 |
-
public PasswordEncoder passwordEncoder() {
|
| 42 |
-
return new BCryptPasswordEncoder();
|
| 43 |
-
}
|
| 44 |
-
|
| 45 |
-
/**
|
| 46 |
-
* Authentication manager bean for manual authentication.
|
| 47 |
-
* @param config Authentication configuration
|
| 48 |
-
* @return AuthenticationManager
|
| 49 |
-
* @throws Exception if configuration fails
|
| 50 |
-
*/
|
| 51 |
-
@Bean
|
| 52 |
-
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
|
| 53 |
-
return config.getAuthenticationManager();
|
| 54 |
-
}
|
| 55 |
-
|
| 56 |
-
/**
|
| 57 |
-
* JWT authentication filter bean.
|
| 58 |
-
* @return JwtAuthenticationFilter instance
|
| 59 |
-
*/
|
| 60 |
-
@Bean
|
| 61 |
-
public JwtAuthenticationFilter jwtAuthenticationFilter() {
|
| 62 |
-
return new JwtAuthenticationFilter(jwtTokenProvider, userDetailsService);
|
| 63 |
-
}
|
| 64 |
-
|
| 65 |
-
/**
|
| 66 |
-
* Security filter chain configuration.
|
| 67 |
-
* Defines endpoint protection rules and integrates JWT filter.
|
| 68 |
-
* @param http HttpSecurity
|
| 69 |
-
* @return SecurityFilterChain
|
| 70 |
-
* @throws Exception if configuration fails
|
| 71 |
-
*/
|
| 72 |
-
@Bean
|
| 73 |
-
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
| 74 |
-
http
|
| 75 |
-
.csrf(AbstractHttpConfigurer::disable)
|
| 76 |
-
.cors(Customizer.withDefaults())
|
| 77 |
-
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
| 78 |
-
.authorizeHttpRequests(auth -> auth
|
| 79 |
-
// Public endpoints - no authentication required
|
| 80 |
-
.requestMatchers(HttpMethod.POST, "/api/auth/register").permitAll()
|
| 81 |
-
.requestMatchers(HttpMethod.POST, "/api/auth/login").permitAll()
|
| 82 |
-
|
| 83 |
-
// Public category and item browsing
|
| 84 |
-
.requestMatchers(HttpMethod.GET, "/api/categories/**").permitAll()
|
| 85 |
-
.requestMatchers(HttpMethod.GET, "/api/items/**").permitAll()
|
| 86 |
-
.requestMatchers(HttpMethod.GET, "/api/users/*/public").permitAll()
|
| 87 |
-
.requestMatchers(HttpMethod.GET, "/api/users/search").permitAll()
|
| 88 |
-
|
| 89 |
-
// All other endpoints require authentication
|
| 90 |
-
.anyRequest().authenticated()
|
| 91 |
-
)
|
| 92 |
-
// Add JWT filter before Spring Security's authentication filter
|
| 93 |
-
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
|
| 94 |
-
|
| 95 |
-
return http.build();
|
| 96 |
-
}
|
| 97 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/config/ValidationConfig.java
DELETED
|
@@ -1,36 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.config;
|
| 2 |
-
|
| 3 |
-
import org.springframework.context.annotation.Bean;
|
| 4 |
-
import org.springframework.context.annotation.Configuration;
|
| 5 |
-
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
| 6 |
-
|
| 7 |
-
import jakarta.validation.Validator;
|
| 8 |
-
|
| 9 |
-
/**
|
| 10 |
-
* Configuration for Jakarta Bean Validation (JSR-380).
|
| 11 |
-
* Ensures validation annotations on entities and DTOs are processed.
|
| 12 |
-
* Issue #29: Production-ready validation support
|
| 13 |
-
*/
|
| 14 |
-
@Configuration
|
| 15 |
-
public class ValidationConfig {
|
| 16 |
-
|
| 17 |
-
/**
|
| 18 |
-
* Configure validator factory bean.
|
| 19 |
-
* Enables @Valid, @NotBlank, @Size, @Email, @Pattern, etc. annotations
|
| 20 |
-
* @return LocalValidatorFactoryBean instance
|
| 21 |
-
*/
|
| 22 |
-
@Bean
|
| 23 |
-
public LocalValidatorFactoryBean validator() {
|
| 24 |
-
return new LocalValidatorFactoryBean();
|
| 25 |
-
}
|
| 26 |
-
|
| 27 |
-
/**
|
| 28 |
-
* Provide Validator bean for programmatic validation.
|
| 29 |
-
* Can be injected into services for manual validation if needed.
|
| 30 |
-
* @return Validator instance
|
| 31 |
-
*/
|
| 32 |
-
@Bean
|
| 33 |
-
public Validator validatorBean() {
|
| 34 |
-
return validator();
|
| 35 |
-
}
|
| 36 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/controller/AuthController.java
DELETED
|
@@ -1,64 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.controller;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.dto.request.UserLoginDto;
|
| 4 |
-
import com.locallend.locallend.dto.request.UserRegistrationDto;
|
| 5 |
-
import com.locallend.locallend.dto.response.JwtAuthResponseDto;
|
| 6 |
-
import com.locallend.locallend.dto.response.UserResponseDto;
|
| 7 |
-
import com.locallend.locallend.model.User;
|
| 8 |
-
import com.locallend.locallend.security.JwtTokenProvider;
|
| 9 |
-
import com.locallend.locallend.service.UserService;
|
| 10 |
-
import com.locallend.locallend.util.UserMapper;
|
| 11 |
-
import jakarta.validation.Valid;
|
| 12 |
-
import org.springframework.beans.factory.annotation.Autowired;
|
| 13 |
-
import org.springframework.http.HttpStatus;
|
| 14 |
-
import org.springframework.http.ResponseEntity;
|
| 15 |
-
import org.springframework.web.bind.annotation.*;
|
| 16 |
-
|
| 17 |
-
/**
|
| 18 |
-
* REST controller for authentication operations.
|
| 19 |
-
* Handles user registration and login with JWT token generation.
|
| 20 |
-
*/
|
| 21 |
-
@RestController
|
| 22 |
-
@RequestMapping("/api/auth")
|
| 23 |
-
public class AuthController {
|
| 24 |
-
|
| 25 |
-
@Autowired
|
| 26 |
-
private UserService userService;
|
| 27 |
-
|
| 28 |
-
@Autowired
|
| 29 |
-
private UserMapper userMapper;
|
| 30 |
-
|
| 31 |
-
@Autowired
|
| 32 |
-
private JwtTokenProvider jwtTokenProvider;
|
| 33 |
-
|
| 34 |
-
/**
|
| 35 |
-
* Register a new user.
|
| 36 |
-
* @param dto User registration data
|
| 37 |
-
* @return Created user response DTO
|
| 38 |
-
*/
|
| 39 |
-
@PostMapping("/register")
|
| 40 |
-
public ResponseEntity<UserResponseDto> register(@Valid @RequestBody UserRegistrationDto dto) {
|
| 41 |
-
User user = userService.registerUser(dto);
|
| 42 |
-
UserResponseDto response = userMapper.toUserResponseDto(user);
|
| 43 |
-
return ResponseEntity.status(HttpStatus.CREATED).body(response);
|
| 44 |
-
}
|
| 45 |
-
|
| 46 |
-
/**
|
| 47 |
-
* Authenticate user and login with JWT token.
|
| 48 |
-
* @param dto Login credentials (username/email and password)
|
| 49 |
-
* @return JWT token and user information
|
| 50 |
-
*/
|
| 51 |
-
@PostMapping("/login")
|
| 52 |
-
public ResponseEntity<JwtAuthResponseDto> login(@Valid @RequestBody UserLoginDto dto) {
|
| 53 |
-
User user = userService.verifyCredentials(dto.getUsernameOrEmail(), dto.getPassword());
|
| 54 |
-
|
| 55 |
-
// Generate JWT token
|
| 56 |
-
String token = jwtTokenProvider.generateToken(user.getUsername());
|
| 57 |
-
|
| 58 |
-
// Prepare response with token and user data
|
| 59 |
-
UserResponseDto userResponse = userMapper.toUserResponseDto(user);
|
| 60 |
-
JwtAuthResponseDto response = new JwtAuthResponseDto(token, userResponse);
|
| 61 |
-
|
| 62 |
-
return ResponseEntity.ok(response);
|
| 63 |
-
}
|
| 64 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/controller/BookingController.java
DELETED
|
@@ -1,261 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.controller;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.dto.request.BookingRequestDto;
|
| 4 |
-
import com.locallend.locallend.dto.response.BookingResponseDto;
|
| 5 |
-
import com.locallend.locallend.exception.BookingConflictException;
|
| 6 |
-
import com.locallend.locallend.exception.BookingNotFoundException;
|
| 7 |
-
import com.locallend.locallend.exception.InvalidBookingPeriodException;
|
| 8 |
-
import com.locallend.locallend.service.BookingService;
|
| 9 |
-
import jakarta.validation.Valid;
|
| 10 |
-
import org.springframework.http.HttpStatus;
|
| 11 |
-
import org.springframework.http.ResponseEntity;
|
| 12 |
-
import org.springframework.web.bind.annotation.*;
|
| 13 |
-
|
| 14 |
-
import java.util.HashMap;
|
| 15 |
-
import java.util.List;
|
| 16 |
-
import java.util.Map;
|
| 17 |
-
|
| 18 |
-
@RestController
|
| 19 |
-
@RequestMapping("/api/bookings")
|
| 20 |
-
@CrossOrigin(origins = "*", maxAge = 3600)
|
| 21 |
-
public class BookingController {
|
| 22 |
-
|
| 23 |
-
private final BookingService bookingService;
|
| 24 |
-
|
| 25 |
-
public BookingController(BookingService bookingService) {
|
| 26 |
-
this.bookingService = bookingService;
|
| 27 |
-
}
|
| 28 |
-
|
| 29 |
-
@PostMapping
|
| 30 |
-
public ResponseEntity<?> createBooking(@Valid @RequestBody BookingRequestDto request,
|
| 31 |
-
@RequestHeader("X-User-Id") String borrowerId) {
|
| 32 |
-
try {
|
| 33 |
-
BookingResponseDto dto = bookingService.createBooking(request, borrowerId);
|
| 34 |
-
return ResponseEntity.status(HttpStatus.CREATED).body(dto);
|
| 35 |
-
} catch (BookingConflictException e) {
|
| 36 |
-
return error(HttpStatus.CONFLICT, "Booking conflict", e.getMessage(), "BOOKING_CONFLICT");
|
| 37 |
-
} catch (InvalidBookingPeriodException e) {
|
| 38 |
-
return error(HttpStatus.BAD_REQUEST, "Invalid booking period", e.getMessage(), "INVALID_PERIOD");
|
| 39 |
-
} catch (IllegalArgumentException | IllegalStateException e) {
|
| 40 |
-
return error(HttpStatus.BAD_REQUEST, "Booking creation failed", e.getMessage(), "BOOKING_CREATE_ERROR");
|
| 41 |
-
} catch (Exception e) {
|
| 42 |
-
return error(HttpStatus.INTERNAL_SERVER_ERROR, "Unexpected error", e.getMessage(), "INTERNAL_ERROR");
|
| 43 |
-
}
|
| 44 |
-
}
|
| 45 |
-
|
| 46 |
-
@GetMapping("/{id}")
|
| 47 |
-
public ResponseEntity<?> getBooking(@PathVariable String id) {
|
| 48 |
-
try {
|
| 49 |
-
BookingResponseDto dto = bookingService.getBookingById(id);
|
| 50 |
-
return ResponseEntity.ok(dto);
|
| 51 |
-
} catch (BookingNotFoundException e) {
|
| 52 |
-
return error(HttpStatus.NOT_FOUND, "Booking not found", e.getMessage(), "BOOKING_NOT_FOUND");
|
| 53 |
-
}
|
| 54 |
-
}
|
| 55 |
-
|
| 56 |
-
/**
|
| 57 |
-
* Get borrower's bookings (Issue #15 naming)
|
| 58 |
-
*/
|
| 59 |
-
@GetMapping("/my-bookings")
|
| 60 |
-
public ResponseEntity<?> myBookings(@RequestHeader("X-User-Id") String userId) {
|
| 61 |
-
List<BookingResponseDto> list = bookingService.getBookingsForBorrower(userId);
|
| 62 |
-
return ResponseEntity.ok(list);
|
| 63 |
-
}
|
| 64 |
-
|
| 65 |
-
/**
|
| 66 |
-
* Get borrower's bookings (original endpoint)
|
| 67 |
-
*/
|
| 68 |
-
@GetMapping("/my")
|
| 69 |
-
public ResponseEntity<?> myBookingsOriginal(@RequestHeader("X-User-Id") String userId) {
|
| 70 |
-
List<BookingResponseDto> list = bookingService.getBookingsForBorrower(userId);
|
| 71 |
-
return ResponseEntity.ok(list);
|
| 72 |
-
}
|
| 73 |
-
|
| 74 |
-
/**
|
| 75 |
-
* Get pending approvals for owner (Issue #15 naming)
|
| 76 |
-
*/
|
| 77 |
-
@GetMapping("/pending-approvals")
|
| 78 |
-
public ResponseEntity<?> pendingApprovals(@RequestHeader("X-User-Id") String ownerId) {
|
| 79 |
-
try {
|
| 80 |
-
com.locallend.locallend.model.enums.BookingStatus pendingStatus =
|
| 81 |
-
com.locallend.locallend.model.enums.BookingStatus.PENDING;
|
| 82 |
-
List<BookingResponseDto> bookings = bookingService.getBookingsForOwner(ownerId);
|
| 83 |
-
// Filter for PENDING status
|
| 84 |
-
List<BookingResponseDto> pending = bookings.stream()
|
| 85 |
-
.filter(b -> b.getStatus() == pendingStatus)
|
| 86 |
-
.toList();
|
| 87 |
-
return ResponseEntity.ok(pending);
|
| 88 |
-
} catch (Exception e) {
|
| 89 |
-
return error(HttpStatus.INTERNAL_SERVER_ERROR, "Error fetching pending approvals", e.getMessage(), "FETCH_ERROR");
|
| 90 |
-
}
|
| 91 |
-
}
|
| 92 |
-
|
| 93 |
-
/**
|
| 94 |
-
* Get owner's bookings (original endpoint)
|
| 95 |
-
*/
|
| 96 |
-
@GetMapping("/my-owned")
|
| 97 |
-
public ResponseEntity<?> myOwnedBookings(@RequestHeader("X-User-Id") String ownerId) {
|
| 98 |
-
List<BookingResponseDto> list = bookingService.getBookingsForOwner(ownerId);
|
| 99 |
-
return ResponseEntity.ok(list);
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
/**
|
| 103 |
-
* Approve booking - Issue #15 naming (alias for confirm)
|
| 104 |
-
*/
|
| 105 |
-
@PatchMapping("/{id}/approve")
|
| 106 |
-
public ResponseEntity<?> approve(@PathVariable String id,
|
| 107 |
-
@RequestHeader("X-User-Id") String ownerId,
|
| 108 |
-
@RequestBody(required = false) Map<String, String> body) {
|
| 109 |
-
String notes = body != null ? body.get("ownerNotes") : null;
|
| 110 |
-
try {
|
| 111 |
-
BookingResponseDto dto = bookingService.confirm(id, ownerId, notes);
|
| 112 |
-
return ResponseEntity.ok(dto);
|
| 113 |
-
} catch (BookingNotFoundException e) {
|
| 114 |
-
return error(HttpStatus.NOT_FOUND, "Booking not found", e.getMessage(), "BOOKING_NOT_FOUND");
|
| 115 |
-
} catch (IllegalArgumentException | IllegalStateException e) {
|
| 116 |
-
return error(HttpStatus.BAD_REQUEST, "Cannot approve booking", e.getMessage(), "BOOKING_APPROVE_ERROR");
|
| 117 |
-
}
|
| 118 |
-
}
|
| 119 |
-
|
| 120 |
-
/**
|
| 121 |
-
* Confirm booking - original endpoint
|
| 122 |
-
*/
|
| 123 |
-
@PatchMapping("/{id}/confirm")
|
| 124 |
-
public ResponseEntity<?> confirm(@PathVariable String id,
|
| 125 |
-
@RequestHeader("X-User-Id") String ownerId,
|
| 126 |
-
@RequestBody(required = false) Map<String, String> body) {
|
| 127 |
-
String notes = body != null ? body.get("ownerNotes") : null;
|
| 128 |
-
try {
|
| 129 |
-
BookingResponseDto dto = bookingService.confirm(id, ownerId, notes);
|
| 130 |
-
return ResponseEntity.ok(dto);
|
| 131 |
-
} catch (BookingNotFoundException e) {
|
| 132 |
-
return error(HttpStatus.NOT_FOUND, "Booking not found", e.getMessage(), "BOOKING_NOT_FOUND");
|
| 133 |
-
} catch (IllegalArgumentException | IllegalStateException e) {
|
| 134 |
-
return error(HttpStatus.BAD_REQUEST, "Cannot confirm booking", e.getMessage(), "BOOKING_CONFIRM_ERROR");
|
| 135 |
-
}
|
| 136 |
-
}
|
| 137 |
-
|
| 138 |
-
/**
|
| 139 |
-
* Start booking - Issue #15 naming (alias for activate)
|
| 140 |
-
*/
|
| 141 |
-
@PatchMapping("/{id}/start")
|
| 142 |
-
public ResponseEntity<?> start(@PathVariable String id,
|
| 143 |
-
@RequestHeader("X-User-Id") String borrowerId) {
|
| 144 |
-
try {
|
| 145 |
-
BookingResponseDto dto = bookingService.activate(id, borrowerId);
|
| 146 |
-
return ResponseEntity.ok(dto);
|
| 147 |
-
} catch (BookingNotFoundException e) {
|
| 148 |
-
return error(HttpStatus.NOT_FOUND, "Booking not found", e.getMessage(), "BOOKING_NOT_FOUND");
|
| 149 |
-
} catch (IllegalArgumentException | IllegalStateException e) {
|
| 150 |
-
return error(HttpStatus.BAD_REQUEST, "Cannot start booking", e.getMessage(), "BOOKING_START_ERROR");
|
| 151 |
-
}
|
| 152 |
-
}
|
| 153 |
-
|
| 154 |
-
/**
|
| 155 |
-
* Activate booking - original endpoint
|
| 156 |
-
*/
|
| 157 |
-
@PatchMapping("/{id}/activate")
|
| 158 |
-
public ResponseEntity<?> activate(@PathVariable String id,
|
| 159 |
-
@RequestHeader("X-User-Id") String borrowerId) {
|
| 160 |
-
try {
|
| 161 |
-
BookingResponseDto dto = bookingService.activate(id, borrowerId);
|
| 162 |
-
return ResponseEntity.ok(dto);
|
| 163 |
-
} catch (BookingNotFoundException e) {
|
| 164 |
-
return error(HttpStatus.NOT_FOUND, "Booking not found", e.getMessage(), "BOOKING_NOT_FOUND");
|
| 165 |
-
} catch (IllegalArgumentException | IllegalStateException e) {
|
| 166 |
-
return error(HttpStatus.BAD_REQUEST, "Cannot activate booking", e.getMessage(), "BOOKING_ACTIVATE_ERROR");
|
| 167 |
-
}
|
| 168 |
-
}
|
| 169 |
-
|
| 170 |
-
@PatchMapping("/{id}/complete")
|
| 171 |
-
public ResponseEntity<?> complete(@PathVariable String id,
|
| 172 |
-
@RequestHeader("X-User-Id") String borrowerId) {
|
| 173 |
-
try {
|
| 174 |
-
BookingResponseDto dto = bookingService.complete(id, borrowerId);
|
| 175 |
-
return ResponseEntity.ok(dto);
|
| 176 |
-
} catch (BookingNotFoundException e) {
|
| 177 |
-
return error(HttpStatus.NOT_FOUND, "Booking not found", e.getMessage(), "BOOKING_NOT_FOUND");
|
| 178 |
-
} catch (IllegalArgumentException | IllegalStateException e) {
|
| 179 |
-
return error(HttpStatus.BAD_REQUEST, "Cannot complete booking", e.getMessage(), "BOOKING_COMPLETE_ERROR");
|
| 180 |
-
}
|
| 181 |
-
}
|
| 182 |
-
|
| 183 |
-
@PatchMapping("/{id}/cancel")
|
| 184 |
-
public ResponseEntity<?> cancel(@PathVariable String id,
|
| 185 |
-
@RequestHeader("X-User-Id") String borrowerId,
|
| 186 |
-
@RequestBody(required = false) Map<String, String> body) {
|
| 187 |
-
String reason = body != null ? body.get("reason") : null;
|
| 188 |
-
try {
|
| 189 |
-
BookingResponseDto dto = bookingService.cancel(id, borrowerId, reason);
|
| 190 |
-
return ResponseEntity.ok(dto);
|
| 191 |
-
} catch (BookingNotFoundException e) {
|
| 192 |
-
return error(HttpStatus.NOT_FOUND, "Booking not found", e.getMessage(), "BOOKING_NOT_FOUND");
|
| 193 |
-
} catch (IllegalArgumentException | IllegalStateException e) {
|
| 194 |
-
return error(HttpStatus.BAD_REQUEST, "Cannot cancel booking", e.getMessage(), "BOOKING_CANCEL_ERROR");
|
| 195 |
-
}
|
| 196 |
-
}
|
| 197 |
-
|
| 198 |
-
@PatchMapping("/{id}/reject")
|
| 199 |
-
public ResponseEntity<?> reject(@PathVariable String id,
|
| 200 |
-
@RequestHeader("X-User-Id") String ownerId,
|
| 201 |
-
@RequestBody(required = false) Map<String, String> body) {
|
| 202 |
-
String reason = body != null ? body.get("reason") : null;
|
| 203 |
-
try {
|
| 204 |
-
BookingResponseDto dto = bookingService.reject(id, ownerId, reason);
|
| 205 |
-
return ResponseEntity.ok(dto);
|
| 206 |
-
} catch (BookingNotFoundException e) {
|
| 207 |
-
return error(HttpStatus.NOT_FOUND, "Booking not found", e.getMessage(), "BOOKING_NOT_FOUND");
|
| 208 |
-
} catch (IllegalArgumentException | IllegalStateException e) {
|
| 209 |
-
return error(HttpStatus.BAD_REQUEST, "Cannot reject booking", e.getMessage(), "BOOKING_REJECT_ERROR");
|
| 210 |
-
}
|
| 211 |
-
}
|
| 212 |
-
|
| 213 |
-
@GetMapping("/active")
|
| 214 |
-
public ResponseEntity<?> activeBookings() {
|
| 215 |
-
return ResponseEntity.ok(bookingService.getActiveBookings());
|
| 216 |
-
}
|
| 217 |
-
|
| 218 |
-
@GetMapping("/overdue")
|
| 219 |
-
public ResponseEntity<?> overdueBookings() {
|
| 220 |
-
return ResponseEntity.ok(bookingService.getOverdueBookings());
|
| 221 |
-
}
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
@GetMapping("/by-status")
|
| 226 |
-
public ResponseEntity<?> bookingsByStatus(@RequestParam String status,
|
| 227 |
-
@RequestHeader("X-User-Id") String userId) {
|
| 228 |
-
try {
|
| 229 |
-
com.locallend.locallend.model.enums.BookingStatus bookingStatus =
|
| 230 |
-
com.locallend.locallend.model.enums.BookingStatus.fromString(status);
|
| 231 |
-
List<BookingResponseDto> bookings = bookingService.getBookingsByStatus(bookingStatus, userId);
|
| 232 |
-
return ResponseEntity.ok(bookings);
|
| 233 |
-
} catch (IllegalArgumentException e) {
|
| 234 |
-
return error(HttpStatus.BAD_REQUEST, "Invalid status", e.getMessage(), "INVALID_STATUS");
|
| 235 |
-
}
|
| 236 |
-
}
|
| 237 |
-
|
| 238 |
-
@GetMapping("/item/{itemId}/active")
|
| 239 |
-
public ResponseEntity<?> activeBookingsForItem(@PathVariable String itemId) {
|
| 240 |
-
return ResponseEntity.ok(bookingService.getActiveBookingsForItem(itemId));
|
| 241 |
-
}
|
| 242 |
-
|
| 243 |
-
@PostMapping("/process-overdue")
|
| 244 |
-
public ResponseEntity<?> processOverdue() {
|
| 245 |
-
int count = bookingService.processOverdueBookings();
|
| 246 |
-
Map<String, Object> resp = new HashMap<>();
|
| 247 |
-
resp.put("success", true);
|
| 248 |
-
resp.put("message", "Processed overdue bookings");
|
| 249 |
-
resp.put("count", count);
|
| 250 |
-
return ResponseEntity.ok(resp);
|
| 251 |
-
}
|
| 252 |
-
|
| 253 |
-
private ResponseEntity<Map<String, Object>> error(HttpStatus status, String message, String details, String code) {
|
| 254 |
-
Map<String, Object> resp = new HashMap<>();
|
| 255 |
-
resp.put("success", false);
|
| 256 |
-
resp.put("message", message);
|
| 257 |
-
resp.put("details", details);
|
| 258 |
-
resp.put("error_code", code);
|
| 259 |
-
return ResponseEntity.status(status).body(resp);
|
| 260 |
-
}
|
| 261 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/controller/CategoryController.java
DELETED
|
@@ -1,287 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.controller;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.dto.CategoryDto;
|
| 4 |
-
import com.locallend.locallend.dto.CreateCategoryRequest;
|
| 5 |
-
import com.locallend.locallend.exception.CategoryNotFoundException;
|
| 6 |
-
import com.locallend.locallend.service.CategoryService;
|
| 7 |
-
|
| 8 |
-
import org.slf4j.Logger;
|
| 9 |
-
import org.slf4j.LoggerFactory;
|
| 10 |
-
import org.springframework.http.HttpStatus;
|
| 11 |
-
import org.springframework.http.ResponseEntity;
|
| 12 |
-
import org.springframework.web.bind.annotation.*;
|
| 13 |
-
import org.springframework.validation.annotation.Validated;
|
| 14 |
-
|
| 15 |
-
import jakarta.validation.Valid;
|
| 16 |
-
import jakarta.validation.constraints.NotBlank;
|
| 17 |
-
import java.util.HashMap;
|
| 18 |
-
import java.util.List;
|
| 19 |
-
import java.util.Map;
|
| 20 |
-
|
| 21 |
-
@RestController
|
| 22 |
-
@RequestMapping("/api/categories")
|
| 23 |
-
@Validated
|
| 24 |
-
@CrossOrigin(origins = "*", maxAge = 3600)
|
| 25 |
-
public class CategoryController {
|
| 26 |
-
|
| 27 |
-
private static final Logger logger = LoggerFactory.getLogger(CategoryController.class);
|
| 28 |
-
|
| 29 |
-
private final CategoryService categoryService;
|
| 30 |
-
|
| 31 |
-
public CategoryController(CategoryService categoryService) {
|
| 32 |
-
this.categoryService = categoryService;
|
| 33 |
-
}
|
| 34 |
-
|
| 35 |
-
@PostMapping
|
| 36 |
-
public ResponseEntity<?> createCategory(@Valid @RequestBody CreateCategoryRequest request) {
|
| 37 |
-
logger.info("Request to create category: {}", request.getName());
|
| 38 |
-
|
| 39 |
-
try {
|
| 40 |
-
CategoryDto createdCategory = categoryService.createCategory(request);
|
| 41 |
-
|
| 42 |
-
Map<String, Object> response = new HashMap<>();
|
| 43 |
-
response.put("success", true);
|
| 44 |
-
response.put("message", "Category created successfully");
|
| 45 |
-
response.put("data", createdCategory);
|
| 46 |
-
|
| 47 |
-
return ResponseEntity.status(HttpStatus.CREATED).body(response);
|
| 48 |
-
|
| 49 |
-
} catch (IllegalArgumentException e) {
|
| 50 |
-
logger.error("Invalid category creation request: {}", e.getMessage());
|
| 51 |
-
|
| 52 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 53 |
-
errorResponse.put("success", false);
|
| 54 |
-
errorResponse.put("message", e.getMessage());
|
| 55 |
-
errorResponse.put("error_code", "CATEGORY_ALREADY_EXISTS");
|
| 56 |
-
|
| 57 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
|
| 58 |
-
|
| 59 |
-
} catch (CategoryNotFoundException e) {
|
| 60 |
-
logger.error("Parent category not found: {}", e.getMessage());
|
| 61 |
-
|
| 62 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 63 |
-
errorResponse.put("success", false);
|
| 64 |
-
errorResponse.put("message", "Parent category not found");
|
| 65 |
-
errorResponse.put("error_code", "PARENT_CATEGORY_NOT_FOUND");
|
| 66 |
-
|
| 67 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
|
| 68 |
-
}
|
| 69 |
-
}
|
| 70 |
-
|
| 71 |
-
@GetMapping
|
| 72 |
-
public ResponseEntity<?> getAllCategories(
|
| 73 |
-
@RequestParam(value = "sort", defaultValue = "name") String sortBy) {
|
| 74 |
-
logger.info("Request to get all categories with sort: {}", sortBy);
|
| 75 |
-
|
| 76 |
-
try {
|
| 77 |
-
List<CategoryDto> categories = categoryService.getAllCategories(sortBy);
|
| 78 |
-
|
| 79 |
-
Map<String, Object> response = new HashMap<>();
|
| 80 |
-
response.put("success", true);
|
| 81 |
-
response.put("message", "Categories retrieved successfully");
|
| 82 |
-
response.put("data", categories);
|
| 83 |
-
response.put("count", categories.size());
|
| 84 |
-
|
| 85 |
-
return ResponseEntity.ok(response);
|
| 86 |
-
|
| 87 |
-
} catch (Exception e) {
|
| 88 |
-
logger.error("Error retrieving categories: {}", e.getMessage());
|
| 89 |
-
|
| 90 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 91 |
-
errorResponse.put("success", false);
|
| 92 |
-
errorResponse.put("message", "Error retrieving categories");
|
| 93 |
-
errorResponse.put("error_code", "INTERNAL_ERROR");
|
| 94 |
-
|
| 95 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 96 |
-
}
|
| 97 |
-
}
|
| 98 |
-
|
| 99 |
-
@GetMapping("/{categoryId}")
|
| 100 |
-
public ResponseEntity<?> getCategoryById(
|
| 101 |
-
@PathVariable @NotBlank(message = "Category ID is required") String categoryId) {
|
| 102 |
-
logger.info("Request to get category by ID: {}", categoryId);
|
| 103 |
-
|
| 104 |
-
try {
|
| 105 |
-
CategoryDto category = categoryService.getCategoryById(categoryId);
|
| 106 |
-
|
| 107 |
-
Map<String, Object> response = new HashMap<>();
|
| 108 |
-
response.put("success", true);
|
| 109 |
-
response.put("message", "Category retrieved successfully");
|
| 110 |
-
response.put("data", category);
|
| 111 |
-
|
| 112 |
-
return ResponseEntity.ok(response);
|
| 113 |
-
|
| 114 |
-
} catch (CategoryNotFoundException e) {
|
| 115 |
-
logger.error("Category not found: {}", e.getMessage());
|
| 116 |
-
|
| 117 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 118 |
-
errorResponse.put("success", false);
|
| 119 |
-
errorResponse.put("message", e.getMessage());
|
| 120 |
-
errorResponse.put("error_code", "CATEGORY_NOT_FOUND");
|
| 121 |
-
|
| 122 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
|
| 123 |
-
}
|
| 124 |
-
}
|
| 125 |
-
|
| 126 |
-
@GetMapping("/root")
|
| 127 |
-
public ResponseEntity<?> getRootCategories(
|
| 128 |
-
@RequestParam(value = "sort", defaultValue = "name") String sortBy) {
|
| 129 |
-
logger.info("Request to get root categories with sort: {}", sortBy);
|
| 130 |
-
|
| 131 |
-
try {
|
| 132 |
-
List<CategoryDto> rootCategories = categoryService.getRootCategories(sortBy);
|
| 133 |
-
|
| 134 |
-
Map<String, Object> response = new HashMap<>();
|
| 135 |
-
response.put("success", true);
|
| 136 |
-
response.put("message", "Root categories retrieved successfully");
|
| 137 |
-
response.put("data", rootCategories);
|
| 138 |
-
response.put("count", rootCategories.size());
|
| 139 |
-
|
| 140 |
-
return ResponseEntity.ok(response);
|
| 141 |
-
|
| 142 |
-
} catch (Exception e) {
|
| 143 |
-
logger.error("Error retrieving root categories: {}", e.getMessage());
|
| 144 |
-
|
| 145 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 146 |
-
errorResponse.put("success", false);
|
| 147 |
-
errorResponse.put("message", "Error retrieving root categories");
|
| 148 |
-
errorResponse.put("error_code", "INTERNAL_ERROR");
|
| 149 |
-
|
| 150 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 151 |
-
}
|
| 152 |
-
}
|
| 153 |
-
|
| 154 |
-
@GetMapping("/{parentId}/subcategories")
|
| 155 |
-
public ResponseEntity<?> getSubcategories(
|
| 156 |
-
@PathVariable @NotBlank(message = "Parent category ID is required") String parentId,
|
| 157 |
-
@RequestParam(value = "sort", defaultValue = "name") String sortBy) {
|
| 158 |
-
logger.info("Request to get subcategories for parent: {}", parentId);
|
| 159 |
-
|
| 160 |
-
try {
|
| 161 |
-
List<CategoryDto> subcategories = categoryService.getSubcategories(parentId, sortBy);
|
| 162 |
-
|
| 163 |
-
Map<String, Object> response = new HashMap<>();
|
| 164 |
-
response.put("success", true);
|
| 165 |
-
response.put("message", "Subcategories retrieved successfully");
|
| 166 |
-
response.put("data", subcategories);
|
| 167 |
-
response.put("count", subcategories.size());
|
| 168 |
-
response.put("parent_id", parentId);
|
| 169 |
-
|
| 170 |
-
return ResponseEntity.ok(response);
|
| 171 |
-
|
| 172 |
-
} catch (CategoryNotFoundException e) {
|
| 173 |
-
logger.error("Parent category not found: {}", e.getMessage());
|
| 174 |
-
|
| 175 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 176 |
-
errorResponse.put("success", false);
|
| 177 |
-
errorResponse.put("message", e.getMessage());
|
| 178 |
-
errorResponse.put("error_code", "PARENT_CATEGORY_NOT_FOUND");
|
| 179 |
-
|
| 180 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
|
| 181 |
-
}
|
| 182 |
-
}
|
| 183 |
-
|
| 184 |
-
@GetMapping("/search")
|
| 185 |
-
public ResponseEntity<?> searchCategories(
|
| 186 |
-
@RequestParam @NotBlank(message = "Search term is required") String q,
|
| 187 |
-
@RequestParam(value = "sort", defaultValue = "name") String sortBy) {
|
| 188 |
-
logger.info("Request to search categories with term: {}", q);
|
| 189 |
-
|
| 190 |
-
try {
|
| 191 |
-
List<CategoryDto> categories = categoryService.searchCategories(q, sortBy);
|
| 192 |
-
|
| 193 |
-
Map<String, Object> response = new HashMap<>();
|
| 194 |
-
response.put("success", true);
|
| 195 |
-
response.put("message", "Categories search completed successfully");
|
| 196 |
-
response.put("data", categories);
|
| 197 |
-
response.put("count", categories.size());
|
| 198 |
-
response.put("search_term", q);
|
| 199 |
-
|
| 200 |
-
return ResponseEntity.ok(response);
|
| 201 |
-
|
| 202 |
-
} catch (Exception e) {
|
| 203 |
-
logger.error("Error searching categories: {}", e.getMessage());
|
| 204 |
-
|
| 205 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 206 |
-
errorResponse.put("success", false);
|
| 207 |
-
errorResponse.put("message", "Error searching categories");
|
| 208 |
-
errorResponse.put("error_code", "SEARCH_ERROR");
|
| 209 |
-
|
| 210 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 211 |
-
}
|
| 212 |
-
}
|
| 213 |
-
|
| 214 |
-
@GetMapping("/popular")
|
| 215 |
-
public ResponseEntity<?> getPopularCategories(
|
| 216 |
-
@RequestParam(value = "min_items", defaultValue = "1") long minItems) {
|
| 217 |
-
logger.info("Request to get popular categories with minimum {} items", minItems);
|
| 218 |
-
|
| 219 |
-
try {
|
| 220 |
-
List<CategoryDto> popularCategories = categoryService.getPopularCategories(minItems);
|
| 221 |
-
|
| 222 |
-
Map<String, Object> response = new HashMap<>();
|
| 223 |
-
response.put("success", true);
|
| 224 |
-
response.put("message", "Popular categories retrieved successfully");
|
| 225 |
-
response.put("data", popularCategories);
|
| 226 |
-
response.put("count", popularCategories.size());
|
| 227 |
-
response.put("min_items", minItems);
|
| 228 |
-
|
| 229 |
-
return ResponseEntity.ok(response);
|
| 230 |
-
|
| 231 |
-
} catch (Exception e) {
|
| 232 |
-
logger.error("Error retrieving popular categories: {}", e.getMessage());
|
| 233 |
-
|
| 234 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 235 |
-
errorResponse.put("success", false);
|
| 236 |
-
errorResponse.put("message", "Error retrieving popular categories");
|
| 237 |
-
errorResponse.put("error_code", "INTERNAL_ERROR");
|
| 238 |
-
|
| 239 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 240 |
-
}
|
| 241 |
-
}
|
| 242 |
-
|
| 243 |
-
@PatchMapping("/{categoryId}/status")
|
| 244 |
-
public ResponseEntity<?> updateCategoryStatus(
|
| 245 |
-
@PathVariable @NotBlank(message = "Category ID is required") String categoryId,
|
| 246 |
-
@RequestParam boolean is_active) {
|
| 247 |
-
logger.info("Request to update category {} status to: {}", categoryId, is_active);
|
| 248 |
-
|
| 249 |
-
try {
|
| 250 |
-
CategoryDto updatedCategory = categoryService.updateCategoryStatus(categoryId, is_active);
|
| 251 |
-
|
| 252 |
-
Map<String, Object> response = new HashMap<>();
|
| 253 |
-
response.put("success", true);
|
| 254 |
-
response.put("message", "Category status updated successfully");
|
| 255 |
-
response.put("data", updatedCategory);
|
| 256 |
-
|
| 257 |
-
return ResponseEntity.ok(response);
|
| 258 |
-
|
| 259 |
-
} catch (CategoryNotFoundException e) {
|
| 260 |
-
logger.error("Category not found: {}", e.getMessage());
|
| 261 |
-
|
| 262 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 263 |
-
errorResponse.put("success", false);
|
| 264 |
-
errorResponse.put("message", e.getMessage());
|
| 265 |
-
errorResponse.put("error_code", "CATEGORY_NOT_FOUND");
|
| 266 |
-
|
| 267 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
|
| 268 |
-
}
|
| 269 |
-
}
|
| 270 |
-
|
| 271 |
-
@ExceptionHandler(org.springframework.web.bind.MethodArgumentNotValidException.class)
|
| 272 |
-
public ResponseEntity<?> handleValidationExceptions(
|
| 273 |
-
org.springframework.web.bind.MethodArgumentNotValidException ex) {
|
| 274 |
-
|
| 275 |
-
Map<String, String> errors = new HashMap<>();
|
| 276 |
-
ex.getBindingResult().getFieldErrors().forEach(error ->
|
| 277 |
-
errors.put(error.getField(), error.getDefaultMessage()));
|
| 278 |
-
|
| 279 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 280 |
-
errorResponse.put("success", false);
|
| 281 |
-
errorResponse.put("message", "Validation failed");
|
| 282 |
-
errorResponse.put("error_code", "VALIDATION_ERROR");
|
| 283 |
-
errorResponse.put("errors", errors);
|
| 284 |
-
|
| 285 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
|
| 286 |
-
}
|
| 287 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/controller/ImageController.java
DELETED
|
@@ -1,200 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.controller;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.service.ImageService;
|
| 4 |
-
import org.slf4j.Logger;
|
| 5 |
-
import org.slf4j.LoggerFactory;
|
| 6 |
-
import org.springframework.http.HttpStatus;
|
| 7 |
-
import org.springframework.http.ResponseEntity;
|
| 8 |
-
import org.springframework.web.bind.annotation.*;
|
| 9 |
-
import org.springframework.web.multipart.MultipartFile;
|
| 10 |
-
|
| 11 |
-
import java.util.HashMap;
|
| 12 |
-
import java.util.List;
|
| 13 |
-
import java.util.Map;
|
| 14 |
-
|
| 15 |
-
/**
|
| 16 |
-
* REST Controller for image upload operations.
|
| 17 |
-
* Handles file uploads to Cloudinary and image deletion.
|
| 18 |
-
*/
|
| 19 |
-
@RestController
|
| 20 |
-
@RequestMapping("/api/images")
|
| 21 |
-
@CrossOrigin(origins = "*", maxAge = 3600)
|
| 22 |
-
public class ImageController {
|
| 23 |
-
|
| 24 |
-
private static final Logger logger = LoggerFactory.getLogger(ImageController.class);
|
| 25 |
-
|
| 26 |
-
private final ImageService imageService;
|
| 27 |
-
|
| 28 |
-
public ImageController(ImageService imageService) {
|
| 29 |
-
this.imageService = imageService;
|
| 30 |
-
}
|
| 31 |
-
|
| 32 |
-
/**
|
| 33 |
-
* Upload a single image
|
| 34 |
-
* POST /api/images/upload
|
| 35 |
-
* @param file The image file to upload
|
| 36 |
-
* @param folder Optional folder name (defaults to "locallend/items")
|
| 37 |
-
* @return JSON response with image URL
|
| 38 |
-
*/
|
| 39 |
-
@PostMapping("/upload")
|
| 40 |
-
public ResponseEntity<?> uploadImage(
|
| 41 |
-
@RequestParam("file") MultipartFile file,
|
| 42 |
-
@RequestParam(value = "folder", defaultValue = "locallend/items") String folder) {
|
| 43 |
-
|
| 44 |
-
try {
|
| 45 |
-
logger.info("Received image upload request: {}", file.getOriginalFilename());
|
| 46 |
-
|
| 47 |
-
if (!imageService.isConfigured()) {
|
| 48 |
-
Map<String, String> error = new HashMap<>();
|
| 49 |
-
error.put("error", "Cloudinary not configured");
|
| 50 |
-
error.put("message", "Please configure Cloudinary credentials in application.properties");
|
| 51 |
-
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(error);
|
| 52 |
-
}
|
| 53 |
-
|
| 54 |
-
String imageUrl = imageService.uploadImage(file, folder);
|
| 55 |
-
|
| 56 |
-
Map<String, Object> response = new HashMap<>();
|
| 57 |
-
response.put("success", true);
|
| 58 |
-
response.put("message", "Image uploaded successfully");
|
| 59 |
-
response.put("url", imageUrl);
|
| 60 |
-
response.put("filename", file.getOriginalFilename());
|
| 61 |
-
|
| 62 |
-
return ResponseEntity.ok(response);
|
| 63 |
-
|
| 64 |
-
} catch (IllegalArgumentException e) {
|
| 65 |
-
logger.warn("Image validation failed: {}", e.getMessage());
|
| 66 |
-
Map<String, String> error = new HashMap<>();
|
| 67 |
-
error.put("error", "Validation failed");
|
| 68 |
-
error.put("message", e.getMessage());
|
| 69 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 70 |
-
|
| 71 |
-
} catch (Exception e) {
|
| 72 |
-
logger.error("Image upload failed", e);
|
| 73 |
-
Map<String, String> error = new HashMap<>();
|
| 74 |
-
error.put("error", "Upload failed");
|
| 75 |
-
error.put("message", "Failed to upload image: " + e.getMessage());
|
| 76 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
|
| 77 |
-
}
|
| 78 |
-
}
|
| 79 |
-
|
| 80 |
-
/**
|
| 81 |
-
* Upload multiple images
|
| 82 |
-
* POST /api/images/upload-multiple
|
| 83 |
-
* @param files Array of image files to upload
|
| 84 |
-
* @param folder Optional folder name (defaults to "locallend/items")
|
| 85 |
-
* @return JSON response with array of image URLs
|
| 86 |
-
*/
|
| 87 |
-
@PostMapping("/upload-multiple")
|
| 88 |
-
public ResponseEntity<?> uploadMultipleImages(
|
| 89 |
-
@RequestParam("files") MultipartFile[] files,
|
| 90 |
-
@RequestParam(value = "folder", defaultValue = "locallend/items") String folder) {
|
| 91 |
-
|
| 92 |
-
try {
|
| 93 |
-
logger.info("Received multiple image upload request: {} files", files.length);
|
| 94 |
-
|
| 95 |
-
if (!imageService.isConfigured()) {
|
| 96 |
-
Map<String, String> error = new HashMap<>();
|
| 97 |
-
error.put("error", "Cloudinary not configured");
|
| 98 |
-
error.put("message", "Please configure Cloudinary credentials in application.properties");
|
| 99 |
-
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(error);
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
if (files.length == 0) {
|
| 103 |
-
Map<String, String> error = new HashMap<>();
|
| 104 |
-
error.put("error", "No files provided");
|
| 105 |
-
error.put("message", "Please select at least one image to upload");
|
| 106 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 107 |
-
}
|
| 108 |
-
|
| 109 |
-
if (files.length > 10) {
|
| 110 |
-
Map<String, String> error = new HashMap<>();
|
| 111 |
-
error.put("error", "Too many files");
|
| 112 |
-
error.put("message", "Maximum 10 images can be uploaded at once");
|
| 113 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 114 |
-
}
|
| 115 |
-
|
| 116 |
-
List<String> imageUrls = imageService.uploadMultipleImages(files, folder);
|
| 117 |
-
|
| 118 |
-
Map<String, Object> response = new HashMap<>();
|
| 119 |
-
response.put("success", true);
|
| 120 |
-
response.put("message", "Images uploaded successfully");
|
| 121 |
-
response.put("urls", imageUrls);
|
| 122 |
-
response.put("count", imageUrls.size());
|
| 123 |
-
|
| 124 |
-
return ResponseEntity.ok(response);
|
| 125 |
-
|
| 126 |
-
} catch (IllegalArgumentException e) {
|
| 127 |
-
logger.warn("Image validation failed: {}", e.getMessage());
|
| 128 |
-
Map<String, String> error = new HashMap<>();
|
| 129 |
-
error.put("error", "Validation failed");
|
| 130 |
-
error.put("message", e.getMessage());
|
| 131 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 132 |
-
|
| 133 |
-
} catch (Exception e) {
|
| 134 |
-
logger.error("Multiple image upload failed", e);
|
| 135 |
-
Map<String, String> error = new HashMap<>();
|
| 136 |
-
error.put("error", "Upload failed");
|
| 137 |
-
error.put("message", "Failed to upload images: " + e.getMessage());
|
| 138 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
|
| 139 |
-
}
|
| 140 |
-
}
|
| 141 |
-
|
| 142 |
-
/**
|
| 143 |
-
* Delete an image from Cloudinary
|
| 144 |
-
* DELETE /api/images
|
| 145 |
-
* @param imageUrl The full Cloudinary URL of the image to delete
|
| 146 |
-
* @return Success or error response
|
| 147 |
-
*/
|
| 148 |
-
@DeleteMapping
|
| 149 |
-
public ResponseEntity<?> deleteImage(@RequestParam("url") String imageUrl) {
|
| 150 |
-
try {
|
| 151 |
-
logger.info("Received image deletion request: {}", imageUrl);
|
| 152 |
-
|
| 153 |
-
if (!imageService.isConfigured()) {
|
| 154 |
-
Map<String, String> error = new HashMap<>();
|
| 155 |
-
error.put("error", "Cloudinary not configured");
|
| 156 |
-
error.put("message", "Please configure Cloudinary credentials in application.properties");
|
| 157 |
-
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(error);
|
| 158 |
-
}
|
| 159 |
-
|
| 160 |
-
boolean deleted = imageService.deleteImage(imageUrl);
|
| 161 |
-
|
| 162 |
-
if (deleted) {
|
| 163 |
-
Map<String, Object> response = new HashMap<>();
|
| 164 |
-
response.put("success", true);
|
| 165 |
-
response.put("message", "Image deleted successfully");
|
| 166 |
-
return ResponseEntity.ok(response);
|
| 167 |
-
} else {
|
| 168 |
-
Map<String, String> error = new HashMap<>();
|
| 169 |
-
error.put("error", "Deletion failed");
|
| 170 |
-
error.put("message", "Could not delete image. It may not exist or URL is invalid.");
|
| 171 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 172 |
-
}
|
| 173 |
-
|
| 174 |
-
} catch (Exception e) {
|
| 175 |
-
logger.error("Image deletion failed", e);
|
| 176 |
-
Map<String, String> error = new HashMap<>();
|
| 177 |
-
error.put("error", "Deletion failed");
|
| 178 |
-
error.put("message", "Failed to delete image: " + e.getMessage());
|
| 179 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
|
| 180 |
-
}
|
| 181 |
-
}
|
| 182 |
-
|
| 183 |
-
/**
|
| 184 |
-
* Health check endpoint to verify Cloudinary configuration
|
| 185 |
-
* GET /api/images/health
|
| 186 |
-
* @return Configuration status
|
| 187 |
-
*/
|
| 188 |
-
@GetMapping("/health")
|
| 189 |
-
public ResponseEntity<?> healthCheck() {
|
| 190 |
-
Map<String, Object> response = new HashMap<>();
|
| 191 |
-
boolean configured = imageService.isConfigured();
|
| 192 |
-
|
| 193 |
-
response.put("configured", configured);
|
| 194 |
-
response.put("message", configured
|
| 195 |
-
? "Cloudinary is properly configured"
|
| 196 |
-
: "Cloudinary credentials not configured");
|
| 197 |
-
|
| 198 |
-
return ResponseEntity.ok(response);
|
| 199 |
-
}
|
| 200 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/controller/ItemController.java
DELETED
|
@@ -1,349 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.controller;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.dto.CreateItemRequest;
|
| 4 |
-
import com.locallend.locallend.dto.ItemDTO;
|
| 5 |
-
import com.locallend.locallend.dto.UpdateItemRequest;
|
| 6 |
-
import com.locallend.locallend.service.ItemService;
|
| 7 |
-
import jakarta.validation.Valid;
|
| 8 |
-
import org.springframework.data.domain.Page;
|
| 9 |
-
import org.springframework.http.HttpStatus;
|
| 10 |
-
import org.springframework.http.ResponseEntity;
|
| 11 |
-
import org.springframework.web.bind.annotation.*;
|
| 12 |
-
|
| 13 |
-
import java.util.HashMap;
|
| 14 |
-
import java.util.Map;
|
| 15 |
-
|
| 16 |
-
/**
|
| 17 |
-
* REST Controller for Item management in the LocalLend platform.
|
| 18 |
-
* Provides endpoints for CRUD operations, search, filtering, and availability management.
|
| 19 |
-
*/
|
| 20 |
-
@RestController
|
| 21 |
-
@RequestMapping("/api/items")
|
| 22 |
-
@CrossOrigin(origins = "*", maxAge = 3600)
|
| 23 |
-
public class ItemController {
|
| 24 |
-
|
| 25 |
-
private final ItemService itemService;
|
| 26 |
-
|
| 27 |
-
public ItemController(ItemService itemService) {
|
| 28 |
-
this.itemService = itemService;
|
| 29 |
-
}
|
| 30 |
-
|
| 31 |
-
/**
|
| 32 |
-
* Create a new item
|
| 33 |
-
* POST /api/items
|
| 34 |
-
* Request body: CreateItemRequest (name, description, categoryId, deposit, images, condition)
|
| 35 |
-
* Request header: X-User-Id (required for owner identification)
|
| 36 |
-
*/
|
| 37 |
-
@PostMapping
|
| 38 |
-
public ResponseEntity<?> createItem(
|
| 39 |
-
@Valid @RequestBody CreateItemRequest request,
|
| 40 |
-
@RequestHeader(value = "X-User-Id", required = true) String userId) {
|
| 41 |
-
|
| 42 |
-
try {
|
| 43 |
-
ItemDTO item = itemService.createItem(request, userId);
|
| 44 |
-
return ResponseEntity.status(HttpStatus.CREATED).body(item);
|
| 45 |
-
} catch (IllegalArgumentException e) {
|
| 46 |
-
Map<String, String> error = new HashMap<>();
|
| 47 |
-
error.put("error", "Invalid request");
|
| 48 |
-
error.put("message", e.getMessage());
|
| 49 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 50 |
-
} catch (Exception e) {
|
| 51 |
-
Map<String, String> error = new HashMap<>();
|
| 52 |
-
error.put("error", "Failed to create item");
|
| 53 |
-
error.put("message", e.getMessage());
|
| 54 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
|
| 55 |
-
}
|
| 56 |
-
}
|
| 57 |
-
|
| 58 |
-
/**
|
| 59 |
-
* Get all available items with pagination and sorting
|
| 60 |
-
* GET /api/items
|
| 61 |
-
* Query params: page (default: 0), size (default: 10), sortBy (default: name), sortDir (default: asc)
|
| 62 |
-
*/
|
| 63 |
-
@GetMapping
|
| 64 |
-
public ResponseEntity<Page<ItemDTO>> getAllAvailableItems(
|
| 65 |
-
@RequestParam(defaultValue = "0") int page,
|
| 66 |
-
@RequestParam(defaultValue = "10") int size,
|
| 67 |
-
@RequestParam(defaultValue = "name") String sortBy,
|
| 68 |
-
@RequestParam(defaultValue = "asc") String sortDir,
|
| 69 |
-
@RequestParam(required = false) String ownerId) {
|
| 70 |
-
|
| 71 |
-
// If caller provided an ownerId, route to the owner-specific service
|
| 72 |
-
// This keeps backward compatibility for callers using the public
|
| 73 |
-
// /api/items endpoint with ?ownerId=<id>
|
| 74 |
-
if (ownerId != null && !ownerId.isBlank()) {
|
| 75 |
-
Page<ItemDTO> items = itemService.getItemsByOwner(ownerId, page, size);
|
| 76 |
-
return ResponseEntity.ok(items);
|
| 77 |
-
}
|
| 78 |
-
|
| 79 |
-
Page<ItemDTO> items = itemService.getAvailableItems(page, size, sortBy, sortDir);
|
| 80 |
-
return ResponseEntity.ok(items);
|
| 81 |
-
}
|
| 82 |
-
|
| 83 |
-
/**
|
| 84 |
-
* Get item by ID
|
| 85 |
-
* GET /api/items/{id}
|
| 86 |
-
*/
|
| 87 |
-
@GetMapping("/{id}")
|
| 88 |
-
public ResponseEntity<?> getItemById(@PathVariable String id) {
|
| 89 |
-
try {
|
| 90 |
-
ItemDTO item = itemService.getItemById(id);
|
| 91 |
-
return ResponseEntity.ok(item);
|
| 92 |
-
} catch (Exception e) {
|
| 93 |
-
Map<String, String> error = new HashMap<>();
|
| 94 |
-
error.put("error", "Item not found");
|
| 95 |
-
error.put("message", e.getMessage());
|
| 96 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 97 |
-
}
|
| 98 |
-
}
|
| 99 |
-
|
| 100 |
-
/**
|
| 101 |
-
* Search available items
|
| 102 |
-
* GET /api/items/search
|
| 103 |
-
* Query params: q (search term), page (default: 0), size (default: 10)
|
| 104 |
-
*/
|
| 105 |
-
@GetMapping("/search")
|
| 106 |
-
public ResponseEntity<Page<ItemDTO>> searchItems(
|
| 107 |
-
@RequestParam(required = true) String q,
|
| 108 |
-
@RequestParam(defaultValue = "0") int page,
|
| 109 |
-
@RequestParam(defaultValue = "10") int size) {
|
| 110 |
-
|
| 111 |
-
Page<ItemDTO> items = itemService.searchAvailableItems(q, page, size);
|
| 112 |
-
return ResponseEntity.ok(items);
|
| 113 |
-
}
|
| 114 |
-
|
| 115 |
-
/**
|
| 116 |
-
* Get items by category
|
| 117 |
-
* GET /api/items/category/{categoryId}
|
| 118 |
-
* Query params: page (default: 0), size (default: 10)
|
| 119 |
-
*/
|
| 120 |
-
@GetMapping("/category/{categoryId}")
|
| 121 |
-
public ResponseEntity<?> getItemsByCategory(
|
| 122 |
-
@PathVariable String categoryId,
|
| 123 |
-
@RequestParam(defaultValue = "0") int page,
|
| 124 |
-
@RequestParam(defaultValue = "10") int size) {
|
| 125 |
-
|
| 126 |
-
try {
|
| 127 |
-
Page<ItemDTO> items = itemService.getAvailableItemsByCategory(categoryId, page, size);
|
| 128 |
-
return ResponseEntity.ok(items);
|
| 129 |
-
} catch (IllegalArgumentException e) {
|
| 130 |
-
Map<String, String> error = new HashMap<>();
|
| 131 |
-
error.put("error", "Invalid category");
|
| 132 |
-
error.put("message", e.getMessage());
|
| 133 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 134 |
-
}
|
| 135 |
-
}
|
| 136 |
-
|
| 137 |
-
/**
|
| 138 |
-
* Get items by owner
|
| 139 |
-
* GET /api/items/owner/{ownerId}
|
| 140 |
-
* Query params: page (default: 0), size (default: 10)
|
| 141 |
-
*/
|
| 142 |
-
@GetMapping("/owner/{ownerId}")
|
| 143 |
-
public ResponseEntity<?> getItemsByOwner(
|
| 144 |
-
@PathVariable String ownerId,
|
| 145 |
-
@RequestParam(defaultValue = "0") int page,
|
| 146 |
-
@RequestParam(defaultValue = "10") int size) {
|
| 147 |
-
|
| 148 |
-
try {
|
| 149 |
-
Page<ItemDTO> items = itemService.getItemsByOwner(ownerId, page, size);
|
| 150 |
-
return ResponseEntity.ok(items);
|
| 151 |
-
} catch (IllegalArgumentException e) {
|
| 152 |
-
Map<String, String> error = new HashMap<>();
|
| 153 |
-
error.put("error", "Invalid owner");
|
| 154 |
-
error.put("message", e.getMessage());
|
| 155 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 156 |
-
}
|
| 157 |
-
}
|
| 158 |
-
|
| 159 |
-
/**
|
| 160 |
-
* Get current user's items
|
| 161 |
-
* GET /api/items/my-items
|
| 162 |
-
* Request header: X-User-Id (required for authentication)
|
| 163 |
-
*/
|
| 164 |
-
@GetMapping("/my-items")
|
| 165 |
-
public ResponseEntity<?> getMyItems(
|
| 166 |
-
@RequestParam(defaultValue = "0") int page,
|
| 167 |
-
@RequestParam(defaultValue = "10") int size,
|
| 168 |
-
@RequestHeader(value = "X-User-Id", required = true) String userId) {
|
| 169 |
-
|
| 170 |
-
try {
|
| 171 |
-
Page<ItemDTO> items = itemService.getItemsByOwner(userId, page, size);
|
| 172 |
-
return ResponseEntity.ok(items);
|
| 173 |
-
} catch (Exception e) {
|
| 174 |
-
Map<String, String> error = new HashMap<>();
|
| 175 |
-
error.put("error", "Failed to retrieve items");
|
| 176 |
-
error.put("message", e.getMessage());
|
| 177 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 178 |
-
}
|
| 179 |
-
}
|
| 180 |
-
|
| 181 |
-
/**
|
| 182 |
-
* Update an item
|
| 183 |
-
* PUT /api/items/{id}
|
| 184 |
-
* Request body: UpdateItemRequest (optional fields: name, description, condition, deposit, images, isAvailable)
|
| 185 |
-
* Request header: X-User-Id (required for owner verification)
|
| 186 |
-
*/
|
| 187 |
-
@PutMapping("/{id}")
|
| 188 |
-
public ResponseEntity<?> updateItem(
|
| 189 |
-
@PathVariable String id,
|
| 190 |
-
@Valid @RequestBody UpdateItemRequest request,
|
| 191 |
-
@RequestHeader(value = "X-User-Id", required = true) String userId) {
|
| 192 |
-
|
| 193 |
-
try {
|
| 194 |
-
ItemDTO updatedItem = itemService.updateItem(id, request, userId);
|
| 195 |
-
return ResponseEntity.ok(updatedItem);
|
| 196 |
-
} catch (com.locallend.locallend.exception.UnauthorizedItemAccessException e) {
|
| 197 |
-
Map<String, String> error = new HashMap<>();
|
| 198 |
-
error.put("error", "Access denied");
|
| 199 |
-
error.put("message", e.getMessage());
|
| 200 |
-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
|
| 201 |
-
} catch (com.locallend.locallend.exception.ItemNotFoundException e) {
|
| 202 |
-
Map<String, String> error = new HashMap<>();
|
| 203 |
-
error.put("error", "Item not found");
|
| 204 |
-
error.put("message", e.getMessage());
|
| 205 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 206 |
-
} catch (Exception e) {
|
| 207 |
-
Map<String, String> error = new HashMap<>();
|
| 208 |
-
error.put("error", "Failed to update item");
|
| 209 |
-
error.put("message", e.getMessage());
|
| 210 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 211 |
-
}
|
| 212 |
-
}
|
| 213 |
-
|
| 214 |
-
/**
|
| 215 |
-
* Toggle item availability
|
| 216 |
-
* PATCH /api/items/{id}/toggle-availability
|
| 217 |
-
* Request header: X-User-Id (required for owner verification)
|
| 218 |
-
*/
|
| 219 |
-
@PatchMapping("/{id}/toggle-availability")
|
| 220 |
-
public ResponseEntity<?> toggleAvailability(
|
| 221 |
-
@PathVariable String id,
|
| 222 |
-
@RequestHeader(value = "X-User-Id", required = true) String userId) {
|
| 223 |
-
|
| 224 |
-
try {
|
| 225 |
-
ItemDTO updatedItem = itemService.toggleAvailability(id, userId);
|
| 226 |
-
return ResponseEntity.ok(updatedItem);
|
| 227 |
-
} catch (com.locallend.locallend.exception.UnauthorizedItemAccessException e) {
|
| 228 |
-
Map<String, String> error = new HashMap<>();
|
| 229 |
-
error.put("error", "Access denied");
|
| 230 |
-
error.put("message", e.getMessage());
|
| 231 |
-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
|
| 232 |
-
} catch (com.locallend.locallend.exception.ItemNotFoundException e) {
|
| 233 |
-
Map<String, String> error = new HashMap<>();
|
| 234 |
-
error.put("error", "Item not found");
|
| 235 |
-
error.put("message", e.getMessage());
|
| 236 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 237 |
-
} catch (Exception e) {
|
| 238 |
-
Map<String, String> error = new HashMap<>();
|
| 239 |
-
error.put("error", "Failed to toggle availability");
|
| 240 |
-
error.put("message", e.getMessage());
|
| 241 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 242 |
-
}
|
| 243 |
-
}
|
| 244 |
-
|
| 245 |
-
/**
|
| 246 |
-
* Set item availability
|
| 247 |
-
* PATCH /api/items/{id}/availability
|
| 248 |
-
* Request body: { "isAvailable": true/false }
|
| 249 |
-
* Request header: X-User-Id (required for owner verification)
|
| 250 |
-
*/
|
| 251 |
-
@PatchMapping("/{id}/availability")
|
| 252 |
-
public ResponseEntity<?> setAvailability(
|
| 253 |
-
@PathVariable String id,
|
| 254 |
-
@RequestBody Map<String, Boolean> request,
|
| 255 |
-
@RequestHeader(value = "X-User-Id", required = true) String userId) {
|
| 256 |
-
|
| 257 |
-
try {
|
| 258 |
-
Boolean isAvailable = request.get("isAvailable");
|
| 259 |
-
if (isAvailable == null) {
|
| 260 |
-
Map<String, String> error = new HashMap<>();
|
| 261 |
-
error.put("error", "Invalid request");
|
| 262 |
-
error.put("message", "isAvailable field is required");
|
| 263 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 264 |
-
}
|
| 265 |
-
|
| 266 |
-
ItemDTO updatedItem = itemService.setAvailability(id, isAvailable, userId);
|
| 267 |
-
return ResponseEntity.ok(updatedItem);
|
| 268 |
-
} catch (com.locallend.locallend.exception.UnauthorizedItemAccessException e) {
|
| 269 |
-
Map<String, String> error = new HashMap<>();
|
| 270 |
-
error.put("error", "Access denied");
|
| 271 |
-
error.put("message", e.getMessage());
|
| 272 |
-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
|
| 273 |
-
} catch (com.locallend.locallend.exception.ItemNotFoundException e) {
|
| 274 |
-
Map<String, String> error = new HashMap<>();
|
| 275 |
-
error.put("error", "Item not found");
|
| 276 |
-
error.put("message", e.getMessage());
|
| 277 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 278 |
-
} catch (Exception e) {
|
| 279 |
-
Map<String, String> error = new HashMap<>();
|
| 280 |
-
error.put("error", "Failed to set availability");
|
| 281 |
-
error.put("message", e.getMessage());
|
| 282 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 283 |
-
}
|
| 284 |
-
}
|
| 285 |
-
|
| 286 |
-
/**
|
| 287 |
-
* Delete an item (soft delete)
|
| 288 |
-
* DELETE /api/items/{id}
|
| 289 |
-
* Request header: X-User-Id (required for owner verification)
|
| 290 |
-
*/
|
| 291 |
-
@DeleteMapping("/{id}")
|
| 292 |
-
public ResponseEntity<?> deleteItem(
|
| 293 |
-
@PathVariable String id,
|
| 294 |
-
@RequestHeader(value = "X-User-Id", required = true) String userId) {
|
| 295 |
-
|
| 296 |
-
try {
|
| 297 |
-
itemService.deleteItem(id, userId);
|
| 298 |
-
Map<String, String> response = new HashMap<>();
|
| 299 |
-
response.put("message", "Item deleted successfully");
|
| 300 |
-
return ResponseEntity.ok(response);
|
| 301 |
-
} catch (com.locallend.locallend.exception.UnauthorizedItemAccessException e) {
|
| 302 |
-
Map<String, String> error = new HashMap<>();
|
| 303 |
-
error.put("error", "Access denied");
|
| 304 |
-
error.put("message", e.getMessage());
|
| 305 |
-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
|
| 306 |
-
} catch (com.locallend.locallend.exception.ItemNotFoundException e) {
|
| 307 |
-
Map<String, String> error = new HashMap<>();
|
| 308 |
-
error.put("error", "Item not found");
|
| 309 |
-
error.put("message", e.getMessage());
|
| 310 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 311 |
-
} catch (Exception e) {
|
| 312 |
-
Map<String, String> error = new HashMap<>();
|
| 313 |
-
error.put("error", "Failed to delete item");
|
| 314 |
-
error.put("message", e.getMessage());
|
| 315 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 316 |
-
}
|
| 317 |
-
}
|
| 318 |
-
|
| 319 |
-
/**
|
| 320 |
-
* Reactivate a soft-deleted item (for testing purposes)
|
| 321 |
-
* POST /api/items/{id}/reactivate
|
| 322 |
-
* Request header: X-User-Id (required for owner verification)
|
| 323 |
-
*/
|
| 324 |
-
@PostMapping("/{id}/reactivate")
|
| 325 |
-
public ResponseEntity<?> reactivateItem(
|
| 326 |
-
@PathVariable String id,
|
| 327 |
-
@RequestHeader(value = "X-User-Id", required = true) String userId) {
|
| 328 |
-
|
| 329 |
-
try {
|
| 330 |
-
ItemDTO item = itemService.reactivateItem(id, userId);
|
| 331 |
-
return ResponseEntity.ok(item);
|
| 332 |
-
} catch (com.locallend.locallend.exception.UnauthorizedItemAccessException e) {
|
| 333 |
-
Map<String, String> error = new HashMap<>();
|
| 334 |
-
error.put("error", "Access denied");
|
| 335 |
-
error.put("message", e.getMessage());
|
| 336 |
-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
|
| 337 |
-
} catch (com.locallend.locallend.exception.ItemNotFoundException e) {
|
| 338 |
-
Map<String, String> error = new HashMap<>();
|
| 339 |
-
error.put("error", "Item not found");
|
| 340 |
-
error.put("message", e.getMessage());
|
| 341 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 342 |
-
} catch (Exception e) {
|
| 343 |
-
Map<String, String> error = new HashMap<>();
|
| 344 |
-
error.put("error", "Failed to reactivate item");
|
| 345 |
-
error.put("message", e.getMessage());
|
| 346 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
|
| 347 |
-
}
|
| 348 |
-
}
|
| 349 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/controller/RatingController.java
DELETED
|
@@ -1,531 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.controller;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.dto.request.RatingCreateDto;
|
| 4 |
-
import com.locallend.locallend.dto.response.RatingResponseDto;
|
| 5 |
-
import com.locallend.locallend.dto.response.RatingStatsResponse;
|
| 6 |
-
import com.locallend.locallend.exception.ValidationException;
|
| 7 |
-
import com.locallend.locallend.model.Rating;
|
| 8 |
-
import com.locallend.locallend.model.RatingType;
|
| 9 |
-
import com.locallend.locallend.service.RatingService;
|
| 10 |
-
import com.locallend.locallend.util.RatingMapper;
|
| 11 |
-
import com.locallend.locallend.util.SecurityUtils;
|
| 12 |
-
|
| 13 |
-
import org.slf4j.Logger;
|
| 14 |
-
import org.slf4j.LoggerFactory;
|
| 15 |
-
import org.springframework.http.HttpStatus;
|
| 16 |
-
import org.springframework.http.ResponseEntity;
|
| 17 |
-
import org.springframework.validation.annotation.Validated;
|
| 18 |
-
import org.springframework.web.bind.annotation.*;
|
| 19 |
-
|
| 20 |
-
import jakarta.validation.Valid;
|
| 21 |
-
import jakarta.validation.constraints.Min;
|
| 22 |
-
import jakarta.validation.constraints.NotBlank;
|
| 23 |
-
import java.util.HashMap;
|
| 24 |
-
import java.util.List;
|
| 25 |
-
import java.util.Map;
|
| 26 |
-
|
| 27 |
-
/**
|
| 28 |
-
* REST Controller for Rating management operations.
|
| 29 |
-
* Provides comprehensive API endpoints for creating and retrieving ratings.
|
| 30 |
-
* Issue #25: Rating Controller APIs
|
| 31 |
-
*/
|
| 32 |
-
@RestController
|
| 33 |
-
@RequestMapping("/api/ratings")
|
| 34 |
-
@Validated
|
| 35 |
-
@CrossOrigin(origins = "*", maxAge = 3600)
|
| 36 |
-
public class RatingController {
|
| 37 |
-
|
| 38 |
-
private static final Logger logger = LoggerFactory.getLogger(RatingController.class);
|
| 39 |
-
|
| 40 |
-
private final RatingService ratingService;
|
| 41 |
-
private final RatingMapper ratingMapper;
|
| 42 |
-
|
| 43 |
-
public RatingController(RatingService ratingService, RatingMapper ratingMapper) {
|
| 44 |
-
this.ratingService = ratingService;
|
| 45 |
-
this.ratingMapper = ratingMapper;
|
| 46 |
-
}
|
| 47 |
-
|
| 48 |
-
/**
|
| 49 |
-
* Create a new rating
|
| 50 |
-
* POST /api/ratings
|
| 51 |
-
*/
|
| 52 |
-
@PostMapping
|
| 53 |
-
public ResponseEntity<?> createRating(@Valid @RequestBody RatingCreateDto request) {
|
| 54 |
-
|
| 55 |
-
logger.info("Request to create rating with type: {}", request.getRatingType());
|
| 56 |
-
|
| 57 |
-
try {
|
| 58 |
-
String raterId = SecurityUtils.getCurrentUserId();
|
| 59 |
-
Rating rating;
|
| 60 |
-
|
| 61 |
-
// Route to appropriate service method based on rating type
|
| 62 |
-
if (request.getRatingType() == RatingType.USER_TO_ITEM) {
|
| 63 |
-
// Item rating
|
| 64 |
-
if (request.getItemId() == null || request.getItemId().trim().isEmpty()) {
|
| 65 |
-
throw new ValidationException("Item ID is required for item ratings");
|
| 66 |
-
}
|
| 67 |
-
rating = ratingService.createItemRating(
|
| 68 |
-
raterId,
|
| 69 |
-
request.getItemId(),
|
| 70 |
-
request.getRatingValue(),
|
| 71 |
-
request.getComment(),
|
| 72 |
-
request.getIsAnonymous() != null ? request.getIsAnonymous() : false
|
| 73 |
-
);
|
| 74 |
-
} else {
|
| 75 |
-
// User-to-user rating (USER_TO_USER, OWNER_TO_BORROWER, BORROWER_TO_OWNER)
|
| 76 |
-
if (request.getRateeId() == null || request.getRateeId().trim().isEmpty()) {
|
| 77 |
-
throw new ValidationException("Ratee ID is required for user ratings");
|
| 78 |
-
}
|
| 79 |
-
rating = ratingService.createUserRating(
|
| 80 |
-
raterId,
|
| 81 |
-
request.getRateeId(),
|
| 82 |
-
request.getRatingType(),
|
| 83 |
-
request.getRatingValue(),
|
| 84 |
-
request.getComment(),
|
| 85 |
-
request.getBookingId()
|
| 86 |
-
);
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
RatingResponseDto responseDto = ratingMapper.toResponseDto(rating);
|
| 90 |
-
|
| 91 |
-
Map<String, Object> response = new HashMap<>();
|
| 92 |
-
response.put("success", true);
|
| 93 |
-
response.put("message", "Rating created successfully");
|
| 94 |
-
response.put("data", responseDto);
|
| 95 |
-
|
| 96 |
-
return ResponseEntity.status(HttpStatus.CREATED).body(response);
|
| 97 |
-
|
| 98 |
-
} catch (ValidationException e) {
|
| 99 |
-
logger.error("Rating validation failed: {}", e.getMessage());
|
| 100 |
-
|
| 101 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 102 |
-
errorResponse.put("success", false);
|
| 103 |
-
errorResponse.put("message", e.getMessage());
|
| 104 |
-
errorResponse.put("error_code", "VALIDATION_ERROR");
|
| 105 |
-
|
| 106 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
|
| 107 |
-
|
| 108 |
-
} catch (Exception e) {
|
| 109 |
-
logger.error("Unexpected error creating rating: {}", e.getMessage());
|
| 110 |
-
|
| 111 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 112 |
-
errorResponse.put("success", false);
|
| 113 |
-
errorResponse.put("message", "Internal server error: " + e.getMessage());
|
| 114 |
-
errorResponse.put("error_code", "INTERNAL_ERROR");
|
| 115 |
-
|
| 116 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 117 |
-
}
|
| 118 |
-
}
|
| 119 |
-
|
| 120 |
-
/**
|
| 121 |
-
* Get ratings for a user
|
| 122 |
-
* GET /api/ratings/user/{userId}
|
| 123 |
-
*/
|
| 124 |
-
@GetMapping("/user/{userId}")
|
| 125 |
-
public ResponseEntity<?> getUserRatings(
|
| 126 |
-
@PathVariable @NotBlank(message = "User ID is required") String userId) {
|
| 127 |
-
|
| 128 |
-
logger.info("Request to get ratings for user: {}", userId);
|
| 129 |
-
|
| 130 |
-
try {
|
| 131 |
-
List<Rating> ratings = ratingService.getRatingsReceivedByUser(userId);
|
| 132 |
-
List<RatingResponseDto> responseDtos = ratingMapper.toResponseDtoList(ratings);
|
| 133 |
-
|
| 134 |
-
Map<String, Object> response = new HashMap<>();
|
| 135 |
-
response.put("success", true);
|
| 136 |
-
response.put("message", "User ratings retrieved successfully");
|
| 137 |
-
response.put("data", responseDtos);
|
| 138 |
-
response.put("count", responseDtos.size());
|
| 139 |
-
|
| 140 |
-
return ResponseEntity.ok(response);
|
| 141 |
-
|
| 142 |
-
} catch (Exception e) {
|
| 143 |
-
logger.error("Error retrieving user ratings: {}", e.getMessage());
|
| 144 |
-
|
| 145 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 146 |
-
errorResponse.put("success", false);
|
| 147 |
-
errorResponse.put("message", "Error retrieving user ratings");
|
| 148 |
-
errorResponse.put("error_code", "RETRIEVAL_ERROR");
|
| 149 |
-
|
| 150 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 151 |
-
}
|
| 152 |
-
}
|
| 153 |
-
|
| 154 |
-
/**
|
| 155 |
-
* Get ratings for an item
|
| 156 |
-
* GET /api/ratings/item/{itemId}
|
| 157 |
-
*/
|
| 158 |
-
@GetMapping("/item/{itemId}")
|
| 159 |
-
public ResponseEntity<?> getItemRatings(
|
| 160 |
-
@PathVariable @NotBlank(message = "Item ID is required") String itemId) {
|
| 161 |
-
|
| 162 |
-
logger.info("Request to get ratings for item: {}", itemId);
|
| 163 |
-
|
| 164 |
-
try {
|
| 165 |
-
List<Rating> ratings = ratingService.getItemRatings(itemId);
|
| 166 |
-
List<RatingResponseDto> responseDtos = ratingMapper.toResponseDtoList(ratings);
|
| 167 |
-
|
| 168 |
-
Map<String, Object> response = new HashMap<>();
|
| 169 |
-
response.put("success", true);
|
| 170 |
-
response.put("message", "Item ratings retrieved successfully");
|
| 171 |
-
response.put("data", responseDtos);
|
| 172 |
-
response.put("count", responseDtos.size());
|
| 173 |
-
|
| 174 |
-
return ResponseEntity.ok(response);
|
| 175 |
-
|
| 176 |
-
} catch (Exception e) {
|
| 177 |
-
logger.error("Error retrieving item ratings: {}", e.getMessage());
|
| 178 |
-
|
| 179 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 180 |
-
errorResponse.put("success", false);
|
| 181 |
-
errorResponse.put("message", "Error retrieving item ratings");
|
| 182 |
-
errorResponse.put("error_code", "RETRIEVAL_ERROR");
|
| 183 |
-
|
| 184 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 185 |
-
}
|
| 186 |
-
}
|
| 187 |
-
|
| 188 |
-
/**
|
| 189 |
-
* Get ratings for a booking
|
| 190 |
-
* GET /api/ratings/booking/{bookingId}
|
| 191 |
-
*/
|
| 192 |
-
@GetMapping("/booking/{bookingId}")
|
| 193 |
-
public ResponseEntity<?> getBookingRatings(
|
| 194 |
-
@PathVariable @NotBlank(message = "Booking ID is required") String bookingId) {
|
| 195 |
-
|
| 196 |
-
logger.info("Request to get ratings for booking: {}", bookingId);
|
| 197 |
-
|
| 198 |
-
try {
|
| 199 |
-
// Filter ratings by booking ID from user and item ratings
|
| 200 |
-
// The existing service doesn't have a specific getByBookingId method
|
| 201 |
-
// For now, we'll return empty list and log a note
|
| 202 |
-
logger.warn("Booking-specific rating retrieval not yet implemented in service layer");
|
| 203 |
-
|
| 204 |
-
Map<String, Object> response = new HashMap<>();
|
| 205 |
-
response.put("success", true);
|
| 206 |
-
response.put("message", "Booking ratings retrieved successfully");
|
| 207 |
-
response.put("data", List.of());
|
| 208 |
-
response.put("count", 0);
|
| 209 |
-
response.put("booking_id", bookingId);
|
| 210 |
-
response.put("note", "Booking-specific queries to be added in future iteration");
|
| 211 |
-
|
| 212 |
-
return ResponseEntity.ok(response);
|
| 213 |
-
|
| 214 |
-
} catch (Exception e) {
|
| 215 |
-
logger.error("Error retrieving booking ratings: {}", e.getMessage());
|
| 216 |
-
|
| 217 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 218 |
-
errorResponse.put("success", false);
|
| 219 |
-
errorResponse.put("message", "Error retrieving booking ratings");
|
| 220 |
-
errorResponse.put("error_code", "RETRIEVAL_ERROR");
|
| 221 |
-
|
| 222 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 223 |
-
}
|
| 224 |
-
}
|
| 225 |
-
|
| 226 |
-
/**
|
| 227 |
-
* Get ratings given by current user
|
| 228 |
-
* GET /api/ratings/my-ratings
|
| 229 |
-
*/
|
| 230 |
-
@GetMapping("/my-ratings")
|
| 231 |
-
public ResponseEntity<?> getMyRatings() {
|
| 232 |
-
|
| 233 |
-
String userId = SecurityUtils.getCurrentUserId();
|
| 234 |
-
logger.info("Request to get ratings by user: {}", userId);
|
| 235 |
-
|
| 236 |
-
try {
|
| 237 |
-
List<Rating> ratings = ratingService.getRatingsByRater(userId);
|
| 238 |
-
List<RatingResponseDto> responseDtos = ratingMapper.toResponseDtoList(ratings);
|
| 239 |
-
|
| 240 |
-
Map<String, Object> response = new HashMap<>();
|
| 241 |
-
response.put("success", true);
|
| 242 |
-
response.put("message", "My ratings retrieved successfully");
|
| 243 |
-
response.put("data", responseDtos);
|
| 244 |
-
response.put("count", responseDtos.size());
|
| 245 |
-
|
| 246 |
-
return ResponseEntity.ok(response);
|
| 247 |
-
|
| 248 |
-
} catch (Exception e) {
|
| 249 |
-
logger.error("Error retrieving user's ratings: {}", e.getMessage());
|
| 250 |
-
|
| 251 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 252 |
-
errorResponse.put("success", false);
|
| 253 |
-
errorResponse.put("message", "Error retrieving your ratings");
|
| 254 |
-
errorResponse.put("error_code", "RETRIEVAL_ERROR");
|
| 255 |
-
|
| 256 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 257 |
-
}
|
| 258 |
-
}
|
| 259 |
-
|
| 260 |
-
/**
|
| 261 |
-
* Get rating statistics for a user
|
| 262 |
-
* GET /api/ratings/user/{userId}/stats
|
| 263 |
-
*/
|
| 264 |
-
@GetMapping("/user/{userId}/stats")
|
| 265 |
-
public ResponseEntity<?> getUserRatingStats(
|
| 266 |
-
@PathVariable @NotBlank(message = "User ID is required") String userId) {
|
| 267 |
-
|
| 268 |
-
logger.info("Request to get rating stats for user: {}", userId);
|
| 269 |
-
|
| 270 |
-
try {
|
| 271 |
-
RatingService.RatingStatistics stats = ratingService.getUserRatingStatistics(userId);
|
| 272 |
-
|
| 273 |
-
// Convert RatingStatistics to RatingStatsResponse
|
| 274 |
-
RatingStatsResponse response = convertToStatsResponse(stats, userId, "USER");
|
| 275 |
-
|
| 276 |
-
Map<String, Object> responseMap = new HashMap<>();
|
| 277 |
-
responseMap.put("success", true);
|
| 278 |
-
responseMap.put("message", "User rating stats retrieved successfully");
|
| 279 |
-
responseMap.put("data", response);
|
| 280 |
-
|
| 281 |
-
return ResponseEntity.ok(responseMap);
|
| 282 |
-
|
| 283 |
-
} catch (Exception e) {
|
| 284 |
-
logger.error("Error retrieving user rating stats: {}", e.getMessage());
|
| 285 |
-
|
| 286 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 287 |
-
errorResponse.put("success", false);
|
| 288 |
-
errorResponse.put("message", "Error retrieving user rating statistics");
|
| 289 |
-
errorResponse.put("error_code", "STATS_ERROR");
|
| 290 |
-
|
| 291 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 292 |
-
}
|
| 293 |
-
}
|
| 294 |
-
|
| 295 |
-
/**
|
| 296 |
-
* Get rating statistics for an item
|
| 297 |
-
* GET /api/ratings/item/{itemId}/stats
|
| 298 |
-
*/
|
| 299 |
-
@GetMapping("/item/{itemId}/stats")
|
| 300 |
-
public ResponseEntity<?> getItemRatingStats(
|
| 301 |
-
@PathVariable @NotBlank(message = "Item ID is required") String itemId) {
|
| 302 |
-
|
| 303 |
-
logger.info("Request to get rating stats for item: {}", itemId);
|
| 304 |
-
|
| 305 |
-
try {
|
| 306 |
-
RatingService.RatingStatistics stats = ratingService.getItemRatingStatistics(itemId);
|
| 307 |
-
|
| 308 |
-
// Convert RatingStatistics to RatingStatsResponse
|
| 309 |
-
RatingStatsResponse response = convertToStatsResponse(stats, itemId, "ITEM");
|
| 310 |
-
|
| 311 |
-
Map<String, Object> responseMap = new HashMap<>();
|
| 312 |
-
responseMap.put("success", true);
|
| 313 |
-
responseMap.put("message", "Item rating stats retrieved successfully");
|
| 314 |
-
responseMap.put("data", response);
|
| 315 |
-
|
| 316 |
-
return ResponseEntity.ok(responseMap);
|
| 317 |
-
|
| 318 |
-
} catch (Exception e) {
|
| 319 |
-
logger.error("Error retrieving item rating stats: {}", e.getMessage());
|
| 320 |
-
|
| 321 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 322 |
-
errorResponse.put("success", false);
|
| 323 |
-
errorResponse.put("message", "Error retrieving item rating statistics");
|
| 324 |
-
errorResponse.put("error_code", "STATS_ERROR");
|
| 325 |
-
|
| 326 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 327 |
-
}
|
| 328 |
-
}
|
| 329 |
-
|
| 330 |
-
/**
|
| 331 |
-
* Update an existing rating
|
| 332 |
-
* PUT /api/ratings/{ratingId}
|
| 333 |
-
*/
|
| 334 |
-
@PutMapping("/{ratingId}")
|
| 335 |
-
public ResponseEntity<?> updateRating(
|
| 336 |
-
@PathVariable @NotBlank(message = "Rating ID is required") String ratingId,
|
| 337 |
-
@RequestParam @Min(value = 1, message = "Rating must be between 1 and 5") @Min(value = 5) Integer ratingValue,
|
| 338 |
-
@RequestParam(required = false) String comment) {
|
| 339 |
-
|
| 340 |
-
String userId = SecurityUtils.getCurrentUserId();
|
| 341 |
-
logger.info("Request to update rating {} by user: {}", ratingId, userId);
|
| 342 |
-
|
| 343 |
-
try {
|
| 344 |
-
Rating updatedRating = ratingService.updateRating(ratingId, userId, ratingValue, comment);
|
| 345 |
-
RatingResponseDto responseDto = ratingMapper.toResponseDto(updatedRating);
|
| 346 |
-
|
| 347 |
-
Map<String, Object> response = new HashMap<>();
|
| 348 |
-
response.put("success", true);
|
| 349 |
-
response.put("message", "Rating updated successfully");
|
| 350 |
-
response.put("data", responseDto);
|
| 351 |
-
|
| 352 |
-
return ResponseEntity.ok(response);
|
| 353 |
-
|
| 354 |
-
} catch (ValidationException e) {
|
| 355 |
-
logger.error("Rating update failed: {}", e.getMessage());
|
| 356 |
-
|
| 357 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 358 |
-
errorResponse.put("success", false);
|
| 359 |
-
errorResponse.put("message", e.getMessage());
|
| 360 |
-
errorResponse.put("error_code", "VALIDATION_ERROR");
|
| 361 |
-
|
| 362 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
|
| 363 |
-
|
| 364 |
-
} catch (Exception e) {
|
| 365 |
-
logger.error("Error updating rating: {}", e.getMessage());
|
| 366 |
-
|
| 367 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 368 |
-
errorResponse.put("success", false);
|
| 369 |
-
errorResponse.put("message", "Error updating rating: " + e.getMessage());
|
| 370 |
-
errorResponse.put("error_code", "UPDATE_ERROR");
|
| 371 |
-
|
| 372 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 373 |
-
}
|
| 374 |
-
}
|
| 375 |
-
|
| 376 |
-
/**
|
| 377 |
-
* Delete a rating
|
| 378 |
-
* DELETE /api/ratings/{ratingId}
|
| 379 |
-
*/
|
| 380 |
-
@DeleteMapping("/{ratingId}")
|
| 381 |
-
public ResponseEntity<?> deleteRating(
|
| 382 |
-
@PathVariable @NotBlank(message = "Rating ID is required") String ratingId) {
|
| 383 |
-
|
| 384 |
-
String userId = SecurityUtils.getCurrentUserId();
|
| 385 |
-
logger.info("Request to delete rating {} by user: {}", ratingId, userId);
|
| 386 |
-
|
| 387 |
-
try {
|
| 388 |
-
ratingService.deleteRating(ratingId, userId);
|
| 389 |
-
|
| 390 |
-
Map<String, Object> response = new HashMap<>();
|
| 391 |
-
response.put("success", true);
|
| 392 |
-
response.put("message", "Rating deleted successfully");
|
| 393 |
-
|
| 394 |
-
return ResponseEntity.ok(response);
|
| 395 |
-
|
| 396 |
-
} catch (ValidationException e) {
|
| 397 |
-
logger.error("Rating deletion failed: {}", e.getMessage());
|
| 398 |
-
|
| 399 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 400 |
-
errorResponse.put("success", false);
|
| 401 |
-
errorResponse.put("message", e.getMessage());
|
| 402 |
-
errorResponse.put("error_code", "VALIDATION_ERROR");
|
| 403 |
-
|
| 404 |
-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(errorResponse);
|
| 405 |
-
|
| 406 |
-
} catch (Exception e) {
|
| 407 |
-
logger.error("Error deleting rating: {}", e.getMessage());
|
| 408 |
-
|
| 409 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 410 |
-
errorResponse.put("success", false);
|
| 411 |
-
errorResponse.put("message", "Error deleting rating: " + e.getMessage());
|
| 412 |
-
errorResponse.put("error_code", "DELETE_ERROR");
|
| 413 |
-
|
| 414 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 415 |
-
}
|
| 416 |
-
}
|
| 417 |
-
|
| 418 |
-
/**
|
| 419 |
-
* Get a specific rating by ID
|
| 420 |
-
* GET /api/ratings/{ratingId}
|
| 421 |
-
*/
|
| 422 |
-
@GetMapping("/{ratingId}")
|
| 423 |
-
public ResponseEntity<?> getRatingById(
|
| 424 |
-
@PathVariable @NotBlank(message = "Rating ID is required") String ratingId) {
|
| 425 |
-
|
| 426 |
-
logger.info("Request to get rating: {}", ratingId);
|
| 427 |
-
|
| 428 |
-
try {
|
| 429 |
-
Rating rating = ratingService.getRatingById(ratingId);
|
| 430 |
-
RatingResponseDto responseDto = ratingMapper.toResponseDto(rating);
|
| 431 |
-
|
| 432 |
-
Map<String, Object> response = new HashMap<>();
|
| 433 |
-
response.put("success", true);
|
| 434 |
-
response.put("message", "Rating retrieved successfully");
|
| 435 |
-
response.put("data", responseDto);
|
| 436 |
-
|
| 437 |
-
return ResponseEntity.ok(response);
|
| 438 |
-
|
| 439 |
-
} catch (Exception e) {
|
| 440 |
-
logger.error("Error retrieving rating: {}", e.getMessage());
|
| 441 |
-
|
| 442 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 443 |
-
errorResponse.put("success", false);
|
| 444 |
-
errorResponse.put("message", "Rating not found");
|
| 445 |
-
errorResponse.put("error_code", "NOT_FOUND");
|
| 446 |
-
|
| 447 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
|
| 448 |
-
}
|
| 449 |
-
}
|
| 450 |
-
/**
|
| 451 |
-
* Check if a booking can be rated by the current user
|
| 452 |
-
* GET /api/ratings/can-rate/{bookingId}
|
| 453 |
-
* Issue #26: Booking-Rating Integration
|
| 454 |
-
*/
|
| 455 |
-
@GetMapping("/can-rate/{bookingId}")
|
| 456 |
-
public ResponseEntity<?> canRateBooking(
|
| 457 |
-
@PathVariable @NotBlank(message = "Booking ID is required") String bookingId) {
|
| 458 |
-
|
| 459 |
-
String userId = SecurityUtils.getCurrentUserId();
|
| 460 |
-
logger.info("Request to check if booking {} can be rated by user: {}", bookingId, userId);
|
| 461 |
-
|
| 462 |
-
try {
|
| 463 |
-
boolean canRate = ratingService.canRateBooking(bookingId, userId);
|
| 464 |
-
|
| 465 |
-
Map<String, Object> response = new HashMap<>();
|
| 466 |
-
response.put("success", true);
|
| 467 |
-
response.put("can_rate", canRate);
|
| 468 |
-
response.put("booking_id", bookingId);
|
| 469 |
-
|
| 470 |
-
return ResponseEntity.ok(response);
|
| 471 |
-
|
| 472 |
-
} catch (Exception e) {
|
| 473 |
-
logger.error("Error checking if booking can be rated: {}", e.getMessage());
|
| 474 |
-
|
| 475 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 476 |
-
errorResponse.put("success", false);
|
| 477 |
-
errorResponse.put("message", "Error checking rating eligibility");
|
| 478 |
-
errorResponse.put("error_code", "CHECK_ERROR");
|
| 479 |
-
|
| 480 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
| 481 |
-
}
|
| 482 |
-
}
|
| 483 |
-
|
| 484 |
-
|
| 485 |
-
// Helper methods
|
| 486 |
-
|
| 487 |
-
/**
|
| 488 |
-
* Convert RatingService.RatingStatistics to RatingStatsResponse DTO
|
| 489 |
-
*/
|
| 490 |
-
private RatingStatsResponse convertToStatsResponse(RatingService.RatingStatistics stats, String subjectId, String subjectType) {
|
| 491 |
-
RatingStatsResponse response = new RatingStatsResponse(
|
| 492 |
-
subjectId,
|
| 493 |
-
subjectType,
|
| 494 |
-
stats.getAverageRating(),
|
| 495 |
-
(long) stats.getTotalRatings()
|
| 496 |
-
);
|
| 497 |
-
|
| 498 |
-
// Convert rating distribution array to map
|
| 499 |
-
Map<String, Long> distributionMap = new HashMap<>();
|
| 500 |
-
int[] distribution = stats.getRatingDistribution();
|
| 501 |
-
distributionMap.put("1", (long) distribution[0]);
|
| 502 |
-
distributionMap.put("2", (long) distribution[1]);
|
| 503 |
-
distributionMap.put("3", (long) distribution[2]);
|
| 504 |
-
distributionMap.put("4", (long) distribution[3]);
|
| 505 |
-
distributionMap.put("5", (long) distribution[4]);
|
| 506 |
-
|
| 507 |
-
response.setRatingDistribution(distributionMap);
|
| 508 |
-
|
| 509 |
-
return response;
|
| 510 |
-
}
|
| 511 |
-
|
| 512 |
-
/**
|
| 513 |
-
* Global exception handler for validation errors
|
| 514 |
-
*/
|
| 515 |
-
@ExceptionHandler(org.springframework.web.bind.MethodArgumentNotValidException.class)
|
| 516 |
-
public ResponseEntity<?> handleValidationExceptions(
|
| 517 |
-
org.springframework.web.bind.MethodArgumentNotValidException ex) {
|
| 518 |
-
|
| 519 |
-
Map<String, String> errors = new HashMap<>();
|
| 520 |
-
ex.getBindingResult().getFieldErrors().forEach(error ->
|
| 521 |
-
errors.put(error.getField(), error.getDefaultMessage()));
|
| 522 |
-
|
| 523 |
-
Map<String, Object> errorResponse = new HashMap<>();
|
| 524 |
-
errorResponse.put("success", false);
|
| 525 |
-
errorResponse.put("message", "Validation failed");
|
| 526 |
-
errorResponse.put("error_code", "VALIDATION_ERROR");
|
| 527 |
-
errorResponse.put("errors", errors);
|
| 528 |
-
|
| 529 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
|
| 530 |
-
}
|
| 531 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/controller/UserController.java
DELETED
|
@@ -1,100 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.controller;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.dto.request.UserUpdateDto;
|
| 4 |
-
import com.locallend.locallend.dto.response.UserPublicDto;
|
| 5 |
-
import com.locallend.locallend.dto.response.UserResponseDto;
|
| 6 |
-
import com.locallend.locallend.exception.BusinessException;
|
| 7 |
-
import com.locallend.locallend.model.User;
|
| 8 |
-
import com.locallend.locallend.service.UserQueryService;
|
| 9 |
-
import com.locallend.locallend.service.UserService;
|
| 10 |
-
import com.locallend.locallend.util.SecurityUtils;
|
| 11 |
-
import com.locallend.locallend.util.UserMapper;
|
| 12 |
-
import jakarta.validation.Valid;
|
| 13 |
-
import org.springframework.beans.factory.annotation.Autowired;
|
| 14 |
-
import org.springframework.data.domain.Page;
|
| 15 |
-
import org.springframework.http.ResponseEntity;
|
| 16 |
-
import org.springframework.web.bind.annotation.*;
|
| 17 |
-
|
| 18 |
-
/**
|
| 19 |
-
* REST controller to manage authenticated user operations and public user queries.
|
| 20 |
-
* Handles profile management, public info lookup, and user search.
|
| 21 |
-
**/
|
| 22 |
-
|
| 23 |
-
@RestController
|
| 24 |
-
@RequestMapping("/api/users")
|
| 25 |
-
public class UserController {
|
| 26 |
-
|
| 27 |
-
@Autowired
|
| 28 |
-
private UserService userService;
|
| 29 |
-
|
| 30 |
-
@Autowired
|
| 31 |
-
private UserQueryService userQueryService;
|
| 32 |
-
|
| 33 |
-
@Autowired
|
| 34 |
-
private UserMapper userMapper;
|
| 35 |
-
|
| 36 |
-
/**
|
| 37 |
-
* Get current user's profile.
|
| 38 |
-
* Extracts user ID from JWT token in SecurityContext.
|
| 39 |
-
*
|
| 40 |
-
* @return Full user profile
|
| 41 |
-
*/
|
| 42 |
-
@GetMapping("/profile")
|
| 43 |
-
public ResponseEntity<UserResponseDto> getProfile() {
|
| 44 |
-
String userId = SecurityUtils.getCurrentUserId();
|
| 45 |
-
User user = userQueryService.findById(userId)
|
| 46 |
-
.orElseThrow(() -> new BusinessException("User not found"));
|
| 47 |
-
return ResponseEntity.ok(userMapper.toUserResponseDto(user));
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
/**
|
| 51 |
-
* Update current user's profile.
|
| 52 |
-
* Extracts user ID from JWT token in SecurityContext.
|
| 53 |
-
*
|
| 54 |
-
* @param updateDto Profile update data
|
| 55 |
-
* @return Updated user profile
|
| 56 |
-
*/
|
| 57 |
-
@PutMapping("/profile")
|
| 58 |
-
public ResponseEntity<UserResponseDto> updateProfile(@Valid @RequestBody UserUpdateDto updateDto) {
|
| 59 |
-
String userId = SecurityUtils.getCurrentUserId();
|
| 60 |
-
User updated = userService.updateProfile(userId,
|
| 61 |
-
updateDto.getName(),
|
| 62 |
-
updateDto.getPhoneNumber(),
|
| 63 |
-
updateDto.getProfileImageUrl());
|
| 64 |
-
return ResponseEntity.ok(userMapper.toUserResponseDto(updated));
|
| 65 |
-
}
|
| 66 |
-
|
| 67 |
-
/**
|
| 68 |
-
* Get public information about any user.
|
| 69 |
-
* Does not expose sensitive information like email or phone.
|
| 70 |
-
*
|
| 71 |
-
* @param id User ID to lookup
|
| 72 |
-
* @return Public user information
|
| 73 |
-
*/
|
| 74 |
-
@GetMapping("/{id}/public")
|
| 75 |
-
public ResponseEntity<UserPublicDto> getPublicInfo(@PathVariable String id) {
|
| 76 |
-
User user = userQueryService.findById(id)
|
| 77 |
-
.orElseThrow(() -> new BusinessException("User not found"));
|
| 78 |
-
return ResponseEntity.ok(userMapper.toUserPublicDto(user));
|
| 79 |
-
}
|
| 80 |
-
|
| 81 |
-
/**
|
| 82 |
-
* Search active users by name or username.
|
| 83 |
-
* Returns paginated results with only public information.
|
| 84 |
-
*
|
| 85 |
-
* @param term Search term (case-insensitive)
|
| 86 |
-
* @param page Page number (default: 0)
|
| 87 |
-
* @param size Page size (default: 10)
|
| 88 |
-
* @return Page of matching users (public info only)
|
| 89 |
-
*/
|
| 90 |
-
@GetMapping("/search")
|
| 91 |
-
public ResponseEntity<Page<UserPublicDto>> search(
|
| 92 |
-
@RequestParam String term,
|
| 93 |
-
@RequestParam(defaultValue = "0") int page,
|
| 94 |
-
@RequestParam(defaultValue = "10") int size) {
|
| 95 |
-
Page<User> users = userQueryService.searchActiveUsers(term, page, size);
|
| 96 |
-
Page<UserPublicDto> result = users.map(userMapper::toUserPublicDto);
|
| 97 |
-
return ResponseEntity.ok(result);
|
| 98 |
-
}
|
| 99 |
-
}
|
| 100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/CategoryDto.java
DELETED
|
@@ -1,106 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto;
|
| 2 |
-
|
| 3 |
-
import com.fasterxml.jackson.annotation.JsonFormat;
|
| 4 |
-
import com.fasterxml.jackson.annotation.JsonProperty;
|
| 5 |
-
|
| 6 |
-
import java.time.LocalDateTime;
|
| 7 |
-
|
| 8 |
-
public class CategoryDto {
|
| 9 |
-
|
| 10 |
-
@JsonProperty("id")
|
| 11 |
-
private String id;
|
| 12 |
-
|
| 13 |
-
@JsonProperty("name")
|
| 14 |
-
private String name;
|
| 15 |
-
|
| 16 |
-
@JsonProperty("description")
|
| 17 |
-
private String description;
|
| 18 |
-
|
| 19 |
-
@JsonProperty("parent_category_id")
|
| 20 |
-
private String parentCategoryId;
|
| 21 |
-
|
| 22 |
-
@JsonProperty("parent_category_name")
|
| 23 |
-
private String parentCategoryName;
|
| 24 |
-
|
| 25 |
-
@JsonProperty("is_active")
|
| 26 |
-
private boolean isActive;
|
| 27 |
-
|
| 28 |
-
@JsonProperty("item_count")
|
| 29 |
-
private long itemCount;
|
| 30 |
-
|
| 31 |
-
@JsonProperty("has_subcategories")
|
| 32 |
-
private boolean hasSubcategories;
|
| 33 |
-
|
| 34 |
-
@JsonProperty("created_at")
|
| 35 |
-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
| 36 |
-
private LocalDateTime createdAt;
|
| 37 |
-
|
| 38 |
-
@JsonProperty("updated_at")
|
| 39 |
-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
| 40 |
-
private LocalDateTime updatedAt;
|
| 41 |
-
|
| 42 |
-
public CategoryDto() {}
|
| 43 |
-
|
| 44 |
-
public CategoryDto(String id, String name, String description, String parentCategoryId,
|
| 45 |
-
String parentCategoryName, boolean isActive, long itemCount,
|
| 46 |
-
boolean hasSubcategories, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
| 47 |
-
this.id = id;
|
| 48 |
-
this.name = name;
|
| 49 |
-
this.description = description;
|
| 50 |
-
this.parentCategoryId = parentCategoryId;
|
| 51 |
-
this.parentCategoryName = parentCategoryName;
|
| 52 |
-
this.isActive = isActive;
|
| 53 |
-
this.itemCount = itemCount;
|
| 54 |
-
this.hasSubcategories = hasSubcategories;
|
| 55 |
-
this.createdAt = createdAt;
|
| 56 |
-
this.updatedAt = updatedAt;
|
| 57 |
-
}
|
| 58 |
-
|
| 59 |
-
public static class Builder {
|
| 60 |
-
private CategoryDto categoryDto = new CategoryDto();
|
| 61 |
-
|
| 62 |
-
public Builder id(String id) { categoryDto.id = id; return this; }
|
| 63 |
-
public Builder name(String name) { categoryDto.name = name; return this; }
|
| 64 |
-
public Builder description(String description) { categoryDto.description = description; return this; }
|
| 65 |
-
public Builder parentCategoryId(String parentCategoryId) { categoryDto.parentCategoryId = parentCategoryId; return this; }
|
| 66 |
-
public Builder parentCategoryName(String parentCategoryName) { categoryDto.parentCategoryName = parentCategoryName; return this; }
|
| 67 |
-
public Builder isActive(boolean isActive) { categoryDto.isActive = isActive; return this; }
|
| 68 |
-
public Builder itemCount(long itemCount) { categoryDto.itemCount = itemCount; return this; }
|
| 69 |
-
public Builder hasSubcategories(boolean hasSubcategories) { categoryDto.hasSubcategories = hasSubcategories; return this; }
|
| 70 |
-
public Builder createdAt(LocalDateTime createdAt) { categoryDto.createdAt = createdAt; return this; }
|
| 71 |
-
public Builder updatedAt(LocalDateTime updatedAt) { categoryDto.updatedAt = updatedAt; return this; }
|
| 72 |
-
public CategoryDto build() { return categoryDto; }
|
| 73 |
-
}
|
| 74 |
-
|
| 75 |
-
public static Builder builder() { return new Builder(); }
|
| 76 |
-
|
| 77 |
-
public String getId() { return id; }
|
| 78 |
-
public void setId(String id) { this.id = id; }
|
| 79 |
-
|
| 80 |
-
public String getName() { return name; }
|
| 81 |
-
public void setName(String name) { this.name = name; }
|
| 82 |
-
|
| 83 |
-
public String getDescription() { return description; }
|
| 84 |
-
public void setDescription(String description) { this.description = description; }
|
| 85 |
-
|
| 86 |
-
public String getParentCategoryId() { return parentCategoryId; }
|
| 87 |
-
public void setParentCategoryId(String parentCategoryId) { this.parentCategoryId = parentCategoryId; }
|
| 88 |
-
|
| 89 |
-
public String getParentCategoryName() { return parentCategoryName; }
|
| 90 |
-
public void setParentCategoryName(String parentCategoryName) { this.parentCategoryName = parentCategoryName; }
|
| 91 |
-
|
| 92 |
-
public boolean isActive() { return isActive; }
|
| 93 |
-
public void setActive(boolean active) { isActive = active; }
|
| 94 |
-
|
| 95 |
-
public long getItemCount() { return itemCount; }
|
| 96 |
-
public void setItemCount(long itemCount) { this.itemCount = itemCount; }
|
| 97 |
-
|
| 98 |
-
public boolean isHasSubcategories() { return hasSubcategories; }
|
| 99 |
-
public void setHasSubcategories(boolean hasSubcategories) { this.hasSubcategories = hasSubcategories; }
|
| 100 |
-
|
| 101 |
-
public LocalDateTime getCreatedAt() { return createdAt; }
|
| 102 |
-
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
| 103 |
-
|
| 104 |
-
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
| 105 |
-
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
| 106 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/CreateCategoryRequest.java
DELETED
|
@@ -1,57 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto;
|
| 2 |
-
|
| 3 |
-
import com.fasterxml.jackson.annotation.JsonProperty;
|
| 4 |
-
import jakarta.validation.constraints.NotBlank;
|
| 5 |
-
import jakarta.validation.constraints.Size;
|
| 6 |
-
import jakarta.validation.constraints.Pattern;
|
| 7 |
-
|
| 8 |
-
public class CreateCategoryRequest {
|
| 9 |
-
|
| 10 |
-
@NotBlank(message = "Category name is required")
|
| 11 |
-
@Size(min = 2, max = 50, message = "Category name must be between 2 and 50 characters")
|
| 12 |
-
@Pattern(regexp = "^[a-zA-Z0-9\\s&-_.()]+$", message = "Category name contains invalid characters")
|
| 13 |
-
@JsonProperty("name")
|
| 14 |
-
private String name;
|
| 15 |
-
|
| 16 |
-
@Size(max = 200, message = "Description cannot exceed 200 characters")
|
| 17 |
-
@JsonProperty("description")
|
| 18 |
-
private String description;
|
| 19 |
-
|
| 20 |
-
@Size(max = 24, message = "Invalid parent category ID format")
|
| 21 |
-
@JsonProperty("parent_category_id")
|
| 22 |
-
private String parentCategoryId;
|
| 23 |
-
|
| 24 |
-
public CreateCategoryRequest() {}
|
| 25 |
-
|
| 26 |
-
public CreateCategoryRequest(String name, String description) {
|
| 27 |
-
this.name = name;
|
| 28 |
-
this.description = description;
|
| 29 |
-
}
|
| 30 |
-
|
| 31 |
-
public CreateCategoryRequest(String name, String description, String parentCategoryId) {
|
| 32 |
-
this.name = name;
|
| 33 |
-
this.description = description;
|
| 34 |
-
this.parentCategoryId = parentCategoryId;
|
| 35 |
-
}
|
| 36 |
-
|
| 37 |
-
public String getName() { return name; }
|
| 38 |
-
public void setName(String name) { this.name = name != null ? name.trim() : null; }
|
| 39 |
-
|
| 40 |
-
public String getDescription() { return description; }
|
| 41 |
-
public void setDescription(String description) { this.description = description != null ? description.trim() : null; }
|
| 42 |
-
|
| 43 |
-
public String getParentCategoryId() { return parentCategoryId; }
|
| 44 |
-
public void setParentCategoryId(String parentCategoryId) { this.parentCategoryId = parentCategoryId != null ? parentCategoryId.trim() : null; }
|
| 45 |
-
|
| 46 |
-
public boolean hasParentCategory() { return parentCategoryId != null && !parentCategoryId.isEmpty(); }
|
| 47 |
-
public boolean hasDescription() { return description != null && !description.isEmpty(); }
|
| 48 |
-
|
| 49 |
-
@Override
|
| 50 |
-
public String toString() {
|
| 51 |
-
return "CreateCategoryRequest{" +
|
| 52 |
-
"name='" + name + '\'' +
|
| 53 |
-
", description='" + description + '\'' +
|
| 54 |
-
", parentCategoryId='" + parentCategoryId + '\'' +
|
| 55 |
-
'}';
|
| 56 |
-
}
|
| 57 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/CreateItemRequest.java
DELETED
|
@@ -1,49 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto;
|
| 2 |
-
|
| 3 |
-
import jakarta.validation.constraints.DecimalMin;
|
| 4 |
-
import jakarta.validation.constraints.NotBlank;
|
| 5 |
-
import jakarta.validation.constraints.NotNull;
|
| 6 |
-
import jakarta.validation.constraints.Size;
|
| 7 |
-
|
| 8 |
-
import java.util.List;
|
| 9 |
-
|
| 10 |
-
public class CreateItemRequest {
|
| 11 |
-
|
| 12 |
-
@NotBlank
|
| 13 |
-
@Size(min = 3, max = 100)
|
| 14 |
-
private String name;
|
| 15 |
-
|
| 16 |
-
@Size(max = 500)
|
| 17 |
-
private String description;
|
| 18 |
-
|
| 19 |
-
@NotNull
|
| 20 |
-
private String categoryId;
|
| 21 |
-
|
| 22 |
-
@DecimalMin(value = "0.0", inclusive = true)
|
| 23 |
-
private Double deposit = 0.0;
|
| 24 |
-
|
| 25 |
-
private List<String> images;
|
| 26 |
-
|
| 27 |
-
private String condition; // NEW|EXCELLENT|GOOD|FAIR|POOR
|
| 28 |
-
|
| 29 |
-
public CreateItemRequest() {}
|
| 30 |
-
|
| 31 |
-
// Getters and setters
|
| 32 |
-
public String getName() { return name; }
|
| 33 |
-
public void setName(String name) { this.name = name; }
|
| 34 |
-
|
| 35 |
-
public String getDescription() { return description; }
|
| 36 |
-
public void setDescription(String description) { this.description = description; }
|
| 37 |
-
|
| 38 |
-
public String getCategoryId() { return categoryId; }
|
| 39 |
-
public void setCategoryId(String categoryId) { this.categoryId = categoryId; }
|
| 40 |
-
|
| 41 |
-
public Double getDeposit() { return deposit; }
|
| 42 |
-
public void setDeposit(Double deposit) { this.deposit = deposit; }
|
| 43 |
-
|
| 44 |
-
public List<String> getImages() { return images; }
|
| 45 |
-
public void setImages(List<String> images) { this.images = images; }
|
| 46 |
-
|
| 47 |
-
public String getCondition() { return condition; }
|
| 48 |
-
public void setCondition(String condition) { this.condition = condition; }
|
| 49 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/ItemDTO.java
DELETED
|
@@ -1,68 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto;
|
| 2 |
-
|
| 3 |
-
import java.time.LocalDateTime;
|
| 4 |
-
import java.util.List;
|
| 5 |
-
|
| 6 |
-
public class ItemDTO {
|
| 7 |
-
private String id;
|
| 8 |
-
private String name;
|
| 9 |
-
private String description;
|
| 10 |
-
private String condition;
|
| 11 |
-
private String status;
|
| 12 |
-
private double deposit;
|
| 13 |
-
private List<String> images;
|
| 14 |
-
private double averageRating;
|
| 15 |
-
private String ownerId;
|
| 16 |
-
private String ownerName;
|
| 17 |
-
private String categoryId;
|
| 18 |
-
private String categoryName;
|
| 19 |
-
private boolean canBeBorrowed;
|
| 20 |
-
private LocalDateTime createdAt;
|
| 21 |
-
private LocalDateTime updatedAt;
|
| 22 |
-
|
| 23 |
-
// Getters and setters
|
| 24 |
-
public String getId() { return id; }
|
| 25 |
-
public void setId(String id) { this.id = id; }
|
| 26 |
-
|
| 27 |
-
public String getName() { return name; }
|
| 28 |
-
public void setName(String name) { this.name = name; }
|
| 29 |
-
|
| 30 |
-
public String getDescription() { return description; }
|
| 31 |
-
public void setDescription(String description) { this.description = description; }
|
| 32 |
-
|
| 33 |
-
public String getCondition() { return condition; }
|
| 34 |
-
public void setCondition(String condition) { this.condition = condition; }
|
| 35 |
-
|
| 36 |
-
public String getStatus() { return status; }
|
| 37 |
-
public void setStatus(String status) { this.status = status; }
|
| 38 |
-
|
| 39 |
-
public double getDeposit() { return deposit; }
|
| 40 |
-
public void setDeposit(double deposit) { this.deposit = deposit; }
|
| 41 |
-
|
| 42 |
-
public List<String> getImages() { return images; }
|
| 43 |
-
public void setImages(List<String> images) { this.images = images; }
|
| 44 |
-
|
| 45 |
-
public double getAverageRating() { return averageRating; }
|
| 46 |
-
public void setAverageRating(double averageRating) { this.averageRating = averageRating; }
|
| 47 |
-
|
| 48 |
-
public String getOwnerId() { return ownerId; }
|
| 49 |
-
public void setOwnerId(String ownerId) { this.ownerId = ownerId; }
|
| 50 |
-
|
| 51 |
-
public String getOwnerName() { return ownerName; }
|
| 52 |
-
public void setOwnerName(String ownerName) { this.ownerName = ownerName; }
|
| 53 |
-
|
| 54 |
-
public String getCategoryId() { return categoryId; }
|
| 55 |
-
public void setCategoryId(String categoryId) { this.categoryId = categoryId; }
|
| 56 |
-
|
| 57 |
-
public String getCategoryName() { return categoryName; }
|
| 58 |
-
public void setCategoryName(String categoryName) { this.categoryName = categoryName; }
|
| 59 |
-
|
| 60 |
-
public boolean isCanBeBorrowed() { return canBeBorrowed; }
|
| 61 |
-
public void setCanBeBorrowed(boolean canBeBorrowed) { this.canBeBorrowed = canBeBorrowed; }
|
| 62 |
-
|
| 63 |
-
public LocalDateTime getCreatedAt() { return createdAt; }
|
| 64 |
-
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
| 65 |
-
|
| 66 |
-
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
| 67 |
-
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
| 68 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/UpdateItemRequest.java
DELETED
|
@@ -1,33 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto;
|
| 2 |
-
|
| 3 |
-
import java.util.List;
|
| 4 |
-
|
| 5 |
-
public class UpdateItemRequest {
|
| 6 |
-
private String name;
|
| 7 |
-
private String description;
|
| 8 |
-
private String condition;
|
| 9 |
-
private Double deposit;
|
| 10 |
-
private List<String> images;
|
| 11 |
-
private Boolean isAvailable;
|
| 12 |
-
|
| 13 |
-
public UpdateItemRequest() {}
|
| 14 |
-
|
| 15 |
-
// Getters and setters
|
| 16 |
-
public String getName() { return name; }
|
| 17 |
-
public void setName(String name) { this.name = name; }
|
| 18 |
-
|
| 19 |
-
public String getDescription() { return description; }
|
| 20 |
-
public void setDescription(String description) { this.description = description; }
|
| 21 |
-
|
| 22 |
-
public String getCondition() { return condition; }
|
| 23 |
-
public void setCondition(String condition) { this.condition = condition; }
|
| 24 |
-
|
| 25 |
-
public Double getDeposit() { return deposit; }
|
| 26 |
-
public void setDeposit(Double deposit) { this.deposit = deposit; }
|
| 27 |
-
|
| 28 |
-
public List<String> getImages() { return images; }
|
| 29 |
-
public void setImages(List<String> images) { this.images = images; }
|
| 30 |
-
|
| 31 |
-
public Boolean getIsAvailable() { return isAvailable; }
|
| 32 |
-
public void setIsAvailable(Boolean isAvailable) { this.isAvailable = isAvailable; }
|
| 33 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/request/BookingRequestDto.java
DELETED
|
@@ -1,78 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.request;
|
| 2 |
-
|
| 3 |
-
import jakarta.validation.constraints.*;
|
| 4 |
-
import java.time.LocalDateTime;
|
| 5 |
-
|
| 6 |
-
/**
|
| 7 |
-
* DTO for creating new bookings in the LocalLend platform.
|
| 8 |
-
*/
|
| 9 |
-
public class BookingRequestDto {
|
| 10 |
-
|
| 11 |
-
@NotBlank(message = "Item ID is required")
|
| 12 |
-
private String itemId;
|
| 13 |
-
|
| 14 |
-
@NotNull(message = "Start date is required")
|
| 15 |
-
@Future(message = "Start date must be in the future")
|
| 16 |
-
private LocalDateTime startDate;
|
| 17 |
-
|
| 18 |
-
@NotNull(message = "End date is required")
|
| 19 |
-
private LocalDateTime endDate;
|
| 20 |
-
|
| 21 |
-
@Size(max = 500, message = "Booking notes cannot exceed 500 characters")
|
| 22 |
-
private String bookingNotes;
|
| 23 |
-
|
| 24 |
-
@DecimalMin(value = "0.0", message = "Deposit amount cannot be negative")
|
| 25 |
-
@DecimalMax(value = "10000.0", message = "Deposit amount cannot exceed 10,000")
|
| 26 |
-
private Double depositAmount;
|
| 27 |
-
|
| 28 |
-
@Min(value = 1, message = "Duration must be at least 1 day")
|
| 29 |
-
@Max(value = 365, message = "Duration cannot exceed 365 days")
|
| 30 |
-
private Integer requestedDurationDays;
|
| 31 |
-
|
| 32 |
-
private Boolean acceptTerms = false;
|
| 33 |
-
|
| 34 |
-
public BookingRequestDto() {}
|
| 35 |
-
|
| 36 |
-
public BookingRequestDto(String itemId, LocalDateTime startDate, LocalDateTime endDate) {
|
| 37 |
-
this.itemId = itemId;
|
| 38 |
-
this.startDate = startDate;
|
| 39 |
-
this.endDate = endDate;
|
| 40 |
-
}
|
| 41 |
-
|
| 42 |
-
@AssertTrue(message = "End date must be after start date")
|
| 43 |
-
public boolean isValidDateRange() {
|
| 44 |
-
if (startDate == null || endDate == null) return true;
|
| 45 |
-
return endDate.isAfter(startDate);
|
| 46 |
-
}
|
| 47 |
-
|
| 48 |
-
@AssertTrue(message = "Must accept terms and conditions")
|
| 49 |
-
public boolean isTermsAccepted() {
|
| 50 |
-
return acceptTerms != null && acceptTerms;
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
public String getItemId() { return itemId; }
|
| 54 |
-
public void setItemId(String itemId) { this.itemId = itemId; }
|
| 55 |
-
public LocalDateTime getStartDate() { return startDate; }
|
| 56 |
-
public void setStartDate(LocalDateTime startDate) { this.startDate = startDate; }
|
| 57 |
-
public LocalDateTime getEndDate() { return endDate; }
|
| 58 |
-
public void setEndDate(LocalDateTime endDate) { this.endDate = endDate; }
|
| 59 |
-
public String getBookingNotes() { return bookingNotes; }
|
| 60 |
-
public void setBookingNotes(String bookingNotes) { this.bookingNotes = bookingNotes; }
|
| 61 |
-
public Double getDepositAmount() { return depositAmount; }
|
| 62 |
-
public void setDepositAmount(Double depositAmount) { this.depositAmount = depositAmount; }
|
| 63 |
-
public Integer getRequestedDurationDays() { return requestedDurationDays; }
|
| 64 |
-
public void setRequestedDurationDays(Integer requestedDurationDays) { this.requestedDurationDays = requestedDurationDays; }
|
| 65 |
-
public Boolean getAcceptTerms() { return acceptTerms; }
|
| 66 |
-
public void setAcceptTerms(Boolean acceptTerms) { this.acceptTerms = acceptTerms; }
|
| 67 |
-
|
| 68 |
-
@Override
|
| 69 |
-
public String toString() {
|
| 70 |
-
return "BookingRequestDto{" +
|
| 71 |
-
"itemId='" + itemId + '\'' +
|
| 72 |
-
", startDate=" + startDate +
|
| 73 |
-
", endDate=" + endDate +
|
| 74 |
-
", requestedDurationDays=" + requestedDurationDays +
|
| 75 |
-
", acceptTerms=" + acceptTerms +
|
| 76 |
-
'}';
|
| 77 |
-
}
|
| 78 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/request/ItemRequestDto.java
DELETED
|
@@ -1,60 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.request;
|
| 2 |
-
|
| 3 |
-
import com.fasterxml.jackson.annotation.JsonProperty;
|
| 4 |
-
import jakarta.validation.constraints.Min;
|
| 5 |
-
import jakarta.validation.constraints.NotBlank;
|
| 6 |
-
import jakarta.validation.constraints.Size;
|
| 7 |
-
|
| 8 |
-
import java.util.List;
|
| 9 |
-
|
| 10 |
-
public class ItemRequestDto {
|
| 11 |
-
|
| 12 |
-
@NotBlank(message = "Item name is required")
|
| 13 |
-
@Size(min = 2, max = 100)
|
| 14 |
-
@JsonProperty("name")
|
| 15 |
-
private String name;
|
| 16 |
-
|
| 17 |
-
@Size(max = 1000)
|
| 18 |
-
@JsonProperty("description")
|
| 19 |
-
private String description;
|
| 20 |
-
|
| 21 |
-
@JsonProperty("condition")
|
| 22 |
-
private String condition;
|
| 23 |
-
|
| 24 |
-
@Min(value = 0, message = "Deposit must be non-negative")
|
| 25 |
-
@JsonProperty("deposit")
|
| 26 |
-
private double deposit = 0.0;
|
| 27 |
-
|
| 28 |
-
@JsonProperty("images")
|
| 29 |
-
private List<String> images;
|
| 30 |
-
|
| 31 |
-
@JsonProperty("category_id")
|
| 32 |
-
private String categoryId;
|
| 33 |
-
|
| 34 |
-
@JsonProperty("owner_id")
|
| 35 |
-
private String ownerId;
|
| 36 |
-
|
| 37 |
-
public ItemRequestDto() {}
|
| 38 |
-
|
| 39 |
-
// Getters and setters
|
| 40 |
-
public String getName() { return name; }
|
| 41 |
-
public void setName(String name) { this.name = name; }
|
| 42 |
-
|
| 43 |
-
public String getDescription() { return description; }
|
| 44 |
-
public void setDescription(String description) { this.description = description; }
|
| 45 |
-
|
| 46 |
-
public String getCondition() { return condition; }
|
| 47 |
-
public void setCondition(String condition) { this.condition = condition; }
|
| 48 |
-
|
| 49 |
-
public double getDeposit() { return deposit; }
|
| 50 |
-
public void setDeposit(double deposit) { this.deposit = deposit; }
|
| 51 |
-
|
| 52 |
-
public List<String> getImages() { return images; }
|
| 53 |
-
public void setImages(List<String> images) { this.images = images; }
|
| 54 |
-
|
| 55 |
-
public String getCategoryId() { return categoryId; }
|
| 56 |
-
public void setCategoryId(String categoryId) { this.categoryId = categoryId; }
|
| 57 |
-
|
| 58 |
-
public String getOwnerId() { return ownerId; }
|
| 59 |
-
public void setOwnerId(String ownerId) { this.ownerId = ownerId; }
|
| 60 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/request/ItemUpdateDto.java
DELETED
|
@@ -1,49 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.request;
|
| 2 |
-
|
| 3 |
-
import com.fasterxml.jackson.annotation.JsonProperty;
|
| 4 |
-
|
| 5 |
-
import java.util.List;
|
| 6 |
-
|
| 7 |
-
/**
|
| 8 |
-
* Partial update DTO for Item
|
| 9 |
-
*/
|
| 10 |
-
public class ItemUpdateDto {
|
| 11 |
-
|
| 12 |
-
@JsonProperty("name")
|
| 13 |
-
private String name;
|
| 14 |
-
|
| 15 |
-
@JsonProperty("description")
|
| 16 |
-
private String description;
|
| 17 |
-
|
| 18 |
-
@JsonProperty("condition")
|
| 19 |
-
private String condition;
|
| 20 |
-
|
| 21 |
-
@JsonProperty("deposit")
|
| 22 |
-
private Double deposit;
|
| 23 |
-
|
| 24 |
-
@JsonProperty("images")
|
| 25 |
-
private List<String> images;
|
| 26 |
-
|
| 27 |
-
@JsonProperty("status")
|
| 28 |
-
private String status;
|
| 29 |
-
|
| 30 |
-
public ItemUpdateDto() {}
|
| 31 |
-
|
| 32 |
-
public String getName() { return name; }
|
| 33 |
-
public void setName(String name) { this.name = name; }
|
| 34 |
-
|
| 35 |
-
public String getDescription() { return description; }
|
| 36 |
-
public void setDescription(String description) { this.description = description; }
|
| 37 |
-
|
| 38 |
-
public String getCondition() { return condition; }
|
| 39 |
-
public void setCondition(String condition) { this.condition = condition; }
|
| 40 |
-
|
| 41 |
-
public Double getDeposit() { return deposit; }
|
| 42 |
-
public void setDeposit(Double deposit) { this.deposit = deposit; }
|
| 43 |
-
|
| 44 |
-
public List<String> getImages() { return images; }
|
| 45 |
-
public void setImages(List<String> images) { this.images = images; }
|
| 46 |
-
|
| 47 |
-
public String getStatus() { return status; }
|
| 48 |
-
public void setStatus(String status) { this.status = status; }
|
| 49 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/request/RatingCreateDto.java
DELETED
|
@@ -1,71 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.request;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.model.RatingType;
|
| 4 |
-
import jakarta.validation.constraints.*;
|
| 5 |
-
|
| 6 |
-
/**
|
| 7 |
-
* DTO for creating a new rating.
|
| 8 |
-
* Includes validation for rating values and cross-field validation for item ratings.
|
| 9 |
-
* Issue #23: Rating Entity, Repository, DTO
|
| 10 |
-
*/
|
| 11 |
-
public class RatingCreateDto {
|
| 12 |
-
|
| 13 |
-
@NotBlank(message = "Ratee ID is required")
|
| 14 |
-
private String rateeId;
|
| 15 |
-
|
| 16 |
-
private String itemId;
|
| 17 |
-
private String bookingId;
|
| 18 |
-
|
| 19 |
-
@NotNull(message = "Rating type is required")
|
| 20 |
-
private RatingType ratingType;
|
| 21 |
-
|
| 22 |
-
@NotNull(message = "Rating value is required")
|
| 23 |
-
@Min(value = 1, message = "Rating must be between 1 and 5")
|
| 24 |
-
@Max(value = 5, message = "Rating must be between 1 and 5")
|
| 25 |
-
private Integer ratingValue;
|
| 26 |
-
|
| 27 |
-
@Size(max = 1000, message = "Comment cannot exceed 1000 characters")
|
| 28 |
-
private String comment;
|
| 29 |
-
|
| 30 |
-
private Boolean isAnonymous = false;
|
| 31 |
-
|
| 32 |
-
// Constructors
|
| 33 |
-
public RatingCreateDto() {}
|
| 34 |
-
|
| 35 |
-
public RatingCreateDto(String rateeId, RatingType ratingType, Integer ratingValue) {
|
| 36 |
-
this.rateeId = rateeId;
|
| 37 |
-
this.ratingType = ratingType;
|
| 38 |
-
this.ratingValue = ratingValue;
|
| 39 |
-
}
|
| 40 |
-
|
| 41 |
-
// Cross-field validation
|
| 42 |
-
@AssertTrue(message = "Item ID is required for item ratings")
|
| 43 |
-
public boolean isItemIdValidForType() {
|
| 44 |
-
if (ratingType == RatingType.USER_TO_ITEM) {
|
| 45 |
-
return itemId != null && !itemId.trim().isEmpty();
|
| 46 |
-
}
|
| 47 |
-
return true;
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
// Getters and Setters
|
| 51 |
-
public String getRateeId() { return rateeId; }
|
| 52 |
-
public void setRateeId(String rateeId) { this.rateeId = rateeId; }
|
| 53 |
-
|
| 54 |
-
public String getItemId() { return itemId; }
|
| 55 |
-
public void setItemId(String itemId) { this.itemId = itemId; }
|
| 56 |
-
|
| 57 |
-
public String getBookingId() { return bookingId; }
|
| 58 |
-
public void setBookingId(String bookingId) { this.bookingId = bookingId; }
|
| 59 |
-
|
| 60 |
-
public RatingType getRatingType() { return ratingType; }
|
| 61 |
-
public void setRatingType(RatingType ratingType) { this.ratingType = ratingType; }
|
| 62 |
-
|
| 63 |
-
public Integer getRatingValue() { return ratingValue; }
|
| 64 |
-
public void setRatingValue(Integer ratingValue) { this.ratingValue = ratingValue; }
|
| 65 |
-
|
| 66 |
-
public String getComment() { return comment; }
|
| 67 |
-
public void setComment(String comment) { this.comment = comment; }
|
| 68 |
-
|
| 69 |
-
public Boolean getIsAnonymous() { return isAnonymous; }
|
| 70 |
-
public void setIsAnonymous(Boolean isAnonymous) { this.isAnonymous = isAnonymous; }
|
| 71 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/request/UserLoginDto.java
DELETED
|
@@ -1,33 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.request;
|
| 2 |
-
|
| 3 |
-
import jakarta.validation.constraints.NotBlank;
|
| 4 |
-
|
| 5 |
-
/**
|
| 6 |
-
* DTO for user login request.
|
| 7 |
-
*/
|
| 8 |
-
public class UserLoginDto {
|
| 9 |
-
@NotBlank(message = "Username or email is required")
|
| 10 |
-
private String usernameOrEmail;
|
| 11 |
-
|
| 12 |
-
@NotBlank(message = "Password is required")
|
| 13 |
-
private String password;
|
| 14 |
-
|
| 15 |
-
public UserLoginDto() {}
|
| 16 |
-
|
| 17 |
-
// Getters and Setters
|
| 18 |
-
public String getUsernameOrEmail() {
|
| 19 |
-
return usernameOrEmail;
|
| 20 |
-
}
|
| 21 |
-
|
| 22 |
-
public void setUsernameOrEmail(String usernameOrEmail) {
|
| 23 |
-
this.usernameOrEmail = usernameOrEmail;
|
| 24 |
-
}
|
| 25 |
-
|
| 26 |
-
public String getPassword() {
|
| 27 |
-
return password;
|
| 28 |
-
}
|
| 29 |
-
|
| 30 |
-
public void setPassword(String password) {
|
| 31 |
-
this.password = password;
|
| 32 |
-
}
|
| 33 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/request/UserRegistrationDto.java
DELETED
|
@@ -1,71 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.request;
|
| 2 |
-
|
| 3 |
-
import jakarta.validation.constraints.Email;
|
| 4 |
-
import jakarta.validation.constraints.NotBlank;
|
| 5 |
-
import jakarta.validation.constraints.Size;
|
| 6 |
-
|
| 7 |
-
/**
|
| 8 |
-
* DTO for user registration request.
|
| 9 |
-
*/
|
| 10 |
-
public class UserRegistrationDto {
|
| 11 |
-
@NotBlank(message = "Username is required")
|
| 12 |
-
@Size(min = 3, max = 50, message = "Username must be between 3 and 50 characters")
|
| 13 |
-
private String username;
|
| 14 |
-
|
| 15 |
-
@NotBlank(message = "Name is required")
|
| 16 |
-
@Size(min = 2, max = 100, message = "Name must be between 2 and 100 characters")
|
| 17 |
-
private String name;
|
| 18 |
-
|
| 19 |
-
@NotBlank(message = "Email is required")
|
| 20 |
-
@Email(message = "Email must be valid")
|
| 21 |
-
private String email;
|
| 22 |
-
|
| 23 |
-
@NotBlank(message = "Password is required")
|
| 24 |
-
@Size(min = 8, message = "Password must be at least 8 characters")
|
| 25 |
-
private String password;
|
| 26 |
-
|
| 27 |
-
private String phoneNumber;
|
| 28 |
-
|
| 29 |
-
public UserRegistrationDto() {}
|
| 30 |
-
|
| 31 |
-
// Getters and Setters
|
| 32 |
-
public String getUsername() {
|
| 33 |
-
return username;
|
| 34 |
-
}
|
| 35 |
-
|
| 36 |
-
public void setUsername(String username) {
|
| 37 |
-
this.username = username;
|
| 38 |
-
}
|
| 39 |
-
|
| 40 |
-
public String getName() {
|
| 41 |
-
return name;
|
| 42 |
-
}
|
| 43 |
-
|
| 44 |
-
public void setName(String name) {
|
| 45 |
-
this.name = name;
|
| 46 |
-
}
|
| 47 |
-
|
| 48 |
-
public String getEmail() {
|
| 49 |
-
return email;
|
| 50 |
-
}
|
| 51 |
-
|
| 52 |
-
public void setEmail(String email) {
|
| 53 |
-
this.email = email;
|
| 54 |
-
}
|
| 55 |
-
|
| 56 |
-
public String getPassword() {
|
| 57 |
-
return password;
|
| 58 |
-
}
|
| 59 |
-
|
| 60 |
-
public void setPassword(String password) {
|
| 61 |
-
this.password = password;
|
| 62 |
-
}
|
| 63 |
-
|
| 64 |
-
public String getPhoneNumber() {
|
| 65 |
-
return phoneNumber;
|
| 66 |
-
}
|
| 67 |
-
|
| 68 |
-
public void setPhoneNumber(String phoneNumber) {
|
| 69 |
-
this.phoneNumber = phoneNumber;
|
| 70 |
-
}
|
| 71 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/request/UserUpdateDto.java
DELETED
|
@@ -1,42 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.request;
|
| 2 |
-
|
| 3 |
-
import jakarta.validation.constraints.Size;
|
| 4 |
-
|
| 5 |
-
/**
|
| 6 |
-
* DTO for user profile update requests.
|
| 7 |
-
*/
|
| 8 |
-
public class UserUpdateDto {
|
| 9 |
-
@Size(min = 2, max = 100, message = "Name must be between 2 and 100 characters")
|
| 10 |
-
private String name;
|
| 11 |
-
|
| 12 |
-
private String phoneNumber;
|
| 13 |
-
|
| 14 |
-
private String profileImageUrl;
|
| 15 |
-
|
| 16 |
-
public UserUpdateDto() {}
|
| 17 |
-
|
| 18 |
-
// Getters and Setters
|
| 19 |
-
public String getName() {
|
| 20 |
-
return name;
|
| 21 |
-
}
|
| 22 |
-
|
| 23 |
-
public void setName(String name) {
|
| 24 |
-
this.name = name;
|
| 25 |
-
}
|
| 26 |
-
|
| 27 |
-
public String getPhoneNumber() {
|
| 28 |
-
return phoneNumber;
|
| 29 |
-
}
|
| 30 |
-
|
| 31 |
-
public void setPhoneNumber(String phoneNumber) {
|
| 32 |
-
this.phoneNumber = phoneNumber;
|
| 33 |
-
}
|
| 34 |
-
|
| 35 |
-
public String getProfileImageUrl() {
|
| 36 |
-
return profileImageUrl;
|
| 37 |
-
}
|
| 38 |
-
|
| 39 |
-
public void setProfileImageUrl(String profileImageUrl) {
|
| 40 |
-
this.profileImageUrl = profileImageUrl;
|
| 41 |
-
}
|
| 42 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/response/BookingResponseDto.java
DELETED
|
@@ -1,138 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.response;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.model.enums.BookingStatus;
|
| 4 |
-
import java.time.LocalDateTime;
|
| 5 |
-
|
| 6 |
-
/**
|
| 7 |
-
* DTO for returning complete booking information to API consumers.
|
| 8 |
-
*/
|
| 9 |
-
public class BookingResponseDto {
|
| 10 |
-
|
| 11 |
-
private String id;
|
| 12 |
-
private String itemId;
|
| 13 |
-
private String itemName;
|
| 14 |
-
private String itemImageUrl;
|
| 15 |
-
private String borrowerId;
|
| 16 |
-
private String borrowerName;
|
| 17 |
-
private String ownerId;
|
| 18 |
-
private String ownerName;
|
| 19 |
-
private BookingStatus status;
|
| 20 |
-
private LocalDateTime startDate;
|
| 21 |
-
private LocalDateTime endDate;
|
| 22 |
-
private LocalDateTime actualStartDate;
|
| 23 |
-
private LocalDateTime actualEndDate;
|
| 24 |
-
private String bookingNotes;
|
| 25 |
-
private String ownerNotes;
|
| 26 |
-
private Double depositAmount;
|
| 27 |
-
private Boolean depositPaid;
|
| 28 |
-
private LocalDateTime createdDate;
|
| 29 |
-
private LocalDateTime updatedDate;
|
| 30 |
-
private LocalDateTime confirmedDate;
|
| 31 |
-
private LocalDateTime pickupDate;
|
| 32 |
-
private LocalDateTime returnDate;
|
| 33 |
-
private LocalDateTime cancelledDate;
|
| 34 |
-
private String cancellationReason;
|
| 35 |
-
private Boolean isRated;
|
| 36 |
-
private Integer durationDays;
|
| 37 |
-
|
| 38 |
-
// Computed fields
|
| 39 |
-
private String statusDescription;
|
| 40 |
-
private String timeAgo;
|
| 41 |
-
private Long daysUntilStart;
|
| 42 |
-
private Long daysUntilEnd;
|
| 43 |
-
private Boolean canBeCancelled;
|
| 44 |
-
private Boolean canBeConfirmed;
|
| 45 |
-
private Boolean canBeActivated;
|
| 46 |
-
private Boolean canBeCompleted;
|
| 47 |
-
private Boolean isOverdue;
|
| 48 |
-
private Boolean requiresDeposit;
|
| 49 |
-
|
| 50 |
-
public BookingResponseDto() {}
|
| 51 |
-
|
| 52 |
-
public String getId() { return id; }
|
| 53 |
-
public void setId(String id) { this.id = id; }
|
| 54 |
-
public String getItemId() { return itemId; }
|
| 55 |
-
public void setItemId(String itemId) { this.itemId = itemId; }
|
| 56 |
-
public String getItemName() { return itemName; }
|
| 57 |
-
public void setItemName(String itemName) { this.itemName = itemName; }
|
| 58 |
-
public String getItemImageUrl() { return itemImageUrl; }
|
| 59 |
-
public void setItemImageUrl(String itemImageUrl) { this.itemImageUrl = itemImageUrl; }
|
| 60 |
-
public String getBorrowerId() { return borrowerId; }
|
| 61 |
-
public void setBorrowerId(String borrowerId) { this.borrowerId = borrowerId; }
|
| 62 |
-
public String getBorrowerName() { return borrowerName; }
|
| 63 |
-
public void setBorrowerName(String borrowerName) { this.borrowerName = borrowerName; }
|
| 64 |
-
public String getOwnerId() { return ownerId; }
|
| 65 |
-
public void setOwnerId(String ownerId) { this.ownerId = ownerId; }
|
| 66 |
-
public String getOwnerName() { return ownerName; }
|
| 67 |
-
public void setOwnerName(String ownerName) { this.ownerName = ownerName; }
|
| 68 |
-
public BookingStatus getStatus() { return status; }
|
| 69 |
-
public void setStatus(BookingStatus status) { this.status = status; }
|
| 70 |
-
public LocalDateTime getStartDate() { return startDate; }
|
| 71 |
-
public void setStartDate(LocalDateTime startDate) { this.startDate = startDate; }
|
| 72 |
-
public LocalDateTime getEndDate() { return endDate; }
|
| 73 |
-
public void setEndDate(LocalDateTime endDate) { this.endDate = endDate; }
|
| 74 |
-
public LocalDateTime getActualStartDate() { return actualStartDate; }
|
| 75 |
-
public void setActualStartDate(LocalDateTime actualStartDate) { this.actualStartDate = actualStartDate; }
|
| 76 |
-
public LocalDateTime getActualEndDate() { return actualEndDate; }
|
| 77 |
-
public void setActualEndDate(LocalDateTime actualEndDate) { this.actualEndDate = actualEndDate; }
|
| 78 |
-
public String getBookingNotes() { return bookingNotes; }
|
| 79 |
-
public void setBookingNotes(String bookingNotes) { this.bookingNotes = bookingNotes; }
|
| 80 |
-
public String getOwnerNotes() { return ownerNotes; }
|
| 81 |
-
public void setOwnerNotes(String ownerNotes) { this.ownerNotes = ownerNotes; }
|
| 82 |
-
public Double getDepositAmount() { return depositAmount; }
|
| 83 |
-
public void setDepositAmount(Double depositAmount) { this.depositAmount = depositAmount; }
|
| 84 |
-
public Boolean getDepositPaid() { return depositPaid; }
|
| 85 |
-
public void setDepositPaid(Boolean depositPaid) { this.depositPaid = depositPaid; }
|
| 86 |
-
public LocalDateTime getCreatedDate() { return createdDate; }
|
| 87 |
-
public void setCreatedDate(LocalDateTime createdDate) { this.createdDate = createdDate; }
|
| 88 |
-
public LocalDateTime getUpdatedDate() { return updatedDate; }
|
| 89 |
-
public void setUpdatedDate(LocalDateTime updatedDate) { this.updatedDate = updatedDate; }
|
| 90 |
-
public LocalDateTime getConfirmedDate() { return confirmedDate; }
|
| 91 |
-
public void setConfirmedDate(LocalDateTime confirmedDate) { this.confirmedDate = confirmedDate; }
|
| 92 |
-
public LocalDateTime getPickupDate() { return pickupDate; }
|
| 93 |
-
public void setPickupDate(LocalDateTime pickupDate) { this.pickupDate = pickupDate; }
|
| 94 |
-
public LocalDateTime getReturnDate() { return returnDate; }
|
| 95 |
-
public void setReturnDate(LocalDateTime returnDate) { this.returnDate = returnDate; }
|
| 96 |
-
public LocalDateTime getCancelledDate() { return cancelledDate; }
|
| 97 |
-
public void setCancelledDate(LocalDateTime cancelledDate) { this.cancelledDate = cancelledDate; }
|
| 98 |
-
public String getCancellationReason() { return cancellationReason; }
|
| 99 |
-
public void setCancellationReason(String cancellationReason) { this.cancellationReason = cancellationReason; }
|
| 100 |
-
public Boolean getIsRated() { return isRated; }
|
| 101 |
-
public void setIsRated(Boolean isRated) { this.isRated = isRated; }
|
| 102 |
-
public Integer getDurationDays() { return durationDays; }
|
| 103 |
-
public void setDurationDays(Integer durationDays) { this.durationDays = durationDays; }
|
| 104 |
-
public String getStatusDescription() { return statusDescription; }
|
| 105 |
-
public void setStatusDescription(String statusDescription) { this.statusDescription = statusDescription; }
|
| 106 |
-
public String getTimeAgo() { return timeAgo; }
|
| 107 |
-
public void setTimeAgo(String timeAgo) { this.timeAgo = timeAgo; }
|
| 108 |
-
public Long getDaysUntilStart() { return daysUntilStart; }
|
| 109 |
-
public void setDaysUntilStart(Long daysUntilStart) { this.daysUntilStart = daysUntilStart; }
|
| 110 |
-
public Long getDaysUntilEnd() { return daysUntilEnd; }
|
| 111 |
-
public void setDaysUntilEnd(Long daysUntilEnd) { this.daysUntilEnd = daysUntilEnd; }
|
| 112 |
-
public Boolean getCanBeCancelled() { return canBeCancelled; }
|
| 113 |
-
public void setCanBeCancelled(Boolean canBeCancelled) { this.canBeCancelled = canBeCancelled; }
|
| 114 |
-
public Boolean getCanBeConfirmed() { return canBeConfirmed; }
|
| 115 |
-
public void setCanBeConfirmed(Boolean canBeConfirmed) { this.canBeConfirmed = canBeConfirmed; }
|
| 116 |
-
public Boolean getCanBeActivated() { return canBeActivated; }
|
| 117 |
-
public void setCanBeActivated(Boolean canBeActivated) { this.canBeActivated = canBeActivated; }
|
| 118 |
-
public Boolean getCanBeCompleted() { return canBeCompleted; }
|
| 119 |
-
public void setCanBeCompleted(Boolean canBeCompleted) { this.canBeCompleted = canBeCompleted; }
|
| 120 |
-
public Boolean getIsOverdue() { return isOverdue; }
|
| 121 |
-
public void setIsOverdue(Boolean isOverdue) { this.isOverdue = isOverdue; }
|
| 122 |
-
public Boolean getRequiresDeposit() { return requiresDeposit; }
|
| 123 |
-
public void setRequiresDeposit(Boolean requiresDeposit) { this.requiresDeposit = requiresDeposit; }
|
| 124 |
-
|
| 125 |
-
@Override
|
| 126 |
-
public String toString() {
|
| 127 |
-
return "BookingResponseDto{" +
|
| 128 |
-
"id='" + id + '\'' +
|
| 129 |
-
", itemId='" + itemId + '\'' +
|
| 130 |
-
", borrowerId='" + borrowerId + '\'' +
|
| 131 |
-
", ownerId='" + ownerId + '\'' +
|
| 132 |
-
", status=" + status +
|
| 133 |
-
", startDate=" + startDate +
|
| 134 |
-
", endDate=" + endDate +
|
| 135 |
-
", durationDays=" + durationDays +
|
| 136 |
-
'}';
|
| 137 |
-
}
|
| 138 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/response/CategoryResponseDto.java
DELETED
|
@@ -1,36 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.response;
|
| 2 |
-
|
| 3 |
-
import com.fasterxml.jackson.annotation.JsonProperty;
|
| 4 |
-
|
| 5 |
-
public class CategoryResponseDto {
|
| 6 |
-
|
| 7 |
-
@JsonProperty("id")
|
| 8 |
-
private String id;
|
| 9 |
-
|
| 10 |
-
@JsonProperty("name")
|
| 11 |
-
private String name;
|
| 12 |
-
|
| 13 |
-
@JsonProperty("description")
|
| 14 |
-
private String description;
|
| 15 |
-
|
| 16 |
-
@JsonProperty("item_count")
|
| 17 |
-
private long itemCount;
|
| 18 |
-
|
| 19 |
-
@JsonProperty("is_active")
|
| 20 |
-
private boolean isActive;
|
| 21 |
-
|
| 22 |
-
public String getId() { return id; }
|
| 23 |
-
public void setId(String id) { this.id = id; }
|
| 24 |
-
|
| 25 |
-
public String getName() { return name; }
|
| 26 |
-
public void setName(String name) { this.name = name; }
|
| 27 |
-
|
| 28 |
-
public String getDescription() { return description; }
|
| 29 |
-
public void setDescription(String description) { this.description = description; }
|
| 30 |
-
|
| 31 |
-
public long getItemCount() { return itemCount; }
|
| 32 |
-
public void setItemCount(long itemCount) { this.itemCount = itemCount; }
|
| 33 |
-
|
| 34 |
-
public boolean isActive() { return isActive; }
|
| 35 |
-
public void setActive(boolean active) { isActive = active; }
|
| 36 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/response/ItemResponseDto.java
DELETED
|
@@ -1,103 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.response;
|
| 2 |
-
|
| 3 |
-
import com.fasterxml.jackson.annotation.JsonFormat;
|
| 4 |
-
import com.fasterxml.jackson.annotation.JsonProperty;
|
| 5 |
-
|
| 6 |
-
import java.time.LocalDateTime;
|
| 7 |
-
import java.util.List;
|
| 8 |
-
|
| 9 |
-
public class ItemResponseDto {
|
| 10 |
-
|
| 11 |
-
@JsonProperty("id")
|
| 12 |
-
private String id;
|
| 13 |
-
|
| 14 |
-
@JsonProperty("name")
|
| 15 |
-
private String name;
|
| 16 |
-
|
| 17 |
-
@JsonProperty("description")
|
| 18 |
-
private String description;
|
| 19 |
-
|
| 20 |
-
@JsonProperty("condition")
|
| 21 |
-
private String condition;
|
| 22 |
-
|
| 23 |
-
@JsonProperty("status")
|
| 24 |
-
private String status;
|
| 25 |
-
|
| 26 |
-
@JsonProperty("deposit")
|
| 27 |
-
private double deposit;
|
| 28 |
-
|
| 29 |
-
@JsonProperty("images")
|
| 30 |
-
private List<String> images;
|
| 31 |
-
|
| 32 |
-
@JsonProperty("average_rating")
|
| 33 |
-
private double averageRating;
|
| 34 |
-
|
| 35 |
-
@JsonProperty("owner_id")
|
| 36 |
-
private String ownerId;
|
| 37 |
-
|
| 38 |
-
@JsonProperty("owner_name")
|
| 39 |
-
private String ownerName;
|
| 40 |
-
|
| 41 |
-
@JsonProperty("category_id")
|
| 42 |
-
private String categoryId;
|
| 43 |
-
|
| 44 |
-
@JsonProperty("category_name")
|
| 45 |
-
private String categoryName;
|
| 46 |
-
|
| 47 |
-
@JsonProperty("can_be_borrowed")
|
| 48 |
-
private boolean canBeBorrowed;
|
| 49 |
-
|
| 50 |
-
@JsonProperty("created_at")
|
| 51 |
-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
| 52 |
-
private LocalDateTime createdAt;
|
| 53 |
-
|
| 54 |
-
@JsonProperty("updated_at")
|
| 55 |
-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
| 56 |
-
private LocalDateTime updatedAt;
|
| 57 |
-
|
| 58 |
-
// Getters and setters
|
| 59 |
-
public String getId() { return id; }
|
| 60 |
-
public void setId(String id) { this.id = id; }
|
| 61 |
-
|
| 62 |
-
public String getName() { return name; }
|
| 63 |
-
public void setName(String name) { this.name = name; }
|
| 64 |
-
|
| 65 |
-
public String getDescription() { return description; }
|
| 66 |
-
public void setDescription(String description) { this.description = description; }
|
| 67 |
-
|
| 68 |
-
public String getCondition() { return condition; }
|
| 69 |
-
public void setCondition(String condition) { this.condition = condition; }
|
| 70 |
-
|
| 71 |
-
public String getStatus() { return status; }
|
| 72 |
-
public void setStatus(String status) { this.status = status; }
|
| 73 |
-
|
| 74 |
-
public double getDeposit() { return deposit; }
|
| 75 |
-
public void setDeposit(double deposit) { this.deposit = deposit; }
|
| 76 |
-
|
| 77 |
-
public List<String> getImages() { return images; }
|
| 78 |
-
public void setImages(List<String> images) { this.images = images; }
|
| 79 |
-
|
| 80 |
-
public double getAverageRating() { return averageRating; }
|
| 81 |
-
public void setAverageRating(double averageRating) { this.averageRating = averageRating; }
|
| 82 |
-
|
| 83 |
-
public String getOwnerId() { return ownerId; }
|
| 84 |
-
public void setOwnerId(String ownerId) { this.ownerId = ownerId; }
|
| 85 |
-
|
| 86 |
-
public String getOwnerName() { return ownerName; }
|
| 87 |
-
public void setOwnerName(String ownerName) { this.ownerName = ownerName; }
|
| 88 |
-
|
| 89 |
-
public String getCategoryId() { return categoryId; }
|
| 90 |
-
public void setCategoryId(String categoryId) { this.categoryId = categoryId; }
|
| 91 |
-
|
| 92 |
-
public String getCategoryName() { return categoryName; }
|
| 93 |
-
public void setCategoryName(String categoryName) { this.categoryName = categoryName; }
|
| 94 |
-
|
| 95 |
-
public boolean isCanBeBorrowed() { return canBeBorrowed; }
|
| 96 |
-
public void setCanBeBorrowed(boolean canBeBorrowed) { this.canBeBorrowed = canBeBorrowed; }
|
| 97 |
-
|
| 98 |
-
public LocalDateTime getCreatedAt() { return createdAt; }
|
| 99 |
-
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
| 100 |
-
|
| 101 |
-
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
| 102 |
-
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
| 103 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/response/ItemSummaryDto.java
DELETED
|
@@ -1,61 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.response;
|
| 2 |
-
|
| 3 |
-
import com.fasterxml.jackson.annotation.JsonProperty;
|
| 4 |
-
|
| 5 |
-
public class ItemSummaryDto {
|
| 6 |
-
|
| 7 |
-
@JsonProperty("id")
|
| 8 |
-
private String id;
|
| 9 |
-
|
| 10 |
-
@JsonProperty("name")
|
| 11 |
-
private String name;
|
| 12 |
-
|
| 13 |
-
@JsonProperty("thumbnail")
|
| 14 |
-
private String thumbnail;
|
| 15 |
-
|
| 16 |
-
@JsonProperty("category_name")
|
| 17 |
-
private String categoryName;
|
| 18 |
-
|
| 19 |
-
@JsonProperty("owner_name")
|
| 20 |
-
private String ownerName;
|
| 21 |
-
|
| 22 |
-
@JsonProperty("status")
|
| 23 |
-
private String status;
|
| 24 |
-
|
| 25 |
-
@JsonProperty("condition")
|
| 26 |
-
private String condition;
|
| 27 |
-
|
| 28 |
-
@JsonProperty("deposit")
|
| 29 |
-
private double deposit;
|
| 30 |
-
|
| 31 |
-
@JsonProperty("average_rating")
|
| 32 |
-
private double averageRating;
|
| 33 |
-
|
| 34 |
-
// Getters and setters
|
| 35 |
-
public String getId() { return id; }
|
| 36 |
-
public void setId(String id) { this.id = id; }
|
| 37 |
-
|
| 38 |
-
public String getName() { return name; }
|
| 39 |
-
public void setName(String name) { this.name = name; }
|
| 40 |
-
|
| 41 |
-
public String getThumbnail() { return thumbnail; }
|
| 42 |
-
public void setThumbnail(String thumbnail) { this.thumbnail = thumbnail; }
|
| 43 |
-
|
| 44 |
-
public String getCategoryName() { return categoryName; }
|
| 45 |
-
public void setCategoryName(String categoryName) { this.categoryName = categoryName; }
|
| 46 |
-
|
| 47 |
-
public String getOwnerName() { return ownerName; }
|
| 48 |
-
public void setOwnerName(String ownerName) { this.ownerName = ownerName; }
|
| 49 |
-
|
| 50 |
-
public String getStatus() { return status; }
|
| 51 |
-
public void setStatus(String status) { this.status = status; }
|
| 52 |
-
|
| 53 |
-
public String getCondition() { return condition; }
|
| 54 |
-
public void setCondition(String condition) { this.condition = condition; }
|
| 55 |
-
|
| 56 |
-
public double getDeposit() { return deposit; }
|
| 57 |
-
public void setDeposit(double deposit) { this.deposit = deposit; }
|
| 58 |
-
|
| 59 |
-
public double getAverageRating() { return averageRating; }
|
| 60 |
-
public void setAverageRating(double averageRating) { this.averageRating = averageRating; }
|
| 61 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/response/JwtAuthResponseDto.java
DELETED
|
@@ -1,43 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.response;
|
| 2 |
-
|
| 3 |
-
/**
|
| 4 |
-
* DTO for JWT authentication response.
|
| 5 |
-
* Contains the JWT token and user information.
|
| 6 |
-
*/
|
| 7 |
-
public class JwtAuthResponseDto {
|
| 8 |
-
private String token;
|
| 9 |
-
private String tokenType = "Bearer";
|
| 10 |
-
private UserResponseDto user;
|
| 11 |
-
|
| 12 |
-
public JwtAuthResponseDto() {}
|
| 13 |
-
|
| 14 |
-
public JwtAuthResponseDto(String token, UserResponseDto user) {
|
| 15 |
-
this.token = token;
|
| 16 |
-
this.user = user;
|
| 17 |
-
}
|
| 18 |
-
|
| 19 |
-
// Getters and Setters
|
| 20 |
-
public String getToken() {
|
| 21 |
-
return token;
|
| 22 |
-
}
|
| 23 |
-
|
| 24 |
-
public void setToken(String token) {
|
| 25 |
-
this.token = token;
|
| 26 |
-
}
|
| 27 |
-
|
| 28 |
-
public String getTokenType() {
|
| 29 |
-
return tokenType;
|
| 30 |
-
}
|
| 31 |
-
|
| 32 |
-
public void setTokenType(String tokenType) {
|
| 33 |
-
this.tokenType = tokenType;
|
| 34 |
-
}
|
| 35 |
-
|
| 36 |
-
public UserResponseDto getUser() {
|
| 37 |
-
return user;
|
| 38 |
-
}
|
| 39 |
-
|
| 40 |
-
public void setUser(UserResponseDto user) {
|
| 41 |
-
this.user = user;
|
| 42 |
-
}
|
| 43 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/response/RatingResponseDto.java
DELETED
|
@@ -1,89 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.response;
|
| 2 |
-
|
| 3 |
-
import com.locallend.locallend.model.RatingType;
|
| 4 |
-
import java.time.LocalDateTime;
|
| 5 |
-
|
| 6 |
-
/**
|
| 7 |
-
* Response DTO for Rating entity.
|
| 8 |
-
* Includes computed fields (timeAgo, canEdit) and optional user/item names.
|
| 9 |
-
* Issue #23: Rating Entity, Repository, DTO
|
| 10 |
-
*/
|
| 11 |
-
public class RatingResponseDto {
|
| 12 |
-
|
| 13 |
-
private String id;
|
| 14 |
-
private String raterId;
|
| 15 |
-
private String raterName;
|
| 16 |
-
private String rateeId;
|
| 17 |
-
private String rateeName;
|
| 18 |
-
private String itemId;
|
| 19 |
-
private String itemName;
|
| 20 |
-
private String bookingId;
|
| 21 |
-
private RatingType ratingType;
|
| 22 |
-
private Integer ratingValue;
|
| 23 |
-
private String comment;
|
| 24 |
-
private LocalDateTime createdDate;
|
| 25 |
-
private LocalDateTime updatedDate;
|
| 26 |
-
private Boolean isAnonymous;
|
| 27 |
-
private Integer helpfulCount;
|
| 28 |
-
private Boolean isVerified;
|
| 29 |
-
private String timeAgo;
|
| 30 |
-
private Boolean canEdit;
|
| 31 |
-
|
| 32 |
-
// Constructors
|
| 33 |
-
public RatingResponseDto() {}
|
| 34 |
-
|
| 35 |
-
// Getters and Setters
|
| 36 |
-
public String getId() { return id; }
|
| 37 |
-
public void setId(String id) { this.id = id; }
|
| 38 |
-
|
| 39 |
-
public String getRaterId() { return raterId; }
|
| 40 |
-
public void setRaterId(String raterId) { this.raterId = raterId; }
|
| 41 |
-
|
| 42 |
-
public String getRaterName() { return raterName; }
|
| 43 |
-
public void setRaterName(String raterName) { this.raterName = raterName; }
|
| 44 |
-
|
| 45 |
-
public String getRateeId() { return rateeId; }
|
| 46 |
-
public void setRateeId(String rateeId) { this.rateeId = rateeId; }
|
| 47 |
-
|
| 48 |
-
public String getRateeName() { return rateeName; }
|
| 49 |
-
public void setRateeName(String rateeName) { this.rateeName = rateeName; }
|
| 50 |
-
|
| 51 |
-
public String getItemId() { return itemId; }
|
| 52 |
-
public void setItemId(String itemId) { this.itemId = itemId; }
|
| 53 |
-
|
| 54 |
-
public String getItemName() { return itemName; }
|
| 55 |
-
public void setItemName(String itemName) { this.itemName = itemName; }
|
| 56 |
-
|
| 57 |
-
public String getBookingId() { return bookingId; }
|
| 58 |
-
public void setBookingId(String bookingId) { this.bookingId = bookingId; }
|
| 59 |
-
|
| 60 |
-
public RatingType getRatingType() { return ratingType; }
|
| 61 |
-
public void setRatingType(RatingType ratingType) { this.ratingType = ratingType; }
|
| 62 |
-
|
| 63 |
-
public Integer getRatingValue() { return ratingValue; }
|
| 64 |
-
public void setRatingValue(Integer ratingValue) { this.ratingValue = ratingValue; }
|
| 65 |
-
|
| 66 |
-
public String getComment() { return comment; }
|
| 67 |
-
public void setComment(String comment) { this.comment = comment; }
|
| 68 |
-
|
| 69 |
-
public LocalDateTime getCreatedDate() { return createdDate; }
|
| 70 |
-
public void setCreatedDate(LocalDateTime createdDate) { this.createdDate = createdDate; }
|
| 71 |
-
|
| 72 |
-
public LocalDateTime getUpdatedDate() { return updatedDate; }
|
| 73 |
-
public void setUpdatedDate(LocalDateTime updatedDate) { this.updatedDate = updatedDate; }
|
| 74 |
-
|
| 75 |
-
public Boolean getIsAnonymous() { return isAnonymous; }
|
| 76 |
-
public void setIsAnonymous(Boolean isAnonymous) { this.isAnonymous = isAnonymous; }
|
| 77 |
-
|
| 78 |
-
public Integer getHelpfulCount() { return helpfulCount; }
|
| 79 |
-
public void setHelpfulCount(Integer helpfulCount) { this.helpfulCount = helpfulCount; }
|
| 80 |
-
|
| 81 |
-
public Boolean getIsVerified() { return isVerified; }
|
| 82 |
-
public void setIsVerified(Boolean isVerified) { this.isVerified = isVerified; }
|
| 83 |
-
|
| 84 |
-
public String getTimeAgo() { return timeAgo; }
|
| 85 |
-
public void setTimeAgo(String timeAgo) { this.timeAgo = timeAgo; }
|
| 86 |
-
|
| 87 |
-
public Boolean getCanEdit() { return canEdit; }
|
| 88 |
-
public void setCanEdit(Boolean canEdit) { this.canEdit = canEdit; }
|
| 89 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/response/RatingStatsResponse.java
DELETED
|
@@ -1,74 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.response;
|
| 2 |
-
|
| 3 |
-
import com.fasterxml.jackson.annotation.JsonProperty;
|
| 4 |
-
import java.util.Map;
|
| 5 |
-
|
| 6 |
-
/**
|
| 7 |
-
* Response DTO for rating statistics.
|
| 8 |
-
* Provides aggregated rating data for users or items.
|
| 9 |
-
* Issue #25: Rating Controller APIs
|
| 10 |
-
*/
|
| 11 |
-
public class RatingStatsResponse {
|
| 12 |
-
|
| 13 |
-
@JsonProperty("subject_id")
|
| 14 |
-
private String subjectId; // User ID or Item ID
|
| 15 |
-
|
| 16 |
-
@JsonProperty("subject_type")
|
| 17 |
-
private String subjectType; // "USER" or "ITEM"
|
| 18 |
-
|
| 19 |
-
@JsonProperty("average_rating")
|
| 20 |
-
private Double averageRating;
|
| 21 |
-
|
| 22 |
-
@JsonProperty("total_ratings")
|
| 23 |
-
private Long totalRatings;
|
| 24 |
-
|
| 25 |
-
@JsonProperty("rating_distribution")
|
| 26 |
-
private Map<String, Long> ratingDistribution; // "5" -> count, "4" -> count, etc.
|
| 27 |
-
|
| 28 |
-
@JsonProperty("recent_average")
|
| 29 |
-
private Double recentAverage; // Last 30 days
|
| 30 |
-
|
| 31 |
-
@JsonProperty("verified_ratings_count")
|
| 32 |
-
private Long verifiedRatingsCount;
|
| 33 |
-
|
| 34 |
-
// Constructors
|
| 35 |
-
public RatingStatsResponse() {}
|
| 36 |
-
|
| 37 |
-
public RatingStatsResponse(String subjectId, String subjectType, Double averageRating, Long totalRatings) {
|
| 38 |
-
this.subjectId = subjectId;
|
| 39 |
-
this.subjectType = subjectType;
|
| 40 |
-
this.averageRating = averageRating;
|
| 41 |
-
this.totalRatings = totalRatings;
|
| 42 |
-
}
|
| 43 |
-
|
| 44 |
-
// Getters and Setters
|
| 45 |
-
public String getSubjectId() { return subjectId; }
|
| 46 |
-
public void setSubjectId(String subjectId) { this.subjectId = subjectId; }
|
| 47 |
-
|
| 48 |
-
public String getSubjectType() { return subjectType; }
|
| 49 |
-
public void setSubjectType(String subjectType) { this.subjectType = subjectType; }
|
| 50 |
-
|
| 51 |
-
public Double getAverageRating() { return averageRating; }
|
| 52 |
-
public void setAverageRating(Double averageRating) { this.averageRating = averageRating; }
|
| 53 |
-
|
| 54 |
-
public Long getTotalRatings() { return totalRatings; }
|
| 55 |
-
public void setTotalRatings(Long totalRatings) { this.totalRatings = totalRatings; }
|
| 56 |
-
|
| 57 |
-
public Map<String, Long> getRatingDistribution() { return ratingDistribution; }
|
| 58 |
-
public void setRatingDistribution(Map<String, Long> ratingDistribution) { this.ratingDistribution = ratingDistribution; }
|
| 59 |
-
|
| 60 |
-
public Double getRecentAverage() { return recentAverage; }
|
| 61 |
-
public void setRecentAverage(Double recentAverage) { this.recentAverage = recentAverage; }
|
| 62 |
-
|
| 63 |
-
public Long getVerifiedRatingsCount() { return verifiedRatingsCount; }
|
| 64 |
-
public void setVerifiedRatingsCount(Long verifiedRatingsCount) { this.verifiedRatingsCount = verifiedRatingsCount; }
|
| 65 |
-
|
| 66 |
-
// Helper methods
|
| 67 |
-
public String getFormattedAverageRating() {
|
| 68 |
-
return averageRating != null ? String.format("%.1f", averageRating) : "N/A";
|
| 69 |
-
}
|
| 70 |
-
|
| 71 |
-
public boolean hasRatings() {
|
| 72 |
-
return totalRatings != null && totalRatings > 0;
|
| 73 |
-
}
|
| 74 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/response/UserPublicDto.java
DELETED
|
@@ -1,76 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.response;
|
| 2 |
-
|
| 3 |
-
/**
|
| 4 |
-
* Public user information DTO.
|
| 5 |
-
* Contains only publicly visible user information (no email, phone, etc.).
|
| 6 |
-
*/
|
| 7 |
-
public class UserPublicDto {
|
| 8 |
-
private String id;
|
| 9 |
-
private String username;
|
| 10 |
-
private String name;
|
| 11 |
-
private String profileImageUrl;
|
| 12 |
-
private Double trustScore;
|
| 13 |
-
private Long itemCount;
|
| 14 |
-
|
| 15 |
-
// Computed field for Issue #29
|
| 16 |
-
private String memberSince; // "Member since MMMM yyyy"
|
| 17 |
-
|
| 18 |
-
public UserPublicDto() {}
|
| 19 |
-
|
| 20 |
-
// Getters and Setters
|
| 21 |
-
public String getId() {
|
| 22 |
-
return id;
|
| 23 |
-
}
|
| 24 |
-
|
| 25 |
-
public void setId(String id) {
|
| 26 |
-
this.id = id;
|
| 27 |
-
}
|
| 28 |
-
|
| 29 |
-
public String getUsername() {
|
| 30 |
-
return username;
|
| 31 |
-
}
|
| 32 |
-
|
| 33 |
-
public void setUsername(String username) {
|
| 34 |
-
this.username = username;
|
| 35 |
-
}
|
| 36 |
-
|
| 37 |
-
public String getName() {
|
| 38 |
-
return name;
|
| 39 |
-
}
|
| 40 |
-
|
| 41 |
-
public void setName(String name) {
|
| 42 |
-
this.name = name;
|
| 43 |
-
}
|
| 44 |
-
|
| 45 |
-
public String getProfileImageUrl() {
|
| 46 |
-
return profileImageUrl;
|
| 47 |
-
}
|
| 48 |
-
|
| 49 |
-
public void setProfileImageUrl(String profileImageUrl) {
|
| 50 |
-
this.profileImageUrl = profileImageUrl;
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
public Double getTrustScore() {
|
| 54 |
-
return trustScore;
|
| 55 |
-
}
|
| 56 |
-
|
| 57 |
-
public void setTrustScore(Double trustScore) {
|
| 58 |
-
this.trustScore = trustScore;
|
| 59 |
-
}
|
| 60 |
-
|
| 61 |
-
public Long getItemCount() {
|
| 62 |
-
return itemCount;
|
| 63 |
-
}
|
| 64 |
-
|
| 65 |
-
public void setItemCount(Long itemCount) {
|
| 66 |
-
this.itemCount = itemCount;
|
| 67 |
-
}
|
| 68 |
-
|
| 69 |
-
public String getMemberSince() {
|
| 70 |
-
return memberSince;
|
| 71 |
-
}
|
| 72 |
-
|
| 73 |
-
public void setMemberSince(String memberSince) {
|
| 74 |
-
this.memberSince = memberSince;
|
| 75 |
-
}
|
| 76 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/dto/response/UserResponseDto.java
DELETED
|
@@ -1,141 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.dto.response;
|
| 2 |
-
|
| 3 |
-
import java.time.LocalDateTime;
|
| 4 |
-
|
| 5 |
-
/**
|
| 6 |
-
* Full user response DTO for authenticated user operations.
|
| 7 |
-
* Contains all non-sensitive user information.
|
| 8 |
-
*/
|
| 9 |
-
public class UserResponseDto {
|
| 10 |
-
private String id;
|
| 11 |
-
private String username;
|
| 12 |
-
private String name;
|
| 13 |
-
private String email;
|
| 14 |
-
private String phoneNumber;
|
| 15 |
-
private String profileImageUrl;
|
| 16 |
-
private String role;
|
| 17 |
-
private Boolean isActive;
|
| 18 |
-
private LocalDateTime createdDate;
|
| 19 |
-
private Double trustScore;
|
| 20 |
-
private Long itemCount;
|
| 21 |
-
|
| 22 |
-
// Computed fields for Issue #29
|
| 23 |
-
private String memberSince; // "Member since MMMM yyyy"
|
| 24 |
-
private Integer totalItemsShared; // Total items created by user
|
| 25 |
-
private Integer totalBookings; // Total bookings as owner or borrower
|
| 26 |
-
|
| 27 |
-
public UserResponseDto() {}
|
| 28 |
-
|
| 29 |
-
// Getters and Setters
|
| 30 |
-
public String getId() {
|
| 31 |
-
return id;
|
| 32 |
-
}
|
| 33 |
-
|
| 34 |
-
public void setId(String id) {
|
| 35 |
-
this.id = id;
|
| 36 |
-
}
|
| 37 |
-
|
| 38 |
-
public String getUsername() {
|
| 39 |
-
return username;
|
| 40 |
-
}
|
| 41 |
-
|
| 42 |
-
public void setUsername(String username) {
|
| 43 |
-
this.username = username;
|
| 44 |
-
}
|
| 45 |
-
|
| 46 |
-
public String getName() {
|
| 47 |
-
return name;
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
public void setName(String name) {
|
| 51 |
-
this.name = name;
|
| 52 |
-
}
|
| 53 |
-
|
| 54 |
-
public String getEmail() {
|
| 55 |
-
return email;
|
| 56 |
-
}
|
| 57 |
-
|
| 58 |
-
public void setEmail(String email) {
|
| 59 |
-
this.email = email;
|
| 60 |
-
}
|
| 61 |
-
|
| 62 |
-
public String getPhoneNumber() {
|
| 63 |
-
return phoneNumber;
|
| 64 |
-
}
|
| 65 |
-
|
| 66 |
-
public void setPhoneNumber(String phoneNumber) {
|
| 67 |
-
this.phoneNumber = phoneNumber;
|
| 68 |
-
}
|
| 69 |
-
|
| 70 |
-
public String getProfileImageUrl() {
|
| 71 |
-
return profileImageUrl;
|
| 72 |
-
}
|
| 73 |
-
|
| 74 |
-
public void setProfileImageUrl(String profileImageUrl) {
|
| 75 |
-
this.profileImageUrl = profileImageUrl;
|
| 76 |
-
}
|
| 77 |
-
|
| 78 |
-
public String getRole() {
|
| 79 |
-
return role;
|
| 80 |
-
}
|
| 81 |
-
|
| 82 |
-
public void setRole(String role) {
|
| 83 |
-
this.role = role;
|
| 84 |
-
}
|
| 85 |
-
|
| 86 |
-
public Boolean getIsActive() {
|
| 87 |
-
return isActive;
|
| 88 |
-
}
|
| 89 |
-
|
| 90 |
-
public void setIsActive(Boolean isActive) {
|
| 91 |
-
this.isActive = isActive;
|
| 92 |
-
}
|
| 93 |
-
|
| 94 |
-
public LocalDateTime getCreatedDate() {
|
| 95 |
-
return createdDate;
|
| 96 |
-
}
|
| 97 |
-
|
| 98 |
-
public void setCreatedDate(LocalDateTime createdDate) {
|
| 99 |
-
this.createdDate = createdDate;
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
public Double getTrustScore() {
|
| 103 |
-
return trustScore;
|
| 104 |
-
}
|
| 105 |
-
|
| 106 |
-
public void setTrustScore(Double trustScore) {
|
| 107 |
-
this.trustScore = trustScore;
|
| 108 |
-
}
|
| 109 |
-
|
| 110 |
-
public Long getItemCount() {
|
| 111 |
-
return itemCount;
|
| 112 |
-
}
|
| 113 |
-
|
| 114 |
-
public void setItemCount(Long itemCount) {
|
| 115 |
-
this.itemCount = itemCount;
|
| 116 |
-
}
|
| 117 |
-
|
| 118 |
-
public String getMemberSince() {
|
| 119 |
-
return memberSince;
|
| 120 |
-
}
|
| 121 |
-
|
| 122 |
-
public void setMemberSince(String memberSince) {
|
| 123 |
-
this.memberSince = memberSince;
|
| 124 |
-
}
|
| 125 |
-
|
| 126 |
-
public Integer getTotalItemsShared() {
|
| 127 |
-
return totalItemsShared;
|
| 128 |
-
}
|
| 129 |
-
|
| 130 |
-
public void setTotalItemsShared(Integer totalItemsShared) {
|
| 131 |
-
this.totalItemsShared = totalItemsShared;
|
| 132 |
-
}
|
| 133 |
-
|
| 134 |
-
public Integer getTotalBookings() {
|
| 135 |
-
return totalBookings;
|
| 136 |
-
}
|
| 137 |
-
|
| 138 |
-
public void setTotalBookings(Integer totalBookings) {
|
| 139 |
-
this.totalBookings = totalBookings;
|
| 140 |
-
}
|
| 141 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/exception/BookingConflictException.java
DELETED
|
@@ -1,37 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.exception;
|
| 2 |
-
|
| 3 |
-
/**
|
| 4 |
-
* Exception thrown when a booking request conflicts with existing bookings or availability constraints.
|
| 5 |
-
*/
|
| 6 |
-
public class BookingConflictException extends RuntimeException {
|
| 7 |
-
|
| 8 |
-
private String itemId;
|
| 9 |
-
private String conflictingBookingId;
|
| 10 |
-
|
| 11 |
-
public BookingConflictException(String message) {
|
| 12 |
-
super(message);
|
| 13 |
-
}
|
| 14 |
-
|
| 15 |
-
public BookingConflictException(String message, String itemId) {
|
| 16 |
-
super(message);
|
| 17 |
-
this.itemId = itemId;
|
| 18 |
-
}
|
| 19 |
-
|
| 20 |
-
public BookingConflictException(String message, String itemId, String conflictingBookingId) {
|
| 21 |
-
super(message);
|
| 22 |
-
this.itemId = itemId;
|
| 23 |
-
this.conflictingBookingId = conflictingBookingId;
|
| 24 |
-
}
|
| 25 |
-
|
| 26 |
-
public BookingConflictException(String message, Throwable cause) {
|
| 27 |
-
super(message, cause);
|
| 28 |
-
}
|
| 29 |
-
|
| 30 |
-
public String getItemId() {
|
| 31 |
-
return itemId;
|
| 32 |
-
}
|
| 33 |
-
|
| 34 |
-
public String getConflictingBookingId() {
|
| 35 |
-
return conflictingBookingId;
|
| 36 |
-
}
|
| 37 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/exception/BookingNotFoundException.java
DELETED
|
@@ -1,32 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.exception;
|
| 2 |
-
|
| 3 |
-
/**
|
| 4 |
-
* Exception thrown when a booking is not found by ID.
|
| 5 |
-
*/
|
| 6 |
-
public class BookingNotFoundException extends RuntimeException {
|
| 7 |
-
|
| 8 |
-
private String bookingId;
|
| 9 |
-
|
| 10 |
-
public BookingNotFoundException(String bookingId) {
|
| 11 |
-
super("Booking not found with ID: " + bookingId);
|
| 12 |
-
this.bookingId = bookingId;
|
| 13 |
-
}
|
| 14 |
-
|
| 15 |
-
public BookingNotFoundException(String bookingId, String message) {
|
| 16 |
-
super(message);
|
| 17 |
-
this.bookingId = bookingId;
|
| 18 |
-
}
|
| 19 |
-
|
| 20 |
-
public BookingNotFoundException(String bookingId, String message, Throwable cause) {
|
| 21 |
-
super(message, cause);
|
| 22 |
-
this.bookingId = bookingId;
|
| 23 |
-
}
|
| 24 |
-
|
| 25 |
-
public String getBookingId() {
|
| 26 |
-
return bookingId;
|
| 27 |
-
}
|
| 28 |
-
|
| 29 |
-
public static BookingNotFoundException withId(String bookingId) {
|
| 30 |
-
return new BookingNotFoundException(bookingId);
|
| 31 |
-
}
|
| 32 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/exception/BusinessException.java
DELETED
|
@@ -1,11 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.exception;
|
| 2 |
-
|
| 3 |
-
/**
|
| 4 |
-
* Exception thrown when business rules are violated.
|
| 5 |
-
* Examples: duplicate user, inactive user, invalid trust score, etc.
|
| 6 |
-
*/
|
| 7 |
-
public class BusinessException extends RuntimeException {
|
| 8 |
-
public BusinessException(String message) {
|
| 9 |
-
super(message);
|
| 10 |
-
}
|
| 11 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/exception/CategoryNotFoundException.java
DELETED
|
@@ -1,36 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.exception;
|
| 2 |
-
|
| 3 |
-
public class CategoryNotFoundException extends RuntimeException {
|
| 4 |
-
|
| 5 |
-
private final String categoryId;
|
| 6 |
-
private final String categoryName;
|
| 7 |
-
|
| 8 |
-
public CategoryNotFoundException(String categoryId) {
|
| 9 |
-
super("Category with ID '" + categoryId + "' not found");
|
| 10 |
-
this.categoryId = categoryId;
|
| 11 |
-
this.categoryName = null;
|
| 12 |
-
}
|
| 13 |
-
|
| 14 |
-
public CategoryNotFoundException(String categoryName, boolean byName) {
|
| 15 |
-
super("Category with name '" + categoryName + "' not found");
|
| 16 |
-
this.categoryId = null;
|
| 17 |
-
this.categoryName = categoryName;
|
| 18 |
-
}
|
| 19 |
-
|
| 20 |
-
public CategoryNotFoundException(String message, String categoryId, String categoryName) {
|
| 21 |
-
super(message);
|
| 22 |
-
this.categoryId = categoryId;
|
| 23 |
-
this.categoryName = categoryName;
|
| 24 |
-
}
|
| 25 |
-
|
| 26 |
-
public static CategoryNotFoundException byId(String categoryId) {
|
| 27 |
-
return new CategoryNotFoundException(categoryId);
|
| 28 |
-
}
|
| 29 |
-
|
| 30 |
-
public static CategoryNotFoundException byName(String categoryName) {
|
| 31 |
-
return new CategoryNotFoundException(categoryName, true);
|
| 32 |
-
}
|
| 33 |
-
|
| 34 |
-
public String getCategoryId() { return categoryId; }
|
| 35 |
-
public String getCategoryName() { return categoryName; }
|
| 36 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/exception/DuplicateResourceException.java
DELETED
|
@@ -1,37 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.exception;
|
| 2 |
-
|
| 3 |
-
/**
|
| 4 |
-
* Exception thrown when attempting to create a resource that already exists.
|
| 5 |
-
* Examples: duplicate username, duplicate email, duplicate category name.
|
| 6 |
-
*/
|
| 7 |
-
public class DuplicateResourceException extends RuntimeException {
|
| 8 |
-
private final String resourceType;
|
| 9 |
-
private final String fieldName;
|
| 10 |
-
private final String fieldValue;
|
| 11 |
-
|
| 12 |
-
public DuplicateResourceException(String resourceType, String fieldName, String fieldValue) {
|
| 13 |
-
super(String.format("%s with %s '%s' already exists", resourceType, fieldName, fieldValue));
|
| 14 |
-
this.resourceType = resourceType;
|
| 15 |
-
this.fieldName = fieldName;
|
| 16 |
-
this.fieldValue = fieldValue;
|
| 17 |
-
}
|
| 18 |
-
|
| 19 |
-
public DuplicateResourceException(String message) {
|
| 20 |
-
super(message);
|
| 21 |
-
this.resourceType = null;
|
| 22 |
-
this.fieldName = null;
|
| 23 |
-
this.fieldValue = null;
|
| 24 |
-
}
|
| 25 |
-
|
| 26 |
-
public String getResourceType() {
|
| 27 |
-
return resourceType;
|
| 28 |
-
}
|
| 29 |
-
|
| 30 |
-
public String getFieldName() {
|
| 31 |
-
return fieldName;
|
| 32 |
-
}
|
| 33 |
-
|
| 34 |
-
public String getFieldValue() {
|
| 35 |
-
return fieldValue;
|
| 36 |
-
}
|
| 37 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/exception/GlobalExceptionHandler.java
DELETED
|
@@ -1,504 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.exception;
|
| 2 |
-
|
| 3 |
-
import org.springframework.http.HttpStatus;
|
| 4 |
-
import org.springframework.http.ResponseEntity;
|
| 5 |
-
import org.springframework.http.converter.HttpMessageNotReadableException;
|
| 6 |
-
import org.springframework.security.access.AccessDeniedException;
|
| 7 |
-
import org.springframework.security.authentication.BadCredentialsException;
|
| 8 |
-
import org.springframework.security.core.AuthenticationException;
|
| 9 |
-
import org.springframework.validation.FieldError;
|
| 10 |
-
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
| 11 |
-
import org.springframework.web.bind.MethodArgumentNotValidException;
|
| 12 |
-
import org.springframework.web.bind.MissingServletRequestParameterException;
|
| 13 |
-
import org.springframework.web.bind.annotation.ControllerAdvice;
|
| 14 |
-
import org.springframework.web.bind.annotation.ExceptionHandler;
|
| 15 |
-
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
| 16 |
-
import org.springframework.web.servlet.NoHandlerFoundException;
|
| 17 |
-
|
| 18 |
-
import java.time.LocalDateTime;
|
| 19 |
-
import java.util.HashMap;
|
| 20 |
-
import java.util.Map;
|
| 21 |
-
|
| 22 |
-
/**
|
| 23 |
-
* Global exception handler for all controllers.
|
| 24 |
-
* Converts exceptions to standardized error responses.
|
| 25 |
-
*/
|
| 26 |
-
@ControllerAdvice
|
| 27 |
-
public class GlobalExceptionHandler {
|
| 28 |
-
|
| 29 |
-
/**
|
| 30 |
-
* Handle BusinessException - domain/business logic violations.
|
| 31 |
-
* @param ex BusinessException
|
| 32 |
-
* @return Error response with 400 BAD REQUEST
|
| 33 |
-
*/
|
| 34 |
-
@ExceptionHandler(BusinessException.class)
|
| 35 |
-
public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {
|
| 36 |
-
ErrorResponse error = new ErrorResponse(
|
| 37 |
-
HttpStatus.BAD_REQUEST.value(),
|
| 38 |
-
ex.getMessage(),
|
| 39 |
-
LocalDateTime.now()
|
| 40 |
-
);
|
| 41 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 42 |
-
}
|
| 43 |
-
|
| 44 |
-
/**
|
| 45 |
-
* Handle validation errors from @Valid annotation.
|
| 46 |
-
* @param ex MethodArgumentNotValidException
|
| 47 |
-
* @return Error response with 400 BAD REQUEST and field errors
|
| 48 |
-
*/
|
| 49 |
-
@ExceptionHandler(MethodArgumentNotValidException.class)
|
| 50 |
-
public ResponseEntity<ValidationErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {
|
| 51 |
-
Map<String, String> fieldErrors = new HashMap<>();
|
| 52 |
-
|
| 53 |
-
ex.getBindingResult().getAllErrors().forEach((error) -> {
|
| 54 |
-
String fieldName = ((FieldError) error).getField();
|
| 55 |
-
String errorMessage = error.getDefaultMessage();
|
| 56 |
-
fieldErrors.put(fieldName, errorMessage);
|
| 57 |
-
});
|
| 58 |
-
|
| 59 |
-
ValidationErrorResponse error = new ValidationErrorResponse(
|
| 60 |
-
HttpStatus.BAD_REQUEST.value(),
|
| 61 |
-
"Validation failed",
|
| 62 |
-
fieldErrors,
|
| 63 |
-
LocalDateTime.now()
|
| 64 |
-
);
|
| 65 |
-
|
| 66 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 67 |
-
}
|
| 68 |
-
|
| 69 |
-
/**
|
| 70 |
-
* Handle custom ValidationException - for domain-specific validation errors.
|
| 71 |
-
* @param ex ValidationException
|
| 72 |
-
* @return Error response with 400 BAD REQUEST and field errors
|
| 73 |
-
*/
|
| 74 |
-
@ExceptionHandler(ValidationException.class)
|
| 75 |
-
public ResponseEntity<ValidationErrorResponse> handleCustomValidationException(ValidationException ex) {
|
| 76 |
-
ValidationErrorResponse error = new ValidationErrorResponse(
|
| 77 |
-
HttpStatus.BAD_REQUEST.value(),
|
| 78 |
-
ex.getMessage(),
|
| 79 |
-
ex.getFieldErrors(),
|
| 80 |
-
LocalDateTime.now()
|
| 81 |
-
);
|
| 82 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 83 |
-
}
|
| 84 |
-
|
| 85 |
-
/**
|
| 86 |
-
* Handle DuplicateResourceException - when trying to create duplicate resource.
|
| 87 |
-
* @param ex DuplicateResourceException
|
| 88 |
-
* @return Error response with 409 CONFLICT
|
| 89 |
-
*/
|
| 90 |
-
@ExceptionHandler(DuplicateResourceException.class)
|
| 91 |
-
public ResponseEntity<ErrorResponse> handleDuplicateResourceException(DuplicateResourceException ex) {
|
| 92 |
-
ErrorResponse error = new ErrorResponse(
|
| 93 |
-
HttpStatus.CONFLICT.value(),
|
| 94 |
-
ex.getMessage(),
|
| 95 |
-
LocalDateTime.now()
|
| 96 |
-
);
|
| 97 |
-
return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
|
| 98 |
-
}
|
| 99 |
-
|
| 100 |
-
/**
|
| 101 |
-
* Handle InvalidOperationException - when operation cannot be performed.
|
| 102 |
-
* @param ex InvalidOperationException
|
| 103 |
-
* @return Error response with 400 BAD REQUEST
|
| 104 |
-
*/
|
| 105 |
-
@ExceptionHandler(InvalidOperationException.class)
|
| 106 |
-
public ResponseEntity<ErrorResponse> handleInvalidOperationException(InvalidOperationException ex) {
|
| 107 |
-
ErrorResponse error = new ErrorResponse(
|
| 108 |
-
HttpStatus.BAD_REQUEST.value(),
|
| 109 |
-
ex.getMessage(),
|
| 110 |
-
LocalDateTime.now()
|
| 111 |
-
);
|
| 112 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 113 |
-
}
|
| 114 |
-
|
| 115 |
-
/**
|
| 116 |
-
* Handle InvalidStateTransitionException - when state transition is not allowed.
|
| 117 |
-
* @param ex InvalidStateTransitionException
|
| 118 |
-
* @return Error response with 400 BAD REQUEST
|
| 119 |
-
*/
|
| 120 |
-
@ExceptionHandler(InvalidStateTransitionException.class)
|
| 121 |
-
public ResponseEntity<ErrorResponse> handleInvalidStateTransitionException(InvalidStateTransitionException ex) {
|
| 122 |
-
ErrorResponse error = new ErrorResponse(
|
| 123 |
-
HttpStatus.BAD_REQUEST.value(),
|
| 124 |
-
ex.getMessage(),
|
| 125 |
-
LocalDateTime.now()
|
| 126 |
-
);
|
| 127 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 128 |
-
}
|
| 129 |
-
|
| 130 |
-
/**
|
| 131 |
-
* Handle InsufficientTrustScoreException - when user's trust score is too low.
|
| 132 |
-
* @param ex InsufficientTrustScoreException
|
| 133 |
-
* @return Error response with 403 FORBIDDEN
|
| 134 |
-
*/
|
| 135 |
-
@ExceptionHandler(InsufficientTrustScoreException.class)
|
| 136 |
-
public ResponseEntity<ErrorResponse> handleInsufficientTrustScoreException(InsufficientTrustScoreException ex) {
|
| 137 |
-
ErrorResponse error = new ErrorResponse(
|
| 138 |
-
HttpStatus.FORBIDDEN.value(),
|
| 139 |
-
ex.getMessage(),
|
| 140 |
-
LocalDateTime.now()
|
| 141 |
-
);
|
| 142 |
-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
|
| 143 |
-
}
|
| 144 |
-
|
| 145 |
-
/**
|
| 146 |
-
* Handle ItemNotAvailableException - when item is not available for booking.
|
| 147 |
-
* @param ex ItemNotAvailableException
|
| 148 |
-
* @return Error response with 409 CONFLICT
|
| 149 |
-
*/
|
| 150 |
-
@ExceptionHandler(ItemNotAvailableException.class)
|
| 151 |
-
public ResponseEntity<ErrorResponse> handleItemNotAvailableException(ItemNotAvailableException ex) {
|
| 152 |
-
ErrorResponse error = new ErrorResponse(
|
| 153 |
-
HttpStatus.CONFLICT.value(),
|
| 154 |
-
ex.getMessage(),
|
| 155 |
-
LocalDateTime.now()
|
| 156 |
-
);
|
| 157 |
-
return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
|
| 158 |
-
}
|
| 159 |
-
|
| 160 |
-
/**
|
| 161 |
-
* Handle BookingConflictException - when booking dates conflict.
|
| 162 |
-
* @param ex BookingConflictException
|
| 163 |
-
* @return Error response with 409 CONFLICT
|
| 164 |
-
*/
|
| 165 |
-
@ExceptionHandler(BookingConflictException.class)
|
| 166 |
-
public ResponseEntity<ErrorResponse> handleBookingConflictException(BookingConflictException ex) {
|
| 167 |
-
ErrorResponse error = new ErrorResponse(
|
| 168 |
-
HttpStatus.CONFLICT.value(),
|
| 169 |
-
ex.getMessage(),
|
| 170 |
-
LocalDateTime.now()
|
| 171 |
-
);
|
| 172 |
-
return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
|
| 173 |
-
}
|
| 174 |
-
|
| 175 |
-
/**
|
| 176 |
-
* Handle InvalidBookingPeriodException - when booking period is invalid.
|
| 177 |
-
* @param ex InvalidBookingPeriodException
|
| 178 |
-
* @return Error response with 400 BAD REQUEST
|
| 179 |
-
*/
|
| 180 |
-
@ExceptionHandler(InvalidBookingPeriodException.class)
|
| 181 |
-
public ResponseEntity<ErrorResponse> handleInvalidBookingPeriodException(InvalidBookingPeriodException ex) {
|
| 182 |
-
ErrorResponse error = new ErrorResponse(
|
| 183 |
-
HttpStatus.BAD_REQUEST.value(),
|
| 184 |
-
ex.getMessage(),
|
| 185 |
-
LocalDateTime.now()
|
| 186 |
-
);
|
| 187 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 188 |
-
}
|
| 189 |
-
|
| 190 |
-
/**
|
| 191 |
-
* Handle ResourceNotFoundException - generic resource not found.
|
| 192 |
-
* @param ex ResourceNotFoundException
|
| 193 |
-
* @return Error response with 404 NOT FOUND
|
| 194 |
-
*/
|
| 195 |
-
@ExceptionHandler(ResourceNotFoundException.class)
|
| 196 |
-
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
|
| 197 |
-
ErrorResponse error = new ErrorResponse(
|
| 198 |
-
HttpStatus.NOT_FOUND.value(),
|
| 199 |
-
ex.getMessage(),
|
| 200 |
-
LocalDateTime.now()
|
| 201 |
-
);
|
| 202 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 203 |
-
}
|
| 204 |
-
|
| 205 |
-
/**
|
| 206 |
-
* Handle CategoryNotFoundException - when category is not found.
|
| 207 |
-
* @param ex CategoryNotFoundException
|
| 208 |
-
* @return Error response with 404 NOT FOUND
|
| 209 |
-
*/
|
| 210 |
-
@ExceptionHandler(CategoryNotFoundException.class)
|
| 211 |
-
public ResponseEntity<ErrorResponse> handleCategoryNotFoundException(CategoryNotFoundException ex) {
|
| 212 |
-
ErrorResponse error = new ErrorResponse(
|
| 213 |
-
HttpStatus.NOT_FOUND.value(),
|
| 214 |
-
ex.getMessage(),
|
| 215 |
-
LocalDateTime.now()
|
| 216 |
-
);
|
| 217 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 218 |
-
}
|
| 219 |
-
|
| 220 |
-
/**
|
| 221 |
-
* Handle ItemNotFoundException - when item is not found.
|
| 222 |
-
* @param ex ItemNotFoundException
|
| 223 |
-
* @return Error response with 404 NOT FOUND
|
| 224 |
-
*/
|
| 225 |
-
@ExceptionHandler(ItemNotFoundException.class)
|
| 226 |
-
public ResponseEntity<ErrorResponse> handleItemNotFoundException(ItemNotFoundException ex) {
|
| 227 |
-
ErrorResponse error = new ErrorResponse(
|
| 228 |
-
HttpStatus.NOT_FOUND.value(),
|
| 229 |
-
ex.getMessage(),
|
| 230 |
-
LocalDateTime.now()
|
| 231 |
-
);
|
| 232 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 233 |
-
}
|
| 234 |
-
|
| 235 |
-
/**
|
| 236 |
-
* Handle UserNotFoundException - when user is not found.
|
| 237 |
-
* @param ex UserNotFoundException
|
| 238 |
-
* @return Error response with 404 NOT FOUND
|
| 239 |
-
*/
|
| 240 |
-
@ExceptionHandler(UserNotFoundException.class)
|
| 241 |
-
public ResponseEntity<ErrorResponse> handleUserNotFoundException(UserNotFoundException ex) {
|
| 242 |
-
ErrorResponse error = new ErrorResponse(
|
| 243 |
-
HttpStatus.NOT_FOUND.value(),
|
| 244 |
-
ex.getMessage(),
|
| 245 |
-
LocalDateTime.now()
|
| 246 |
-
);
|
| 247 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 248 |
-
}
|
| 249 |
-
|
| 250 |
-
/**
|
| 251 |
-
* Handle BookingNotFoundException - when booking is not found.
|
| 252 |
-
* @param ex BookingNotFoundException
|
| 253 |
-
* @return Error response with 404 NOT FOUND
|
| 254 |
-
*/
|
| 255 |
-
@ExceptionHandler(BookingNotFoundException.class)
|
| 256 |
-
public ResponseEntity<ErrorResponse> handleBookingNotFoundException(BookingNotFoundException ex) {
|
| 257 |
-
ErrorResponse error = new ErrorResponse(
|
| 258 |
-
HttpStatus.NOT_FOUND.value(),
|
| 259 |
-
ex.getMessage(),
|
| 260 |
-
LocalDateTime.now()
|
| 261 |
-
);
|
| 262 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 263 |
-
}
|
| 264 |
-
|
| 265 |
-
/**
|
| 266 |
-
* Handle RatingNotFoundException - when rating is not found.
|
| 267 |
-
* @param ex RatingNotFoundException
|
| 268 |
-
* @return Error response with 404 NOT FOUND
|
| 269 |
-
*/
|
| 270 |
-
@ExceptionHandler(RatingNotFoundException.class)
|
| 271 |
-
public ResponseEntity<ErrorResponse> handleRatingNotFoundException(RatingNotFoundException ex) {
|
| 272 |
-
ErrorResponse error = new ErrorResponse(
|
| 273 |
-
HttpStatus.NOT_FOUND.value(),
|
| 274 |
-
ex.getMessage(),
|
| 275 |
-
LocalDateTime.now()
|
| 276 |
-
);
|
| 277 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 278 |
-
}
|
| 279 |
-
|
| 280 |
-
/**
|
| 281 |
-
* Handle UnauthorizedItemAccessException - when user tries to access/modify item they don't own.
|
| 282 |
-
* @param ex UnauthorizedItemAccessException
|
| 283 |
-
* @return Error response with 403 FORBIDDEN
|
| 284 |
-
*/
|
| 285 |
-
@ExceptionHandler(UnauthorizedItemAccessException.class)
|
| 286 |
-
public ResponseEntity<ErrorResponse> handleUnauthorizedItemAccessException(UnauthorizedItemAccessException ex) {
|
| 287 |
-
ErrorResponse error = new ErrorResponse(
|
| 288 |
-
HttpStatus.FORBIDDEN.value(),
|
| 289 |
-
ex.getMessage(),
|
| 290 |
-
LocalDateTime.now()
|
| 291 |
-
);
|
| 292 |
-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
|
| 293 |
-
}
|
| 294 |
-
|
| 295 |
-
/**
|
| 296 |
-
* Handle UnauthorizedAccessException - generic unauthorized access.
|
| 297 |
-
* @param ex UnauthorizedAccessException
|
| 298 |
-
* @return Error response with 403 FORBIDDEN
|
| 299 |
-
*/
|
| 300 |
-
@ExceptionHandler(UnauthorizedAccessException.class)
|
| 301 |
-
public ResponseEntity<ErrorResponse> handleUnauthorizedAccessException(UnauthorizedAccessException ex) {
|
| 302 |
-
ErrorResponse error = new ErrorResponse(
|
| 303 |
-
HttpStatus.FORBIDDEN.value(),
|
| 304 |
-
ex.getMessage(),
|
| 305 |
-
LocalDateTime.now()
|
| 306 |
-
);
|
| 307 |
-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
|
| 308 |
-
}
|
| 309 |
-
|
| 310 |
-
/**
|
| 311 |
-
* Handle Spring Security AuthenticationException - authentication failures.
|
| 312 |
-
* @param ex AuthenticationException
|
| 313 |
-
* @return Error response with 401 UNAUTHORIZED
|
| 314 |
-
*/
|
| 315 |
-
@ExceptionHandler(AuthenticationException.class)
|
| 316 |
-
public ResponseEntity<ErrorResponse> handleAuthenticationException(AuthenticationException ex) {
|
| 317 |
-
ErrorResponse error = new ErrorResponse(
|
| 318 |
-
HttpStatus.UNAUTHORIZED.value(),
|
| 319 |
-
"Authentication failed: " + ex.getMessage(),
|
| 320 |
-
LocalDateTime.now()
|
| 321 |
-
);
|
| 322 |
-
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(error);
|
| 323 |
-
}
|
| 324 |
-
|
| 325 |
-
/**
|
| 326 |
-
* Handle Spring Security BadCredentialsException - invalid username/password.
|
| 327 |
-
* @param ex BadCredentialsException
|
| 328 |
-
* @return Error response with 401 UNAUTHORIZED
|
| 329 |
-
*/
|
| 330 |
-
@ExceptionHandler(BadCredentialsException.class)
|
| 331 |
-
public ResponseEntity<ErrorResponse> handleBadCredentialsException(BadCredentialsException ex) {
|
| 332 |
-
ErrorResponse error = new ErrorResponse(
|
| 333 |
-
HttpStatus.UNAUTHORIZED.value(),
|
| 334 |
-
"Invalid username or password",
|
| 335 |
-
LocalDateTime.now()
|
| 336 |
-
);
|
| 337 |
-
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(error);
|
| 338 |
-
}
|
| 339 |
-
|
| 340 |
-
/**
|
| 341 |
-
* Handle Spring Security AccessDeniedException - insufficient permissions.
|
| 342 |
-
* @param ex AccessDeniedException
|
| 343 |
-
* @return Error response with 403 FORBIDDEN
|
| 344 |
-
*/
|
| 345 |
-
@ExceptionHandler(AccessDeniedException.class)
|
| 346 |
-
public ResponseEntity<ErrorResponse> handleAccessDeniedException(AccessDeniedException ex) {
|
| 347 |
-
ErrorResponse error = new ErrorResponse(
|
| 348 |
-
HttpStatus.FORBIDDEN.value(),
|
| 349 |
-
"Access denied: You don't have permission to access this resource",
|
| 350 |
-
LocalDateTime.now()
|
| 351 |
-
);
|
| 352 |
-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
|
| 353 |
-
}
|
| 354 |
-
|
| 355 |
-
/**
|
| 356 |
-
* Handle HttpMessageNotReadableException - malformed JSON request body.
|
| 357 |
-
* @param ex HttpMessageNotReadableException
|
| 358 |
-
* @return Error response with 400 BAD REQUEST
|
| 359 |
-
*/
|
| 360 |
-
@ExceptionHandler(HttpMessageNotReadableException.class)
|
| 361 |
-
public ResponseEntity<ErrorResponse> handleHttpMessageNotReadableException(HttpMessageNotReadableException ex) {
|
| 362 |
-
ErrorResponse error = new ErrorResponse(
|
| 363 |
-
HttpStatus.BAD_REQUEST.value(),
|
| 364 |
-
"Malformed JSON request: " + ex.getMessage(),
|
| 365 |
-
LocalDateTime.now()
|
| 366 |
-
);
|
| 367 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 368 |
-
}
|
| 369 |
-
|
| 370 |
-
/**
|
| 371 |
-
* Handle MethodArgumentTypeMismatchException - wrong parameter type.
|
| 372 |
-
* @param ex MethodArgumentTypeMismatchException
|
| 373 |
-
* @return Error response with 400 BAD REQUEST
|
| 374 |
-
*/
|
| 375 |
-
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
|
| 376 |
-
public ResponseEntity<ErrorResponse> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) {
|
| 377 |
-
String message = String.format("Parameter '%s' should be of type %s",
|
| 378 |
-
ex.getName(),
|
| 379 |
-
ex.getRequiredType() != null ? ex.getRequiredType().getSimpleName() : "unknown");
|
| 380 |
-
|
| 381 |
-
ErrorResponse error = new ErrorResponse(
|
| 382 |
-
HttpStatus.BAD_REQUEST.value(),
|
| 383 |
-
message,
|
| 384 |
-
LocalDateTime.now()
|
| 385 |
-
);
|
| 386 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 387 |
-
}
|
| 388 |
-
|
| 389 |
-
/**
|
| 390 |
-
* Handle MissingServletRequestParameterException - missing required parameter.
|
| 391 |
-
* @param ex MissingServletRequestParameterException
|
| 392 |
-
* @return Error response with 400 BAD REQUEST
|
| 393 |
-
*/
|
| 394 |
-
@ExceptionHandler(MissingServletRequestParameterException.class)
|
| 395 |
-
public ResponseEntity<ErrorResponse> handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
|
| 396 |
-
String message = String.format("Required parameter '%s' is missing", ex.getParameterName());
|
| 397 |
-
|
| 398 |
-
ErrorResponse error = new ErrorResponse(
|
| 399 |
-
HttpStatus.BAD_REQUEST.value(),
|
| 400 |
-
message,
|
| 401 |
-
LocalDateTime.now()
|
| 402 |
-
);
|
| 403 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 404 |
-
}
|
| 405 |
-
|
| 406 |
-
/**
|
| 407 |
-
* Handle HttpRequestMethodNotSupportedException - unsupported HTTP method.
|
| 408 |
-
* @param ex HttpRequestMethodNotSupportedException
|
| 409 |
-
* @return Error response with 405 METHOD NOT ALLOWED
|
| 410 |
-
*/
|
| 411 |
-
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
| 412 |
-
public ResponseEntity<ErrorResponse> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) {
|
| 413 |
-
String message = String.format("Method '%s' is not supported for this endpoint", ex.getMethod());
|
| 414 |
-
|
| 415 |
-
ErrorResponse error = new ErrorResponse(
|
| 416 |
-
HttpStatus.METHOD_NOT_ALLOWED.value(),
|
| 417 |
-
message,
|
| 418 |
-
LocalDateTime.now()
|
| 419 |
-
);
|
| 420 |
-
return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).body(error);
|
| 421 |
-
}
|
| 422 |
-
|
| 423 |
-
/**
|
| 424 |
-
* Handle NoHandlerFoundException - endpoint not found.
|
| 425 |
-
* @param ex NoHandlerFoundException
|
| 426 |
-
* @return Error response with 404 NOT FOUND
|
| 427 |
-
*/
|
| 428 |
-
@ExceptionHandler(NoHandlerFoundException.class)
|
| 429 |
-
public ResponseEntity<ErrorResponse> handleNoHandlerFoundException(NoHandlerFoundException ex) {
|
| 430 |
-
String message = String.format("Endpoint '%s' not found", ex.getRequestURL());
|
| 431 |
-
|
| 432 |
-
ErrorResponse error = new ErrorResponse(
|
| 433 |
-
HttpStatus.NOT_FOUND.value(),
|
| 434 |
-
message,
|
| 435 |
-
LocalDateTime.now()
|
| 436 |
-
);
|
| 437 |
-
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
| 438 |
-
}
|
| 439 |
-
|
| 440 |
-
/**
|
| 441 |
-
* Handle IllegalArgumentException - invalid arguments to methods.
|
| 442 |
-
* @param ex IllegalArgumentException
|
| 443 |
-
* @return Error response with 400 BAD REQUEST
|
| 444 |
-
*/
|
| 445 |
-
@ExceptionHandler(IllegalArgumentException.class)
|
| 446 |
-
public ResponseEntity<ErrorResponse> handleIllegalArgumentException(IllegalArgumentException ex) {
|
| 447 |
-
ErrorResponse error = new ErrorResponse(
|
| 448 |
-
HttpStatus.BAD_REQUEST.value(),
|
| 449 |
-
"Invalid argument: " + ex.getMessage(),
|
| 450 |
-
LocalDateTime.now()
|
| 451 |
-
);
|
| 452 |
-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
| 453 |
-
}
|
| 454 |
-
|
| 455 |
-
/**
|
| 456 |
-
* Handle generic exceptions.
|
| 457 |
-
* @param ex Exception
|
| 458 |
-
* @return Error response with 500 INTERNAL SERVER ERROR
|
| 459 |
-
*/
|
| 460 |
-
@ExceptionHandler(Exception.class)
|
| 461 |
-
public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
|
| 462 |
-
ErrorResponse error = new ErrorResponse(
|
| 463 |
-
HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
| 464 |
-
"An unexpected error occurred: " + ex.getMessage(),
|
| 465 |
-
LocalDateTime.now()
|
| 466 |
-
);
|
| 467 |
-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
|
| 468 |
-
}
|
| 469 |
-
|
| 470 |
-
/**
|
| 471 |
-
* Standard error response structure.
|
| 472 |
-
*/
|
| 473 |
-
public static class ErrorResponse {
|
| 474 |
-
private int status;
|
| 475 |
-
private String message;
|
| 476 |
-
private LocalDateTime timestamp;
|
| 477 |
-
|
| 478 |
-
public ErrorResponse(int status, String message, LocalDateTime timestamp) {
|
| 479 |
-
this.status = status;
|
| 480 |
-
this.message = message;
|
| 481 |
-
this.timestamp = timestamp;
|
| 482 |
-
}
|
| 483 |
-
|
| 484 |
-
// Getters
|
| 485 |
-
public int getStatus() { return status; }
|
| 486 |
-
public String getMessage() { return message; }
|
| 487 |
-
public LocalDateTime getTimestamp() { return timestamp; }
|
| 488 |
-
}
|
| 489 |
-
|
| 490 |
-
/**
|
| 491 |
-
* Validation error response with field-level errors.
|
| 492 |
-
*/
|
| 493 |
-
public static class ValidationErrorResponse extends ErrorResponse {
|
| 494 |
-
private Map<String, String> fieldErrors;
|
| 495 |
-
|
| 496 |
-
public ValidationErrorResponse(int status, String message, Map<String, String> fieldErrors, LocalDateTime timestamp) {
|
| 497 |
-
super(status, message, timestamp);
|
| 498 |
-
this.fieldErrors = fieldErrors;
|
| 499 |
-
}
|
| 500 |
-
|
| 501 |
-
// Getter
|
| 502 |
-
public Map<String, String> getFieldErrors() { return fieldErrors; }
|
| 503 |
-
}
|
| 504 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/exception/InsufficientTrustScoreException.java
DELETED
|
@@ -1,31 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.exception;
|
| 2 |
-
|
| 3 |
-
/**
|
| 4 |
-
* Exception thrown when a user's trust score is too low to perform an operation.
|
| 5 |
-
* Example: Cannot create booking with trust score below threshold.
|
| 6 |
-
*/
|
| 7 |
-
public class InsufficientTrustScoreException extends RuntimeException {
|
| 8 |
-
private final String userId;
|
| 9 |
-
private final Double currentScore;
|
| 10 |
-
private final Double requiredScore;
|
| 11 |
-
|
| 12 |
-
public InsufficientTrustScoreException(String userId, Double currentScore, Double requiredScore) {
|
| 13 |
-
super(String.format("User '%s' has insufficient trust score. Current: %.2f, Required: %.2f",
|
| 14 |
-
userId, currentScore, requiredScore));
|
| 15 |
-
this.userId = userId;
|
| 16 |
-
this.currentScore = currentScore;
|
| 17 |
-
this.requiredScore = requiredScore;
|
| 18 |
-
}
|
| 19 |
-
|
| 20 |
-
public String getUserId() {
|
| 21 |
-
return userId;
|
| 22 |
-
}
|
| 23 |
-
|
| 24 |
-
public Double getCurrentScore() {
|
| 25 |
-
return currentScore;
|
| 26 |
-
}
|
| 27 |
-
|
| 28 |
-
public Double getRequiredScore() {
|
| 29 |
-
return requiredScore;
|
| 30 |
-
}
|
| 31 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/exception/InvalidBookingPeriodException.java
DELETED
|
@@ -1,38 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.exception;
|
| 2 |
-
|
| 3 |
-
/**
|
| 4 |
-
* Exception thrown when a booking period violates rental period constraints.
|
| 5 |
-
*/
|
| 6 |
-
public class InvalidBookingPeriodException extends RuntimeException {
|
| 7 |
-
|
| 8 |
-
private Integer minDays;
|
| 9 |
-
private Integer maxDays;
|
| 10 |
-
private Long requestedDays;
|
| 11 |
-
|
| 12 |
-
public InvalidBookingPeriodException(String message) {
|
| 13 |
-
super(message);
|
| 14 |
-
}
|
| 15 |
-
|
| 16 |
-
public InvalidBookingPeriodException(String message, Integer minDays, Integer maxDays, Long requestedDays) {
|
| 17 |
-
super(message);
|
| 18 |
-
this.minDays = minDays;
|
| 19 |
-
this.maxDays = maxDays;
|
| 20 |
-
this.requestedDays = requestedDays;
|
| 21 |
-
}
|
| 22 |
-
|
| 23 |
-
public InvalidBookingPeriodException(String message, Throwable cause) {
|
| 24 |
-
super(message, cause);
|
| 25 |
-
}
|
| 26 |
-
|
| 27 |
-
public Integer getMinDays() {
|
| 28 |
-
return minDays;
|
| 29 |
-
}
|
| 30 |
-
|
| 31 |
-
public Integer getMaxDays() {
|
| 32 |
-
return maxDays;
|
| 33 |
-
}
|
| 34 |
-
|
| 35 |
-
public Long getRequestedDays() {
|
| 36 |
-
return requestedDays;
|
| 37 |
-
}
|
| 38 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/main/java/com/locallend/locallend/exception/InvalidOperationException.java
DELETED
|
@@ -1,30 +0,0 @@
|
|
| 1 |
-
package com.locallend.locallend.exception;
|
| 2 |
-
|
| 3 |
-
/**
|
| 4 |
-
* Exception thrown when an operation cannot be performed due to the current state.
|
| 5 |
-
* Examples: Cannot delete active booking, cannot modify completed booking, etc.
|
| 6 |
-
*/
|
| 7 |
-
public class InvalidOperationException extends RuntimeException {
|
| 8 |
-
private final String operation;
|
| 9 |
-
private final String reason;
|
| 10 |
-
|
| 11 |
-
public InvalidOperationException(String operation, String reason) {
|
| 12 |
-
super(String.format("Cannot perform operation '%s': %s", operation, reason));
|
| 13 |
-
this.operation = operation;
|
| 14 |
-
this.reason = reason;
|
| 15 |
-
}
|
| 16 |
-
|
| 17 |
-
public InvalidOperationException(String message) {
|
| 18 |
-
super(message);
|
| 19 |
-
this.operation = null;
|
| 20 |
-
this.reason = null;
|
| 21 |
-
}
|
| 22 |
-
|
| 23 |
-
public String getOperation() {
|
| 24 |
-
return operation;
|
| 25 |
-
}
|
| 26 |
-
|
| 27 |
-
public String getReason() {
|
| 28 |
-
return reason;
|
| 29 |
-
}
|
| 30 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|