Skip to content

Commit

Permalink
#2270 added initDB script
Browse files Browse the repository at this point in the history
  • Loading branch information
DarioGii committed Dec 14, 2024
1 parent 12ac34d commit 564c11a
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 86 deletions.
28 changes: 26 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,11 @@ dependencies {
implementation "org.springframework.session:spring-session-core:$springBootVersion"
implementation "org.springframework:spring-jdbc"

implementation "com.unboundid.product.scim2:scim2-sdk-client:2.3.5"
// Don't upgrade h2database
runtimeOnly "org.postgresql:postgresql:42.7.4"
// runtimeOnly 'com.mysql:mysql-connector-j:9.1.0'
// runtimeOnly 'com.oracle.database.jdbc:ojdbc11:23.6.0.24.10'

implementation "com.unboundid.product.scim2:scim2-sdk-client:2.3.5"
constraints {
implementation "org.opensaml:opensaml-core:$openSamlVersion"
implementation "org.opensaml:opensaml-saml-api:$openSamlVersion"
Expand Down Expand Up @@ -392,11 +394,33 @@ dependencies {
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
dependsOn "spotlessApply"
dependsOn "initDB"
}

compileJava {
options.compilerArgs << "-parameters"
}

bootRun {
if (project.hasProperty("args")) {
args = project.args.split(" ")
}
}


tasks.register("initDB", Exec) {
description = "Creates a database of the specified type (postgresql, mysql, oracle)."
def scriptPath = "$projectDir/scripts/init_db.sh"
// Set the database type argument
def dbType = project.hasProperty('dbType') ? project.property('dbType') : "postgresql"

if (!["postgresql", "mysql", "oracle"].contains(dbType)) {
throw new GradleException("Invalid database type: $dbType. Valid types are: postgresql, mysql, oracle.")
} else {
commandLine "bash", scriptPath, dbType
}
}

task writeVersion {
def propsFile = file("src/main/resources/version.properties")
def props = new Properties()
Expand Down
101 changes: 101 additions & 0 deletions scripts/init_db.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/bin/bash

# Enable robust error handling
set -o errexit
set -o nounset
set -o pipefail

# Variables
DB_NAME="stirling_pdf"
DB_USER="admin"
DB_PASSWORD="stirling"
DB_TYPE=${1:-"postgresql"} # Default to PostgreSQL if not provided
DB_HOST="localhost"
DB_PORT=""

# Check database type and set defaults
case "$DB_TYPE" in
postgresql)
DB_PORT="5432"
;;
mysql)
DB_PORT="3306"
;;
oracle)
DB_PORT="1521"
;;
*)
echo "Unsupported database type: $DB_TYPE"
exit 1
;;
esac

# Function to create PostgreSQL database and user
create_postgres() {
echo "Creating PostgreSQL database '$DB_NAME'..."

# Check if the database exists
if psql -h "$DB_HOST" -p "$DB_PORT" -U postgres -lqt | cut -d \| -f 1 | grep -qw "$DB_NAME"; then
echo "Database '$DB_NAME' already exists."
else
# Create user and database
psql -h "$DB_HOST" -p "$DB_PORT" -U postgres -c "DO \$$ BEGIN IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '$DB_USER') THEN CREATE USER $DB_USER WITH ENCRYPTED PASSWORD '$DB_PASSWORD'; END IF; END \$$;"
createdb -h "$DB_HOST" -p "$DB_PORT" -U postgres --owner="$DB_USER" "$DB_NAME"
echo "Database '$DB_NAME' created successfully with owner '$DB_USER'."
fi
}

# Function to create MySQL database and user
create_mysql() {
echo "Creating MySQL database '$DB_NAME'..."

# Check if the database exists
if mysql -h "$DB_HOST" -P "$DB_PORT" -u root -e "SHOW DATABASES LIKE '$DB_NAME';" | grep -qw "$DB_NAME"; then
echo "Database '$DB_NAME' already exists."
else
# Create user and database
mysql -h "$DB_HOST" -P "$DB_PORT" -u root -e "CREATE DATABASE IF NOT EXISTS $DB_NAME;"
mysql -h "$DB_HOST" -P "$DB_PORT" -u root -e "CREATE USER IF NOT EXISTS '$DB_USER'@'%' IDENTIFIED BY '$DB_PASSWORD';"
mysql -h "$DB_HOST" -P "$DB_PORT" -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'%';"
echo "Database '$DB_NAME' created successfully with owner '$DB_USER'."
fi
}

