Add WhatsApp reminder

This commit is contained in:
2024-06-18 21:21:27 +02:00
parent 0d5307cf1a
commit 662850c35c
8 changed files with 422 additions and 56 deletions

View File

@@ -6,8 +6,8 @@ apply plugin: 'java'
apply plugin: 'application' apply plugin: 'application'
mainClassName = 'App' mainClassName = 'App'
sourceCompatibility = 15 sourceCompatibility = 16
targetCompatibility = 15 targetCompatibility = 16
version = '1.0' version = '1.0'
compileJava.options.encoding = 'UTF-8' compileJava.options.encoding = 'UTF-8'
compileTestJava.options.encoding = 'UTF-8' compileTestJava.options.encoding = 'UTF-8'

View File

@@ -0,0 +1,83 @@
pipeline {
agent any
stages {
stage('Restore tlw-database-tool') {
steps {
copyArtifacts filter: '**/tlw-database-tool-1.0.jar', fingerprintArtifacts: true, projectName: 'build tlw-database-tool', selector: lastSuccessful(), target: '.'
}
}
stage('Execute') {
steps {
script {
String jdkPath = tool name: 'OpenJDK19', type: 'jdk'
withCredentials([
usernamePassword(credentialsId: 'aws', usernameVariable: 'AWS_ACCESS_KEY_ID', passwordVariable: 'AWS_SECRET_KEY'),
usernamePassword(credentialsId: 'forum_database', usernameVariable: 'TLW_DATABASE_USERNAME', passwordVariable: 'TLW_DATABASE_PASSWORD'),
usernamePassword(credentialsId: 'forum_user', usernameVariable: 'FORUM_USERNAME', passwordVariable: 'FORUM_PASSWORD')
secretText(credentialsId: 'WhatsApp_Token', secretVariable: 'TLW_WHATSAPP_API_KEY')
secretText(credentialsId: 'OPENAI_TOKEN', secretVariable: 'OPENAI_TOKEN')
]) {
withEnv([
"JAVA_HOME=${jdkPath}/jdk-19.0.2"
]) {
try {
sh "ls build/libs"
sh "java -jar build/libs/tlw-database-tool-1.0.jar --mode WhatsAppNotifier --season ${season} --league 1 --configFile Tippliga 2>&1 >> log.txt"
} catch (Exception e) {
telegramSendManual("TLW-Database-Tool crashed!")
}
String outputString = readFile 'log.txt'
if(outputString != "") {
ArrayList<String> outputList = outputString.replace("\n\n", "\n").split('\n').toList()
outputList = clean(outputList)
outputList.each {
telegramSendManual(it)
}
}
}
}
}
}
}
}
post {
always {
deleteDir()
}
failure {
telegramSendManual("Build failed!\n${env.BUILD_URL}console")
}
}
}
private ArrayList<String> clean(ArrayList<String> orig) {
ArrayList<String> cleaned = new ArrayList<String>()
orig.each{line ->
if(line.indexOf(" [main] INFO de.jeyp91 - ") >= 0) {
line = line.substring(20, line.size())
}
if(line.indexOf(" [main] ERROR de.jeyp91") >= 0) {
line = line.substring(20, line.size())
}
cleaned.add(line)
}
return cleaned.unique()
}
def telegramSendManual(String text) {
sleep 1
if(text) {
def encodedMessage = URLEncoder.encode(text, "UTF-8")
println encodedMessage
httpRequest(
httpMode: 'GET',
contentType: 'APPLICATION_JSON',
responseHandle: 'NONE',
url: "https://api.telegram.org/bot1298223079:AAEplcQpfzFG59qNYAYuSbJKtB9HMXCCE_U/sendMessage?text=$encodedMessage&chat_id=459231986&disable_web_page_preview=true",
wrapAsMultipart: false,
consoleLogResponseBody: true
)
}
}

View File

