Compare commits

...

7 Commits

Author SHA1 Message Date
dalbodeule
9963f504c5 Update SnapAdmin version and improve foreign key mapping logic
Bumped the `VERSION` constant from 0.4.1 to 0.6.2. Enhanced the `mapForeignKeyType` method to scan the entire class hierarchy for `@Id` annotations, ensuring better support for inherited entity structures.
2025-05-24 19:09:12 +09:00
dalbodeule
61ff240456 Remove @EnableWebMvc annotation from SnapAdminMvcConfig
The `@EnableWebMvc` annotation was removed to prevent overriding Spring Boot's default MVC configuration. This change ensures better compatibility with existing configurations and avoids potential conflicts in the application.
2025-05-22 00:50:02 +09:00
dalbodeule
35b02d156b Add debugBackend module with database and security setup
Introduced a new `debugBackend` module to support debugging and development tasks. This includes configuration for PostgreSQL, Redis, Hibernate, Spring Boot, and a basic security setup. Also added required entities, repositories, and runtime hints for SnapAdmin integration.
2025-05-21 16:33:56 +09:00
dalbodeule
50f2844319 Refactor DbField to handle disableEditField explicitly.
Removed the `isDisable` parameter from the `DbField` constructor and set `disableEditField` through a dedicated method. Updated relevant logic to ensure proper handling of non-editable fields across the application.
2025-05-20 16:28:47 +09:00
dalbodeule
28063ed583 Enable flexible date parsing, add field edit restrictions, and hide controllers.
Enhances date/time field parsing with support for multiple formats across `InstantFieldType`, `LocalDateTimeFieldType`, `OffsetDateTimeFieldType`, and others. Introduces `DisableEditField` annotation to restrict editing of specific fields and updates templates, controllers, and schemas accordingly. Hides controllers from swagger documentation and adds error handling for unexpected scenarios.
2025-05-20 15:51:33 +09:00
dalbodeule
2e3e11aafb Switch to Gradle and update project structure
Replaced Maven with Gradle, updating configurations and dependencies to reflect the change. Added IntelliJ IDEA project settings and updated `.gitignore` for Gradle, IDE, and OS-specific files. Refactored package names and added enhancements such as compiler arguments and environmental versioning.
2025-05-14 22:07:02 +09:00
dalbodeule
e4ea60fd85 Migrate build system from Maven to Gradle
Replaced Maven with Gradle by introducing a Gradle build structure, updating dependencies, and configuration files. Additionally, refactored package structure from `tech.ailef` to `space.mori.dalbodeule` for consistency.
2025-05-14 21:24:41 +09:00
145 changed files with 1980 additions and 1106 deletions

162
.gitignore vendored
View File

@@ -1,36 +1,134 @@
wip-commit.sh
test-release.sh
TODO
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
# Created by https://www.toptal.com/developers/gitignore/api/gradle,java,macos,windows,linux,dotenv
# Edit at https://www.toptal.com/developers/gitignore?templates=gradle,java,macos,windows,linux,dotenv
### STS ###
.apt_generated
.classpath
.factorypath
### dotenv ###
.env
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
### Gradle ###
.gradle
**/build/
!src/**/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties
# Cache of project
.gradletasknamecache
# Eclipse Gradle plugin generated files
# Eclipse Core
.project
.settings
.springBeans
.sts4-cache
# JDT-specific (Eclipse Java Development Tools)
.classpath
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### Gradle Patch ###
# Java heap dump
*.hprof
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
# End of https://www.toptal.com/developers/gitignore/api/gradle,java,macos,windows,linux,dotenv

10
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,10 @@
# 디폴트 무시된 파일
/shelf/
/workspace.xml
# 에디터 기반 HTTP 클라이언트 요청
/httpRequests/
# 환경에 따라 달라지는 Maven 홈 디렉터리
/mavenHomeManager.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

9
.idea/compiler.xml generated Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_STRING" value="-parameters" />
</component>
</project>

17
.idea/dataSources.xml generated Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="mydatabase@localhost" uuid="2f05e8c9-fa97-4b20-aa60-3de9e52721d6">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://localhost:55432/mydatabase</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
<property name="com.intellij.clouds.kubernetes.db.container.port" />
</jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

14
.idea/discord.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
<option name="description" value="" />
<option name="applicationTheme" value="default" />
<option name="iconsTheme" value="default" />
<option name="button1Title" value="" />
<option name="button1Url" value="" />
<option name="button2Title" value="" />
<option name="button2Url" value="" />
<option name="customApplicationId" value="" />
</component>
</project>

6
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
</component>
</project>

17
.idea/gradle.xml generated Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/debugBackend" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

20
.idea/jarRepositories.xml generated Normal file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>

6
.idea/kotlinc.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="2.1.10" />
</component>
</project>

15
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="graalvm-23" project-jdk-type="JavaSDK" />
</project>

11
.idea/snap-admin.iml generated Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Chameleon" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/build/resources/main/templates" />
</list>
</option>
</component>
</module>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

Binary file not shown.

View File

@@ -1,2 +0,0 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar

75
build.gradle.kts Normal file
View File

