mirror of
https://github.com/hykilpikonna/AquaDX.git
synced 2026-08-22 17:24:39 -05:00
Merge remote-tracking branch 'origin/v1-dev' into delete-account
This commit is contained in:
8
.dockerignore
Normal file
8
.dockerignore
Normal file
@@ -0,0 +1,8 @@
|
||||
*
|
||||
!gradlew
|
||||
!gradle/
|
||||
!gradle/**
|
||||
!build.gradle.kts
|
||||
!settings.gradle.kts
|
||||
!src/
|
||||
!src/**
|
||||
4
.github/workflows/gradle.yml
vendored
4
.github/workflows/gradle.yml
vendored
@@ -12,9 +12,9 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '21'
|
||||
java-version: '25'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Build with Gradle
|
||||
|
||||
4
.github/workflows/nightly.yml
vendored
4
.github/workflows/nightly.yml
vendored
@@ -17,9 +17,9 @@ jobs:
|
||||
fetch-depth: '10'
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '25'
|
||||
distribution: 'temurin'
|
||||
server-id: github
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Use a multi-stage build to keep the image size small
|
||||
# Start with a Gradle image for building the project
|
||||
#FROM gradle:jdk21-alpine as builder
|
||||
FROM gradle:8.8.0-jdk21 as builder
|
||||
# Pin the builder so ARM64 deployments cannot reuse an older floating jdk25 image.
|
||||
FROM gradle:9.6.1-jdk25 AS builder
|
||||
|
||||
# Copy the Gradle wrapper and configuration files separately to leverage Docker cache
|
||||
COPY --chown=gradle:gradle gradlew /home/gradle/
|
||||
@@ -16,6 +15,7 @@ RUN sed -i 's/\r$//' ./gradlew
|
||||
|
||||
# Download dependencies - cached if build.gradle.kts and settings.gradle.kts are unchanged
|
||||
RUN chmod +x ./gradlew
|
||||
RUN java -version
|
||||
RUN ./gradlew dependencies
|
||||
|
||||
# Copy the project source, this layer is rebuilt whenever a file has changed
|
||||
@@ -25,7 +25,7 @@ COPY --chown=gradle:gradle src /home/gradle/src
|
||||
RUN ./gradlew build -x test
|
||||
|
||||
# Start with a fresh image for the runtime
|
||||
FROM eclipse-temurin:21-jre-alpine
|
||||
FROM eclipse-temurin:25-jre-alpine
|
||||
|
||||
# Set the deployment directory
|
||||
WORKDIR /app
|
||||
|
||||
117
build.gradle.kts
117
build.gradle.kts
@@ -2,9 +2,10 @@
|
||||
import java.time.Instant
|
||||
import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
val ktVer = "2.1.10"
|
||||
val ktVer = "2.4.0"
|
||||
|
||||
java
|
||||
kotlin("jvm") version ktVer
|
||||
@@ -13,9 +14,9 @@ plugins {
|
||||
kotlin("plugin.serialization") version ktVer
|
||||
kotlin("plugin.allopen") version ktVer
|
||||
kotlin("kapt") version ktVer
|
||||
id("org.springframework.boot") version "3.2.3"
|
||||
id("com.github.ben-manes.versions") version "0.51.0"
|
||||
id("org.hibernate.orm") version "6.4.4.Final"
|
||||
id("org.springframework.boot") version "4.1.0"
|
||||
id("com.github.ben-manes.versions") version "0.54.0"
|
||||
id("org.hibernate.orm") version "7.4.4.Final"
|
||||
application
|
||||
}
|
||||
|
||||
@@ -26,6 +27,9 @@ repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
extra["netty.version"] = "4.2.16.Final"
|
||||
extra["kotlin-coroutines.version"] = "1.11.0"
|
||||
|
||||
dependencies {
|
||||
// Spring boot
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
@@ -34,28 +38,30 @@ dependencies {
|
||||
exclude(group = "org.springframework.boot", module = "spring-boot-starter-tomcat")
|
||||
}
|
||||
implementation("org.springframework.boot:spring-boot-starter-jetty")
|
||||
implementation("io.netty:netty-all")
|
||||
implementation("org.apache.commons:commons-lang3:3.14.0")
|
||||
implementation("org.apache.httpcomponents.client5:httpclient5")
|
||||
implementation("org.flywaydb:flyway-core:10.10.0")
|
||||
implementation("org.flywaydb:flyway-mysql:10.10.0")
|
||||
implementation(enforcedPlatform("io.netty:netty-bom:4.2.16.Final"))
|
||||
implementation("io.netty:netty-all:4.2.16.Final")
|
||||
implementation("org.apache.commons:commons-lang3:3.20.0")
|
||||
implementation("org.apache.httpcomponents.client5:httpclient5:5.6.2")
|
||||
implementation("org.springframework.boot:spring-boot-starter-flyway")
|
||||
implementation("org.flywaydb:flyway-core:12.10.0")
|
||||
implementation("org.flywaydb:flyway-mysql:12.10.0")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test") {
|
||||
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
|
||||
}
|
||||
testImplementation("org.springframework.security:spring-security-test")
|
||||
implementation("net.logstash.logback:logstash-logback-encoder:7.4")
|
||||
implementation("net.logstash.logback:logstash-logback-encoder:9.0")
|
||||
|
||||
// Metrics
|
||||
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
||||
implementation("io.micrometer:micrometer-registry-prometheus")
|
||||
|
||||
// Database
|
||||
runtimeOnly("org.mariadb.jdbc:mariadb-java-client:3.3.3")
|
||||
runtimeOnly("org.xerial:sqlite-jdbc:3.45.2.0")
|
||||
implementation("org.hibernate.orm:hibernate-core:6.4.4.Final")
|
||||
implementation("org.hibernate.orm:hibernate-community-dialects:6.4.4.Final")
|
||||
implementation("io.github.openfeign.querydsl:querydsl-jpa:6.10.1")
|
||||
kapt("io.github.openfeign.querydsl:querydsl-apt:6.10.1:jpa")
|
||||
runtimeOnly("org.mariadb.jdbc:mariadb-java-client:3.5.9")
|
||||
runtimeOnly("org.xerial:sqlite-jdbc:3.53.2.0")
|
||||
implementation("org.hibernate.orm:hibernate-core:7.4.4.Final")
|
||||
implementation("org.hibernate.orm:hibernate-community-dialects:7.4.4.Final")
|
||||
implementation("io.github.openfeign.querydsl:querydsl-jpa:7.4.0")
|
||||
kapt("io.github.openfeign.querydsl:querydsl-apt:7.4.0:jpa")
|
||||
|
||||
// JSR305 for nullable
|
||||
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
||||
@@ -65,50 +71,60 @@ dependencies {
|
||||
// =============================
|
||||
|
||||
// Network
|
||||
implementation("io.ktor:ktor-client-core:3.0.3")
|
||||
implementation("io.ktor:ktor-client-cio:3.0.3")
|
||||
implementation("io.ktor:ktor-client-content-negotiation:3.0.3")
|
||||
implementation("io.ktor:ktor-client-encoding:3.0.3")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json:3.0.3")
|
||||
implementation("io.ktor:ktor-client-core:3.5.1")
|
||||
implementation("io.ktor:ktor-client-cio:3.5.1")
|
||||
implementation("io.ktor:ktor-client-content-negotiation:3.5.1")
|
||||
implementation("io.ktor:ktor-client-encoding:3.5.1")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json:3.5.1")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
|
||||
// Somehow these are needed for ktor even though they're not in the documentation
|
||||
runtimeOnly("org.reactivestreams:reactive-streams:1.0.4")
|
||||
runtimeOnly("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.8.0")
|
||||
runtimeOnly("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.11.0")
|
||||
|
||||
// Email
|
||||
implementation("org.simplejavamail:simple-java-mail:8.6.3")
|
||||
implementation("org.simplejavamail:spring-module:8.6.3")
|
||||
implementation("org.simplejavamail:simple-java-mail:9.0.1")
|
||||
implementation("org.simplejavamail:spring-module:9.0.1")
|
||||
|
||||
// GeoIP
|
||||
implementation("com.maxmind.geoip2:geoip2:4.2.0")
|
||||
implementation("com.maxmind.geoip2:geoip2:5.1.0")
|
||||
|
||||
// JWT Authentication
|
||||
implementation("io.jsonwebtoken:jjwt-api:0.12.5")
|
||||
runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.5")
|
||||
runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.5")
|
||||
implementation("io.jsonwebtoken:jjwt-api:0.13.0")
|
||||
runtimeOnly("io.jsonwebtoken:jjwt-impl:0.13.0")
|
||||
runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.13.0")
|
||||
|
||||
// Content validation
|
||||
implementation("org.apache.tika:tika-core:2.9.1")
|
||||
implementation("org.apache.tika:tika-core:3.3.1")
|
||||
|
||||
// Import: DateTime Parsing
|
||||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.0")
|
||||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.1")
|
||||
|
||||
// Serialization
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.22.1")
|
||||
|
||||
// Testing
|
||||
testImplementation("io.kotest:kotest-runner-junit5-jvm:5.8.1")
|
||||
testImplementation("io.kotest:kotest-assertions-core")
|
||||
testImplementation("io.kotest:kotest-runner-junit5-jvm:6.2.2")
|
||||
testImplementation("io.kotest:kotest-assertions-core:6.2.2")
|
||||
}
|
||||
|
||||
group = "icu.samnya"
|
||||
version = "1.0.0"
|
||||
description = "AquaDX Arcade Server"
|
||||
java.sourceCompatibility = JavaVersion.VERSION_21
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_25
|
||||
targetCompatibility = JavaVersion.VERSION_25
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(25))
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(21)
|
||||
jvmToolchain(25)
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_25)
|
||||
}
|
||||
}
|
||||
|
||||
springBoot {
|
||||
@@ -119,14 +135,6 @@ application {
|
||||
mainClass = "icu.samnyan.aqua.EntryKt"
|
||||
}
|
||||
|
||||
hibernate {
|
||||
enhancement {
|
||||
enableLazyInitialization = true
|
||||
enableAssociationManagement = false
|
||||
enableExtendedEnhancement = false
|
||||
}
|
||||
}
|
||||
|
||||
kapt {
|
||||
includeCompileClasspath = false
|
||||
keepJavacAnnotationProcessors = true
|
||||
@@ -138,29 +146,36 @@ allOpen {
|
||||
annotation("jakarta.persistence.Embeddable")
|
||||
}
|
||||
|
||||
val buildTime: String by extra(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z").withZone(ZoneId.of("UTC")).format(Instant.now()))
|
||||
val buildTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z").withZone(ZoneId.of("UTC")).format(Instant.now())
|
||||
val projectVersion = version.toString()
|
||||
extra["buildTime"] = buildTime
|
||||
|
||||
tasks.processResources {
|
||||
filesMatching("**/application.properties") {
|
||||
expand(project.properties)
|
||||
expand(
|
||||
mapOf(
|
||||
"version" to projectVersion,
|
||||
"ext" to mapOf("buildTime" to buildTime),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
enabled = project.hasProperty("runTests")
|
||||
enabled = providers.gradleProperty("runTests").isPresent
|
||||
useJUnitPlatform()
|
||||
jvmArgs("-Dkotest.assertions.collection.print.size=100")
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
tasks.withType<Javadoc> {
|
||||
tasks.withType<Javadoc>().configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
tasks.getByName<Jar>("jar") {
|
||||
tasks.named<Jar>("jar") {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
@@ -170,12 +185,12 @@ sourceSets {
|
||||
}
|
||||
}
|
||||
|
||||
val copyDependencies by tasks.registering(Copy::class) {
|
||||
val copyDependencies = tasks.register<Copy>("copyDependencies") {
|
||||
from(configurations.runtimeClasspath)
|
||||
into("${layout.buildDirectory.get()}/libs/lib")
|
||||
}
|
||||
|
||||
val packageThin by tasks.registering(Jar::class) {
|
||||
tasks.register<Jar>("packageThin") {
|
||||
group = "build"
|
||||
from(sourceSets.main.get().output)
|
||||
manifest {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM archlinux:latest
|
||||
|
||||
RUN pacman -Syu --noconfirm \
|
||||
&& pacman -S --noconfirm openssh sudo jdk21-openjdk wget which procps-ng zsh git curlie micro ripgrep python3 exa \
|
||||
&& pacman -S --noconfirm openssh sudo jdk25-openjdk wget which procps-ng zsh git curlie micro ripgrep python3 exa \
|
||||
&& rm -rf /var/cache/pacman/pkg/* \
|
||||
&& mkdir -p /var/run/sshd \
|
||||
&& chsh -s /bin/zsh root \
|
||||
|
||||
@@ -41,10 +41,10 @@ docker compose up
|
||||
```
|
||||
|
||||
### Building
|
||||
You need to install JDK 21 on your system, then run `./gradlew clean build`. The jar file will be built into the `build/libs` folder.
|
||||
You need to install JDK 25 on your system, then run `./gradlew clean build`. The jar file will be built into the `build/libs` folder.
|
||||
|
||||
## Why drop SQLite support?
|
||||
|
||||
If you wonder why I dropped SQLite support, ask SQLite devs why they still haven't supported adding a single constraint to a table without all the hassle of creating a new one and migrating all data over and finally deleting the original.
|
||||
|
||||

|
||||

|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -2,4 +2,8 @@
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
|
||||
}
|
||||
|
||||
rootProject.name = "AquaDX"
|
||||
|
||||
@@ -277,4 +277,4 @@ fun List<List<Any?>>.numCsv(vararg head: Str) = head.joinToString(",") + "\n" +
|
||||
joinToString("\n") { it.joinToString(",") }
|
||||
|
||||
// DI
|
||||
inline fun <reified T> ApplicationContext.lazy() = lazy { getBean(T::class.java) }
|
||||
inline fun <reified T : Any> ApplicationContext.lazy() = kotlin.lazy { getBean(T::class.java) }
|
||||
|
||||
@@ -32,7 +32,6 @@ val JSON_DATETIME = SimpleModule().addDeserializer(java.time.LocalDateTime::clas
|
||||
} }
|
||||
})
|
||||
val JACKSON = jacksonObjectMapper().apply {
|
||||
setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||
setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL)
|
||||
findAndRegisterModules()
|
||||
registerModule(JSON_FUZZY_BOOLEAN)
|
||||
|
||||
@@ -68,7 +68,7 @@ class CardController(
|
||||
*/
|
||||
@API("/link")
|
||||
@Doc("Bind a card to the user. This action will migrate selected data from the card to the user's ghost card.", "Success message")
|
||||
suspend fun link(@RP token: Str, @RP cardId: Str, @RP migrate: Str) = jwt.auth(token) { u ->
|
||||
suspend fun link(@RP token: Str, @RP cardId: Str, @RP migrate: Str): Any = jwt.auth(token) { u ->
|
||||
// Check if the user's card limit is reached
|
||||
if (u.cards.size >= props.linkCardLimit) 400 - "Card limit reached"
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ class Fedy(
|
||||
forEach { (k, v) -> v?.let { GAME_OPTIONS_FIELDS[k]?.set(options, it) } }
|
||||
}
|
||||
us.userRepo.save(ru)
|
||||
if (fields.containsKey("pwHash") ?: false) { us.clearAllSessions(ru) }
|
||||
if (fields.containsKey("pwHash")) { us.clearAllSessions(ru) }
|
||||
UserUpdateRes(user = ru.fedyBasicInfo())
|
||||
} caught { UserUpdateRes(error = it) }
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package icu.samnyan.aqua.net.components
|
||||
|
||||
import jakarta.mail.Message
|
||||
import ext.Bool
|
||||
import ext.Str
|
||||
import ext.logger
|
||||
import icu.samnyan.aqua.net.db.*
|
||||
import org.simplejavamail.api.email.Recipient
|
||||
import org.simplejavamail.api.mailer.Mailer
|
||||
import org.simplejavamail.email.EmailBuilder
|
||||
import org.simplejavamail.springsupport.SimpleJavaMailSpringSupport
|
||||
import org.springframework.beans.factory.ObjectProvider
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
import org.springframework.context.annotation.Configuration
|
||||
@@ -25,15 +29,19 @@ class EmailProperties {
|
||||
var webHost: Str = "aquadx.net"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = "aqua-net.email", name = ["enable"], havingValue = "true")
|
||||
@Import(SimpleJavaMailSpringSupport::class)
|
||||
class EmailMailerConfiguration
|
||||
|
||||
/**
|
||||
* Email service. All email related operations should be placed here.
|
||||
*
|
||||
* Library Documentation: https://www.simplejavamail.org/
|
||||
*/
|
||||
@Service
|
||||
@Import(SimpleJavaMailSpringSupport::class)
|
||||
class EmailService(
|
||||
val mailer: Mailer,
|
||||
val mailerProvider: ObjectProvider<Mailer>,
|
||||
val props: EmailProperties,
|
||||
val confirmationRepo: EmailConfirmationRepo,
|
||||
val resetPasswordRepo: ResetPasswordRepo,
|
||||
@@ -44,13 +52,16 @@ class EmailService(
|
||||
val resetTemplate: Str = this::class.java.getResource("/email/reset.html")?.readText()
|
||||
?: throw Exception("Password Reset Template Not Found")
|
||||
|
||||
private fun mailer() = mailerProvider.getIfAvailable()
|
||||
?: throw IllegalStateException("Email is enabled, but Simple Java Mail is not configured")
|
||||
|
||||
@Async
|
||||
@EventListener(ApplicationStartedEvent::class)
|
||||
fun test() {
|
||||
if (!props.enable) return
|
||||
|
||||
try {
|
||||
mailer.testConnection()
|
||||
mailer().testConnection()
|
||||
log.info("Email Service Connected")
|
||||
} catch (e: Exception) {
|
||||
log.error("Email Service Connection Failed", e)
|
||||
@@ -71,9 +82,9 @@ class EmailService(
|
||||
|
||||
// Send email
|
||||
log.info("Sending verification email to ${user.email}")
|
||||
mailer.sendMail(EmailBuilder.startingBlank()
|
||||
mailer().sendMail(EmailBuilder.startingBlank()
|
||||
.from(props.senderName, props.senderAddr)
|
||||
.to(user.computedName, user.email)
|
||||
.withRecipients(Recipient(user.computedName, user.email, Message.RecipientType.TO, null))
|
||||
.withSubject("Verify Your Email Address for AquaNet")
|
||||
.withHTMLText(confirmTemplate
|
||||
.replace("{{name}}", user.computedName)
|
||||
@@ -94,9 +105,9 @@ class EmailService(
|
||||
|
||||
// Send email
|
||||
log.info("Sending reset password email to ${user.email}")
|
||||
mailer.sendMail(EmailBuilder.startingBlank()
|
||||
mailer().sendMail(EmailBuilder.startingBlank()
|
||||
.from(props.senderName, props.senderAddr)
|
||||
.to(user.computedName, user.email)
|
||||
.withRecipients(Recipient(user.computedName, user.email, Message.RecipientType.TO, null))
|
||||
.withSubject("Reset Your Password for AquaNet")
|
||||
.withHTMLText(resetTemplate
|
||||
.replace("{{name}}", user.computedName)
|
||||
@@ -108,9 +119,9 @@ class EmailService(
|
||||
if (!props.enable) return
|
||||
|
||||
log.info("Sending test email to $addr")
|
||||
mailer.sendMail(EmailBuilder.startingBlank()
|
||||
mailer().sendMail(EmailBuilder.startingBlank()
|
||||
.from(props.senderName, props.senderAddr)
|
||||
.to(name, addr)
|
||||
.withRecipients(Recipient(name, addr, Message.RecipientType.TO, null))
|
||||
.withSubject("Test Email")
|
||||
.withPlainText("This is a test email to check if AquaNet Email Works").buildEmail()).thenRun {
|
||||
log.info("Test email sent to $addr")
|
||||
|
||||
@@ -77,7 +77,7 @@ class GeoIP(
|
||||
{
|
||||
return try {
|
||||
val ipa = InetAddress.getByName(ip)
|
||||
geoLite.country(ipa)?.country?.isoCode ?: ""
|
||||
geoLite.country(ipa)?.country()?.isoCode() ?: ""
|
||||
}
|
||||
catch (e: AddressNotFoundException) { "" }
|
||||
catch (e: Exception) {
|
||||
@@ -85,4 +85,4 @@ class GeoIP(
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,21 +221,23 @@ class AquaUserServices(
|
||||
400 - "User with username `$this` already exists"
|
||||
}
|
||||
|
||||
fun validateEmail(email: Str) = email.apply {
|
||||
// Check if email is valid
|
||||
if (!isValidEmail()) 400 - "Invalid email"
|
||||
|
||||
// Check if user with the same email exists
|
||||
if (userRepo.findByEmailIgnoreCase(email) != null)
|
||||
400 - "User with email `$email` already exists"
|
||||
}
|
||||
|
||||
fun checkPwHash(password: Str) = password.run {
|
||||
// Validate password
|
||||
if (length < 8) 400 - "Password must be at least 8 characters"
|
||||
|
||||
hasher.encode(this)
|
||||
}
|
||||
fun validateEmail(email: Str): Str {
|
||||
// Check if email is valid
|
||||
if (!email.isValidEmail()) 400 - "Invalid email"
|
||||
|
||||
// Check if user with the same email exists
|
||||
if (userRepo.findByEmailIgnoreCase(email) != null)
|
||||
400 - "User with email `$email` already exists"
|
||||
|
||||
return email
|
||||
}
|
||||
|
||||
fun checkPwHash(password: Str): Str {
|
||||
// Validate password
|
||||
if (password.length < 8) 400 - "Password must be at least 8 characters"
|
||||
|
||||
return hasher.encode(password) ?: (500 - "Failed to hash password")
|
||||
}
|
||||
|
||||
fun checkDisplayName(displayName: Str) = displayName.apply {
|
||||
// Check if display name is valid
|
||||
|
||||
@@ -41,7 +41,7 @@ interface IExportClass<UserModel: IUserData> {
|
||||
}
|
||||
|
||||
@NoRepositoryBean
|
||||
interface IUserRepo<UserModel, ThisModel>: JpaRepository<ThisModel, Long> {
|
||||
interface IUserRepo<UserModel : IUserData, ThisModel : Any>: JpaRepository<ThisModel, Long> {
|
||||
fun findByUser(user: UserModel): List<ThisModel>
|
||||
fun findSingleByUser(user: UserModel): ThisModel?
|
||||
}
|
||||
|
||||
@@ -96,7 +96,6 @@ class AimeDB(
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Netty 5") // TODO: Move this to ChannelInboundHandler
|
||||
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
|
||||
logger.error("AimeDB: Error", cause)
|
||||
ctx.close()
|
||||
|
||||
@@ -4,7 +4,8 @@ import ext.logger
|
||||
import io.netty.bootstrap.ServerBootstrap
|
||||
import io.netty.channel.ChannelInitializer
|
||||
import io.netty.channel.ChannelOption
|
||||
import io.netty.channel.nio.NioEventLoopGroup
|
||||
import io.netty.channel.MultiThreadIoEventLoopGroup
|
||||
import io.netty.channel.nio.NioIoHandler
|
||||
import io.netty.channel.socket.SocketChannel
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel
|
||||
import io.netty.handler.logging.LogLevel
|
||||
@@ -38,7 +39,10 @@ class AimeDbServer(
|
||||
if (!props.enable) return logger.info("Aime DB is disabled.")
|
||||
|
||||
val bootstrap = ServerBootstrap()
|
||||
.group(NioEventLoopGroup(), NioEventLoopGroup())
|
||||
.group(
|
||||
MultiThreadIoEventLoopGroup(NioIoHandler.newFactory()),
|
||||
MultiThreadIoEventLoopGroup(NioIoHandler.newFactory())
|
||||
)
|
||||
.handler(LoggingHandler(LogLevel.DEBUG))
|
||||
.channel(NioServerSocketChannel::class.java)
|
||||
.childHandler(initializer)
|
||||
|
||||
@@ -11,8 +11,8 @@ import org.eclipse.jetty.util.resource.URLResourceFactory
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer
|
||||
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory
|
||||
import org.springframework.boot.jetty.JettyServerCustomizer
|
||||
import org.springframework.boot.jetty.servlet.JettyServletWebServerFactory
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
@@ -18,7 +18,7 @@ import icu.samnyan.aqua.sega.util.StaticRepo
|
||||
|
||||
|
||||
@NoRepositoryBean
|
||||
interface Chu3UserLinked<T> : IUserRepo<Chu3UserData, T> {
|
||||
interface Chu3UserLinked<T : Any> : IUserRepo<Chu3UserData, T> {
|
||||
fun findByUser_Card_ExtId(extId: Long): List<T>
|
||||
fun findSingleByUser_Card_ExtId(extId: Long): T?
|
||||
fun findByUser_Card_ExtId(extId: Long, pageable: Pageable): Page<T>
|
||||
|
||||
@@ -60,9 +60,9 @@ class PsRankingHandler(val db: DivaRepos) {
|
||||
score1.add(obj.first.maxScore)
|
||||
score2.add(obj.second.maxScore)
|
||||
score3.add(obj.third.maxScore)
|
||||
name1.add(encode(obj.first.pdId?.playerName ?: "xxx"))
|
||||
name2.add(encode(obj.second.pdId?.playerName ?: "xxx"))
|
||||
name3.add(encode(obj.third.pdId?.playerName ?: "xxx"))
|
||||
name1.add(encode(obj.first.pdId.playerName))
|
||||
name2.add(encode(obj.second.pdId.playerName))
|
||||
name3.add(encode(obj.third.pdId.playerName))
|
||||
}
|
||||
|
||||
return PsRankingResponse(
|
||||
|
||||
@@ -9,7 +9,6 @@ import icu.samnyan.aqua.sega.diva.model.db.userdata.*
|
||||
import icu.samnyan.aqua.sega.diva.util.DivaCalculator
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.springframework.stereotype.Component
|
||||
import java.lang.String
|
||||
import java.time.LocalDateTime
|
||||
import java.util.*
|
||||
import java.util.function.Supplier
|
||||
@@ -100,7 +99,7 @@ class StageResultHandler(val db: DivaRepos, val calc: DivaCalculator) {
|
||||
|
||||
// Calculate reward
|
||||
// Contest reward
|
||||
var contestSpecifier = String.join(",", *request.cr_sp)
|
||||
var contestSpecifier = request.cr_sp.joinToString(",")
|
||||
val contestRewardType = arrayOf<kotlin.String?>("-1", "-1", "-1")
|
||||
val contestRewardValue = arrayOf<kotlin.String?>("-1", "-1", "-1")
|
||||
val contestRewardString1 = arrayOf<kotlin.String?>("***", "***", "***")
|
||||
@@ -204,10 +203,10 @@ class StageResultHandler(val db: DivaRepos, val calc: DivaCalculator) {
|
||||
request.cr_cid,
|
||||
request.cr_tv,
|
||||
contestSpecifier,
|
||||
String.join(",", *contestRewardType),
|
||||
String.join(",", *contestRewardValue),
|
||||
String.join(",", *contestRewardString1),
|
||||
String.join(",", *contestRewardString2),
|
||||
contestRewardType.joinToString(","),
|
||||
contestRewardValue.joinToString(","),
|
||||
contestRewardString1.joinToString(","),
|
||||
contestRewardString2.joinToString(","),
|
||||
contestEntryRewardType,
|
||||
contestEntryRewardValue,
|
||||
contestEntryRewardString1,
|
||||
@@ -328,7 +327,7 @@ class StageResultHandler(val db: DivaRepos, val calc: DivaCalculator) {
|
||||
while (result.size < 60) {
|
||||
result.add("-1")
|
||||
}
|
||||
return String.join(",", result)
|
||||
return result.joinToString(",")
|
||||
}
|
||||
|
||||
private fun updateReward(
|
||||
|
||||
@@ -11,7 +11,6 @@ import icu.samnyan.aqua.sega.diva.model.db.gamedata.Contest
|
||||
import icu.samnyan.aqua.sega.diva.model.db.userdata.PlayerContest
|
||||
import icu.samnyan.aqua.sega.diva.util.DivaStringUtils
|
||||
import org.springframework.stereotype.Component
|
||||
import java.lang.String
|
||||
import java.time.LocalDateTime
|
||||
import java.util.function.Supplier
|
||||
import kotlin.Any
|
||||
@@ -47,7 +46,7 @@ class EndHandler(val db: DivaRepos) {
|
||||
profile.contestNowPlayingId = request.cr_cid
|
||||
profile.contestNowPlayingResultRank = currentResultRank
|
||||
profile.contestNowPlayingValue = request.cr_tv
|
||||
profile.contestNowPlayingSpecifier = String.join(",", *request.cr_sp)
|
||||
profile.contestNowPlayingSpecifier = request.cr_sp.joinToString(",")
|
||||
} else {
|
||||
val contestRecord =
|
||||
db.contest.findByPdIdAndContestId(profile, request.cr_cid).orElseGet(
|
||||
|
||||
@@ -85,7 +85,7 @@ class Contest : Serializable {
|
||||
}
|
||||
list += listOf(-1, -2, "7fffffffffffffffffffffffffffffff")
|
||||
} else {
|
||||
val groups = pvl!!.split(',').dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
val groups = pvl.split(',').dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
if (groups.size < i) {
|
||||
list += listOf(-1, -1, -2, -2, -1, -2, "7fffffffffffffffffffffffffffffff")
|
||||
} else {
|
||||
@@ -98,7 +98,7 @@ class Contest : Serializable {
|
||||
list.add(this.maxComplexity)
|
||||
list.add(-1)
|
||||
} else {
|
||||
val diffList = pvdl!!.split(',').dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
val diffList = pvdl.split(',').dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
if (diffList.size < i) {
|
||||
list.add(this.minComplexity)
|
||||
list.add(this.maxComplexity)
|
||||
|
||||
@@ -20,7 +20,7 @@ import icu.samnyan.aqua.sega.util.StaticRepo
|
||||
import java.util.*
|
||||
|
||||
@NoRepositoryBean
|
||||
interface Mai2UserLinked<T>: JpaRepository<T, Long>, IUserRepo<Mai2UserDetail, T> {
|
||||
interface Mai2UserLinked<T : Any>: JpaRepository<T, Long>, IUserRepo<Mai2UserDetail, T> {
|
||||
fun findByUser_Card_ExtId(userId: Long): List<T>
|
||||
fun findByUser_Card_ExtId(userId: Long, page: Pageable): Page<T>
|
||||
fun findSingleByUser_Card_ExtId(userId: Long): T?
|
||||
|
||||
@@ -18,7 +18,7 @@ import java.util.*
|
||||
|
||||
|
||||
@NoRepositoryBean
|
||||
interface OngekiUserLinked<T> : IUserRepo<UserData, T> {
|
||||
interface OngekiUserLinked<T : Any> : IUserRepo<UserData, T> {
|
||||
fun findByUser_Card_ExtId(extId: Long): List<T>
|
||||
fun findSingleByUser_Card_ExtId(extId: Long): T?
|
||||
fun findByUser_Card_ExtId(extId: Long, pageable: Pageable): Page<T>
|
||||
@@ -221,4 +221,3 @@ class OngekiRepos(
|
||||
val u: OngekiUserRepos,
|
||||
val g: OngekiGameRepos,
|
||||
)
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ interface WcUserRepo : JpaRepository<WaccaUser, Long>, GenericUserDataRepo<Wacca
|
||||
}
|
||||
|
||||
@NoRepositoryBean
|
||||
interface IWaccaUserLinked<T> : JpaRepository<T, Long> {
|
||||
interface IWaccaUserLinked<T : Any> : JpaRepository<T, Long> {
|
||||
fun findByUser(user: WaccaUser): List<T>
|
||||
fun findByUserCardExtId(userId: Long): List<T>
|
||||
fun findByUserCardExtId(extId: Long): List<T>
|
||||
@Transactional
|
||||
fun deleteByUser(user: WaccaUser)
|
||||
}
|
||||
@@ -54,4 +54,4 @@ class WaccaRepos(
|
||||
val bestScore: WcUserBestScoreRepo,
|
||||
val playLog: WcUserPlayLogRepo,
|
||||
val stageUp: WcUserStageUpRepo
|
||||
)
|
||||
)
|
||||
|
||||
@@ -33,7 +33,6 @@ class WaccaUser : BaseEntity(), IUserData {
|
||||
var titles: MutableList<Int> = mutableListOf(0, 0, 0)
|
||||
override var playerRating = 0
|
||||
override var highestRating = 0
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
var vipExpireTime: Date = Date(0)
|
||||
var alwaysVip = false
|
||||
var loginCount = 0
|
||||
@@ -50,11 +49,8 @@ class WaccaUser : BaseEntity(), IUserData {
|
||||
override var lastRomVersion = "1.0.0"
|
||||
@Convert(converter = IntegerListConverter::class)
|
||||
var lastSongInfo: MutableList<Int> = mutableListOf(0, 0, 0, 0, 0)
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
var lastConsecDate: Date = Date(0)
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
override var lastPlayDate: Date = Date()
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
override var firstPlayDate: Date = Date()
|
||||
var gateTutorialFlags: String = "[[1, 0], [2, 0], [3, 0], [4, 0], [5, 0]]"
|
||||
@Convert(converter = IntegerListConverter::class)
|
||||
@@ -71,4 +67,4 @@ class WaccaUser : BaseEntity(), IUserData {
|
||||
else vipExpireTime
|
||||
|
||||
val moddedWp get() = if (card?.aquaUser?.gameOptions?.waccaInfiniteWp == true) 999999 else wp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ class WcUserGate : WaccaUserEntity() {
|
||||
var progress = 0
|
||||
var loops = 0
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
var lastUsed = Date(0)
|
||||
var missionFlag = 0
|
||||
var totalPoints = 0
|
||||
@@ -77,7 +76,6 @@ class WcUserItem(
|
||||
var p2: Long = 0L,
|
||||
var p3: Long = 0L,
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
var acquiredDate: Date = Date(),
|
||||
) : WaccaUserEntity() {
|
||||
fun ls() = when (type) {
|
||||
@@ -136,7 +134,6 @@ class WcUserPlayLog : WaccaUserEntity(), IGenericGamePlaylog {
|
||||
override var beforeRating = 0
|
||||
override var afterRating = 0
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
override var userPlayDate = Date()
|
||||
|
||||
fun clears() = ls(1, +isClear, +isFullCombo, +isMissless, +isAllPerfect)
|
||||
|
||||
@@ -4,8 +4,8 @@ import icu.samnyan.aqua.sega.aimedb.AimeDbProps
|
||||
import icu.samnyan.aqua.sega.allnet.AllNetProps
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder
|
||||
import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder
|
||||
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier
|
||||
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder
|
||||
import org.apache.hc.client5.http.ssl.TrustAllStrategy
|
||||
import org.apache.hc.core5.ssl.SSLContextBuilder
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
@@ -71,11 +71,11 @@ class AutoChecker(
|
||||
val rt = HttpComponentsClientHttpRequestFactory().apply {
|
||||
httpClient = HttpClients.custom()
|
||||
.setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create()
|
||||
.setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create()
|
||||
.setTlsSocketStrategy(ClientTlsStrategyBuilder.create()
|
||||
.setHostnameVerifier(NoopHostnameVerifier.INSTANCE)
|
||||
.setSslContext(SSLContextBuilder.create()
|
||||
.loadTrustMaterial(TrustAllStrategy.INSTANCE)
|
||||
.build()).build()).build()).build()
|
||||
.build()).buildClassic()).build()).build()
|
||||
}.let { RestTemplate(it) }
|
||||
|
||||
val url = "https://${aimedb.address}:$BILLING_PORT/sys/test"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
|
||||
<conversionRule conversionWord="cmp" converterClass="icu.samnyan.aqua.spring.LoggerComponent" />
|
||||
<conversionRule conversionWord="cls" converterClass="icu.samnyan.aqua.spring.LoggerClassColor" />
|
||||
<conversionRule conversionWord="correlationId" converterClass="org.springframework.boot.logging.logback.CorrelationIdConverter" />
|
||||
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
|
||||
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
|
||||
<conversionRule conversionWord="clr" class="org.springframework.boot.logging.logback.ColorConverter" />
|
||||
<conversionRule conversionWord="cmp" class="icu.samnyan.aqua.spring.LoggerComponent" />
|
||||
<conversionRule conversionWord="cls" class="icu.samnyan.aqua.spring.LoggerClassColor" />
|
||||
<conversionRule conversionWord="correlationId" class="org.springframework.boot.logging.logback.CorrelationIdConverter" />
|
||||
<conversionRule conversionWord="wex" class="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
|
||||
<conversionRule conversionWord="wEx" class="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
|
||||
|
||||
<!-- Define the log file name and path -->
|
||||
<property name="LOG_FILE" value="logs/AquaDX.log"/>
|
||||
|
||||
Reference in New Issue
Block a user