diff --git a/.github/workflows/backdeploy.yaml b/.github/workflows/backdeploy.yaml index bd9b277a..c3adff92 100644 --- a/.github/workflows/backdeploy.yaml +++ b/.github/workflows/backdeploy.yaml @@ -17,30 +17,30 @@ env: jobs: build: runs-on: ubuntu-latest + defaults: + run: + working-directory: ./server steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Restore gradle dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: "~/.gradle" - key: ${{ runner.os }}-modules-${{ hashFiles('**/server/build.gradle') }} - - name: Set up JDK 11 - uses: actions/setup-java@v2 + key: ${{ runner.os }}-modules-${{ hashFiles('**/build.gradle.kts') }} + - name: Set up JDK 21 + uses: actions/setup-java@v4 with: - java-version: "11" - distribution: "adopt" - - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b + distribution: "zulu" + java-version: "21" - name: Add version info run: | export GIT_HASH=$(git rev-parse --short HEAD) - sed -i "s|version: 1.0.0|version: ${GIT_HASH}|g" server/src/main/resources/application.yaml + sed -i "s|version: 1.0.0|version: ${GIT_HASH}|g" src/main/resources/application.yaml - name: Build jar - run: ./server/gradlew build -p server -x test + run: ./gradlew build -x test - name: Build and push to ECR run: | - cd server ./gradlew clean build --info -x test export STAGE=prod diff --git a/.github/workflows/backtest.yaml b/.github/workflows/backtest.yaml index d9b50b56..4ead02ab 100644 --- a/.github/workflows/backtest.yaml +++ b/.github/workflows/backtest.yaml @@ -11,28 +11,24 @@ on: jobs: build: runs-on: ubuntu-latest + defaults: + run: + working-directory: ./server steps: - name: Checkout uses: actions/checkout@v4 - - name: Restoreß dependencies - uses: actions/cache@v3 - with: - path: "**/server/test-web-server/node_modules" - key: ${{ runner.os }}-v2-${{ hashFiles('**/server/test-web-server/package-lock.json') }} - name: Restore gradle dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: "~/.gradle" - key: ${{ runner.os }}-modules-${{ hashFiles('**/server/build.gradle') }} - - name: Set up JDK 11 + key: ${{ runner.os }}-modules-${{ hashFiles('**/build.gradle.kts') }} + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: "11" - distribution: "adopt" - - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@v1 + distribution: "zulu" + java-version: "21" - name: Run containers - run: docker compose -f server/docker-compose-test.yaml up -d + run: docker compose -f docker-compose-test.yaml up -d - name: Wait for database to start run: | for i in `seq 1 60`; @@ -43,4 +39,4 @@ jobs: done echo Failed waiting for mysql && exit 1 - name: Build and test - run: ./server/gradlew clean build -p server --info + run: ./gradlew clean build --info diff --git a/client/src/main/api/DatabaseQueryApi.ts b/client/src/main/api/DatabaseQueryApi.ts index be6bc78b..19846811 100644 --- a/client/src/main/api/DatabaseQueryApi.ts +++ b/client/src/main/api/DatabaseQueryApi.ts @@ -9,17 +9,17 @@ export class DatabaseQueryApi { BASE_URL: string; constructor() { - this.BASE_URL = API_URL + "/database/"; + this.BASE_URL = API_URL + "/database"; } queryDatabase = (sqlQuery: string, page: number, size: number) => { - let url = this.BASE_URL + "query"; + let url = this.BASE_URL + "/query"; let body = { sqlQuery, page, size }; return Axios.post(url, body); }; queryDatabaseMeta = () => { - let url = this.BASE_URL + "meta"; + let url = this.BASE_URL + "/meta"; return Axios.get(url); }; } diff --git a/client/src/main/components/Footer.tsx b/client/src/main/components/Footer.tsx index a12c306b..46779cd5 100644 --- a/client/src/main/components/Footer.tsx +++ b/client/src/main/components/Footer.tsx @@ -15,9 +15,7 @@ const Footer = () => { FAQ
  • - - Contact - + Contact
  • diff --git a/client/src/main/components/Topbar.css b/client/src/main/components/Topbar.css index e192afb0..8646a51c 100644 --- a/client/src/main/components/Topbar.css +++ b/client/src/main/components/Topbar.css @@ -17,4 +17,4 @@ nav a span { #top-bar .ant-menu-item img { vertical-align: middle; -} \ No newline at end of file +} diff --git a/server/Dockerfile b/server/Dockerfile index 00163d3b..e5a4ac2c 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,4 +1,4 @@ -FROM adoptopenjdk/openjdk11:latest -ARG JAR_FILE=build/libs/statistics-server.jar +FROM eclipse-temurin:21 +ARG JAR_FILE=build/libs/app.jar COPY ${JAR_FILE} app.jar ENTRYPOINT ["java","-jar","/app.jar"] diff --git a/server/build.gradle b/server/build.gradle deleted file mode 100644 index a9fc6438..00000000 --- a/server/build.gradle +++ /dev/null @@ -1,81 +0,0 @@ -plugins { - id "io.spring.dependency-management" version "1.0.11.RELEASE" - id 'org.springframework.boot' version '2.6.3' - id "org.sonarqube" version "3.3" - id "jacoco" - id "java" -} - -group = "org.worldcubeassociation" -version = "0.0.1-SNAPSHOT" -sourceCompatibility = "11" - -ext { - lombokVersion = "1.18.24" - simpleflatmapperVersion = "8.2.3" - springfoxVersion = "3.0.0" - restAssuredVersion = "5.1.1" - jacksonVersion = "2.13.3" -} - -repositories { - mavenCentral() -} - -bootJar { - archiveFileName = "statistics-server.jar" -} - -tasks.named("test") { - useJUnitPlatform() -} - -test { - finalizedBy jacocoTestReport // report is always generated after tests run -} - -jacocoTestReport { - dependsOn test // tests are required to run before generating the report - - reports { - xml.required = true - csv.required = false - html.outputLocation = layout.buildDirectory.dir("jacocoHtml") - } -} - -dependencies { - implementation "org.springframework.boot:spring-boot-starter" - implementation "org.springframework.boot:spring-boot-starter-web" - implementation "org.springframework.boot:spring-boot-starter-actuator" - implementation "org.springframework.boot:spring-boot-starter-data-jpa" - implementation "org.springframework.boot:spring-boot-starter-data-jdbc" - implementation "org.springframework.boot:spring-boot-starter-validation" - - testImplementation "org.springframework.boot:spring-boot-starter-test" - - implementation "org.projectlombok:lombok:$lombokVersion" - compileOnly "org.projectlombok:lombok:$lombokVersion" - annotationProcessor "org.projectlombok:lombok:$lombokVersion" - - implementation 'mysql:mysql-connector-java:8.0.29' - - implementation 'org.springdoc:springdoc-openapi-ui:1.6.9' - - implementation "org.apache.commons:commons-lang3:3.12.0" - - implementation 'org.yaml:snakeyaml:1.30' - - implementation 'com.vladmihalcea:hibernate-types-5:2.16.2' - - implementation "org.simpleflatmapper:sfm-springjdbc:$simpleflatmapperVersion" - implementation "org.simpleflatmapper:sfm-tuples:$simpleflatmapperVersion" - - testImplementation "io.rest-assured:rest-assured:$restAssuredVersion" - testImplementation "io.rest-assured:json-path:$restAssuredVersion" - testImplementation "io.rest-assured:xml-path:$restAssuredVersion" - - testImplementation 'com.google.guava:guava:31.1-jre' - - implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jacksonVersion" -} \ No newline at end of file diff --git a/server/build.gradle.kts b/server/build.gradle.kts new file mode 100644 index 00000000..e5d9c649 --- /dev/null +++ b/server/build.gradle.kts @@ -0,0 +1,74 @@ +plugins { + kotlin("jvm") version "1.9.25" + kotlin("plugin.spring") version "1.9.25" + id("org.springframework.boot") version "3.4.4" + id("io.spring.dependency-management") version "1.1.7" +} + +group = "com.example" +version = "0.0.1-SNAPSHOT" + +// Multiple usages +val springBootVersion = "3.4.4" +val lombokVersion = "1.18.38" +val simpleFlatMapperVersion = "8.2.3" + +// Single usage +val openApiVersion = "2.8.6" +val hypersistenceUtilsVersion = "3.9.0" +val mySqlConnectorVersion = "8.0.33" +val guavaVersion = "33.4.8-jre" +val restAssuredVersion = "5.5.1" + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter") + implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}") + implementation("org.springframework.boot:spring-boot-starter-data-jpa:${springBootVersion}") + implementation("org.springframework.boot:spring-boot-starter-validation:${springBootVersion}") + + implementation("com.google.guava:guava:$guavaVersion") + implementation("mysql:mysql-connector-java:${mySqlConnectorVersion}") + implementation("org.simpleflatmapper:sfm-tuples:${simpleFlatMapperVersion}") + implementation("org.simpleflatmapper:sfm-springjdbc:${simpleFlatMapperVersion}") + implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:$openApiVersion") + implementation("io.hypersistence:hypersistence-utils-hibernate-63:${hypersistenceUtilsVersion}") + + implementation("org.jetbrains.kotlin:kotlin-reflect") + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") + + compileOnly("org.projectlombok:lombok:$lombokVersion") + annotationProcessor("org.projectlombok:lombok:$lombokVersion") + + testCompileOnly("org.projectlombok:lombok:$lombokVersion") + testAnnotationProcessor("org.projectlombok:lombok:$lombokVersion") + + testImplementation("io.rest-assured:rest-assured:${restAssuredVersion}") +} + +kotlin { + compilerOptions { + freeCompilerArgs.addAll("-Xjsr305=strict") + } +} + +tasks.withType { + useJUnitPlatform() +} + +tasks { + bootJar { + archiveFileName.set("app.jar") + } +} diff --git a/server/gradle/wrapper/gradle-wrapper.jar b/server/gradle/wrapper/gradle-wrapper.jar index 7454180f..9bbc975c 100644 Binary files a/server/gradle/wrapper/gradle-wrapper.jar and b/server/gradle/wrapper/gradle-wrapper.jar differ diff --git a/server/gradle/wrapper/gradle-wrapper.properties b/server/gradle/wrapper/gradle-wrapper.properties index 2e6e5897..37f853b1 100644 --- a/server/gradle/wrapper/gradle-wrapper.properties +++ b/server/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/server/gradlew b/server/gradlew index 1b6c7873..faf93008 100755 --- a/server/gradlew +++ b/server/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +82,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +133,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +200,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +216,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/server/gradlew.bat b/server/gradlew.bat index ac1b06f9..9b42019c 100644 --- a/server/gradlew.bat +++ b/server/gradlew.bat @@ -13,8 +13,10 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +27,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/server/settings.gradle b/server/settings.gradle deleted file mode 100644 index 096502d2..00000000 --- a/server/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'server' diff --git a/server/settings.gradle.kts b/server/settings.gradle.kts new file mode 100644 index 00000000..ee663863 --- /dev/null +++ b/server/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "Statistics Server" diff --git a/server/src/main/java/org/worldcubeassociation/statistics/StatisticsApplication.java b/server/src/main/java/org/worldcubeassociation/statistics/StatisticsApplication.java index 3b209af8..98ed2792 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/StatisticsApplication.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/StatisticsApplication.java @@ -1,11 +1,11 @@ package org.worldcubeassociation.statistics; +import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import javax.annotation.PostConstruct; @Slf4j @SpringBootApplication @@ -17,9 +17,9 @@ public class StatisticsApplication { @PostConstruct private void message() { log.info("\n----------------------------------------------------------\n" - + "\tAccess URL:\n" - + "\thttp://localhost:{}/swagger-ui/index.html\n" - + "----------------------------------------------------------", port); + + "\tAccess URL:\n" + + "\thttp://localhost:{}/swagger-ui/index.html\n" + + "----------------------------------------------------------", port); } public static void main(String[] args) { diff --git a/server/src/main/java/org/worldcubeassociation/statistics/config/GlobalException.java b/server/src/main/java/org/worldcubeassociation/statistics/config/GlobalException.java index 518348d4..644800bc 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/config/GlobalException.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/config/GlobalException.java @@ -11,8 +11,8 @@ import org.worldcubeassociation.statistics.exception.NotFoundException; import org.worldcubeassociation.statistics.exception.UnauthorizedException; -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; import java.util.stream.Collectors; @ControllerAdvice diff --git a/server/src/main/java/org/worldcubeassociation/statistics/config/Swagger2Config.java b/server/src/main/java/org/worldcubeassociation/statistics/config/Swagger2Config.java index c41c419c..5bdab6e2 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/config/Swagger2Config.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/config/Swagger2Config.java @@ -16,9 +16,10 @@ public class Swagger2Config { @Bean public OpenAPI publicApi() { return new OpenAPI() - .info(new Info().title("WCA Statistics API") - .description("An API for serving WCA Statistics project.") - .version(version) - .license(new License().name("GPLv3").url("https://www.gnu.org/licenses/gpl-3.0.html"))); + .info(new Info().title("WCA Statistics API") + .description("An API for serving WCA Statistics project.") + .version(version) + .license( + new License().name("GPLv3").url("https://www.gnu.org/licenses/gpl-3.0.html"))); } } \ No newline at end of file diff --git a/server/src/main/java/org/worldcubeassociation/statistics/controller/BestEverRanksController.java b/server/src/main/java/org/worldcubeassociation/statistics/controller/BestEverRanksController.java index bf447b2c..39178542 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/controller/BestEverRanksController.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/controller/BestEverRanksController.java @@ -5,7 +5,7 @@ import org.worldcubeassociation.statistics.request.BestEverRanksRequest; import org.worldcubeassociation.statistics.response.BestEverRanksResponse; -import javax.validation.Valid; +import jakarta.validation.Valid; @RequestMapping("best-ever-rank") @CrossOrigin(origins = "*", allowedHeaders = "*") // Enable this for testing diff --git a/server/src/main/java/org/worldcubeassociation/statistics/controller/DatabaseQueryController.java b/server/src/main/java/org/worldcubeassociation/statistics/controller/DatabaseQueryController.java index 8a0acd69..00de279d 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/controller/DatabaseQueryController.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/controller/DatabaseQueryController.java @@ -11,7 +11,7 @@ import org.worldcubeassociation.statistics.request.DatabaseQueryRequest; import org.worldcubeassociation.statistics.response.DatabaseQueryMetaResponse; -import javax.validation.Valid; +import jakarta.validation.Valid; @RequestMapping("database") @CrossOrigin(origins = "*", allowedHeaders = "*") // Enable this for testing diff --git a/server/src/main/java/org/worldcubeassociation/statistics/controller/StatisticsController.java b/server/src/main/java/org/worldcubeassociation/statistics/controller/StatisticsController.java index 82fd7197..9973ead2 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/controller/StatisticsController.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/controller/StatisticsController.java @@ -16,7 +16,7 @@ import org.worldcubeassociation.statistics.dto.StatisticsResponseDTO; import java.io.IOException; -import javax.validation.Valid; +import jakarta.validation.Valid; @RequestMapping("statistics") @CrossOrigin(origins = "*", allowedHeaders = "*") // Enable this for testing diff --git a/server/src/main/java/org/worldcubeassociation/statistics/controller/SumOfRanksController.java b/server/src/main/java/org/worldcubeassociation/statistics/controller/SumOfRanksController.java index 02c070ae..7cee0233 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/controller/SumOfRanksController.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/controller/SumOfRanksController.java @@ -12,7 +12,7 @@ import org.worldcubeassociation.statistics.response.rank.SumOfRanksResponse; import java.util.List; -import javax.validation.Valid; +import jakarta.validation.Valid; @RequestMapping("sum-of-ranks") @CrossOrigin(origins = "*", allowedHeaders = "*") diff --git a/server/src/main/java/org/worldcubeassociation/statistics/controller/impl/StatisticsControllerImpl.java b/server/src/main/java/org/worldcubeassociation/statistics/controller/impl/StatisticsControllerImpl.java index 541b632b..61dcd4e2 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/controller/impl/StatisticsControllerImpl.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/controller/impl/StatisticsControllerImpl.java @@ -10,7 +10,7 @@ import org.worldcubeassociation.statistics.service.AuthorizationService; import org.worldcubeassociation.statistics.service.StatisticsService; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.io.IOException; @RestController diff --git a/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsDTO.java b/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsDTO.java index e7c629d8..7f46b0dc 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsDTO.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsDTO.java @@ -1,19 +1,20 @@ package org.worldcubeassociation.statistics.dto; + import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.Data; import org.worldcubeassociation.statistics.enums.DisplayModeEnum; -import java.util.List; -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - @Data @JsonInclude(JsonInclude.Include.NON_NULL) public class StatisticsDTO { + @JsonProperty("version") private static final String VERSION = "v1"; @@ -22,7 +23,7 @@ public class StatisticsDTO { private String title; @Schema(title = "Explanation about the current statistic.", - example = "Number of competitions in each country sorted from the highest to the lowest.") + example = "Number of competitions in each country sorted from the highest to the lowest.") private String explanation; @NotNull @@ -30,9 +31,10 @@ public class StatisticsDTO { @NotNull @Schema( - title = "In case of grouped statistics, you can select DEFAULT to display all of them in the frontend or " - + "'SELECTOR' to group them in a selector.", - example = "DEFAULT") + title = + "In case of grouped statistics, you can select DEFAULT to display all of them in the frontend or " + + "'SELECTOR' to group them in a selector.", + example = "DEFAULT") private DisplayModeEnum displayMode; @NotBlank diff --git a/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsGroupRequestDTO.java b/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsGroupRequestDTO.java index d32839c7..a4f82a86 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsGroupRequestDTO.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsGroupRequestDTO.java @@ -1,12 +1,12 @@ package org.worldcubeassociation.statistics.dto; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.NotBlank; import lombok.Data; import lombok.EqualsAndHashCode; import java.util.List; -import javax.validation.constraints.AssertTrue; -import javax.validation.constraints.NotBlank; @Data @EqualsAndHashCode(callSuper = true) diff --git a/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsGroupResponseDTO.java b/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsGroupResponseDTO.java index ff6c9277..41040441 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsGroupResponseDTO.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsGroupResponseDTO.java @@ -2,35 +2,36 @@ import com.fasterxml.jackson.annotation.JsonInclude; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.util.List; import lombok.Data; import lombok.EqualsAndHashCode; -import java.util.List; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - @Data @EqualsAndHashCode(callSuper = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class StatisticsGroupResponseDTO extends StatisticsGroupBaseDTO { + @NotNull @Schema(title = "Group identifier", example = "[\"2010\"], [\"Brazil\", \"2010\"]") private List<@NotBlank String> keys; @Schema( - title = "The same query but filtered somehow (example by user, country or competition) with a replaceable" - + " placeholder for finding a specific result", - example = - "select countryId, count(*) qt from Competitions where countryId = ':COUNTRY_ID' group by " - + "countryId " - + "order by qt desc") + title = + "The same query but filtered somehow (example by user, country or competition) with a replaceable" + + " placeholder for finding a specific result", + example = + "select countryId, count(*) qt from Competitions where countryId = ':COUNTRY_ID' group by " + + "countryId " + + "order by qt desc") private String sqlQueryCustom; @NotNull @Size(max = 100) // Competitions has over 60 columns @Schema(title = "Custom table headers. If none is provided, it will default to the SQL columns response.", - example = "[\"Country\",\"Competitions\"]") + example = "[\"Country\",\"Competitions\"]") private List headers; @NotNull diff --git a/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsRequestDTO.java b/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsRequestDTO.java index 19f9f712..632fc81b 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsRequestDTO.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsRequestDTO.java @@ -2,17 +2,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; import lombok.Data; import org.worldcubeassociation.statistics.enums.DisplayModeEnum; -import java.util.List; -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; - @Data public class StatisticsRequestDTO { + @JsonProperty("version") private static final String VERSION = "v1"; @@ -21,21 +21,22 @@ public class StatisticsRequestDTO { private String title; @Schema(title = "Explanation about the current statistic.", - example = "Number of competitions in each country sorted from the highest to the lowest.") + example = "Number of competitions in each country sorted from the highest to the lowest.") private String explanation; @NotEmpty @Schema(title = - "Groups statistics results by key. Example: you can use [{'key': '2010', 'explanation': 'Competitions in " - + "2010', 'sqlQuery': 'select * from... where year = 2010'}, {'key': '2015', 'explanation': " - + "'Competitions in 2015', 'sqlQuery': 'select * from ... where year = 2015'}]") + "Groups statistics results by key. Example: you can use [{'key': '2010', 'explanation': 'Competitions in " + + "2010', 'sqlQuery': 'select * from... where year = 2010'}, {'key': '2015', 'explanation': " + + "'Competitions in 2015', 'sqlQuery': 'select * from ... where year = 2015'}]") private List<@Valid StatisticsGroupRequestDTO> queries; @Valid @Schema( - title = "In case of grouped statistics, you can select DEFAULT to display all of them in the frontend or " - + "'SELECTOR' to group them in a selector.", - example = "DEFAULT") + title = + "In case of grouped statistics, you can select DEFAULT to display all of them in the frontend or " + + "'SELECTOR' to group them in a selector.", + example = "DEFAULT") private DisplayModeEnum displayMode; @NotBlank diff --git a/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsResponseDTO.java b/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsResponseDTO.java index 49ef6b5e..a40d5a1a 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsResponseDTO.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/dto/StatisticsResponseDTO.java @@ -2,12 +2,12 @@ import com.fasterxml.jackson.annotation.JsonInclude; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.Data; import lombok.EqualsAndHashCode; import java.time.LocalDateTime; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; @Data @EqualsAndHashCode(callSuper = true) diff --git a/server/src/main/java/org/worldcubeassociation/statistics/model/BaseEntity.java b/server/src/main/java/org/worldcubeassociation/statistics/model/BaseEntity.java deleted file mode 100644 index 0c8b9dd6..00000000 --- a/server/src/main/java/org/worldcubeassociation/statistics/model/BaseEntity.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.worldcubeassociation.statistics.model; - -import com.vladmihalcea.hibernate.type.json.JsonBinaryType; -import com.vladmihalcea.hibernate.type.json.JsonStringType; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; - -import javax.persistence.MappedSuperclass; - -@TypeDefs({ - @TypeDef(name = "json", typeClass = JsonStringType.class), - @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) -}) -@MappedSuperclass -public class BaseEntity { -} diff --git a/server/src/main/java/org/worldcubeassociation/statistics/model/BestEverRank.java b/server/src/main/java/org/worldcubeassociation/statistics/model/BestEverRank.java index f6fc24d3..96bc5fa4 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/model/BestEverRank.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/model/BestEverRank.java @@ -1,22 +1,21 @@ package org.worldcubeassociation.statistics.model; +import io.hypersistence.utils.hibernate.type.json.JsonType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import java.time.LocalDateTime; +import java.util.List; import lombok.Data; -import lombok.EqualsAndHashCode; import lombok.experimental.FieldNameConstants; import org.hibernate.annotations.Type; import org.worldcubeassociation.statistics.dto.besteverrank.EventRankDTO; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import java.time.LocalDateTime; -import java.util.List; - @Data @Entity @FieldNameConstants(asEnum = true) -@EqualsAndHashCode(callSuper = true) -public class BestEverRank extends BaseEntity implements Comparable { +public class BestEverRank implements Comparable { + @Id @Column(name = "person_id") private String personId; @@ -24,7 +23,7 @@ public class BestEverRank extends BaseEntity implements Comparable @Column(name = "last_modified") private LocalDateTime lastModified; - @Type(type = "json") + @Type(JsonType.class) @Column(columnDefinition = "json", name = "best_ever_rank") private List eventRanks; diff --git a/server/src/main/java/org/worldcubeassociation/statistics/model/Event.java b/server/src/main/java/org/worldcubeassociation/statistics/model/Event.java index a8243058..e29340fd 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/model/Event.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/model/Event.java @@ -3,8 +3,8 @@ import lombok.Data; import lombok.experimental.FieldNameConstants; -import javax.persistence.Entity; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; @Data @Entity diff --git a/server/src/main/java/org/worldcubeassociation/statistics/model/RecordEvolution.java b/server/src/main/java/org/worldcubeassociation/statistics/model/RecordEvolution.java index 8b58e0da..b6590a77 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/model/RecordEvolution.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/model/RecordEvolution.java @@ -1,26 +1,25 @@ package org.worldcubeassociation.statistics.model; +import io.hypersistence.utils.hibernate.type.json.JsonType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import java.util.List; import lombok.Data; -import lombok.EqualsAndHashCode; import lombok.experimental.FieldNameConstants; import org.hibernate.annotations.Type; import org.worldcubeassociation.statistics.dto.recordevolution.EvolutionDto; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import java.util.List; - @Data @Entity @FieldNameConstants(asEnum = true) -@EqualsAndHashCode(callSuper = true) -public class RecordEvolution extends BaseEntity { +public class RecordEvolution { + @Id @Column(name = "event_id") private String eventId; - @Type(type = "json") + @Type(JsonType.class) @Column(columnDefinition = "json", name = "evolution") private List evolution; } diff --git a/server/src/main/java/org/worldcubeassociation/statistics/model/Statistics.java b/server/src/main/java/org/worldcubeassociation/statistics/model/Statistics.java index 71858e47..b832e38c 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/model/Statistics.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/model/Statistics.java @@ -1,23 +1,22 @@ package org.worldcubeassociation.statistics.model; +import io.hypersistence.utils.hibernate.type.json.JsonType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Id; +import java.time.LocalDateTime; +import java.util.List; import lombok.Data; -import lombok.EqualsAndHashCode; import org.hibernate.annotations.Type; import org.worldcubeassociation.statistics.dto.StatisticsGroupResponseDTO; import org.worldcubeassociation.statistics.enums.DisplayModeEnum; -import java.time.LocalDateTime; -import java.util.List; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; - @Data @Entity -@EqualsAndHashCode(callSuper = true) -public class Statistics extends BaseEntity { +public class Statistics { + @Id private String path; @@ -32,8 +31,7 @@ public class Statistics extends BaseEntity { @Column(name = "group_name") private String groupName; - @Type(type = "json") - @Column(columnDefinition = "json") + @Type(JsonType.class) private List statistics; @Column(name = "last_modified") diff --git a/server/src/main/java/org/worldcubeassociation/statistics/model/StatisticsControl.java b/server/src/main/java/org/worldcubeassociation/statistics/model/StatisticsControl.java index 680922ae..2d5a02c1 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/model/StatisticsControl.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/model/StatisticsControl.java @@ -1,27 +1,19 @@ package org.worldcubeassociation.statistics.model; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import java.time.LocalDateTime; -import java.util.List; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; -import javax.persistence.Table; -import lombok.Data; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; -import org.hibernate.annotations.Type; -import org.worldcubeassociation.statistics.dto.StatisticsGroupResponseDTO; -import org.worldcubeassociation.statistics.enums.DisplayModeEnum; @Getter @Setter @Entity -@EqualsAndHashCode(callSuper = true) @Table(name = "statistics_control") -public class StatisticsControl extends BaseEntity { +public class StatisticsControl { + @Id private String path; diff --git a/server/src/main/java/org/worldcubeassociation/statistics/repository/StatisticsRepository.java b/server/src/main/java/org/worldcubeassociation/statistics/repository/StatisticsRepository.java index 50728474..62b31121 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/repository/StatisticsRepository.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/repository/StatisticsRepository.java @@ -11,7 +11,7 @@ public interface StatisticsRepository extends JpaRepository { @Query("select new org.worldcubeassociation.statistics.dto.ControlItemDTO(path, title, groupName) from Statistics" - + " where :term is null or :term = '' or lower(statistics) like concat('%', lower(:term), '%')") + + " where :term is null or :term = '' or lower(cast(statistics as char)) like concat('%', lower(:term), '%')") List list(String term); // Actually, it is just an approximation diff --git a/server/src/main/java/org/worldcubeassociation/statistics/repository/jdbc/impl/RecordEvolutionRepositoryJdbcImpl.java b/server/src/main/java/org/worldcubeassociation/statistics/repository/jdbc/impl/RecordEvolutionRepositoryJdbcImpl.java index 65feb139..fe032b70 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/repository/jdbc/impl/RecordEvolutionRepositoryJdbcImpl.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/repository/jdbc/impl/RecordEvolutionRepositoryJdbcImpl.java @@ -1,6 +1,5 @@ package org.worldcubeassociation.statistics.repository.jdbc.impl; -import org.simpleflatmapper.jdbc.spring.JdbcTemplateMapperFactory; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; @@ -11,6 +10,7 @@ import org.worldcubeassociation.statistics.repository.jdbc.RecordEvolutionRepositoryJdbc; import org.worldcubeassociation.statistics.util.JsonUtil; import org.worldcubeassociation.statistics.util.StatisticsUtil; +import org.simpleflatmapper.jdbc.spring.JdbcTemplateMapperFactory; import java.time.LocalDate; import java.util.HashMap; diff --git a/server/src/main/java/org/worldcubeassociation/statistics/request/BestEverRanksRequest.java b/server/src/main/java/org/worldcubeassociation/statistics/request/BestEverRanksRequest.java index bb04a602..0bd74d73 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/request/BestEverRanksRequest.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/request/BestEverRanksRequest.java @@ -5,8 +5,8 @@ import lombok.experimental.FieldNameConstants; import java.util.List; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; @Data @FieldNameConstants(asEnum = true) diff --git a/server/src/main/java/org/worldcubeassociation/statistics/request/DatabaseQueryRequest.java b/server/src/main/java/org/worldcubeassociation/statistics/request/DatabaseQueryRequest.java index 0d6e9b67..b5c197ca 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/request/DatabaseQueryRequest.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/request/DatabaseQueryRequest.java @@ -2,9 +2,9 @@ import lombok.Data; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; @Data public class DatabaseQueryRequest { diff --git a/server/src/main/java/org/worldcubeassociation/statistics/request/PageRequest.java b/server/src/main/java/org/worldcubeassociation/statistics/request/PageRequest.java index 16d9d82e..0c02b11c 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/request/PageRequest.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/request/PageRequest.java @@ -2,8 +2,8 @@ import lombok.Data; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; @Data public class PageRequest { diff --git a/server/src/main/java/org/worldcubeassociation/statistics/service/StatisticsService.java b/server/src/main/java/org/worldcubeassociation/statistics/service/StatisticsService.java index d207abca..ffddedd5 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/service/StatisticsService.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/service/StatisticsService.java @@ -7,7 +7,7 @@ import java.io.IOException; import java.time.LocalDateTime; -import javax.validation.Valid; +import jakarta.validation.Valid; public interface StatisticsService { StatisticsResponseDTO sqlToStatistics(StatisticsRequestDTO statisticsRequestDTO) throws IOException; diff --git a/server/src/main/java/org/worldcubeassociation/statistics/service/impl/StatisticsServiceImpl.java b/server/src/main/java/org/worldcubeassociation/statistics/service/impl/StatisticsServiceImpl.java index 72c40233..5bfb5168 100644 --- a/server/src/main/java/org/worldcubeassociation/statistics/service/impl/StatisticsServiceImpl.java +++ b/server/src/main/java/org/worldcubeassociation/statistics/service/impl/StatisticsServiceImpl.java @@ -1,6 +1,7 @@ package org.worldcubeassociation.statistics.service.impl; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.validation.Valid; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; @@ -15,7 +16,6 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; -import javax.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.core.io.Resource; @@ -23,6 +23,8 @@ import org.springframework.core.io.support.ResourcePatternUtils; import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; import org.worldcubeassociation.statistics.dto.ControlItemDTO; import org.worldcubeassociation.statistics.dto.DatabaseQueryBaseDTO; import org.worldcubeassociation.statistics.dto.StatisticsDTO; @@ -204,6 +206,7 @@ private void resourcesToStatistics(List resources) throws IOException } @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) public StatisticsListDTO list(String term) { /* It would be better if we could write a query to retrieve the items ordered already, but mysql does not support it @@ -239,10 +242,10 @@ public StatisticsListDTO list(String term) { .statistics(k.getValue() // Sort inner statistics based on title .stream().sorted(Comparator.comparing(ControlItemDTO::getTitle)) - .collect(Collectors.toList())).build()) + .toList()).build()) // Sorts groups based on group name .sorted(Comparator.comparing(StatisticsGroupDTO::getGroup)) - .collect(Collectors.toList()); + .toList(); StatisticsListDTO statisticsListDTO = new StatisticsListDTO(); statisticsListDTO.setList(list); diff --git a/server/src/main/resources/application-cron.yaml b/server/src/main/resources/application-cron.yaml index 0a03cb34..70d4560a 100644 --- a/server/src/main/resources/application-cron.yaml +++ b/server/src/main/resources/application-cron.yaml @@ -4,7 +4,11 @@ spring: url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_DATABASE} username: ${DB_USERNAME} password: ${DB_PASSWORD} - initialization-mode: always + sql: + init: + mode: always + schema-locations: classpath:schema.sql + api: wca: baseurl: https://www.worldcubeassociation.org diff --git a/server/src/main/resources/application-local.yaml b/server/src/main/resources/application-local.yaml index 50596e01..a6071646 100644 --- a/server/src/main/resources/application-local.yaml +++ b/server/src/main/resources/application-local.yaml @@ -4,7 +4,10 @@ spring: url: jdbc:mysql://localhost:3306/wca_development username: root password: - initialization-mode: always + sql: + init: + mode: always + schema-locations: classpath:schema.sql api: wca: baseurl: https://www.worldcubeassociation.org diff --git a/server/src/main/resources/application-test.yaml b/server/src/main/resources/application-test.yaml index 5f283ad7..a288e6e0 100644 --- a/server/src/main/resources/application-test.yaml +++ b/server/src/main/resources/application-test.yaml @@ -4,7 +4,10 @@ spring: url: jdbc:mysql://localhost:3307/wca_development username: root password: - initialization-mode: always + sql: + init: + mode: always + schema-locations: classpath:schema.sql api: wca: baseurl: http://localhost:3500 diff --git a/server/src/test/java/org/worldcubeassociation/statistics/integration/AbstractTest.java b/server/src/test/java/org/worldcubeassociation/statistics/integration/AbstractIT.java similarity index 92% rename from server/src/test/java/org/worldcubeassociation/statistics/integration/AbstractTest.java rename to server/src/test/java/org/worldcubeassociation/statistics/integration/AbstractIT.java index ebe2dbe5..3e699fb5 100644 --- a/server/src/test/java/org/worldcubeassociation/statistics/integration/AbstractTest.java +++ b/server/src/test/java/org/worldcubeassociation/statistics/integration/AbstractIT.java @@ -21,7 +21,7 @@ import org.skyscreamer.jsonassert.comparator.CustomComparator; import org.skyscreamer.jsonassert.comparator.DefaultComparator; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.TestPropertySource; import org.worldcubeassociation.statistics.util.LoadResourceUtil; @@ -29,18 +29,18 @@ @ActiveProfiles("test") @TestPropertySource(locations = "classpath:application-test.yaml") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class AbstractTest { +public class AbstractIT { private static final String PROTOCOL_HTTP = "http://"; private static final String TEST_HOST = "localhost"; @LocalServerPort - private int API_PORT; + private int apiPort; protected RequestSpecification createRequestSpecification() { return new RequestSpecBuilder() .setContentType(ContentType.JSON) - .setBaseUri(String.format("%s%s:%s", PROTOCOL_HTTP, TEST_HOST, API_PORT)) + .setBaseUri(String.format("%s%s:%s", PROTOCOL_HTTP, TEST_HOST, apiPort)) .addFilter(new ResponseLoggingFilter()) .addFilter(new RequestLoggingFilter()) .build(); @@ -69,8 +69,8 @@ public void validateResponse(Object index, Response response, DefaultComparator final String expectedPayload = LoadResourceUtil.getResource(resource); - JSONAssert.assertEquals( - expectedPayload, actualPayload, comparator); + JSONAssert.assertEquals(String.format("File %s", resource), expectedPayload, + actualPayload, comparator); } catch (UncheckedIOException | JSONException ex) { if (ex.getCause() instanceof FileNotFoundException) { @@ -81,7 +81,7 @@ public void validateResponse(Object index, Response response, DefaultComparator success("Test file did not exist. File created and test succeeded"); } catch (Exception e) { - throw new AbstractTest.TestCasePayloadGeneratedException(actualPayload, + throw new AbstractIT.TestCasePayloadGeneratedException(actualPayload, resource); } } diff --git a/server/src/test/java/org/worldcubeassociation/statistics/integration/controller/BestEverRanksControllerIT.java b/server/src/test/java/org/worldcubeassociation/statistics/integration/controller/BestEverRanksControllerIT.java index 2023a964..02d80afd 100644 --- a/server/src/test/java/org/worldcubeassociation/statistics/integration/controller/BestEverRanksControllerIT.java +++ b/server/src/test/java/org/worldcubeassociation/statistics/integration/controller/BestEverRanksControllerIT.java @@ -10,7 +10,7 @@ import org.junit.jupiter.params.provider.MethodSource; import org.springframework.http.HttpStatus; import org.springframework.test.context.jdbc.Sql; -import org.worldcubeassociation.statistics.integration.AbstractTest; +import org.worldcubeassociation.statistics.integration.AbstractIT; import java.util.List; import java.util.Map; @@ -21,7 +21,7 @@ @DisplayName("Best ever rank") @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @Sql({"/test-scripts/cleanTestData.sql", "/test-scripts/BestEverRanksControllerIT.sql"}) -public class BestEverRanksControllerIT extends AbstractTest { +public class BestEverRanksControllerIT extends AbstractIT { private static final String BASE_PATH = "/best-ever-rank/"; @Order(1) diff --git a/server/src/test/java/org/worldcubeassociation/statistics/integration/controller/DatabaseQueryControllerIT.java b/server/src/test/java/org/worldcubeassociation/statistics/integration/controller/DatabaseQueryControllerIT.java index ded14dbc..08c57ba5 100644 --- a/server/src/test/java/org/worldcubeassociation/statistics/integration/controller/DatabaseQueryControllerIT.java +++ b/server/src/test/java/org/worldcubeassociation/statistics/integration/controller/DatabaseQueryControllerIT.java @@ -8,15 +8,15 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mockito; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.jdbc.Sql; import org.springframework.web.client.RestTemplate; import org.worldcubeassociation.statistics.dto.UserInfoWrapperDTO; -import org.worldcubeassociation.statistics.integration.AbstractTest; +import org.worldcubeassociation.statistics.integration.AbstractIT; import java.util.Map; import java.util.stream.Stream; @@ -29,10 +29,10 @@ @DisplayName("Database query") @Sql({"/test-scripts/cleanTestData.sql", "/test-scripts/BestEverRanksControllerIT.sql"}) -public class DatabaseQueryControllerIT extends AbstractTest { - private static final String BASE_PATH = "/database/"; +public class DatabaseQueryControllerIT extends AbstractIT { + private static final String BASE_PATH = "/database"; - @MockBean + @MockitoBean private RestTemplate restTemplate; @MethodSource("queryArguments") @@ -53,7 +53,7 @@ public void query(int index, HttpStatus status, String token, Map