@@ -0,0 +1,75 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This project uses @Incubating APIs which are subject to change.
*/
plugins {
`java-library`
`maven-publish`
id("co.uzzu.dotenv.gradle") version "4.0.0"
}
repositories {
mavenLocal()
maven {
url = uri("https://repo.maven.apache.org/maven2/")
}
}
publishing {
repositories {
maven {
name = "Gitea"
url = uri(
"https://git.mori.space/api/packages/${env.GITEA_USERNAME.value}/maven"
)
credentials(HttpHeaderCredentials::class) {
name = "Authorization"
value = "token ${env.GITEA_TOKEN.value}"
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}
dependencies {
api(libs.org.apache.poi.poi)
api(libs.org.apache.poi.poi.ooxml)
api(libs.org.apache.tika.tika.core)
api(libs.org.springframework.boot.spring.boot.starter.data.jpa)
api(libs.org.springframework.boot.spring.boot.starter.thymeleaf)
api(libs.org.springframework.boot.spring.boot.starter.jdbc)
api(libs.com.h2database.h2)
api(libs.org.apache.commons.commons.csv)
api(libs.org.springframework.boot.spring.boot.starter.validation)
api(libs.org.springframework.boot.spring.boot.starter.web)
api(libs.org.springframework.boot.spring.boot.configuration.processor)
api("io.swagger.core.v3:swagger-annotations:2.2.15")
testImplementation(libs.org.springframework.boot.spring.boot.starter.test)
}
group = "space.mori.dalbodeule"
version = env.VERSION.value
description = "SnapAdmin"
java.sourceCompatibility = JavaVersion.VERSION_17
publishing {
publications.create<MavenPublication>("maven") {
from(components["java"])
}
}
tasks.withType<JavaCompile>() {
options.encoding = "UTF-8"
options.compilerArgs.add("-parameters")
}
tasks.withType<Javadoc>() {
options.encoding = "UTF-8"
}

View File

@@ -0,0 +1,76 @@
plugins {
kotlin("jvm") version "2.1.10"
kotlin("plugin.spring") version "2.1.10"
id("org.hibernate.orm") version "6.5.2.Final"
id("org.springframework.boot") version "3.4.5"
id("io.spring.dependency-management") version "1.1.7"
id("org.graalvm.buildtools.native") version "0.10.5"
}
group = "space.mori.dalbodeule"
version = "0.5.1"
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
hibernate {
enhancement {
enableAssociationManagement.set(false)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-batch")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-data-redis")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.springframework.boot:spring-boot-starter-websocket")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6")
implementation("io.swagger.core.v3:swagger-core:2.2.30")
implementation("io.swagger.core.v3:swagger-annotations:2.2.30")
implementation("io.github.cdimascio:dotenv-kotlin:6.4.1")
developmentOnly("org.springframework.boot:spring-boot-docker-compose")
runtimeOnly("org.postgresql:postgresql:42.7.4")
implementation("jakarta.xml.bind:jakarta.xml.bind-api:4.0.2")
implementation("javax.xml.bind:jaxb-api:2.3.1")
// HTTP 클라이언트
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation(rootProject)
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testImplementation("org.springframework.batch:spring-batch-test")
testImplementation("org.springframework.security:spring-security-test")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testImplementation(kotlin("test"))
}
tasks.named<org.springframework.boot.gradle.tasks.run.BootRun>("bootRun") {
systemProperty("spring.profiles.active", "dev")
}
kotlin {
compilerOptions {
freeCompilerArgs.addAll("-Xjsr305=strict")
}
}
tasks.withType<Test> {
useJUnitPlatform()
}

21
debugBackend/compose.yaml Normal file
View File

@@ -0,0 +1,21 @@
services:
pgvector:
image: 'pgvector/pgvector:pg16'
environment:
- 'POSTGRES_DB=mydatabase'
- 'POSTGRES_PASSWORD=secret'
- 'POSTGRES_USER=myuser'
labels:
- "org.springframework.boot.service-connection=postgres"
ports:
- target: 5432
published: 55432
protocol: tcp
volumes:
- postgresql:/var/lib/postgresql/data
redis:
image: 'redis:latest'
ports:
- '6379'
volumes:
postgresql:

View File

@@ -0,0 +1,32 @@
package space.mori.dalbodeule.debug
import io.github.cdimascio.dotenv.dotenv
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.boot.runApplication
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import space.mori.dalbodeule.snapadmin.external.annotations.SnapAdminEnabled
val dotenv = dotenv {
ignoreIfMissing = true
}
@SnapAdminEnabled
@SpringBootApplication
@EnableJpaRepositories(basePackages = ["space.mori.dalbodeule.debug.repository"])
@EntityScan(basePackages = ["space.mori.dalbodeule.debug.model"])
class DebugApplication
fun main(args: Array<String>) {
val envVars = mapOf(
"DB_HOST" to dotenv["DB_HOST"],
"DB_PORT" to dotenv["DB_PORT"],
"DB_NAME" to dotenv["DB_NAME"],
"DB_USER" to dotenv["DB_USER"],
"DB_PASSWORD" to dotenv["DB_PASSWORD"]
)
runApplication<DebugApplication>(*args) {
setDefaultProperties(envVars)
}
}

View File

@@ -0,0 +1,43 @@
package space.mori.dalbodeule.debug.config
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.provisioning.InMemoryUserDetailsManager
import org.springframework.security.web.SecurityFilterChain
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain {
return http
.csrf { it.disable() }
.authorizeHttpRequests {
it.anyRequest().authenticated()
}
.httpBasic {}
.build()
}
@Bean
fun userDetailsService(passwordEncoder: PasswordEncoder): UserDetailsService {
val admin = User.builder()
.username("test@gmail.com")
.password(passwordEncoder.encode("password"))
.roles("ADMIN")
.build()
return InMemoryUserDetailsManager(admin)
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
}

View File

@@ -0,0 +1,21 @@
package space.mori.dalbodeule.debug.model
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.Table
@Entity
@Table(name="test_table")
data class TestTable(
@Id
@GeneratedValue(strategy = GenerationType.UUID)
var id: String? = null,
@Column(nullable = false, length = 32)
var name: String
) {
constructor(): this(null, "")
}

View File

@@ -0,0 +1,7 @@
package space.mori.dalbodeule.debug.repository
import org.springframework.data.jpa.repository.JpaRepository
import space.mori.dalbodeule.debug.model.TestTable
interface TestTableRepository: JpaRepository<TestTable, String> {
}

View File

@@ -0,0 +1,18 @@
spring:
datasource:
url: jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
username: ${DB_USER}
password: ${DB_PASSWORD}
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
database-platform: org.hibernate.dialect.PostgreSQLDialect
snapadmin:
enabled: true
baseUrl: admin
models-package: space.mori.dalbodeule.debug.model
logging:
level:
root: INFO

7
gradle.properties Normal file
View File

@@ -0,0 +1,7 @@
# This file was generated by the Gradle 'init' task.
# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
org.gradle.configuration-cache=true
org.gradle.parallel=true
org.gradle.caching=true

30
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,30 @@
# This file was generated by the Gradle 'init' task.
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
[versions]
com-h2database-h2 = "2.3.232"
org-apache-commons-commons-csv = "1.14.0"
org-apache-poi-poi = "5.4.1"
org-apache-poi-poi-ooxml = "5.4.1"
org-apache-tika-tika-core = "3.1.0"
org-springframework-boot-spring-boot-configuration-processor = "3.4.5"
org-springframework-boot-spring-boot-starter-data-jpa = "3.4.5"
org-springframework-boot-spring-boot-starter-jdbc = "3.4.5"
org-springframework-boot-spring-boot-starter-test = "3.4.5"
org-springframework-boot-spring-boot-starter-thymeleaf = "3.4.5"
org-springframework-boot-spring-boot-starter-validation = "3.4.5"
org-springframework-boot-spring-boot-starter-web = "3.4.5"
[libraries]
com-h2database-h2 = { module = "com.h2database:h2", version.ref = "com-h2database-h2" }
org-apache-commons-commons-csv = { module = "org.apache.commons:commons-csv", version.ref = "org-apache-commons-commons-csv" }
org-apache-poi-poi = { module = "org.apache.poi:poi", version.ref = "org-apache-poi-poi" }
org-apache-poi-poi-ooxml = { module = "org.apache.poi:poi-ooxml", version.ref = "org-apache-poi-poi-ooxml" }
org-apache-tika-tika-core = { module = "org.apache.tika:tika-core", version.ref = "org-apache-tika-tika-core" }
org-springframework-boot-spring-boot-configuration-processor = { module = "org.springframework.boot:spring-boot-configuration-processor", version.ref = "org-springframework-boot-spring-boot-configuration-processor" }
org-springframework-boot-spring-boot-starter-data-jpa = { module = "org.springframework.boot:spring-boot-starter-data-jpa", version.ref = "org-springframework-boot-spring-boot-starter-data-jpa" }
org-springframework-boot-spring-boot-starter-jdbc = { module = "org.springframework.boot:spring-boot-starter-jdbc", version.ref = "org-springframework-boot-spring-boot-starter-jdbc" }
org-springframework-boot-spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "org-springframework-boot-spring-boot-starter-test" }
org-springframework-boot-spring-boot-starter-thymeleaf = { module = "org.springframework.boot:spring-boot-starter-thymeleaf", version.ref = "org-springframework-boot-spring-boot-starter-thymeleaf" }
org-springframework-boot-spring-boot-starter-validation = { module = "org.springframework.boot:spring-boot-starter-validation", version.ref = "org-springframework-boot-spring-boot-starter-validation" }
org-springframework-boot-spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "org-springframework-boot-spring-boot-starter-web" }

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

251
gradlew vendored Executable file
View File

@@ -0,0 +1,251 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# 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/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# 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
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
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
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# 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" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# 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.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

94
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,94 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@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
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
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
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
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
:execute
@rem Setup the command line
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
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!
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
:omega

308
mvnw vendored
View File

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

150
pom.xml
View File

@@ -1,150 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.5</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>tech.ailef</groupId>
<artifactId>snap-admin</artifactId>
<version>0.2.2</version>
<name>SnapAdmin</name>
<description>SnapAdmin is an auto-generated CRUD admin panel for Spring Boot/JPA apps</description>
<properties>
<java.version>17</java.version>
</properties>
<licenses>
<license>
<name>MIT License</name>
<url>https://opensource.org/license/mit</url>
</license>
</licenses>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.jreleaser</groupId>
<artifactId>jreleaser-maven-plugin</artifactId>
<version>1.3.1</version>
<configuration>
<jreleaser>
<signing>
<active>ALWAYS</active>
<armored>true</armored>
</signing>
<deploy>
<maven>
<nexus2>
<maven-central>
<active>ALWAYS</active>
<url>https://s01.oss.sonatype.org/service/local</url>
<closeRepository>true</closeRepository>
<releaseRepository>true</releaseRepository>
<stagingRepositories>target/staging-deploy</stagingRepositories>
</maven-central>
</nexus2>
</maven>
</deploy>
</jreleaser>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<id>attach-javadoc</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-source</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tika/tika-core -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-csv -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

9
settings.gradle.kts Normal file
View File

@@ -0,0 +1,9 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This project uses @Incubating APIs which are subject to change.
*/
rootProject.name = "snap-admin"
include("debugBackend")

View File