@@ -5,6 +5,7 @@ import de.jeyp91.tippligaforum.MatchesListForumUpdater;
import de.jeyp91.tippliga.*; import de.jeyp91.tippliga.*;
import de.jeyp91.tippligaforum.TippligaConfigProvider; import de.jeyp91.tippligaforum.TippligaConfigProvider;
import de.jeyp91.tippligaforum.TippligaSQLConnector; import de.jeyp91.tippligaforum.TippligaSQLConnector;
import de.jeyp91.whatsapp.WhatsAppNotifier;
import net.sourceforge.argparse4j.ArgumentParsers; import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.inf.ArgumentParser; import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.ArgumentParserException; import net.sourceforge.argparse4j.inf.ArgumentParserException;
@@ -43,46 +44,50 @@ public class App {
initOptions(args); initOptions(args);
String sql = ""; String sql = "";
String beautifulInfo = ""; String beautifulInfo = "";
switch(mode) { switch (mode) {
case "MatchdaysUpdater": case "MatchdaysUpdater" -> {
TLWMatchdaysUpdater matchdaysUpdater = new TLWMatchdaysUpdater(season, league, configFile); TLWMatchdaysUpdater matchdaysUpdater = new TLWMatchdaysUpdater(season, league, configFile);
sql = matchdaysUpdater.getUpdateSql(); sql = matchdaysUpdater.getUpdateSql();
beautifulInfo = matchdaysUpdater.getBeautifulInfo(); beautifulInfo = matchdaysUpdater.getBeautifulInfo();
matchdaysUpdater.updateGoogleCalendar(); matchdaysUpdater.updateGoogleCalendar();
break; }
case "MatchesCreatorFootball": case "MatchesCreatorFootball" -> {
TLWMatchesCreatorFootball creator = new TLWMatchesCreatorFootball(season, league, configFile); TLWMatchesCreatorFootball creator = new TLWMatchesCreatorFootball(season, league, configFile);
sql = creator.getSQLInsertString(); sql = creator.getSQLInsertString();
break; }
case "MatchesUpdaterFootball": case "MatchesUpdaterFootball" -> {
TLWMatchesUpdaterFootball tlwMatchesUpdaterFootball = new TLWMatchesUpdaterFootball(season, league, configFile); TLWMatchesUpdaterFootball tlwMatchesUpdaterFootball = new TLWMatchesUpdaterFootball(season, league, configFile);
sql = tlwMatchesUpdaterFootball.getUpdateSQL(); sql = tlwMatchesUpdaterFootball.getUpdateSQL();
beautifulInfo = tlwMatchesUpdaterFootball.getBeautifulInfo(); beautifulInfo = tlwMatchesUpdaterFootball.getBeautifulInfo();
break; }
case "MatchesResultsUpdater": case "MatchesResultsUpdater" -> {
TLWMatchesResultsUpdater tlwMatchesResultsUpdater = new TLWMatchesResultsUpdater(season, league, configFile); TLWMatchesResultsUpdater tlwMatchesResultsUpdater = new TLWMatchesResultsUpdater(season, league, configFile);
beautifulInfo = tlwMatchesResultsUpdater.getBeautifulInfo(); beautifulInfo = tlwMatchesResultsUpdater.getBeautifulInfo();
break; }
case "TeamsUpdater": case "TeamsUpdater" -> {
TLWTeamsUpdater teamsUpdater = new TLWTeamsUpdater(season, league, configFile); TLWTeamsUpdater teamsUpdater = new TLWTeamsUpdater(season, league, configFile);
sql = teamsUpdater.getInsertSQL(); sql = teamsUpdater.getInsertSQL();
break; }
case "APIFootballUpdater": case "APIFootballUpdater" -> {
APIFootballUpdater apiFootballUpdater = new APIFootballUpdater(); APIFootballUpdater apiFootballUpdater = new APIFootballUpdater();
apiFootballUpdater.updateAllFixtures(season); apiFootballUpdater.updateAllFixtures(season);
apiFootballUpdater.updateAllRounds(season); apiFootballUpdater.updateAllRounds(season);
break; }
case "MatchesListGistUpdater": case "MatchesListGistUpdater" -> {
MatchesListForumUpdater matchesListForumUpdater = new MatchesListForumUpdater(season); MatchesListForumUpdater matchesListForumUpdater = new MatchesListForumUpdater(season);
matchesListForumUpdater.updateAllLeagues(season); matchesListForumUpdater.updateAllLeagues(season);
break; }
case "PostChecksum": case "PostChecksum" -> {
TippligaConfigProvider configProvider = new TippligaConfigProvider(season); TippligaConfigProvider configProvider = new TippligaConfigProvider(season);
String checksum = configProvider.getChecksumOfConfigPost(configFile); String checksum = configProvider.getChecksumOfConfigPost(configFile);
System.out.println(checksum); System.out.println(checksum);
break; }
default: case "WhatsAppNotifier" -> {
break; WhatsAppNotifier notifier = new WhatsAppNotifier();
notifier.sendNotifications();
}
default -> {
}
} }
if(!StatusHolder.getError() && !sql.equals("")) { if(!StatusHolder.getError() && !sql.equals("")) {
TippligaSQLConnector con = TippligaSQLConnector.getInstance(); TippligaSQLConnector con = TippligaSQLConnector.getInstance();
@@ -99,7 +104,7 @@ public class App {
parser.addArgument("-m", "--mode") parser.addArgument("-m", "--mode")
.dest("mode") .dest("mode")
.choices("MatchdaysUpdater", "MatchesCreatorFootball", "MatchesUpdaterFootball", "MatchesResultsUpdater", "TeamsUpdater", "APIFootballUpdater", "MatchesListGistUpdater", "PostChecksum") .choices("MatchdaysUpdater", "MatchesCreatorFootball", "MatchesUpdaterFootball", "MatchesResultsUpdater", "TeamsUpdater", "APIFootballUpdater", "MatchesListGistUpdater", "PostChecksum", "WhatsAppNotifier")
.help("") .help("")
.required(true) .required(true)
.type(String.class); .type(String.class);

View File

@@ -157,7 +157,7 @@ public class TippligaGoogleEventManager {
.setDateTime(deliveryDateTime) .setDateTime(deliveryDateTime)
.setTimeZone("Europe/Berlin"); .setTimeZone("Europe/Berlin");
// Set reminder to 12 hours before // Set reminder to 12 remainingHours before
Event.Reminders reminders = new Event.Reminders(); Event.Reminders reminders = new Event.Reminders();
reminders.setUseDefault(true); reminders.setUseDefault(true);

View File

@@ -5,6 +5,7 @@ import de.jeyp91.tippliga.TLWLeague;
import de.jeyp91.tippliga.TLWMatch; import de.jeyp91.tippliga.TLWMatch;
import de.jeyp91.tippliga.TLWMatchday; import de.jeyp91.tippliga.TLWMatchday;
import de.jeyp91.tippliga.TLWTeam; import de.jeyp91.tippliga.TLWTeam;
import de.jeyp91.whatsapp.WhatsAppReminder;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -64,7 +65,7 @@ public class TippligaSQLConnector {
} }
public static TippligaSQLConnector getInstance() { public static TippligaSQLConnector getInstance() {
if(tlwSqlCon == null) { if (tlwSqlCon == null) {
tlwSqlCon = new TippligaSQLConnector(); tlwSqlCon = new TippligaSQLConnector();
} }
return tlwSqlCon; return tlwSqlCon;
@@ -157,37 +158,37 @@ public class TippligaSQLConnector {
public ArrayList<TLWMatchday> getUpdatedMatchdaysBasedOnMatches(String season, String league) { public ArrayList<TLWMatchday> getUpdatedMatchdaysBasedOnMatches(String season, String league) {
String queryString = """ String queryString = """
SELECT
d1.season,
d1.league,
d1.matchday,
d1.status,
d1.delivery_date,
min(STR_TO_DATE(d2.match_datetime, '%Y-%m-%d %H:%i:%s')) as delivery_date_2,
min(STR_TO_DATE(d3.match_datetime, '%Y-%m-%d %H:%i:%s')) as delivery_date_3,
d1.matchday_name,
d1.matches
FROM (
SELECT SELECT
md.season, d1.season,
md.league, d1.league,
md.matchday, d1.matchday,
md.status, d1.status,
min(STR_TO_DATE(ma.match_datetime, '%Y-%m-%d %H:%i:%s')) AS delivery_date, d1.delivery_date,
md.matchday_name, min(STR_TO_DATE(d2.match_datetime, '%Y-%m-%d %H:%i:%s')) as delivery_date_2,
md.matches min(STR_TO_DATE(d3.match_datetime, '%Y-%m-%d %H:%i:%s')) as delivery_date_3,
FROM phpbb_footb_matchdays md d1.matchday_name,
LEFT JOIN phpbb_footb_matches ma ON (md.season = ma.season AND md.league = ma.league AND md.matchday = ma.matchday) d1.matches
WHERE md.season =""" + " " + season + " " + """ FROM (
AND md.league =""" + " " + league + " " + """ SELECT
GROUP BY md.season, md.league, md.matchday md.season,
) AS d1 md.league,
LEFT JOIN phpbb_footb_matches d2 ON (d1.season = d2.season AND d1.league = d2.league AND d1.matchday = d2.matchday md.matchday,
AND DATEDIFF(DATE(STR_TO_DATE(d2.match_datetime, '%Y-%m-%d %H:%i:%s')), DATE(d1.delivery_date)) > 0) md.status,
LEFT JOIN phpbb_footb_matches d3 ON (d1.season = d3.season AND d1.league = d3.league AND d1.matchday = d3.matchday min(STR_TO_DATE(ma.match_datetime, '%Y-%m-%d %H:%i:%s')) AS delivery_date,
AND DATEDIFF(DATE(STR_TO_DATE(d3.match_datetime, '%Y-%m-%d %H:%i:%s')), DATE(d1.delivery_date)) > 6) md.matchday_name,
GROUP BY d1.season, d1.league, d1.matchday; md.matches
"""; FROM phpbb_footb_matchdays md
LEFT JOIN phpbb_footb_matches ma ON (md.season = ma.season AND md.league = ma.league AND md.matchday = ma.matchday)
WHERE md.season =""" + " " + season + " " + """
AND md.league =""" + " " + league + " " + """
GROUP BY md.season, md.league, md.matchday
) AS d1
LEFT JOIN phpbb_footb_matches d2 ON (d1.season = d2.season AND d1.league = d2.league AND d1.matchday = d2.matchday
AND DATEDIFF(DATE(STR_TO_DATE(d2.match_datetime, '%Y-%m-%d %H:%i:%s')), DATE(d1.delivery_date)) > 0)
LEFT JOIN phpbb_footb_matches d3 ON (d1.season = d3.season AND d1.league = d3.league AND d1.matchday = d3.matchday
AND DATEDIFF(DATE(STR_TO_DATE(d3.match_datetime, '%Y-%m-%d %H:%i:%s')), DATE(d1.delivery_date)) > 6)
GROUP BY d1.season, d1.league, d1.matchday;
""";
ArrayList<TLWMatchday> matchdays = new ArrayList<>(); ArrayList<TLWMatchday> matchdays = new ArrayList<>();
ResultSet rset = executeQuery(queryString); ResultSet rset = executeQuery(queryString);
@@ -243,7 +244,7 @@ public class TippligaSQLConnector {
return post; return post;
} }
public ResultSet executeQuery (String queryString){ public ResultSet executeQuery(String queryString) {
Statement stmt; Statement stmt;
ResultSet rset = null; ResultSet rset = null;
try { try {
@@ -255,7 +256,7 @@ public class TippligaSQLConnector {
return rset; return rset;
} }
public void executeUpdate (String queryString){ public void executeUpdate(String queryString) {
Statement stmt; Statement stmt;
try { try {
stmt = con.createStatement(); stmt = con.createStatement();
@@ -321,4 +322,119 @@ public class TippligaSQLConnector {
post = post.replace("'", "&#039;"); post = post.replace("'", "&#039;");
return post; return post;
} }
public ArrayList<WhatsAppReminder> getNextWhatsAppReminders(int hours) {
final String remindersToSendQuery = """
WITH delivery_date_next_day AS (
SELECT
m.season,
m.league,
l.league_name,
l.league_type,
m.matchday,
m.matchday_name,
delivery_date,
STR_TO_DATE(delivery_date, '%Y-%m-%d %H:%i:%s') as parsed_delivery_date
FROM phpbb_footb_matchdays m
LEFT JOIN phpbb_footb_leagues l ON (m.season = l.season AND m.league = l.league)
HAVING parsed_delivery_date > NOW() AND parsed_delivery_date < NOW() + INTERVAL {{remainingHours}} HOUR
)
SELECT
d.season,
d.league,
d.league_name,
d.matchday,
IF(d.matchday_name = '', CONCAT(d.matchday, '. Spieltag'), d.matchday_name) AS matchday_name,
d.delivery_date,
CASE
WHEN DATE (d.parsed_delivery_date) = CURDATE() THEN 'heute'
WHEN DATE (d.parsed_delivery_date) = CURDATE() + INTERVAL 1 DAY THEN 'morgen'
ELSE DATE (d.parsed_delivery_date)
END AS today_or_tomorrow,
TIME_FORMAT(TIME(d.parsed_delivery_date), '%H:%i') AS time,
'{{remainingHours}}' AS remaining_hours,
b.user_id,
u.username,
pf.pf_handynummer,
count(*) AS missing_bets
FROM delivery_date_next_day d
LEFT JOIN phpbb_footb_matches m
ON (d.season = m.season
AND d.league = m.league
AND d.matchday = m.matchday)
LEFT JOIN phpbb_footb_bets b
ON (m.season = b.season
AND m.league = b.league
AND m.match_no = b.match_no)
LEFT JOIN phpbb_footb_matches mb
ON (d.season = mb.season
AND d.league = mb.league - 50
AND d.matchday = mb.matchday
AND (b.user_id + 2000 = mb.team_id_home OR b.user_id + 2000 = mb.team_id_guest))
LEFT JOIN phpbb_footb_whatsapp_reminders r
ON (m.season = r.season
AND m.league = r.league
AND m.matchday = r.matchday
AND r.delivery_date = d.delivery_date
AND b.user_id = r.user_id
AND r.remaining_hours = {{remainingHours}})
LEFT JOIN phpbb_users u
ON (b.user_id = u.user_id)
LEFT JOIN phpbb_profile_fields_data pf
ON (u.user_id = pf.user_id)
WHERE ((d.league_type = 1 AND mb.match_no IS NOT NULL) OR d.league_type = 2)
AND (b.goals_home = '' OR b.goals_guest = '')
AND r.timestamp IS NULL
AND m.status = 0
AND pf.pf_handynummer != ''
GROUP BY d.league_name, d.matchday, u.username, pf.pf_handynummer;
""".replace("{{remainingHours}}", "" + hours);
final int SEASON = 1;
final int LEAGUE = 2;
final int LEAGUE_NAME = 3;
final int MATCHDAY = 4;
final int MATCHDAY_NAME = 5;
final int DELIVERY_DATE = 6;
final int TODAY_OR_TOMORROW = 7;
final int TIME = 8;
final int HOURS = 9;
final int USER_ID = 10;
final int USERNAME = 11;
final int PHONE_NUMBER = 12;
final int MISSING_BETS = 13;
try {
ResultSet rset = executeQuery(remindersToSendQuery);
ArrayList <WhatsAppReminder> reminders = new ArrayList<>();
while (rset.next()) {
reminders.add(
new WhatsAppReminder(
Integer.parseInt(rset.getString(SEASON)),
Integer.parseInt(rset.getString(LEAGUE)),
rset.getString(LEAGUE_NAME),
Integer.parseInt(rset.getString(MATCHDAY)),
rset.getString(MATCHDAY_NAME),
rset.getString(DELIVERY_DATE),
rset.getString(TODAY_OR_TOMORROW),
rset.getString(TIME),
Integer.parseInt(rset.getString(HOURS)),
Integer.parseInt(rset.getString(USER_ID)),
rset.getString(USERNAME),
rset.getString(PHONE_NUMBER),
Integer.parseInt(rset.getString(MISSING_BETS))
)
);
}
return reminders;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void markWhatsAppReminderAsSent(WhatsAppReminder reminder) {
String query = """
INSERT INTO phpbb_footb_whatsapp_reminders
(season, league, matchday, delivery_date, user_id, remaining_hours)
VALUES
(""" + reminder.season() + ", " + reminder.league() + ", " + reminder.matchday() + ", '" + reminder.deliveryDate() + "', " + reminder.userId() + ", " + reminder.remainingHours() + ");";
executeUpdate(query);
}
} }

View File

@@ -0,0 +1,81 @@
package de.jeyp91.whatsapp;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;
import static de.jeyp91.apifootball.APIFootballConnector.stringToJSONObject;
public class OpenAIConnector {
private final HttpClient client;
private final String OPENAI_TOKEN = System.getenv("OPENAI_TOKEN");
private final String OPENAPI_URL = "https://api.openai.com/v1/chat/completions";
private final String OPENAPI_MODEL = "gpt-3.5-turbo-0125";
private final HashMap<String, String> generatedMessages = new HashMap<>();
public OpenAIConnector() {
client = HttpClient.newBuilder().build();
}
public String getReminderMessage(WhatsAppReminder reminder) {
String key = reminder.leagueName() + reminder.matchdayName() + reminder.todayTomorrow() + reminder.time();
String message;
if (generatedMessages.containsKey(key)) {
message = generatedMessages.get(key);
} else {
message = executeReminderPrompt(reminder.leagueName(), reminder.matchdayName(), reminder.todayTomorrow(), reminder.time(), reminder.remainingHours());
generatedMessages.put(key, message);
}
message = message.replace("Hey", "Hey " + reminder.username());
String end = "\nDu kannst deine Tipps wie immer unter https://tippliga-wuerzburg.de/app.php/football/bet abgeben.\nViele Grüße\nDie Tippliga Admins";
message += end;
return message;
}
private String executeReminderPrompt(String leagueName, String matchdayName, String deliveryDay, String time, int remainingHours) {
String systemPrompt = "Generiere eine Nachricht, die dem Zweck dient, jemanden daran zu erinnern, seine noch fehlenden Tipps für den kommenden Spieltag abzuschicken. Die Nachricht muss so klingen, als ob ein Freund sie in natürlicher Sprache abschickt. Sie muss auf Deutsch sein. Die Nachricht muss den richtigen Singular und Plural für die Anzahl der fehlenden Wetten verwenden. Halte dich genau an die Vorlage und ersetze die Teile gekennzeichnet durch \"{}\" durch passende Passagen. Die Antwort auf diesen Prompt soll ausschließlich die Nachricht sein.\n\n "
+"Dies ist die Vorlage:\n"
+"Hey,\n"
+ (remainingHours == 24 ? "{ein netter einleitender Satz der \"league_name\", \"matchday_name\" enthält}.\n" : "{ein einleitender Satz der \"league_name\", \"matchday_name\" enthält und klar macht, dass die Zeit abläuft und nur noch weniger als eine Stunde Zeit für die Abgabe der Tipps bleibt}.\n")
+"Bitte gib die fehlenden Tipps bis {delivery_day} um {time} ab.";
JSONObject userInput = new JSONObject();
userInput.put("league_name", leagueName);
userInput.put("matchday_name", matchdayName);
userInput.put("delivery_day", deliveryDay);
userInput.put("time", time);
String user = userInput.toJSONString();
JSONObject jsonBody = new JSONObject();
jsonBody.put("model", OPENAPI_MODEL);
JSONArray messages = new JSONArray();
JSONObject system = new JSONObject();
system.put("role", "system");
system.put("content", systemPrompt);
messages.add(system);
JSONObject userMessage = new JSONObject();
userMessage.put("role", "user");
userMessage.put("content", user);
messages.add(userMessage);
jsonBody.put("messages", messages);
HttpRequest openAIRequest = HttpRequest.newBuilder()
.uri(URI.create(OPENAPI_URL))
.headers("Content-Type", "application/json")
.headers("Authorization", "Bearer " + OPENAI_TOKEN)
.POST(HttpRequest.BodyPublishers.ofString(jsonBody.toJSONString()))
.build();
JSONObject response = new JSONObject();
try {
response = stringToJSONObject(client.send(openAIRequest, HttpResponse.BodyHandlers.ofString()).body());
} catch (Exception e) {
e.printStackTrace();
}
JSONArray choices = (JSONArray) response.get("choices");
JSONObject choice = (JSONObject) choices.get(0);
JSONObject message = (JSONObject) choice.get("message");
return message.get("content").toString();
}
}

View File

@@ -0,0 +1,65 @@
package de.jeyp91.whatsapp;
import de.jeyp91.tippligaforum.TippligaSQLConnector;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.simple.JSONObject;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.ArrayList;
public class WhatsAppNotifier {
private final String host = System.getenv("TLW_WHATSAPP_HOST");
private final String port = System.getenv("TLW_WHATSAPP_PORT");
private final String apiKey = System.getenv("TLW_WHATSAPP_API_KEY");
private static final Logger logger = LogManager.getLogger(WhatsAppNotifier.class);
private final HttpClient client;
private final OpenAIConnector openAIConnector = new OpenAIConnector();
public WhatsAppNotifier() {
client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
}
public void sendNotifications() {
ArrayList<WhatsAppReminder> reminders = TippligaSQLConnector.getInstance().getNextWhatsAppReminders(24);
reminders.addAll(TippligaSQLConnector.getInstance().getNextWhatsAppReminders(1));
reminders.forEach(reminder -> {
boolean success = sendMessage(reminder);
if (success) {
markReminderAsSent(reminder);
}
});
}
public boolean sendMessage(WhatsAppReminder reminder) {
String message = openAIConnector.getReminderMessage(reminder);
JSONObject body = new JSONObject();
body.put("number", reminder.phoneNumber().substring(2));
body.put("message", message);
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(this.host + (this.port != null ? ":" + this.port : "") + "/send"))
.headers("Content-Type", "application/json")
.headers("x-api-key", apiKey)
.POST(HttpRequest.BodyPublishers.ofString(body.toJSONString()))
.build();
boolean success = false;
try {
client.send(req, HttpResponse.BodyHandlers.ofString()).body();
success = true;
} catch (Exception e) {
logger.error("Failed to send WhatsApp message: " + e.getMessage());
}
return success;
}
public void markReminderAsSent(WhatsAppReminder reminder) {
TippligaSQLConnector.getInstance().markWhatsAppReminderAsSent(reminder);
}
}

View File

@@ -0,0 +1,16 @@
package de.jeyp91.whatsapp;
public record WhatsAppReminder(int season,
int league,
String leagueName,
int matchday,
String matchdayName,
String deliveryDate,
String todayTomorrow,
String time,
int remainingHours,
int userId,
String username,
String phoneNumber,
int missingBets) {
}