first implementation of cal.db, that
- successfully connects to db - updated db sheme - succeeds in listing appointments Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -2,6 +2,10 @@ description = "OpenCloudCal : Application"
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":de.srsoftware.cal.api"))
|
implementation(project(":de.srsoftware.cal.api"))
|
||||||
|
implementation(project(":de.srsoftware.cal.db"))
|
||||||
implementation(project(":de.srsoftware.cal.importer"))
|
implementation(project(":de.srsoftware.cal.importer"))
|
||||||
|
|
||||||
|
implementation("de.srsoftware:configuration.api:1.0.0")
|
||||||
|
implementation("de.srsoftware:configuration.json:1.0.0")
|
||||||
implementation("de.srsoftware:tools.util:1.1.1")
|
implementation("de.srsoftware:tools.util:1.1.1")
|
||||||
}
|
implementation("com.mysql:mysql-connector-j:9.1.0")}
|
||||||
|
|||||||
@@ -1,38 +1,47 @@
|
|||||||
/* © SRSoftware 2024 */
|
/* © SRSoftware 2024 */
|
||||||
package de.srsoftware.cal.app;
|
package de.srsoftware.cal.app;
|
||||||
|
|
||||||
import de.srsoftware.cal.importer.jena.Kassablanca;
|
import de.srsoftware.cal.db.Database;
|
||||||
|
import de.srsoftware.cal.db.MariaDB;
|
||||||
|
import de.srsoftware.configuration.Configuration;
|
||||||
|
import de.srsoftware.configuration.JsonConfig;
|
||||||
|
import java.io.IOException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test application
|
* Test application
|
||||||
*/
|
*/
|
||||||
public class Application {
|
public class Application {
|
||||||
|
private static final String JDBC = "opencloudcal.db.jdbc";
|
||||||
|
private static final String USER = "opencloudcal.db.user";
|
||||||
|
private static final String PASS = "opencloudcal.db.pass";
|
||||||
|
private static final String MISSING = "missing required configuration property \"%s\"";
|
||||||
|
|
||||||
private Application() {
|
private Application() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Database connect(Configuration config) throws SQLException {
|
||||||
|
Optional<String> jdbc = config.get(JDBC);
|
||||||
|
if (jdbc.isEmpty()) throw new RuntimeException(MISSING.formatted(JDBC));
|
||||||
|
|
||||||
|
String user = config.get(USER, "opencloudcal");
|
||||||
|
|
||||||
|
Optional<String> pass = config.get(PASS);
|
||||||
|
if (pass.isEmpty()) throw new RuntimeException(MISSING.formatted(PASS));
|
||||||
|
|
||||||
|
return MariaDB.connect(jdbc.get(), user, pass.get());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sandbox
|
* sandbox
|
||||||
* @param args default
|
* @param args default
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) throws NoSuchAlgorithmException {
|
public static void main(String[] args) throws NoSuchAlgorithmException, IOException, SQLException {
|
||||||
|
JsonConfig jsonConfig = new JsonConfig("OpenCloudCal");
|
||||||
String host = null;
|
var db = connect(jsonConfig);
|
||||||
String database = null;
|
var appointments = db.list(null, null);
|
||||||
String user = null;
|
for (var event : appointments) System.out.println(event);
|
||||||
String pass = null;
|
|
||||||
int port = 3306;
|
|
||||||
|
|
||||||
// TODO: we need configuration here!
|
|
||||||
|
|
||||||
try (Connection con = DriverManager
|
|
||||||
.getConnection("jdbc:mysql://%s:%s/%s".formatted(host,port,database), user, pass)) {
|
|
||||||
// use con here
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
de.srsoftware.cal.base/build.gradle.kts
Normal file
9
de.srsoftware.cal.base/build.gradle.kts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
description = "OpenCloudCal : Base"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":de.srsoftware.cal.api"))
|
||||||
|
|
||||||
|
implementation("de.srsoftware:tools.optionals:1.0.0")
|
||||||
|
implementation("de.srsoftware:tools.util:1.2.0")
|
||||||
|
implementation("de.srsoftware:tools.web:1.3.3")
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/* © SRSoftware 2024 */
|
/* © SRSoftware 2024 */
|
||||||
package de.srsoftware.cal.importer;
|
package de.srsoftware.cal;
|
||||||
|
|
||||||
import static de.srsoftware.tools.Optionals.nullable;
|
import static de.srsoftware.tools.Optionals.nullable;
|
||||||
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
/* © SRSoftware 2024 */
|
/* © SRSoftware 2024 */
|
||||||
package de.srsoftware.cal.importer;
|
package de.srsoftware.cal;
|
||||||
|
|
||||||
import static de.srsoftware.tools.Strings.hex;
|
|
||||||
import static de.srsoftware.tools.TagFilter.ofType;
|
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
import de.srsoftware.cal.api.*;
|
import de.srsoftware.cal.api.*;
|
||||||
@@ -42,7 +40,7 @@ public abstract class BaseImporter implements Importer {
|
|||||||
return extractAttachmentsTag(eventTag) //
|
return extractAttachmentsTag(eventTag) //
|
||||||
.optional()
|
.optional()
|
||||||
.stream()
|
.stream()
|
||||||
.flatMap(tag -> tag.find(ofType("img")).stream())
|
.flatMap(tag -> tag.find(TagFilter.ofType("img")).stream())
|
||||||
.map(tag -> tag.get("src"))
|
.map(tag -> tag.get("src"))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.map(Payload::of)
|
.map(Payload::of)
|
||||||
@@ -211,7 +209,7 @@ public abstract class BaseImporter implements Importer {
|
|||||||
* @return the hash of the plain text
|
* @return the hash of the plain text
|
||||||
*/
|
*/
|
||||||
protected String hash(String plain){
|
protected String hash(String plain){
|
||||||
return hex(digest.digest(plain.getBytes(UTF_8)));
|
return Strings.hex(digest.digest(plain.getBytes(UTF_8)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static <T> Result<T> invalidParameter(Result<?> result) {
|
protected static <T> Result<T> invalidParameter(Result<?> result) {
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
description = "OpenCloudCal : Database"
|
description = "OpenCloudCal : Database"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":de.srsoftware.cal.api"))
|
||||||
|
implementation(project(":de.srsoftware.cal.base"))
|
||||||
|
|
||||||
|
implementation("de.srsoftware:tools.jdbc:1.0.0")
|
||||||
|
implementation("de.srsoftware:tools.optionals:1.0.0")
|
||||||
|
implementation("de.srsoftware:tools.util:1.2.0")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/* © SRSoftware 2024 */
|
||||||
|
package de.srsoftware.cal.db;
|
||||||
|
|
||||||
|
import de.srsoftware.cal.api.Appointment;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for calendar database
|
||||||
|
*/
|
||||||
|
public interface Database {
|
||||||
|
/**
|
||||||
|
* add an appointment to the database
|
||||||
|
* @param appointment the appointment to store
|
||||||
|
* @return the Database object
|
||||||
|
*/
|
||||||
|
public Database add(Appointment appointment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list appointments unfiltered
|
||||||
|
* @param count the maximum number of appointments to return
|
||||||
|
* @param offset the number of appointments to skip
|
||||||
|
* @return the list of appointments fetched from the db
|
||||||
|
*/
|
||||||
|
public List<Appointment> list(Integer count, Integer offset) throws SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list appointments
|
||||||
|
* @param tags only list appointments which have matching tags
|
||||||
|
* @param count the maximum number of appointments to return
|
||||||
|
* @param offset the number of appointments to skip
|
||||||
|
* @return the list of appointments fetched from the db
|
||||||
|
*/
|
||||||
|
public List<Appointment> listByTags(Set<String> tags, Integer count, Integer offset);
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/* © SRSoftware 2024 */
|
||||||
|
package de.srsoftware.cal.db;
|
||||||
|
|
||||||
|
import static de.srsoftware.tools.Optionals.allEmpty;
|
||||||
|
import static de.srsoftware.tools.Optionals.nullable;
|
||||||
|
|
||||||
|
import de.srsoftware.cal.BaseAppointment;
|
||||||
|
import de.srsoftware.cal.api.Appointment;
|
||||||
|
import de.srsoftware.tools.Calc;
|
||||||
|
import de.srsoftware.tools.jdbc.Query;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class MariaDB implements Database {
|
||||||
|
private static final String SELECT_APPOINTMENTS = "SELECT * FROM appointments";
|
||||||
|
private static final String SELECT_APPOINTMENTS_WITH_HASHES = SELECT_APPOINTMENTS + " a LEFT JOIN appointment_hashes h ON a.aid = h.aid";
|
||||||
|
private static final String SELECT_VERSION = "SELECT value FROM config WHERE keyname = 'dbversion'";
|
||||||
|
private static final String CREATE_HASHES = "CREATE TABLE appointment_hashes (aid INT NOT NULL, hash VARCHAR(255) NOT NULL, UNIQUE(aid), UNIQUE(hash))";
|
||||||
|
private static final String INSERT_HASH = "INSERT INTO appointment_hashes (aid, hash) values (?, ?) ON DUPLICATE KEY UPDATE hash=hash;";
|
||||||
|
private static final String UPDATE_DB_VERSION = "UPDATE config SET value = ? WHERE keyname = 'dbversion'";
|
||||||
|
private static Connection connection;
|
||||||
|
|
||||||
|
private MariaDB(Connection conn) throws SQLException {
|
||||||
|
connection = conn;
|
||||||
|
applyUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyUpdates() throws SQLException {
|
||||||
|
var rs = Query.of(SELECT_VERSION).execute(connection);
|
||||||
|
var version = 0;
|
||||||
|
if (rs.next()) {
|
||||||
|
version = rs.getInt("value");
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
switch (version) {
|
||||||
|
case 0:
|
||||||
|
createTables();
|
||||||
|
case 1:
|
||||||
|
update1();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update1() throws SQLException {
|
||||||
|
var list = new ArrayList<Appointment>();
|
||||||
|
var results = Query.of(SELECT_APPOINTMENTS).execute(connection);
|
||||||
|
while (results.next()) {
|
||||||
|
var id = results.getInt("aid");
|
||||||
|
var title = results.getString("title");
|
||||||
|
var description = results.getString("description");
|
||||||
|
if (allEmpty(title, description)) continue;
|
||||||
|
var stamp = results.getTimestamp("start");
|
||||||
|
var start = nullable(stamp).map(Timestamp::toLocalDateTime).orElse(null);
|
||||||
|
var end = nullable(results.getTimestamp("end")).map(Timestamp::toLocalDateTime).orElse(null);
|
||||||
|
var location = results.getString("location");
|
||||||
|
Calc //
|
||||||
|
.hash(start + "@" + location)
|
||||||
|
.map(hash -> new BaseAppointment(id, title, description, start, end, location, hash))
|
||||||
|
.ifPresent(list::add);
|
||||||
|
}
|
||||||
|
results.close();
|
||||||
|
connection.setAutoCommit(false);
|
||||||
|
|
||||||
|
Query.of(CREATE_HASHES).statement(connection).execute();
|
||||||
|
for (var appointment : list) {
|
||||||
|
var stmt = Query.of(INSERT_HASH).statement(connection);
|
||||||
|
stmt.setLong(1, appointment.id());
|
||||||
|
stmt.setString(2, appointment.hash());
|
||||||
|
stmt.execute();
|
||||||
|
}
|
||||||
|
connection.commit();
|
||||||
|
var stmt = Query.of(UPDATE_DB_VERSION).statement(connection);
|
||||||
|
stmt.setLong(1, 2);
|
||||||
|
stmt.execute();
|
||||||
|
connection.setAutoCommit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTables() {
|
||||||
|
throw new RuntimeException("%s.createTables() not implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Database add(Appointment appointment) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Database connect(String jdbc, String user, String pass) throws SQLException {
|
||||||
|
return new MariaDB(DriverManager.getConnection(jdbc, user, pass));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Appointment> list(Integer count, Integer offset) throws SQLException {
|
||||||
|
var list = new ArrayList<Appointment>();
|
||||||
|
var results = Query.of(SELECT_APPOINTMENTS_WITH_HASHES).execute(connection);
|
||||||
|
while (results.next()) {
|
||||||
|
var id = results.getInt("aid");
|
||||||
|
var title = results.getString("title");
|
||||||
|
var description = results.getString("description");
|
||||||
|
if (allEmpty(title, description)) continue;
|
||||||
|
var start = results.getTimestamp("start").toLocalDateTime();
|
||||||
|
var end = nullable(results.getTimestamp("end")).map(Timestamp::toLocalDateTime).orElse(null);
|
||||||
|
var location = results.getString("location");
|
||||||
|
var hash = results.getString("hash");
|
||||||
|
if (hash == null) hash = Calc.hash(start + "@" + location).orElse(null);
|
||||||
|
list.add(new BaseAppointment(id, title, description, start, end, location, hash));
|
||||||
|
}
|
||||||
|
results.close();
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Appointment> listByTags(Set<String> tags, Integer count, Integer offset) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,8 @@ description = "OpenCloudCal : Importers"
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":de.srsoftware.cal.api"))
|
implementation(project(":de.srsoftware.cal.api"))
|
||||||
|
implementation(project(":de.srsoftware.cal.base"))
|
||||||
implementation("de.srsoftware:tools.optionals:1.0.0")
|
implementation("de.srsoftware:tools.optionals:1.0.0")
|
||||||
implementation("de.srsoftware:tools.util:1.1.3")
|
implementation("de.srsoftware:tools.util:1.2.0")
|
||||||
implementation("de.srsoftware:tools.web:1.3.3")
|
implementation("de.srsoftware:tools.web:1.3.3")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package de.srsoftware.cal.importer.jena;
|
|||||||
|
|
||||||
import static de.srsoftware.tools.TagFilter.*;
|
import static de.srsoftware.tools.TagFilter.*;
|
||||||
|
|
||||||
import de.srsoftware.cal.importer.BaseImporter;
|
import de.srsoftware.cal.BaseImporter;
|
||||||
import de.srsoftware.tools.*;
|
import de.srsoftware.tools.*;
|
||||||
import de.srsoftware.tools.Error;
|
import de.srsoftware.tools.Error;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ package de.srsoftware.cal.importer.jena;
|
|||||||
import static de.srsoftware.tools.Optionals.nullable;
|
import static de.srsoftware.tools.Optionals.nullable;
|
||||||
import static de.srsoftware.tools.TagFilter.*;
|
import static de.srsoftware.tools.TagFilter.*;
|
||||||
|
|
||||||
import de.srsoftware.cal.importer.BaseImporter;
|
import de.srsoftware.cal.BaseImporter;
|
||||||
import de.srsoftware.tools.Error;
|
import de.srsoftware.tools.Error;
|
||||||
import de.srsoftware.tools.Payload;
|
import de.srsoftware.tools.Payload;
|
||||||
import de.srsoftware.tools.Result;
|
import de.srsoftware.tools.Result;
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ include("de.srsoftware.cal.api")
|
|||||||
include("de.srsoftware.cal.db")
|
include("de.srsoftware.cal.db")
|
||||||
include("de.srsoftware.cal.importer")
|
include("de.srsoftware.cal.importer")
|
||||||
include("de.srsoftware.cal.web")
|
include("de.srsoftware.cal.web")
|
||||||
|
include("de.srsoftware.cal.base")
|
||||||
|
|||||||
Reference in New Issue
Block a user