@@ -0,0 +1,135 @@
package space.mori.dalbodeule.snapadmin.aot;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import space.mori.dalbodeule.snapadmin.external.SnapAdmin;
import space.mori.dalbodeule.snapadmin.external.SnapAdminProperties;
import space.mori.dalbodeule.snapadmin.external.annotations.Disable;
import space.mori.dalbodeule.snapadmin.external.annotations.DisableEditField;
import space.mori.dalbodeule.snapadmin.external.annotations.DisplayFormat;
import space.mori.dalbodeule.snapadmin.external.annotations.DisplayImage; // Assuming this is used
import space.mori.dalbodeule.snapadmin.external.annotations.HiddenEditForm; // Assuming this is used
import space.mori.dalbodeule.snapadmin.external.dbmapping.CustomJpaRepository;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObjectSchema;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.*;
import space.mori.dalbodeule.snapadmin.external.dto.MappingError;
import space.mori.dalbodeule.snapadmin.external.misc.Utils;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import static org.springframework.aot.hint.MemberCategory.*;
public class SnapAdminRuntimeHints implements RuntimeHintsRegistrar {
private static final Set<Class<?>> dbFieldTypes = new HashSet<>(Arrays.asList(
BooleanFieldType.class, LongFieldType.class, IntegerFieldType.class,
BigIntegerFieldType.class, ShortFieldType.class, StringFieldType.class,
LocalDateFieldType.class, DateFieldType.class, LocalDateTimeFieldType.class,
InstantFieldType.class, FloatFieldType.class, DoubleFieldType.class,
BigDecimalFieldType.class, ByteArrayFieldType.class, OffsetDateTimeFieldType.class,
ByteFieldType.class, UUIDFieldType.class, CharFieldType.class,
EnumFieldType.class, TextFieldType.class
// Add any other concrete DbFieldType implementations here
));
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
// Register SnapAdmin's own classes
hints.reflection().registerType(SnapAdmin.class, INTROSPECT_DECLARED_METHODS, INVOKE_DECLARED_METHODS);
hints.reflection().registerType(SnapAdminProperties.class, INVOKE_DECLARED_CONSTRUCTORS, INVOKE_PUBLIC_METHODS); // For Spring binding
hints.reflection().registerType(DbObjectSchema.class, INVOKE_DECLARED_CONSTRUCTORS, INTROSPECT_DECLARED_METHODS, INVOKE_PUBLIC_METHODS);
// CustomJpaRepository 인터페이스 자체는 생성자 호출 힌트가 불필요할 수 있음
hints.reflection().registerType(DbField.class, INVOKE_DECLARED_CONSTRUCTORS, INTROSPECT_DECLARED_METHODS, INVOKE_PUBLIC_METHODS);
hints.reflection().registerType(MappingError.class, INVOKE_DECLARED_CONSTRUCTORS);
// hints.reflection().registerType(Utils.class); // 사용 패턴 확인 후 필요하면 활성화
// Register DbFieldType and its subclasses for default constructor invocation
hints.reflection().registerType(DbFieldType.class);
for (Class<?> dbFieldTypeClass : dbFieldTypes) {
hints.reflection().registerType(dbFieldTypeClass, INVOKE_DECLARED_CONSTRUCTORS);
}
// EnumFieldType has a special constructor too
hints.reflection().registerType(EnumFieldType.class, INVOKE_DECLARED_CONSTRUCTORS);
// Register SnapAdmin's custom annotations (and assume their attributes might be read)
registerAnnotation(hints, Disable.class);
registerAnnotation(hints, DisableEditField.class);
registerAnnotation(hints, DisplayFormat.class);
registerAnnotation(hints, DisplayImage.class);
registerAnnotation(hints, HiddenEditForm.class);
// Register Jakarta Persistence annotations (and assume their attributes might be read)
registerAnnotation(hints, jakarta.persistence.Entity.class);
registerAnnotation(hints, jakarta.persistence.Id.class);
registerAnnotation(hints, jakarta.persistence.Column.class);
registerAnnotation(hints, jakarta.persistence.Lob.class);
registerAnnotation(hints, jakarta.persistence.Enumerated.class);
registerAnnotation(hints, jakarta.persistence.EnumType.class); // TYPE_VISIBLE 제거
registerAnnotation(hints, jakarta.persistence.OneToMany.class);
registerAnnotation(hints, jakarta.persistence.ManyToMany.class);
registerAnnotation(hints, jakarta.persistence.ManyToOne.class);
registerAnnotation(hints, jakarta.persistence.OneToOne.class);
registerAnnotation(hints, jakarta.persistence.JoinColumn.class);
// Add other JPA annotations if used, e.g. @Table, @Transient
// Hints for operations on arbitrary (user-defined) @Entity classes
// 가능하면 스캔 범위를 제한하거나, 필요한 메서드만 등록
// 예시: 특정 패키지 내의 @Entity 클래스 스캔
// ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
// scanner.addIncludeFilter(new AnnotationTypeFilter(jakarta.persistence.Entity.class));
// for (BeanDefinition bd : scanner.findCandidateComponents("com.example.entities")) {
// try {
// Class<?> entityClass = Class.forName(bd.getBeanClassName());
// hints.reflection().registerType(entityClass, INTROSPECT_DECLARED_FIELDS, INVOKE_DECLARED_METHODS);
// } catch (ClassNotFoundException e) {
// // Handle exception
// }
// }
// Register SnapAdmin's own classes
hints.reflection().registerType(SnapAdmin.class, INTROSPECT_DECLARED_METHODS, INVOKE_DECLARED_METHODS);
hints.reflection().registerType(SnapAdminProperties.class, INVOKE_DECLARED_CONSTRUCTORS, INVOKE_PUBLIC_METHODS); // For Spring binding
hints.reflection().registerType(DbObjectSchema.class, INVOKE_DECLARED_CONSTRUCTORS, INTROSPECT_DECLARED_METHODS, INVOKE_PUBLIC_METHODS);
hints.reflection().registerType(CustomJpaRepository.class, INVOKE_DECLARED_CONSTRUCTORS);
hints.reflection().registerType(DbField.class, INVOKE_DECLARED_CONSTRUCTORS, INTROSPECT_DECLARED_METHODS, INVOKE_PUBLIC_METHODS);
hints.reflection().registerType(MappingError.class, INVOKE_DECLARED_CONSTRUCTORS);
hints.reflection().registerType(Utils.class); // If it contains static methods called, or if instantiated
// For Class.forName(className) on unknown classes (typically user entities)
// and subsequent operations like getDeclaredFields(), getAnnotation(), newInstance()
// This is a general hint. Users should still ensure their entities are hinted.
// Consider making this more specific if possible, e.g., by scanning packages if configured.
hints.reflection().registerType(Object.class,
INTROSPECT_DECLARED_CONSTRUCTORS, INVOKE_DECLARED_CONSTRUCTORS,
INTROSPECT_DECLARED_METHODS, INVOKE_DECLARED_METHODS, // For getters/setters if library invokes them
DECLARED_FIELDS // For field access
);
// For ClassPathScanningCandidateComponentProvider
hints.reflection().registerType(org.springframework.beans.factory.config.BeanDefinition.class, INVOKE_PUBLIC_METHODS); // For getBeanClassName()
hints.reflection().registerType(org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.class, INVOKE_DECLARED_CONSTRUCTORS);
hints.reflection().registerType(org.springframework.core.type.filter.AnnotationTypeFilter.class, INVOKE_DECLARED_CONSTRUCTORS);
// Resource hints if any .properties or .xml files are loaded from classpath by the library
// hints.resources().registerPattern("my-library-config.xml");
// Proxy hints if JDK proxies are created for library interfaces
// hints.proxies().registerJdkProxy(MyLibraryInterface.class);
// Serialization hints if objects are serialized by the library
// hints.serialization().registerType(MySerializableObject.class);
}
private void registerAnnotation(RuntimeHints hints, Class<?> annotationType) {
hints.reflection().registerType(annotationType, INVOKE_DECLARED_METHODS);
}
private void registerAnnotation(RuntimeHints hints, Class<?> annotationType, org.springframework.aot.hint.MemberCategory... categories) {
hints.reflection().registerType(annotationType, categories);
}
}

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external;
package space.mori.dalbodeule.snapadmin.external;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -50,20 +50,21 @@ import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import tech.ailef.snapadmin.external.annotations.Disable;
import tech.ailef.snapadmin.external.annotations.DisplayFormat;
import tech.ailef.snapadmin.external.dbmapping.CustomJpaRepository;
import tech.ailef.snapadmin.external.dbmapping.DbObjectSchema;
import tech.ailef.snapadmin.external.dbmapping.fields.DbField;
import tech.ailef.snapadmin.external.dbmapping.fields.DbFieldType;
import tech.ailef.snapadmin.external.dbmapping.fields.EnumFieldType;
import tech.ailef.snapadmin.external.dbmapping.fields.StringFieldType;
import tech.ailef.snapadmin.external.dbmapping.fields.TextFieldType;
import tech.ailef.snapadmin.external.dto.MappingError;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import tech.ailef.snapadmin.external.exceptions.SnapAdminNotFoundException;
import tech.ailef.snapadmin.external.exceptions.UnsupportedFieldTypeException;
import tech.ailef.snapadmin.external.misc.Utils;
import space.mori.dalbodeule.snapadmin.external.annotations.Disable;
import space.mori.dalbodeule.snapadmin.external.annotations.DisableEditField;
import space.mori.dalbodeule.snapadmin.external.annotations.DisplayFormat;
import space.mori.dalbodeule.snapadmin.external.dbmapping.CustomJpaRepository;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObjectSchema;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.DbField;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.DbFieldType;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.EnumFieldType;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.StringFieldType;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.TextFieldType;
import space.mori.dalbodeule.snapadmin.external.dto.MappingError;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminNotFoundException;
import space.mori.dalbodeule.snapadmin.external.exceptions.UnsupportedFieldTypeException;
import space.mori.dalbodeule.snapadmin.external.misc.Utils;
/**
* The main SnapAdmin class is responsible for the initialization phase. This class scans
@@ -88,7 +89,7 @@ public class SnapAdmin {
private boolean authenticated;
private static final String VERSION = "0.2.0";
private static final String VERSION = "0.6.2";
/**
* Builds the SnapAdmin instance by scanning the `@Entity` beans and loading
@@ -219,10 +220,12 @@ public class SnapAdmin {
Field[] fields = klass.getDeclaredFields();
for (Field f : fields) {
try {
if(f.getName().contains("hibernate")) continue;
DbField field = mapField(f, schema);
field.setSchema(schema);
schema.addField(field);
} catch (UnsupportedFieldTypeException e) {
if(klass.getSimpleName().startsWith("$$_hibernate")) continue;
logger.warn("The class " + klass.getSimpleName() + " contains the field `"
+ f.getName() + "` of type `" + f.getType().getSimpleName() + "`, which is not supported");
schema.addError(
@@ -351,7 +354,8 @@ public class SnapAdmin {
}
DisplayFormat displayFormat = f.getAnnotation(DisplayFormat.class);
DisableEditField disableEdit = f.getAnnotation(DisableEditField.class);
DbField field = new DbField(f.getName(), fieldName, f, fieldType, schema, displayFormat != null ? displayFormat.format() : null);
field.setConnectedType(connectedType);
@@ -362,6 +366,8 @@ public class SnapAdmin {
if (field.isPrimaryKey())
field.setNullable(false);
field.setDisableEditField(disableEdit != null);
return field;
}
@@ -390,25 +396,32 @@ public class SnapAdmin {
* @return
*/
private DbFieldType mapForeignKeyType(Class<?> entityClass) {
try {
Object linkedEntity = entityClass.getConstructor().newInstance();
Class<?> linkType = null;
for (Field ef : linkedEntity.getClass().getDeclaredFields()) {
if (ef.getAnnotationsByType(Id.class).length != 0) {
linkType = ef.getType();
}
}
if (linkType == null)
throw new SnapAdminException("Unable to find @Id field in Entity class " + entityClass);
return DbFieldType.fromClass(linkType).getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
throw new SnapAdminException(e);
}
}
try {
Object linkedEntity = entityClass.getConstructor().newInstance();
Class<?> clazz = linkedEntity.getClass();
Field idField = null;
// 상속 계층 전체를 스캔하여 @Id 필드 탐색
while (clazz != null && clazz != Object.class) {
for (Field ef : clazz.getDeclaredFields()) {
if (ef.getAnnotationsByType(jakarta.persistence.Id.class).length != 0) {
idField = ef;
break;
}
}
if (idField != null) break;
clazz = clazz.getSuperclass();
}
if (idField == null)
throw new SnapAdminException("Unable to find @Id field in Entity class hierarchy: " + entityClass);
return DbFieldType.fromClass(idField.getType()).getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
throw new SnapAdminException(e);
}
}
public boolean isAuthenticated() {
return authenticated;
@@ -418,4 +431,4 @@ public class SnapAdmin {
this.authenticated = authenticated;
}
}
}

