Rename datasource package
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
package wtf.beatrice.hidekobot.datasources;
|
||||
|
||||
public enum ConfigurationEntry
|
||||
{
|
||||
|
||||
BOT_TOKEN("bot-token", "MTAxMjUzNzI5MTMwODI4NjAyMw.GWeNuh.00000000000000000000000000000000000000"),
|
||||
BOT_OWNER_ID("bot-owner-id", 100000000000000000L),
|
||||
BOT_COLOR("bot-color", "PINK"),
|
||||
HEARTBEAT_LINK("heartbeat-link", "https://your-heartbeat-api.com/api/push/apikey?status=up&msg=OK&ping="),
|
||||
|
||||
;
|
||||
|
||||
|
||||
private String path;
|
||||
private Object defaultValue;
|
||||
ConfigurationEntry(String path, Object defaultValue)
|
||||
{
|
||||
this.path = path;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public String getPath() { return path; }
|
||||
public Object getDefaultValue() { return defaultValue; }
|
||||
}
|
@@ -0,0 +1,140 @@
|
||||
package wtf.beatrice.hidekobot.datasources;
|
||||
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import wtf.beatrice.hidekobot.HidekoBot;
|
||||
import wtf.beatrice.hidekobot.util.Logger;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class ConfigurationSource
|
||||
{
|
||||
|
||||
|
||||
private final LinkedHashMap<String, Object> configurationEntries = new LinkedHashMap<>();
|
||||
private final Logger logger;
|
||||
private final String configFilePath;
|
||||
|
||||
public ConfigurationSource(String configFilePath)
|
||||
{
|
||||
this.configFilePath = configFilePath;
|
||||
logger = new Logger(getClass());
|
||||
}
|
||||
|
||||
public void initConfig()
|
||||
{
|
||||
// load the YAML file from the archive's resources folder
|
||||
/*
|
||||
* note: this is no longer technically a YAML file, but we are using a very similar structure
|
||||
* to what SnakeYaml does, so that it can map all entries directly to a YAML file itself.
|
||||
* we used to have a config.yml file in the "resources" folder, but that is no longer necessary.
|
||||
*/
|
||||
LinkedHashMap<String, Object> internalConfigContents = new LinkedHashMap<>(); // map holding all file entries
|
||||
for(ConfigurationEntry entry : ConfigurationEntry.values())
|
||||
{
|
||||
internalConfigContents.put(entry.getPath(), entry.getDefaultValue());
|
||||
}
|
||||
|
||||
if(internalConfigContents.isEmpty())
|
||||
{
|
||||
logger.log("Error reading internal configuration!");
|
||||
HidekoBot.shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
// check if config files exists in filesystem
|
||||
File fsConfigFile = new File(configFilePath);
|
||||
if(!fsConfigFile.exists())
|
||||
{
|
||||
// try to create config file
|
||||
try { fsConfigFile.createNewFile(); }
|
||||
catch (IOException e) {
|
||||
logger.log("Error creating configuration file!");
|
||||
logger.log(e.getMessage());
|
||||
HidekoBot.shutdown();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// load the YAML file from the filesystem
|
||||
Yaml fsConfigYaml = new Yaml();
|
||||
LinkedHashMap<String, Object> fsConfigContents = null; // map holding all file entries
|
||||
try (InputStream fsConfigStream = new FileInputStream(fsConfigFile))
|
||||
{ fsConfigContents = fsConfigYaml.load(fsConfigStream); }
|
||||
catch (IOException e) { logger.log(e.getMessage()); }
|
||||
|
||||
|
||||
if(fsConfigContents == null) // if file contents are empty or corrupted...
|
||||
{
|
||||
// "clean" them (this effectively forces a config file reset)
|
||||
fsConfigContents = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
// check for missing keys
|
||||
boolean missingKeys = false;
|
||||
for(String key : internalConfigContents.keySet())
|
||||
{
|
||||
// if key is missing
|
||||
if(!fsConfigContents.containsKey(key))
|
||||
{
|
||||
// quit and flag it, as we need to complete the file with the missing ones
|
||||
missingKeys = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if keys are missing
|
||||
if(missingKeys)
|
||||
{
|
||||
// create a new mixed map that will take existing values from the non-missing keys
|
||||
// and fill everything else with the default values
|
||||
LinkedHashMap<String, Object> filledEntries = new LinkedHashMap<>();
|
||||
for(String key : internalConfigContents.keySet())
|
||||
{
|
||||
if(fsConfigContents.containsKey(key))
|
||||
{
|
||||
// if the key already exists, copy the original value
|
||||
filledEntries.put(key, fsConfigContents.get(key));
|
||||
} else {
|
||||
// else, copy the value from the example config file
|
||||
filledEntries.put(key, internalConfigContents.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// new writer to actually write the contents to the file
|
||||
PrintWriter missingKeysWriter = new PrintWriter(fsConfigFile);
|
||||
|
||||
// set yaml options to make the output prettier
|
||||
DumperOptions dumperOptions = new DumperOptions();
|
||||
dumperOptions.setIndent(2);
|
||||
dumperOptions.setPrettyFlow(true);
|
||||
dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
|
||||
// create the yaml object and dump the values to filesystem
|
||||
Yaml yaml = new Yaml(dumperOptions);
|
||||
yaml.dump(filledEntries, missingKeysWriter);
|
||||
} catch (FileNotFoundException e) {
|
||||
logger.log(e.getMessage());
|
||||
HidekoBot.shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
// finally, dump all entries to cache.
|
||||
loadConfig(filledEntries);
|
||||
} else {
|
||||
// if no key is missing, just cache all entries and values from filesystem.
|
||||
loadConfig(fsConfigContents);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void loadConfig(LinkedHashMap<String, Object> configurationEntries)
|
||||
{
|
||||
this.configurationEntries.putAll(configurationEntries);
|
||||
}
|
||||
public Object getConfigValue(ConfigurationEntry key)
|
||||
{
|
||||
return configurationEntries.get(key.getPath());
|
||||
}
|
||||
}
|
@@ -0,0 +1,377 @@
|
||||
package wtf.beatrice.hidekobot.datasources;
|
||||
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.channel.ChannelType;
|
||||
import wtf.beatrice.hidekobot.Cache;
|
||||
import wtf.beatrice.hidekobot.util.Logger;
|
||||
|
||||
import java.sql.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DatabaseSource
|
||||
{
|
||||
|
||||
private final static String sqliteURL = "jdbc:sqlite:%path%";
|
||||
private Connection dbConnection = null;
|
||||
private final String dbPath;
|
||||
private final Logger logger;
|
||||
|
||||
public DatabaseSource(String dbPath)
|
||||
{
|
||||
this.dbPath = dbPath;
|
||||
this.logger = new Logger(getClass());
|
||||
}
|
||||
|
||||
public boolean connect()
|
||||
{
|
||||
String url = sqliteURL.replace("%path%", dbPath);
|
||||
|
||||
if(!close()) return false;
|
||||
|
||||
try {
|
||||
dbConnection = DriverManager.getConnection(url);
|
||||
logger.log("Database connection established!");
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public boolean close()
|
||||
{
|
||||
if (dbConnection != null)
|
||||
{
|
||||
try {
|
||||
if(!dbConnection.isClosed())
|
||||
{
|
||||
dbConnection.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
dbConnection = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* DB STRUCTURE
|
||||
* TABLE 1: pending_disabled_messages
|
||||
* ----------------------------------------------------------------------------------
|
||||
* | guild_id | channel_id | message_id | expiry_timestamp |
|
||||
* ----------------------------------------------------------------------------------
|
||||
* |39402849302 | 39402849302 | 39402849302 | 2022-11-20 22:45:53:300 |
|
||||
* ---------------------------------------------------------------------------------
|
||||
*
|
||||
*
|
||||
* TABLE 2: command_runners
|
||||
* --------------------------------------------------------------------------------------------
|
||||
* | guild_id | channel_id | message_id | user_id | channel_type |
|
||||
* --------------------------------------------------------------------------------------------
|
||||
* | 39402849302 | 39402849302 | 39402849302 | 39402849302 | PRIVATE |
|
||||
* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
|
||||
//todo: javadocs
|
||||
|
||||
public boolean initDb()
|
||||
{
|
||||
List<String> newTables = new ArrayList<>();
|
||||
|
||||
newTables.add("CREATE TABLE IF NOT EXISTS pending_disabled_messages (" +
|
||||
"guild_id TEXT NOT NULL, " +
|
||||
"channel_id TEXT NOT NULL," +
|
||||
"message_id TEXT NOT NULL," +
|
||||
"expiry_timestamp TEXT NOT NULL " +
|
||||
");");
|
||||
|
||||
newTables.add("CREATE TABLE IF NOT EXISTS command_runners (" +
|
||||
"guild_id TEXT NOT NULL, " +
|
||||
"channel_id TEXT NOT NULL," + // channel the command was run in
|
||||
"message_id TEXT NOT NULL," + // message id of the bot's response
|
||||
"user_id TEXT NOT NULL, " + // user who ran the command
|
||||
"channel_type TEXT NOT NULL" + // channel type (PRIVATE, FORUM, ...)
|
||||
");");
|
||||
|
||||
for(String sql : newTables)
|
||||
{
|
||||
try (Statement stmt = dbConnection.createStatement()) {
|
||||
// execute the statement
|
||||
stmt.execute(sql);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean trackRanCommandReply(Message message, User user)
|
||||
{
|
||||
String userId = user.getId();
|
||||
String guildId;
|
||||
|
||||
ChannelType channelType = message.getChannelType();
|
||||
if(!(channelType.isGuild()))
|
||||
{
|
||||
guildId = userId;
|
||||
} else {
|
||||
guildId = message.getGuild().getId();
|
||||
}
|
||||
|
||||
String channelId = message.getChannel().getId();
|
||||
String messageId = message.getId();
|
||||
|
||||
|
||||
String query = "INSERT INTO command_runners " +
|
||||
"(guild_id, channel_id, message_id, user_id, channel_type) VALUES " +
|
||||
" (?, ?, ?, ?, ?);";
|
||||
|
||||
try(PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
|
||||
{
|
||||
preparedStatement.setString(1, guildId);
|
||||
preparedStatement.setString(2, channelId);
|
||||
preparedStatement.setString(3, messageId);
|
||||
preparedStatement.setString(4, userId);
|
||||
preparedStatement.setString(5, channelType.name());
|
||||
|
||||
preparedStatement.executeUpdate();
|
||||
|
||||
return true;
|
||||
} catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isUserTrackedFor(String userId, String messageId)
|
||||
{
|
||||
String trackedUserId = getTrackedReplyUserId(messageId);
|
||||
if(trackedUserId == null) return false;
|
||||
return userId.equals(trackedUserId);
|
||||
}
|
||||
|
||||
public ChannelType getTrackedMessageChannelType(String messageId)
|
||||
{
|
||||
String query = "SELECT channel_type " +
|
||||
"FROM command_runners " +
|
||||
"WHERE message_id = ?;";
|
||||
|
||||
try(PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
|
||||
{
|
||||
preparedStatement.setString(1, messageId);
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
if(resultSet.isClosed()) return null;
|
||||
while(resultSet.next())
|
||||
{
|
||||
String channelTypeName = resultSet.getString("channel_type");
|
||||
return ChannelType.valueOf(channelTypeName);
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public String getTrackedReplyUserId(String messageId)
|
||||
{
|
||||
String query = "SELECT user_id " +
|
||||
"FROM command_runners " +
|
||||
"WHERE message_id = ?;";
|
||||
|
||||
try(PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
|
||||
{
|
||||
preparedStatement.setString(1, messageId);
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
if(resultSet.isClosed()) return null;
|
||||
while(resultSet.next())
|
||||
{
|
||||
return resultSet.getString("user_id");
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean queueDisabling(Message message)
|
||||
{
|
||||
String messageId = message.getId();
|
||||
String channelId = message.getChannel().getId();
|
||||
String guildId;
|
||||
|
||||
ChannelType channelType = message.getChannelType();
|
||||
if(!(channelType.isGuild()))
|
||||
{
|
||||
guildId = "PRIVATE";
|
||||
} else {
|
||||
guildId = message.getGuild().getId();
|
||||
}
|
||||
|
||||
LocalDateTime expiryTime = LocalDateTime.now().plusSeconds(Cache.getExpiryTimeSeconds());
|
||||
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(Cache.getExpiryTimestampFormat());
|
||||
String expiryTimeFormatted = dateTimeFormatter.format(expiryTime);
|
||||
|
||||
String query = "INSERT INTO pending_disabled_messages " +
|
||||
"(guild_id, channel_id, message_id, expiry_timestamp) VALUES " +
|
||||
" (?, ?, ?, ?);";
|
||||
|
||||
try(PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
|
||||
{
|
||||
preparedStatement.setString(1, guildId);
|
||||
preparedStatement.setString(2, channelId);
|
||||
preparedStatement.setString(3, messageId);
|
||||
preparedStatement.setString(4, expiryTimeFormatted);
|
||||
|
||||
preparedStatement.executeUpdate();
|
||||
|
||||
return true;
|
||||
} catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<String> getQueuedExpiringMessages()
|
||||
{
|
||||
List<String> messages = new ArrayList<>();
|
||||
|
||||
String query = "SELECT message_id " +
|
||||
"FROM pending_disabled_messages ";
|
||||
|
||||
try (Statement statement = dbConnection.createStatement())
|
||||
{
|
||||
ResultSet resultSet = statement.executeQuery(query);
|
||||
if(resultSet.isClosed()) return messages;
|
||||
while(resultSet.next())
|
||||
{
|
||||
messages.add(resultSet.getString("message_id"));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
public boolean untrackExpiredMessage(String messageId)
|
||||
{
|
||||
String query = "DELETE FROM pending_disabled_messages WHERE message_id = ?;";
|
||||
|
||||
try(PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
|
||||
{
|
||||
preparedStatement.setString(1, messageId);
|
||||
preparedStatement.execute();
|
||||
} catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
query = "DELETE FROM command_runners WHERE message_id = ?;";
|
||||
try(PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
|
||||
{
|
||||
preparedStatement.setString(1, messageId);
|
||||
preparedStatement.execute();
|
||||
} catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getQueuedExpiringMessageExpiryDate(String messageId)
|
||||
{
|
||||
String query = "SELECT expiry_timestamp " +
|
||||
"FROM pending_disabled_messages " +
|
||||
"WHERE message_id = ?;";
|
||||
|
||||
try(PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
|
||||
{
|
||||
preparedStatement.setString(1, messageId);
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
if(resultSet.isClosed()) return null;
|
||||
while(resultSet.next())
|
||||
{
|
||||
return resultSet.getString("expiry_timestamp");
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getQueuedExpiringMessageChannel(String messageId)
|
||||
{
|
||||
String query = "SELECT channel_id " +
|
||||
"FROM pending_disabled_messages " +
|
||||
"WHERE message_id = ?;";
|
||||
|
||||
try(PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
|
||||
{
|
||||
preparedStatement.setString(1, messageId);
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
if(resultSet.isClosed()) return null;
|
||||
while(resultSet.next())
|
||||
{
|
||||
return resultSet.getString("channel_id");
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getQueuedExpiringMessageGuild(String messageId)
|
||||
{
|
||||
String query = "SELECT guild_id " +
|
||||
"FROM pending_disabled_messages " +
|
||||
"WHERE message_id = ?;";
|
||||
|
||||
try(PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
|
||||
{
|
||||
preparedStatement.setString(1, messageId);
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
if(resultSet.isClosed()) return null;
|
||||
while(resultSet.next())
|
||||
{
|
||||
return resultSet.getString("guild_id");
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
package wtf.beatrice.hidekobot.datasources;
|
||||
|
||||
import wtf.beatrice.hidekobot.HidekoBot;
|
||||
import wtf.beatrice.hidekobot.util.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
public class PropertiesSource
|
||||
{
|
||||
|
||||
private Properties properties = null;
|
||||
private final String fileName = "default.properties";
|
||||
private final Logger logger = new Logger(getClass());
|
||||
|
||||
public void load()
|
||||
{
|
||||
properties = new Properties();
|
||||
|
||||
try (InputStream internalPropertiesStream = getClass()
|
||||
.getClassLoader()
|
||||
.getResourceAsStream(fileName))
|
||||
{
|
||||
properties.load(internalPropertiesStream);
|
||||
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.log(e.getMessage());
|
||||
HidekoBot.shutdown();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public String getProperty(String property)
|
||||
{ return properties == null ? "" : properties.getProperty(property); }
|
||||
}
|
Reference in New Issue
Block a user