# Function to create Oracle database and user
create_oracle() {
echo "Creating Oracle database '$DB_NAME'..."
# Check if the user exists
EXISTS=$(sqlplus -s sys/oracle@//"$DB_HOST":"$DB_PORT"/orcl as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT COUNT(*) FROM dba_users WHERE username = UPPER('$DB_USER');
EXIT;
EOF
)
if [ "$EXISTS" -gt 0 ]; then
echo "User '$DB_USER' already exists."
else
# Create user and schema
sqlplus -s sys/oracle@//"$DB_HOST":"$DB_PORT"/orcl as sysdba <<EOF
CREATE USER $DB_USER IDENTIFIED BY $DB_PASSWORD;
GRANT CONNECT, RESOURCE TO $DB_USER;
GRANT CREATE SESSION, CREATE TABLE TO $DB_USER;
CREATE TABLESPACE $DB_NAME DATAFILE '$DB_NAME.dbf' SIZE 10M AUTOEXTEND ON NEXT 10M MAXSIZE 100M;
ALTER USER $DB_USER DEFAULT TABLESPACE $DB_NAME;
EXIT;
EOF
echo "User '$DB_USER' and tablespace '$DB_NAME' created successfully."
fi
}

# Execute the appropriate function based on the database type
case "$DB_TYPE" in
postgresql)
create_postgres
;;
mysql)
create_mysql
;;
oracle)
create_oracle
;;
esac
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
import stirling.software.SPDF.utils.FileInfo;

