Skip to content

Commit

Permalink
Merge branch 'master' into feature/issue-98
Browse files Browse the repository at this point in the history
  • Loading branch information
The4thLaw committed Mar 1, 2024
2 parents 16b3f1c + 9bb5062 commit 0ab4ed5
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![Build Status](https://github.com/The4thLaw/demyo/workflows/Java%20build%20(for%20branches)/badge.svg)](https://github.com/The4thLaw/demyo/actions) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=The4thLaw_demyo&metric=alert_status)](https://sonarcloud.io/dashboard?id=The4thLaw_demyo) [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=The4thLaw_demyo&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=The4thLaw_demyo) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=The4thLaw_demyo&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=The4thLaw_demyo) [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=The4thLaw_demyo&metric=security_rating)](https://sonarcloud.io/dashboard?id=The4thLaw_demyo)

## Description
Demyo is a Comic Manager intented for local usage trough a Web interface.
Demyo is a Comic Manager intended for local usage trough a Web interface.

Check the features and screenshots, and download the releases on the official website at https://www.demyo.org/ .

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ private static class SingletonHolder {
private final int httpPort;
/** The directory to store user data. */
private final Path userDirectory;
/** The file to store the database. */
/** The path/URL for the database. Similar to the databaseFile but without file extensions. Feed this to H2. */
private final Path databaseUrlPath;
/** The file where the database is stored. */
private final Path databaseFile;
/** The directory to store user images. */
private final Path imagesDirectory;
Expand Down Expand Up @@ -141,7 +143,17 @@ private SystemConfiguration() {
userPluginDirectory = userDirectory.resolve(PLUGIN_DIR_NAME);
imagesDirectory = userDirectory.resolve("images");
thumbnailDirectory = userDirectory.resolve("thumbnails");
databaseFile = userDirectory.resolve("demyo.mv.db");
databaseUrlPath = userDirectory.resolve("demyo");
Path mainDatabaseFile = userDirectory.resolve("demyo.mv.db");
// Old versions of H2 had a different naming convention, try it as well in case we need to migrate
Path legacyDatabaseFile = userDirectory.resolve("demyo.h2.db");

if (!Files.exists(mainDatabaseFile) && Files.exists(legacyDatabaseFile)) {
databaseFile = legacyDatabaseFile;
} else {
databaseFile = mainDatabaseFile;
}

createDirectoryIfNeeded(userDirectory);
createDirectoryIfNeeded(imagesDirectory);
createDirectoryIfNeeded(tempDirectory);
Expand Down Expand Up @@ -364,6 +376,16 @@ public Path getUserDirectory() {
return userDirectory;
}

/**
* Gets the path/URL for the database.
* Similar to the databaseFile but without file extensions. Feed this to H2.
*
* @return the path
*/
public Path getDatabaseUrlPath() {
return databaseUrlPath;
}

/**
* Gets the file to store the database.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.demyo.dao;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -42,8 +41,9 @@ public List<Tag> findAllWithUsageCounts() {
Map<Long, Integer> occurrences = new HashMap<>();
for (Object result : results) {
Object[] row = (Object[]) result;
occurrences.put(Long.valueOf((int) row[0]), ((BigInteger) row[1]).intValue()); // Doubt we'll have > 2^32
// albums
long id = ((Number) row[0]).longValue();
int count = ((Number) row[1]).intValue();
occurrences.put(id, count);
}

// Set all counts one by one
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.regex.Pattern;

import javax.sql.DataSource;

import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.configuration.ClassicConfiguration;
import org.h2.engine.Constants;
import org.h2.jdbcx.JdbcDataSource;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
Expand Down Expand Up @@ -56,7 +54,6 @@ public class DaoConfig {

private static final String DB_USER = "demyo";
private static final String DB_PASSWORD = "demyo";
private static final String DB_FILE_SUFFIX = Pattern.quote(Constants.SUFFIX_MV_FILE) + "$";
/** The version of H2 used before we started tracking the version numbers. */
private static final int DEMYO_3_0_H2_VERSION = 196;

Expand All @@ -69,12 +66,13 @@ public DaoConfig() {

@Bean(name = DS_BEAN_NAME)
public DataSource dataSource() throws IOException, SQLException {
// To debug, use java -cp h2-*.jar org.h2.tools.Console

SystemConfiguration sysConfig = SystemConfiguration.getInstance();
Path databaseFile = sysConfig.getDatabaseFile();
boolean isNewDatabase = !Files.exists(databaseFile);
// To debug, use java -cp h2-*.jar org.h2.tools.Console
String databaseFilePath = databaseFile.toAbsolutePath().toString().replaceAll(DB_FILE_SUFFIX, "");

String databaseFilePath = sysConfig.getDatabaseUrlPath().toString();
String url = "jdbc:h2:" + databaseFilePath + ";DB_CLOSE_DELAY=120;IGNORECASE=TRUE";
LOGGER.debug("Database URL is {}", url);

Expand All @@ -96,6 +94,7 @@ public DataSource dataSource() throws IOException, SQLException {
}
return ds;
}

private static void migrateH2IfNeeded(boolean isNewDatabase, Path databaseFilePath, String url) throws IOException {
Path h2CacheDirectory;
String h2CacheProperty = System.getProperty("demyo.h2.cacheDirectoryName");
Expand All @@ -107,17 +106,18 @@ private static void migrateH2IfNeeded(boolean isNewDatabase, Path databaseFilePa
}
H2LocalUpgrader upgrader = new H2LocalUpgrader(h2CacheDirectory);
H2VersionManager vm = new H2VersionManager(DEMYO_3_0_H2_VERSION, databaseFilePath, upgrader);
// Get the version before the upgrade
int oldVersion = vm.getCurrentVersion();
vm.migrateH2IfNeeded(isNewDatabase, url, DB_USER, DB_PASSWORD);

int version = vm.getCurrentVersion();
if (version == DEMYO_3_0_H2_VERSION) {
if (!isNewDatabase && oldVersion == DEMYO_3_0_H2_VERSION) {
// H2 at the version of Demyo 3.0 supported stuff that it shouldn't have and on which migrations
// relied:
// - UNSIGNED INT as a datatype
// - Dangling commas at the end of a list of columns in a create statement
// - MODIFY COLUMN could be used rather than ALTER COLUMN
// So we need to repair because the SQL files were changes accordingly and their hashes have changed
LOGGER.info("Migrating from H2 {} requires a Flyway repair", version);
LOGGER.info("Migrating from H2 {} requires a Flyway repair", oldVersion);
SystemConfiguration.getInstance().setFlywayRepairRequired(true);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
CREATE TABLE images (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
url VARCHAR(255) NOT NULL,
description VARCHAR(255) NULL
);
CREATE INDEX ON images(description);

CREATE TABLE publishers (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(255) NOT NULL,
website VARCHAR(255) NULL,
feed VARCHAR(255) NULL,
Expand All @@ -17,7 +17,7 @@ CREATE TABLE publishers (
CREATE INDEX ON publishers(name);

CREATE TABLE collections (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(255) NOT NULL,
website VARCHAR(255) NULL,
feed VARCHAR(255) NULL,
Expand All @@ -30,7 +30,7 @@ CREATE TABLE collections (
CREATE INDEX ON collections(name);

CREATE TABLE authors (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(127) NOT NULL,
fname VARCHAR(127) NULL,
nickname VARCHAR(127) NULL,
Expand All @@ -42,7 +42,7 @@ CREATE TABLE authors (
CREATE INDEX ON authors(name);

CREATE TABLE series (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(255) NOT NULL,
summary CLOB NULL,
completed BOOLEAN DEFAULT 'false',
Expand All @@ -61,12 +61,12 @@ CREATE TABLE series_relations (
CREATE INDEX ON series_relations(main);

CREATE TABLE bindings (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(255) NOT NULL
);

CREATE TABLE albums (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
series_id INT NULL, /* One shots have no series */
cycle SMALLINT NULL,
number FLOAT NULL,
Expand Down Expand Up @@ -148,7 +148,7 @@ CREATE TABLE albums_translators (
);

CREATE TABLE tags (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(127) NOT NULL UNIQUE,
fgcolour CHAR(7) DEFAULT NULL,
bgcolour CHAR(7) DEFAULT NULL
Expand All @@ -164,7 +164,7 @@ CREATE TABLE albums_tags (
);

CREATE TABLE sources (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(127) NOT NULL,
owner VARCHAR(127) NULL,
email VARCHAR(255) NULL,
Expand All @@ -175,12 +175,12 @@ CREATE TABLE sources (
);

CREATE TABLE derivative_types (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(127) NOT NULL
);

CREATE TABLE derivatives (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
series_id INT NULL, /* Since Albums may not have a Series, Derivatives could as well */
album_id INT NULL,
artist_id INT NULL,
Expand Down Expand Up @@ -223,7 +223,7 @@ CREATE TABLE derivatives_images (
);

CREATE TABLE borrowers (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(127) NOT NULL,
fname VARCHAR(127) NULL,
email VARCHAR(255) NULL,
Expand All @@ -241,7 +241,7 @@ CREATE TABLE albums_borrowers (
);

CREATE TABLE searches (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
model VARCHAR(255) NOT NULL, /* The kind of item being searched. */
status VARCHAR(63) NOT NULL, /* The status. Either temporary or saved. */
name VARCHAR(255) NULL, /* User-specified name */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
CREATE TABLE configuration (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
config_key VARCHAR(255) NOT NULL,
config_value VARCHAR(2048) NULL
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ ALTER TABLE derivatives
-- Create the table

CREATE TABLE readers (
id INT AUTO_INCREMENT PRIMARY KEY,
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(255) NOT NULL,
colour CHAR(7) DEFAULT NULL
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -73,6 +74,16 @@ public Reader getByIdForView(long id) {
return entity;
}

private Reader createDefaultReader() {
Reader defaultReader = new Reader();
defaultReader.setName(translationService.translate("field.Reader.name.default"));
save(defaultReader); // Will create a default configuration

// Return the created reader rather than reloading it from the database: since the transaction is not
// yet committed, the configuration entries wouldn't be available
return defaultReader;
}

@Transactional(readOnly = true)
@Override
public Reader getUniqueReader() {
Expand All @@ -83,20 +94,27 @@ public Reader getUniqueReader() {
// - It acts as a failsafe if the Reader somehow got missing
// - It deals with imports of Demyo 1.x and 2.0, which didn't have this data
// - It allows creating a default configuration which can evolve over time
Reader defaultReader = new Reader();
defaultReader.setName(translationService.translate("field.Reader.name.default"));
save(defaultReader); // Will create a default configuration

// Return the created reader rather than reloading it from the database: since the transaction is not
// yet committed, the configuration entries wouldn't be available
return defaultReader;
return createDefaultReader();
} else if (count != 1) {
return null;
}
long uniqueId = repo.findFirstByOrderById().getId();
return getByIdForView(uniqueId);
}

@Transactional(readOnly = false)
@Cacheable(cacheNames = "ModelLists", key = "#root.targetClass.simpleName.replaceAll('Service$', '')")
@Override
public List<Reader> findAll() {
var readers = super.findAll();
if (!readers.isEmpty()) {
return readers;
}
// Never allow an empty list of readers, it can for example lead to users not being able to select a reader if
// theirs was deleted.
return List.of(createDefaultReader());
}

@Transactional
@Override
public void addFavouriteSeries(long readerId, long seriesId) {
Expand Down

0 comments on commit 0ab4ed5

Please sign in to comment.