View File

@@ -0,0 +1,55 @@
package space.mori.dalbodeule.snapadmin.external;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import space.mori.dalbodeule.snapadmin.external.controller.DataExportController;
import space.mori.dalbodeule.snapadmin.external.controller.FileDownloadController;
import space.mori.dalbodeule.snapadmin.external.controller.GlobalController;
import space.mori.dalbodeule.snapadmin.external.controller.SnapAdminController;
import space.mori.dalbodeule.snapadmin.external.controller.rest.AutocompleteController;
import space.mori.dalbodeule.snapadmin.external.dbmapping.CustomJpaRepository;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObjectSchema;
import space.mori.dalbodeule.snapadmin.external.dbmapping.SnapAdminRepository;
import space.mori.dalbodeule.snapadmin.internal.InternalSnapAdminConfiguration;
import space.mori.dalbodeule.snapadmin.internal.UserConfiguration;
import space.mori.dalbodeule.snapadmin.internal.service.ConsoleQueryService;
import space.mori.dalbodeule.snapadmin.internal.service.UserActionService;
import space.mori.dalbodeule.snapadmin.internal.service.UserSettingsService;
/**
* SnapAdmin 자동 설정 클래스. 메인 애플리케이션의 JPA 설정을 재사용합니다.
*/
@Configuration
@ConditionalOnProperty(name = "snapadmin.enabled", havingValue = "true", matchIfMissing = false)
@EnableConfigurationProperties(SnapAdminProperties.class)
@EnableJpaRepositories(basePackages = "space.mori.dalbodeule.snapadmin.internal.repository")
@EntityScan(basePackages = "space.mori.dalbodeule.snapadmin.internal.model")
@Import({
SnapAdmin.class,
SnapAdminMvcConfig.class,
StartupAuthCheckRunner.class,
ThymeleafUtils.class,
// controllers
SnapAdminController.class,
DataExportController.class,
FileDownloadController.class,
GlobalController.class,
AutocompleteController.class,
// dbmapping
SnapAdminRepository.class,
// internals
ConsoleQueryService.class,
UserActionService.class,
UserSettingsService.class,
InternalSnapAdminConfiguration.class,
UserConfiguration.class
})
public class SnapAdminAutoConfiguration {
}

View File