public interface DatabaseBackupInterface {
void initDatabase();

void exportDatabase() throws IOException;

void importDatabase();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ public class InitialSecuritySetup {

@PostConstruct
public void init() throws IllegalArgumentException, IOException {
databaseBackupHelper.initDatabase();

if (databaseBackupHelper.hasBackup() && !userService.hasUsers()) {
if (databaseBackupHelper.hasBackup() && userService.hasUsers()) {
databaseBackupHelper.importDatabase();
} else if (!userService.hasUsers()) {
initializeAdminUser();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.nio.file.attribute.BasicFileAttributes;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
Expand Down Expand Up @@ -40,75 +39,25 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
public static final String BACKUP_PREFIX = "backup_";
public static final String SQL_SUFFIX = ".sql";

@Value("${dbType:postgresql}")
private String dbType;

@Value("${spring.datasource.url}")
private String url;

@Value("${spring.datasource.username}")
private String databaseUsername;
private String username;

@Value("${spring.datasource.password}")
private String databasePassword;

@Value("${spring.datasource.stirling.url}")
private String stirlingUrl;

@Value("${spring.datasource.stirling.username}")
private String stirlingDatabaseUsername;

@Value("${spring.datasource.stirling.password}")
private String stirlingDatabasePassword;
private String password;

private final Path BACKUP_PATH = Paths.get("configs/db/backup/");

// fixMe: should check if backups exist without returning the whole list
@Override
public void initDatabase() {
log.info("Creating database stirling-pdf-DB");

String initDBAndRoleScript =
"""
CREATE DATABASE "stirling-pdf-DB";
CREATE USER %s WITH ENCRYPTED PASSWORD '%s';
ALTER DATABASE "stirling-pdf-DB" OWNER TO %s;
GRANT ALL PRIVILEGES ON DATABASE "stirling-pdf-DB" TO %s;
"""
.formatted(
stirlingDatabaseUsername,
stirlingDatabasePassword,
stirlingDatabaseUsername,
stirlingDatabaseUsername);
try (Connection conn =
DriverManager.getConnection(url, databaseUsername, databasePassword);
PreparedStatement initStmt = conn.prepareStatement(initDBAndRoleScript)) {
initStmt.execute();

String setRoleScript = "SET ROLE " + stirlingDatabaseUsername + ";";

try (Connection stirlingDBConn =
DriverManager.getConnection(
stirlingUrl,
stirlingDatabaseUsername,
stirlingDatabasePassword);
PreparedStatement stmt = conn.prepareStatement(setRoleScript)) {
stmt.execute();

log.info("Database stirling-pdf-DB created");
log.info("User admin created");

ensureBackupDirectoryExists();
} catch (SQLException e) {
log.error("Failed to set admin to stirling-pdf-DB: {}", e.getMessage(), e);
}
} catch (SQLException e) {
log.error("Failed to create stirling-pdf-DB: {}", e.getMessage(), e);
}
}

@Override
public boolean hasBackup() {
// Check if there is at least one backup
try (Stream<Path> entries = Files.list(BACKUP_PATH)) {
return entries.findFirst().isEmpty();
return entries.findFirst().isPresent();
} catch (IOException e) {
log.error("Error reading backup directory: {}", e.getMessage(), e);
throw new RuntimeException(e);
Expand Down Expand Up @@ -147,6 +96,7 @@ public List<FileInfo> getBackupList() {
} catch (IOException e) {
log.error("Error reading backup directory: {}", e.getMessage(), e);
}

return backupFiles;
}

Expand All @@ -156,7 +106,6 @@ public boolean importDatabaseFromUI(String fileName) throws IOException {
importDatabaseFromUI(getBackupFilePath(fileName));
return true;
} catch (IOException e) {
// fixme: do we want to show the filename here?
log.error(
"Error importing database from file: {}, message: {}",
fileName,
Expand Down Expand Up @@ -205,9 +154,7 @@ public void exportDatabase() {
Path insertOutputFilePath =
this.getBackupFilePath(BACKUP_PREFIX + dateNow.format(myFormatObj) + SQL_SUFFIX);

try (Connection conn =
DriverManager.getConnection(
stirlingUrl, stirlingDatabaseUsername, stirlingDatabasePassword)) {
try (Connection conn = DriverManager.getConnection(url, username, password)) {
ScriptUtils.executeSqlScript(
conn, new EncodedResource(new PathResource(insertOutputFilePath)));

Expand Down Expand Up @@ -236,8 +183,7 @@ private static void deleteOldestBackup(List<FileInfo> filteredBackupList) {
// Retrieves the H2 database version.
public String getH2Version() {
String version = "Unknown";
try (Connection conn =
DriverManager.getConnection(stirlingUrl, stirlingDatabaseUsername, stirlingDatabasePassword)) {
try (Connection conn = DriverManager.getConnection(url, username, password)) {
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) {
if (rs.next()) {
Expand Down Expand Up @@ -277,8 +223,7 @@ public Path getBackupFilePath(String fileName) {
}

private void executeDatabaseScript(Path scriptPath) {
try (Connection conn =
DriverManager.getConnection(stirlingUrl, stirlingDatabaseUsername, stirlingDatabasePassword)) {
try (Connection conn = DriverManager.getConnection(url, username, password)) {
ScriptUtils.executeSqlScript(conn, new EncodedResource(new PathResource(scriptPath)));

log.info("Database import completed: {}", scriptPath);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/stirling/software/SPDF/model/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class User implements Serializable {
@ElementCollection
@MapKeyColumn(name = "setting_key")
@Lob
@Column(name = "setting_value", columnDefinition = "CLOB")
@Column(name = "setting_value", columnDefinition = "text")
@CollectionTable(name = "user_settings", joinColumns = @JoinColumn(name = "user_id"))
private Map<String, String> settings = new HashMap<>(); // Key-value pairs of settings.

Expand Down
17 changes: 7 additions & 10 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ logging.level.org.eclipse.jetty=WARN
#logging.level.stirling.software.SPDF.config.security: DEBUG
logging.level.com.zaxxer.hikari=WARN

spring.jpa.open-in-view=false

server.forward-headers-strategy=NATIVE

server.error.path=/error
Expand Down Expand Up @@ -41,17 +39,16 @@ spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:1200000}
#spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/
#spring.thymeleaf.cache=false

spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.platform=postgres
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.datasource.stirling.url=jdbc:postgresql://localhost:5432/stirling-pdf-DB
spring.datasource.stirling.username=admin
spring.datasource.stirling.password=stirling
spring.datasource.url=jdbc:postgresql://localhost:5432/stirling_pdf
# postgresql | oracle | mysql
spring.datasource.driver=postgresql
spring.datasource.username=admin
spring.datasource.password=stirling
spring.jpa.open-in-view=false
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.flyway.baselineOneMigrate=true
server.servlet.session.timeout=30m
# Change the default URL path for OpenAPI JSON
springdoc.api-docs.path=/v1/api-docs
Expand Down
6 changes: 3 additions & 3 deletions src/main/resources/settings.yml.template
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ system:
tessdataDir: /usr/share/tessdata # path to the directory containing the Tessdata files. This setting is relevant for Windows systems. For Windows users, this path should be adjusted to point to the appropriate directory where the Tessdata files are stored.
enableAnalytics: undefined # set to 'true' to enable analytics, set to 'false' to disable analytics; for enterprise users, this is set to true
datasource:
url: jdbc:postgresql://localhost:5432/postgres
driver: postgresql
username: postgres
password: postgres
url: jdbc:postgresql://localhost:5432/stirling_pdf
username: admin
password: stirling

ui:
appName: '' # application's visible name
Expand Down

0 comments on commit 564c11a

Please sign in to comment.