@@ -18,16 +18,14 @@
*/
package tech.ailef.snapadmin.external;
package space.mori.dalbodeule.snapadmin.external;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
public class SnapAdminMvcConfig implements WebMvcConfigurer {
@Autowired
private SnapAdminProperties properties;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external;
package space.mori.dalbodeule.snapadmin.external;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external;
package space.mori.dalbodeule.snapadmin.external;
import java.io.IOException;
import java.net.HttpURLConnection;
@@ -30,7 +30,7 @@ import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
/**
* Runs at startup to determine if SnapAdmin is protected with authentication.

View File

@@ -0,0 +1,7 @@
package space.mori.dalbodeule.snapadmin.external;
public class ThymeleafUtils {
public String getSimpleName(Class<?> clazz) {
return clazz.getSimpleName();
}
}

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -28,6 +28,6 @@ import java.lang.annotation.Target;
* Disables edit actions on the Entity class.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DisableEdit {
@Target(ElementType.FIELD)
public @interface DisableEditField {
}

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
/**
* Type of filters that can be used in the faceted search.

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -0,0 +1,11 @@
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface HiddenEditForm {
}

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -0,0 +1,14 @@
package space.mori.dalbodeule.snapadmin.external.annotations;
import org.springframework.context.annotation.Import;
import space.mori.dalbodeule.snapadmin.external.SnapAdminAutoConfiguration;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(SnapAdminAutoConfiguration.class) // SnapAdmin 설정 클래스를 Import
public @interface SnapAdminEnabled {
// 필요한 속성이 있다면 정의
}

View File

@@ -19,4 +19,4 @@
/**
* Annotations defined to allow user customization
*/
package tech.ailef.snapadmin.external.annotations;
package space.mori.dalbodeule.snapadmin.external.annotations;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.controller;
package space.mori.dalbodeule.snapadmin.external.controller;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -29,6 +29,7 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import io.swagger.v3.oas.annotations.Hidden;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.poi.ss.usermodel.Cell;
@@ -41,6 +42,8 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
@@ -54,38 +57,44 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import tech.ailef.snapadmin.external.SnapAdmin;
import tech.ailef.snapadmin.external.dbmapping.DbFieldValue;
import tech.ailef.snapadmin.external.dbmapping.DbObject;
import tech.ailef.snapadmin.external.dbmapping.DbObjectSchema;
import tech.ailef.snapadmin.external.dbmapping.SnapAdminRepository;
import tech.ailef.snapadmin.external.dbmapping.fields.DbField;
import tech.ailef.snapadmin.external.dbmapping.query.DbQueryResult;
import tech.ailef.snapadmin.external.dbmapping.query.DbQueryResultRow;
import tech.ailef.snapadmin.external.dto.DataExportFormat;
import tech.ailef.snapadmin.external.dto.QueryFilter;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import tech.ailef.snapadmin.external.exceptions.SnapAdminNotFoundException;
import tech.ailef.snapadmin.external.misc.Utils;
import tech.ailef.snapadmin.internal.model.ConsoleQuery;
import tech.ailef.snapadmin.internal.repository.ConsoleQueryRepository;
import space.mori.dalbodeule.snapadmin.external.SnapAdmin;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbFieldValue;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObject;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObjectSchema;
import space.mori.dalbodeule.snapadmin.external.dbmapping.SnapAdminRepository;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.DbField;
import space.mori.dalbodeule.snapadmin.external.dbmapping.query.DbQueryResult;
import space.mori.dalbodeule.snapadmin.external.dbmapping.query.DbQueryResultRow;
import space.mori.dalbodeule.snapadmin.external.dto.DataExportFormat;
import space.mori.dalbodeule.snapadmin.external.dto.QueryFilter;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminNotFoundException;
import space.mori.dalbodeule.snapadmin.external.misc.Utils;
import space.mori.dalbodeule.snapadmin.internal.model.ConsoleQuery;
import space.mori.dalbodeule.snapadmin.internal.repository.ConsoleQueryRepository;
@Controller
@RequestMapping(value = { "/${snapadmin.baseUrl}/", "/${snapadmin.baseUrl}" })
@Import(ObjectMapper.class)
@Hidden
public class DataExportController {
private static final Logger logger = LoggerFactory.getLogger(DataExportFormat.class);
@Autowired
private SnapAdmin snapAdmin;
private final SnapAdmin snapAdmin;
private final SnapAdminRepository repository;
private final ConsoleQueryRepository queryRepository;
private final ObjectMapper mapper;
@Autowired
private SnapAdminRepository repository;
@Autowired
private ConsoleQueryRepository queryRepository;
@Autowired
private ObjectMapper mapper;
public DataExportController(
@Autowired SnapAdmin snapAdmin,
@Autowired SnapAdminRepository repository,
@Autowired ConsoleQueryRepository queryRepository,
@Autowired ObjectMapper mapper
) {
this.snapAdmin = snapAdmin;
this.repository = repository;
this.queryRepository = queryRepository;
this.mapper = mapper;
}
@GetMapping("/console/export/{queryId}")
public ResponseEntity<byte[]> export(@PathVariable String queryId, @RequestParam String format,

View File

@@ -17,10 +17,11 @@
*/
package tech.ailef.snapadmin.external.controller;
package space.mori.dalbodeule.snapadmin.external.controller;
import java.util.Optional;
import io.swagger.v3.oas.annotations.Hidden;
import org.apache.tika.Tika;
import org.apache.tika.mime.MimeTypeException;
import org.apache.tika.mime.MimeTypes;
@@ -36,18 +37,19 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.server.ResponseStatusException;
import tech.ailef.snapadmin.external.SnapAdmin;
import tech.ailef.snapadmin.external.dbmapping.DbFieldValue;
import tech.ailef.snapadmin.external.dbmapping.DbObject;
import tech.ailef.snapadmin.external.dbmapping.DbObjectSchema;
import tech.ailef.snapadmin.external.dbmapping.SnapAdminRepository;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.SnapAdmin;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbFieldValue;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObject;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObjectSchema;
import space.mori.dalbodeule.snapadmin.external.dbmapping.SnapAdminRepository;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
/**
* Controller to serve file or images (`@DisplayImage`)
*/
@Controller
@RequestMapping(value = {"/${snapadmin.baseUrl}/download", "/${snapadmin.baseUrl}/download/"})
@Hidden
public class FileDownloadController {
@Autowired
private SnapAdminRepository repository;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.controller;
package space.mori.dalbodeule.snapadmin.external.controller;
import java.security.Principal;
import java.util.Map;
@@ -30,11 +30,12 @@ import org.springframework.web.bind.annotation.ModelAttribute;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import tech.ailef.snapadmin.external.SnapAdmin;
import tech.ailef.snapadmin.external.SnapAdminProperties;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import tech.ailef.snapadmin.external.exceptions.SnapAdminNotFoundException;
import tech.ailef.snapadmin.internal.UserConfiguration;
import space.mori.dalbodeule.snapadmin.external.SnapAdmin;
import space.mori.dalbodeule.snapadmin.external.SnapAdminProperties;
import space.mori.dalbodeule.snapadmin.external.ThymeleafUtils;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminNotFoundException;
import space.mori.dalbodeule.snapadmin.internal.UserConfiguration;
/**
* This class registers some global ModelAttributes and exception handlers.
@@ -61,6 +62,7 @@ public class GlobalController {
model.addAttribute("snapadmin_baseUrl", getBaseUrl());
model.addAttribute("snapadmin_version", snapAdmin.getVersion());
model.addAttribute("snapadmin_properties", props);
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/other/error";
}
@@ -73,6 +75,7 @@ public class GlobalController {
model.addAttribute("snapadmin_baseUrl", getBaseUrl());
model.addAttribute("snapadmin_version", snapAdmin.getVersion());
model.addAttribute("snapadmin_properties", props);
model.addAttribute("utils", new ThymeleafUtils());
response.setStatus(404);
return "snapadmin/other/error";
}

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.controller;
package space.mori.dalbodeule.snapadmin.external.controller;
import java.security.Principal;
import java.text.DecimalFormat;
@@ -32,6 +32,7 @@ import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
import io.swagger.v3.oas.annotations.Hidden;
import org.hibernate.id.IdentifierGenerationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -56,35 +57,37 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolationException;
import tech.ailef.snapadmin.external.SnapAdmin;
import tech.ailef.snapadmin.external.SnapAdminProperties;
import tech.ailef.snapadmin.external.dbmapping.DbObject;
import tech.ailef.snapadmin.external.dbmapping.DbObjectSchema;
import tech.ailef.snapadmin.external.dbmapping.SnapAdminRepository;
import tech.ailef.snapadmin.external.dbmapping.query.DbQueryResult;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import tech.ailef.snapadmin.external.dto.FacetedSearchRequest;
import tech.ailef.snapadmin.external.dto.LogsSearchRequest;
import tech.ailef.snapadmin.external.dto.PaginatedResult;
import tech.ailef.snapadmin.external.dto.PaginationInfo;
import tech.ailef.snapadmin.external.dto.QueryFilter;
import tech.ailef.snapadmin.external.dto.ValidationErrorsContainer;
import tech.ailef.snapadmin.external.exceptions.InvalidPageException;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import tech.ailef.snapadmin.external.exceptions.SnapAdminNotFoundException;
import tech.ailef.snapadmin.external.misc.Utils;
import tech.ailef.snapadmin.internal.model.ConsoleQuery;
import tech.ailef.snapadmin.internal.model.UserAction;
import tech.ailef.snapadmin.internal.model.UserSetting;
import tech.ailef.snapadmin.internal.service.ConsoleQueryService;
import tech.ailef.snapadmin.internal.service.UserActionService;
import tech.ailef.snapadmin.internal.service.UserSettingsService;
import space.mori.dalbodeule.snapadmin.external.SnapAdmin;
import space.mori.dalbodeule.snapadmin.external.SnapAdminProperties;
import space.mori.dalbodeule.snapadmin.external.ThymeleafUtils;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObject;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObjectSchema;
import space.mori.dalbodeule.snapadmin.external.dbmapping.SnapAdminRepository;
import space.mori.dalbodeule.snapadmin.external.dbmapping.query.DbQueryResult;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.FacetedSearchRequest;
import space.mori.dalbodeule.snapadmin.external.dto.LogsSearchRequest;
import space.mori.dalbodeule.snapadmin.external.dto.PaginatedResult;
import space.mori.dalbodeule.snapadmin.external.dto.PaginationInfo;
import space.mori.dalbodeule.snapadmin.external.dto.QueryFilter;
import space.mori.dalbodeule.snapadmin.external.dto.ValidationErrorsContainer;
import space.mori.dalbodeule.snapadmin.external.exceptions.InvalidPageException;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminNotFoundException;
import space.mori.dalbodeule.snapadmin.external.misc.Utils;
import space.mori.dalbodeule.snapadmin.internal.model.ConsoleQuery;
import space.mori.dalbodeule.snapadmin.internal.model.UserAction;
import space.mori.dalbodeule.snapadmin.internal.model.UserSetting;
import space.mori.dalbodeule.snapadmin.internal.service.ConsoleQueryService;
import space.mori.dalbodeule.snapadmin.internal.service.UserActionService;
import space.mori.dalbodeule.snapadmin.internal.service.UserSettingsService;
/**
* The main SnapAdmin controller that register most of the routes of the web interface.
*/
@Controller
@RequestMapping(value= {"/${snapadmin.baseUrl}", "/${snapadmin.baseUrl}/"})
@Hidden
public class SnapAdminController {
private static final Logger logger = LoggerFactory.getLogger(SnapAdminController.class);
@@ -222,6 +225,7 @@ public class SnapAdminController {
model.addAttribute("query", query);
model.addAttribute("sortOrder", sortOrder);
model.addAttribute("activeFilters", queryFilters);
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/model/list";
} catch (InvalidPageException e) {
@@ -235,6 +239,7 @@ public class SnapAdminController {
model.addAttribute("query", query);
model.addAttribute("sortOrder", sortOrder);
model.addAttribute("activeFilters", queryFilters);
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/model/list";
}
}
@@ -251,6 +256,7 @@ public class SnapAdminController {
model.addAttribute("activePage", "entities");
model.addAttribute("schema", schema);
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/model/schema";
}
@@ -278,6 +284,7 @@ public class SnapAdminController {
model.addAttribute("object", object);
model.addAttribute("activePage", "entities");
model.addAttribute("schema", schema);
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/model/show";
}
@@ -298,6 +305,7 @@ public class SnapAdminController {
model.addAttribute("title", "Entities | " + schema.getJavaClass().getSimpleName() + " | Create");
model.addAttribute("activePage", "entities");
model.addAttribute("create", true);
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/model/create";
}
@@ -326,6 +334,7 @@ public class SnapAdminController {
model.addAttribute("schema", schema);
model.addAttribute("activePage", "entities");
model.addAttribute("create", false);
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/model/create";
}
@@ -520,9 +529,14 @@ public class SnapAdminController {
} else {
throw new RuntimeException(e);
}
} catch (Exception e) {
// 추가: 일반적인 예외 처리
logger.error("Unexpected error during data submission: ", e);
attr.addFlashAttribute("errorTitle", "System Error");
attr.addFlashAttribute("error", e.getMessage());
attr.addFlashAttribute("params", params);
}
if (attr.getFlashAttributes().containsKey("error")) {
if (create)
return "redirect:/" + properties.getBaseUrl() + "/model/" + schema.getClassName() + "/create";
@@ -543,6 +557,7 @@ public class SnapAdminController {
model.addAttribute("title", "Action logs");
model.addAttribute("schemas", snapAdmin.getSchemas());
model.addAttribute("searchRequest", searchRequest);
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/logs";
}
@@ -551,6 +566,7 @@ public class SnapAdminController {
public String settings(Model model) {
model.addAttribute("title", "Settings");
model.addAttribute("activePage", "settings");
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/settings/settings";
}
@@ -558,6 +574,7 @@ public class SnapAdminController {
public String help(Model model) {
model.addAttribute("title", "Help");
model.addAttribute("activePage", "help");
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/help";
}
@@ -664,6 +681,7 @@ public class SnapAdminController {
model.addAttribute("title", "SQL Console | " + activeQuery.getTitle());
double elapsedTime = (System.currentTimeMillis() - startTime) / 1000.0;
model.addAttribute("elapsedTime", new DecimalFormat("0.0#").format(elapsedTime));
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/console";
}
@@ -671,6 +689,7 @@ public class SnapAdminController {
@GetMapping("/settings/appearance")
public String settingsAppearance(Model model) {
model.addAttribute("activePage", "settings");
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/settings/appearance";
}
@@ -679,6 +698,7 @@ public class SnapAdminController {
model.addAttribute("error", "Forbidden");
model.addAttribute("status", "403");
model.addAttribute("message", "You don't have the privileges to perform this action");
model.addAttribute("utils", new ThymeleafUtils());
return "snapadmin/other/error";
}
@@ -692,6 +712,7 @@ public class SnapAdminController {
userSettingsService.save(new UserSetting(paramName, params.get(paramName)));
}
model.addAttribute("activePage", "settings");
model.addAttribute("utils", new ThymeleafUtils());
return next;
}

View File

@@ -20,4 +20,4 @@
/**
* Controllers registered for the web UI
*/
package tech.ailef.snapadmin.external.controller;
package space.mori.dalbodeule.snapadmin.external.controller;

View File

@@ -17,11 +17,12 @@
*/
package tech.ailef.snapadmin.external.controller.rest;
package space.mori.dalbodeule.snapadmin.external.controller.rest;
import java.util.List;
import java.util.stream.Collectors;
import io.swagger.v3.oas.annotations.Hidden;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
@@ -30,16 +31,17 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import tech.ailef.snapadmin.external.SnapAdmin;
import tech.ailef.snapadmin.external.dbmapping.DbObjectSchema;
import tech.ailef.snapadmin.external.dbmapping.SnapAdminRepository;
import tech.ailef.snapadmin.external.dto.AutocompleteSearchResult;
import space.mori.dalbodeule.snapadmin.external.SnapAdmin;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObjectSchema;
import space.mori.dalbodeule.snapadmin.external.dbmapping.SnapAdminRepository;
import space.mori.dalbodeule.snapadmin.external.dto.AutocompleteSearchResult;
/**
* API controller for autocomplete results
*/
@RestController
@RequestMapping(value= {"/${snapadmin.baseUrl}/api/autocomplete", "/${snapadmin.baseUrl}/api/autocomplete/"})
@Hidden
public class AutocompleteController {
@Autowired
private SnapAdmin snapAdmin;

View File

@@ -0,0 +1,4 @@
/**
* Rest controllers
*/
package space.mori.dalbodeule.snapadmin.external.controller.rest;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.dbmapping;
package space.mori.dalbodeule.snapadmin.external.dbmapping;
import java.io.IOException;
import java.time.LocalDate;
@@ -40,12 +40,12 @@ import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import tech.ailef.snapadmin.external.dbmapping.fields.DbField;
import tech.ailef.snapadmin.external.dbmapping.fields.StringFieldType;
import tech.ailef.snapadmin.external.dbmapping.fields.TextFieldType;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import tech.ailef.snapadmin.external.dto.QueryFilter;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.DbField;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.StringFieldType;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.TextFieldType;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.QueryFilter;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
@SuppressWarnings("rawtypes")
public class CustomJpaRepository extends SimpleJpaRepository {
@@ -123,6 +123,7 @@ public class CustomJpaRepository extends SimpleJpaRepository {
for (DbField field : schema.getSortedFields()) {
if (field.isPrimaryKey()) continue;
if (field.isReadOnly()) continue;
if (field.isDisableEditField()) continue;
boolean keepValue = params.getOrDefault("__keep_" + field.getName(), "off").equals("on");
if (keepValue) continue;

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.dbmapping;
package space.mori.dalbodeule.snapadmin.external.dbmapping;
import java.time.Instant;
import java.time.LocalDateTime;
@@ -27,7 +27,7 @@ import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonIgnore;
import tech.ailef.snapadmin.external.dbmapping.fields.DbField;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.DbField;
/**
* Wrapper for the value of a field

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.dbmapping;
package space.mori.dalbodeule.snapadmin.external.dbmapping;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -34,10 +34,10 @@ import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import tech.ailef.snapadmin.external.annotations.DisplayName;
import tech.ailef.snapadmin.external.dbmapping.fields.BooleanFieldType;
import tech.ailef.snapadmin.external.dbmapping.fields.DbField;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.annotations.DisplayName;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.BooleanFieldType;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.DbField;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
/**
* Wrapper for all objects retrieved from the database.

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.dbmapping;
package space.mori.dalbodeule.snapadmin.external.dbmapping;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -35,22 +35,23 @@ import org.springframework.web.multipart.MultipartFile;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import tech.ailef.snapadmin.external.SnapAdmin;
import tech.ailef.snapadmin.external.annotations.ComputedColumn;
import tech.ailef.snapadmin.external.annotations.DisableCreate;
import tech.ailef.snapadmin.external.annotations.DisableDelete;
import tech.ailef.snapadmin.external.annotations.DisableEdit;
import tech.ailef.snapadmin.external.annotations.DisableExport;
import tech.ailef.snapadmin.external.annotations.HiddenColumn;
import tech.ailef.snapadmin.external.dbmapping.fields.DbField;
import tech.ailef.snapadmin.external.dto.MappingError;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import tech.ailef.snapadmin.external.exceptions.SnapAdminNotFoundException;
import tech.ailef.snapadmin.external.misc.Utils;
import space.mori.dalbodeule.snapadmin.external.SnapAdmin;
import space.mori.dalbodeule.snapadmin.external.annotations.ComputedColumn;
import space.mori.dalbodeule.snapadmin.external.annotations.DisableCreate;
import space.mori.dalbodeule.snapadmin.external.annotations.DisableDelete;
import space.mori.dalbodeule.snapadmin.external.annotations.DisableEditField;
import space.mori.dalbodeule.snapadmin.external.annotations.DisableExport;
import space.mori.dalbodeule.snapadmin.external.annotations.HiddenColumn;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.DbField;
import space.mori.dalbodeule.snapadmin.external.dto.MappingError;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminNotFoundException;
import space.mori.dalbodeule.snapadmin.external.misc.Utils;
/**
* A class that represents a table/`@Entity` as reconstructed from the
@@ -99,6 +100,10 @@ public class DbObjectSchema {
* @param snapAdmin the SnapAdmin instance
*/
public DbObjectSchema(Class<?> klass, SnapAdmin snapAdmin) {
if (klass.getAnnotation(Entity.class) == null) {
throw new SnapAdminException("Class " + klass.getName() + " is not an @Entity");
}
this.snapAdmin = snapAdmin;
this.entityClass = klass;
@@ -351,7 +356,7 @@ public class DbObjectSchema {
}
public boolean isEditEnabled() {
return entityClass.getAnnotation(DisableEdit.class) == null;
return entityClass.getAnnotation(DisableEditField.class) == null;
}
public boolean isCreateEnabled() {

View File

@@ -18,7 +18,7 @@
*/
package tech.ailef.snapadmin.external.dbmapping;
package space.mori.dalbodeule.snapadmin.external.dbmapping;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
@@ -46,18 +46,18 @@ import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import tech.ailef.snapadmin.external.SnapAdmin;
import tech.ailef.snapadmin.external.annotations.ReadOnly;
import tech.ailef.snapadmin.external.dbmapping.fields.DbField;
import tech.ailef.snapadmin.external.dbmapping.query.DbQueryOutputField;
import tech.ailef.snapadmin.external.dbmapping.query.DbQueryResult;
import tech.ailef.snapadmin.external.dbmapping.query.DbQueryResultRow;
import tech.ailef.snapadmin.external.dto.FacetedSearchRequest;
import tech.ailef.snapadmin.external.dto.PaginatedResult;
import tech.ailef.snapadmin.external.dto.PaginationInfo;
import tech.ailef.snapadmin.external.dto.QueryFilter;
import tech.ailef.snapadmin.external.exceptions.InvalidPageException;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.SnapAdmin;
import space.mori.dalbodeule.snapadmin.external.annotations.ReadOnly;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.DbField;
import space.mori.dalbodeule.snapadmin.external.dbmapping.query.DbQueryOutputField;
import space.mori.dalbodeule.snapadmin.external.dbmapping.query.DbQueryResult;
import space.mori.dalbodeule.snapadmin.external.dbmapping.query.DbQueryResultRow;
import space.mori.dalbodeule.snapadmin.external.dto.FacetedSearchRequest;
import space.mori.dalbodeule.snapadmin.external.dto.PaginatedResult;
import space.mori.dalbodeule.snapadmin.external.dto.PaginationInfo;
import space.mori.dalbodeule.snapadmin.external.dto.QueryFilter;
import space.mori.dalbodeule.snapadmin.external.exceptions.InvalidPageException;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
/**
* Implements the basic CRUD operations (and some more)

View File

@@ -16,12 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.math.BigDecimal;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class BigDecimalFieldType extends DbFieldType {
@Override

View File

@@ -16,12 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.math.BigInteger;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class BigIntegerFieldType extends DbFieldType {
@Override

View File

@@ -16,11 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class BooleanFieldType extends DbFieldType {
@Override

View File

@@ -16,15 +16,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.io.IOException;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
public class ByteArrayFieldType extends DbFieldType {
@Override

View File

@@ -16,12 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
public class ByteFieldType extends DbFieldType {
@Override

View File

@@ -17,11 +17,11 @@
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class CharFieldType extends DbFieldType {
@Override

View File

@@ -16,12 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
public class ComputedFieldType extends DbFieldType {
@Override

View File

@@ -16,15 +16,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.sql.Date;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
public class DateFieldType extends DbFieldType {
@Override

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.lang.reflect.Field;
import java.util.List;
@@ -32,13 +32,13 @@ import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import tech.ailef.snapadmin.external.annotations.DisplayImage;
import tech.ailef.snapadmin.external.annotations.Filterable;
import tech.ailef.snapadmin.external.annotations.FilterableType;
import tech.ailef.snapadmin.external.annotations.ReadOnly;
import tech.ailef.snapadmin.external.dbmapping.DbFieldValue;
import tech.ailef.snapadmin.external.dbmapping.DbObject;
import tech.ailef.snapadmin.external.dbmapping.DbObjectSchema;
import space.mori.dalbodeule.snapadmin.external.annotations.DisplayImage;
import space.mori.dalbodeule.snapadmin.external.annotations.Filterable;
import space.mori.dalbodeule.snapadmin.external.annotations.FilterableType;
import space.mori.dalbodeule.snapadmin.external.annotations.ReadOnly;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbFieldValue;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObject;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObjectSchema;
/**
* Represent a field on the database, generated from an Entity class instance variable.
@@ -87,6 +87,8 @@ public class DbField {
* annotation has been applied.
*/
private String format;
private boolean disableEditField = false;
/**
* The schema this field belongs to
@@ -189,6 +191,14 @@ public class DbField {
public boolean isText() {
return type instanceof TextFieldType;
}
public boolean isDisableEditField() {
return disableEditField;
}
public void setDisableEditField(boolean managed) {
this.disableEditField = managed;
}
/**
* Returns the value to use in the "step" HTML attribute

View File

@@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -27,9 +27,9 @@ import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import tech.ailef.snapadmin.external.exceptions.UnsupportedFieldTypeException;
import tech.ailef.snapadmin.external.misc.Utils;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.exceptions.UnsupportedFieldTypeException;
import space.mori.dalbodeule.snapadmin.external.misc.Utils;
public abstract class DbFieldType {

View File

@@ -16,11 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class DoubleFieldType extends DbFieldType {
@Override

View File

@@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -25,8 +25,8 @@ import java.util.List;
import java.util.stream.Collectors;
import jakarta.persistence.EnumType;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
public class EnumFieldType extends DbFieldType {

View File

@@ -16,11 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class FloatFieldType extends DbFieldType {
@Override

View File

@@ -0,0 +1,139 @@
/*
* SnapAdmin - An automatically generated CRUD admin UI for Spring Boot apps
* Copyright (C) 2023 Ailef (http://ailef.tech)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import java.time.*;
import java.time.format.*;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
public class InstantFieldType extends DbFieldType {
// 다양한 날짜/시간 형식을 처리할 수 있는 포맷터들
private static final DateTimeFormatter[] FORMATTERS = {
DateTimeFormatter.ISO_INSTANT,
DateTimeFormatter.ISO_DATE_TIME,
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"),
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
};
@Override
public String getFragmentName() {
return "datetime";
}
@Override
public Object parseValue(Object value) {
if (value == null) return null;
// 이미 Instant 타입인 경우
if (value instanceof Instant) {
return value;
}
// LocalDateTime에서 Instant로 변환
if (value instanceof LocalDateTime) {
return ((LocalDateTime) value)
.atZone(ZoneId.systemDefault())
.toInstant();
}
// Date에서 Instant로 변환
if (value instanceof Date) {
return ((Date) value).toInstant();
}
// LocalDate에서 Instant로 변환
if (value instanceof LocalDate) {
return ((LocalDate) value)
.atStartOfDay(ZoneId.systemDefault())
.toInstant();
}
// 문자열 처리
String stringValue = value.toString();
if (stringValue.isBlank()) return null;
stringValue = stringValue.trim();
// 직접 Instant 파싱 시도
try {
return Instant.parse(stringValue);
} catch (DateTimeParseException e) {
// 실패, 다른 방법으로 시도
}
// 다른 날짜/시간 형식을 통해 변환 시도
for (DateTimeFormatter formatter : FORMATTERS) {
try {
// ISO_INSTANT의 경우 Instant.parse()와 동일하므로 스킵
if (formatter == DateTimeFormatter.ISO_INSTANT) {
continue;
}
// ISO_DATE_TIME 형식은 ZoneId가 필요
if (formatter == DateTimeFormatter.ISO_DATE_TIME) {
return ZonedDateTime.parse(stringValue, formatter).toInstant();
}
// Z로 끝나는 형식은 UTC 시간으로 파싱
if (stringValue.endsWith("Z")) {
return ZonedDateTime.parse(stringValue, formatter.withZone(ZoneOffset.UTC))
.toInstant();
}
// 기타 형식은 시스템 기본 시간대 사용
TemporalAccessor ta = formatter.parse(stringValue);
return LocalDateTime.from(ta)
.atZone(ZoneId.systemDefault())
.toInstant();
} catch (DateTimeParseException e) {
// 다음 형식 시도
continue;
}
}
// 밀리초 타임스탬프로 시도
try {
long timestamp = Long.parseLong(stringValue);
return Instant.ofEpochMilli(timestamp);
} catch (NumberFormatException e) {
// 숫자 파싱 실패, 무시
}
// 모든 파싱 시도 실패
return null;
}
@Override
public Class<?> getJavaClass() {
return Instant.class;
}
@Override
public List<CompareOperator> getCompareOperators() {
return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE);
}
}

View File

@@ -16,11 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class IntegerFieldType extends DbFieldType {
@Override

View File

@@ -16,12 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.time.LocalDate;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class LocalDateFieldType extends DbFieldType {
@Override

View File

@@ -0,0 +1,82 @@
/*
* SnapAdmin - An automatically generated CRUD admin UI for Spring Boot apps
* Copyright (C) 2023 Ailef (http://ailef.tech)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class LocalDateTimeFieldType extends DbFieldType {
private static final DateTimeFormatter[] FORMATTERS = {
DateTimeFormatter.ISO_LOCAL_DATE_TIME,
DateTimeFormatter.ISO_DATE_TIME,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"),
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"),
DateTimeFormatter.ofPattern("yyyy-MM-dd")
};
@Override
public String getFragmentName() {
return "datetime";
}
@Override
public Object parseValue(Object value) {
if (value == null || value.toString().isBlank()) return null;
// 이미 LocalDateTime 객체인 경우
if (value instanceof LocalDateTime) {
return value;
}
String stringValue = value.toString().trim();
// 여러 형식으로 파싱 시도
for (DateTimeFormatter formatter : FORMATTERS) {
try {
// 날짜만 있는 형식인 경우 시간을 00:00:00으로 설정
if (formatter.equals(DateTimeFormatter.ofPattern("yyyy-MM-dd"))) {
return LocalDate.parse(stringValue, formatter).atStartOfDay();
}
return LocalDateTime.parse(stringValue, formatter);
} catch (DateTimeParseException e) {
// 이 형식으로 파싱 실패, 다음 형식 시도
continue;
}
}
// 모든 형식 파싱 실패 시 예외 발생
throw new IllegalArgumentException("날짜/시간 형식을 파싱할 수 없습니다: " + stringValue);
}
@Override
public Class<?> getJavaClass() {
return LocalDateTime.class;
}
@Override
public List<CompareOperator> getCompareOperators() {
return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE);
}
}

View File

@@ -16,11 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class LongFieldType extends DbFieldType {
@Override

View File

@@ -16,13 +16,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import jakarta.persistence.ManyToMany;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
public class ManyToManyFieldType extends DbFieldType {
@Override

View File

@@ -0,0 +1,160 @@
/*
* SnapAdmin - An automatically generated CRUD admin UI for Spring Boot apps
* Copyright (C) 2023 Ailef (http://ailef.tech)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class OffsetDateTimeFieldType extends DbFieldType {
// 다양한 날짜/시간 형식을 처리할 수 있는 포맷터들
private static final DateTimeFormatter[] FORMATTERS = {
DateTimeFormatter.ISO_OFFSET_DATE_TIME,
DateTimeFormatter.ISO_ZONED_DATE_TIME,
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX"),
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssXXX")
};
@Override
public String getFragmentName() {
return "datetime";
}
@Override
public Object parseValue(Object value) {
if (value == null) return null;
// 이미 OffsetDateTime 타입인 경우
if (value instanceof OffsetDateTime) {
return value;
}
// ZonedDateTime에서 OffsetDateTime으로 변환
if (value instanceof ZonedDateTime) {
return ((ZonedDateTime) value).toOffsetDateTime();
}
// LocalDateTime에서 OffsetDateTime으로 변환 (시스템 기본 오프셋 사용)
if (value instanceof LocalDateTime) {
return ((LocalDateTime) value)
.atZone(ZoneId.systemDefault())
.toOffsetDateTime();
}
// Instant에서 OffsetDateTime으로 변환
if (value instanceof Instant) {
return ((Instant) value)
.atZone(ZoneId.systemDefault())
.toOffsetDateTime();
}
// LocalDate에서 OffsetDateTime으로 변환
if (value instanceof LocalDate) {
return ((LocalDate) value)
.atStartOfDay()
.atZone(ZoneId.systemDefault())
.toOffsetDateTime();
}
// 문자열 처리
String stringValue = value.toString();
if (stringValue.isBlank()) return null;
stringValue = stringValue.trim();
// 직접 OffsetDateTime 파싱 시도
try {
return OffsetDateTime.parse(stringValue);
} catch (DateTimeParseException e) {
// 실패, 다른 방법으로 시도
}
// 여러 가지 형식으로 파싱 시도
for (DateTimeFormatter formatter : FORMATTERS) {
try {
// ISO_OFFSET_DATE_TIME은 이미 위에서 시도했으므로 스킵
if (formatter == DateTimeFormatter.ISO_OFFSET_DATE_TIME) {
continue;
}
if (formatter == DateTimeFormatter.ISO_ZONED_DATE_TIME) {
return ZonedDateTime.parse(stringValue, formatter).toOffsetDateTime();
}
return OffsetDateTime.parse(stringValue, formatter);
} catch (DateTimeParseException e) {
// 다음 형식 시도
continue;
}
}
// ISO 날짜/시간 형식에 시스템 기본 오프셋 추가 시도
try {
LocalDateTime ldt = LocalDateTime.parse(stringValue);
return ldt.atZone(ZoneId.systemDefault()).toOffsetDateTime();
} catch (DateTimeParseException e) {
// 실패, 다음 방법 시도
}
// 날짜만 있는 경우 (UTC 자정으로 처리)
try {
LocalDate date = LocalDate.parse(stringValue);
return date.atStartOfDay().atZone(ZoneId.systemDefault()).toOffsetDateTime();
} catch (DateTimeParseException e) {
// 날짜 파싱 실패, 무시
}
// 밀리초 타임스탬프로 시도
try {
long timestamp = Long.parseLong(stringValue);
return Instant.ofEpochMilli(timestamp)
.atZone(ZoneId.systemDefault())
.toOffsetDateTime();
} catch (NumberFormatException e) {
// 숫자 파싱 실패, 무시
}
// Z로 끝나는 UTC 시간 문자열 처리 시도
if (stringValue.endsWith("Z")) {
try {
Instant instant = Instant.parse(stringValue);
return instant.atZone(ZoneId.systemDefault()).toOffsetDateTime();
} catch (DateTimeParseException e) {
// 실패, 무시
}
}
// 모든 파싱 시도 실패
return null;
}
@Override
public Class<?> getJavaClass() {
return OffsetDateTime.class;
}
@Override
public List<CompareOperator> getCompareOperators() {
return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE);
}
}

View File

@@ -16,13 +16,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import jakarta.persistence.OneToMany;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
public class OneToManyFieldType extends DbFieldType {
@Override

View File

@@ -16,13 +16,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import jakarta.persistence.OneToOne;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
public class OneToOneFieldType extends DbFieldType {
@Override

View File

@@ -16,11 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class ShortFieldType extends DbFieldType {
@Override

View File

@@ -16,11 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class StringFieldType extends DbFieldType {
@Override

View File

@@ -16,11 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class TextFieldType extends DbFieldType {
@Override

View File

@@ -16,11 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tech.ailef.snapadmin.external.dbmapping.fields;
package space.mori.dalbodeule.snapadmin.external.dbmapping.fields;
import java.util.List;
import tech.ailef.snapadmin.external.dto.CompareOperator;
import space.mori.dalbodeule.snapadmin.external.dto.CompareOperator;
public class UUIDFieldType extends DbFieldType {
@Override

View File

@@ -20,4 +20,4 @@
/**
* Representation of the user database and repository classes.
*/
package tech.ailef.snapadmin.external.dbmapping;
package space.mori.dalbodeule.snapadmin.external.dbmapping;

View File

@@ -18,17 +18,17 @@
*/
package tech.ailef.snapadmin.external.dbmapping.query;
package space.mori.dalbodeule.snapadmin.external.dbmapping.query;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
import tech.ailef.snapadmin.external.SnapAdmin;
import tech.ailef.snapadmin.external.dbmapping.DbObjectSchema;
import tech.ailef.snapadmin.external.dbmapping.fields.DbField;
import tech.ailef.snapadmin.external.dbmapping.fields.DbFieldType;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import tech.ailef.snapadmin.external.exceptions.UnsupportedFieldTypeException;
import space.mori.dalbodeule.snapadmin.external.SnapAdmin;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObjectSchema;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.DbField;
import space.mori.dalbodeule.snapadmin.external.dbmapping.fields.DbFieldType;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.exceptions.UnsupportedFieldTypeException;
/*
* A class that holds output fields from a user-provided SQL query

View File

@@ -18,7 +18,7 @@
*/
package tech.ailef.snapadmin.external.dbmapping.query;
package space.mori.dalbodeule.snapadmin.external.dbmapping.query;
import java.util.ArrayList;
import java.util.List;

View File

@@ -18,13 +18,13 @@
*/
package tech.ailef.snapadmin.external.dbmapping.query;
package space.mori.dalbodeule.snapadmin.external.dbmapping.query;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import tech.ailef.snapadmin.external.exceptions.SnapAdminException;
import space.mori.dalbodeule.snapadmin.external.exceptions.SnapAdminException;
/**
* A single row of results coming from a user-provided SQL query

View File

@@ -17,10 +17,10 @@
*/
package tech.ailef.snapadmin.external.dto;
package space.mori.dalbodeule.snapadmin.external.dto;
import tech.ailef.snapadmin.external.controller.rest.AutocompleteController;
import tech.ailef.snapadmin.external.dbmapping.DbObject;
import space.mori.dalbodeule.snapadmin.external.controller.rest.AutocompleteController;
import space.mori.dalbodeule.snapadmin.external.dbmapping.DbObject;
/**
* An object to hold autocomplete results returned from the {@linkplain AutocompleteController}.

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.dto;
package space.mori.dalbodeule.snapadmin.external.dto;
/**
* A list of operators that are used in faceted search.

View File

@@ -18,7 +18,7 @@
*/
package tech.ailef.snapadmin.external.dto;
package space.mori.dalbodeule.snapadmin.external.dto;
public enum DataExportFormat {
CSV,

View File

@@ -17,7 +17,7 @@
*/
package tech.ailef.snapadmin.external.dto;
package space.mori.dalbodeule.snapadmin.external.dto;
import java.util.ArrayList;
import java.util.Set;

Some files were not shown because too many files have changed in this diff Show More