Files
PulseCast/pulsecast.php
2026-02-11 19:40:12 +00:00

705 lines
30 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Plugin Name: PulseCast
* Plugin URI: https://git.viper.ipv64.net/M_Viper/PulseCast/
* Description: Sende Broadcasts (sofort oder geplant) an deine StatusAPI direkt aus dem WordPress-Backend. Scheduler serverseitig (StatusAPI) bevorzugt.
* Version: 1.0.1
* Author: M_Viper
* Author URI: https://m-viper.de
*/
if (!defined('ABSPATH')) exit;
/**
* PulseCast - Update-Notice (Gitea Releases)
* Zeigt eine Admin-Notice, wenn eine neue Version auf Gitea verfügbar ist.
*/
// Plugin-Version aus Header lesen
function pulsecast_get_plugin_version() {
if (!function_exists('get_plugin_data')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$plugin_data = get_plugin_data(__FILE__);
return $plugin_data['Version'] ?? '0.0.0';
}
// Cache manuell leeren (Button "Jetzt neu prüfen")
function pulsecast_clear_update_cache() {
if (isset($_GET['pulsecast_clear_cache']) && current_user_can('manage_options')) {
check_admin_referer('pulsecast_clear_cache_action');
delete_transient('pulsecast_latest_release');
wp_redirect(admin_url('plugins.php'));
exit;
}
}
add_action('admin_init', 'pulsecast_clear_update_cache');
// Neueste Release-Infos von Gitea holen
function pulsecast_get_latest_release_info($force_refresh = false) {
$transient_key = 'pulsecast_latest_release';
if ($force_refresh) {
delete_transient($transient_key);
}
$release_info = get_transient($transient_key);
if (false === $release_info) {
$response = wp_remote_get(
'https://git.viper.ipv64.net/api/v1/repos/M_Viper/PulseCast/releases/latest',
array('timeout' => 10)
);
if (!is_wp_error($response) && 200 === wp_remote_retrieve_response_code($response)) {
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if ($data && isset($data['tag_name'])) {
$tag = ltrim((string)$data['tag_name'], 'vV');
$release_info = array(
'version' => $tag,
'download_url' => $data['zipball_url'] ?? '',
'notes' => $data['body'] ?? '',
'published_at' => $data['published_at'] ?? '',
);
// Cache für 6 Stunden
set_transient($transient_key, $release_info, 6 * HOUR_IN_SECONDS);
} else {
set_transient($transient_key, array(), HOUR_IN_SECONDS);
}
} else {
set_transient($transient_key, array(), HOUR_IN_SECONDS);
}
}
return $release_info;
}
// Admin-Notice anzeigen, wenn Update verfügbar
function pulsecast_show_update_notice() {
if (!current_user_can('manage_options')) return;
$current_version = pulsecast_get_plugin_version();
$latest_release = pulsecast_get_latest_release_info();
if (!empty($latest_release['version']) && version_compare($current_version, $latest_release['version'], '<')) {
$refresh_url = wp_nonce_url(admin_url('plugins.php?pulsecast_clear_cache=1'), 'pulsecast_clear_cache_action');
?>
<div class="notice notice-warning is-dismissible">
<h3>PulseCast Update verfügbar</h3>
<p>
Installiert: <strong><?php echo esc_html($current_version); ?></strong><br>
Neueste Version: <strong><?php echo esc_html($latest_release['version']); ?></strong>
</p>
<p>
<a href="<?php echo esc_url($latest_release['download_url']); ?>" class="button button-primary" target="_blank" rel="noreferrer noopener">
Update herunterladen
</a>
<a href="https://git.viper.ipv64.net/M_Viper/PulseCast/releases" class="button" target="_blank" rel="noreferrer noopener">
Release Notes
</a>
<a href="<?php echo esc_url($refresh_url); ?>" class="button">
Jetzt neu prüfen
</a>
</p>
</div>
<?php
}
}
add_action('admin_notices', 'pulsecast_show_update_notice');
class PulseCast {
const OPTION_KEY = 'pulsecast_settings';
const SCHEDULES_KEY = 'pulsecast_schedules';
const CRON_HOOK = 'pulsecast_send_event';
public function __construct() {
add_action('admin_menu', [$this, 'admin_menu']);
add_action('admin_post_pulsecast_send', [$this, 'handle_send_post']);
add_action('admin_post_pulsecast_schedule', [$this, 'handle_schedule_post']);
add_action('admin_post_pulsecast_delete_schedule', [$this, 'handle_delete_schedule']);
add_action('admin_post_pulsecast_resync', [$this, 'handle_resync_post']);
add_action(self::CRON_HOOK, [$this, 'cron_send_broadcast'], 10, 1);
add_filter('cron_schedules', [$this, 'add_weekly_cron']);
register_activation_hook(__FILE__, [$this, 'activate']);
register_deactivation_hook(__FILE__, [$this, 'deactivate']);
}
public function activate() {
if (!get_option(self::OPTION_KEY)) {
$defaults = [
'api_url' => '',
'api_key' => '',
'broadcast_prefix' => '[Broadcast]',
'broadcast_prefix_color' => '&c',
'broadcast_bracket_color' => '&8', // Neu: Standard Dunkelgrau
'broadcast_message_color' => '&f',
];
add_option(self::OPTION_KEY, $defaults);
}
if (!get_option(self::SCHEDULES_KEY)) {
add_option(self::SCHEDULES_KEY, []);
}
}
public function deactivate() {
$schedules = get_option(self::SCHEDULES_KEY, []);
foreach ($schedules as $id => $s) {
$next = wp_next_scheduled(self::CRON_HOOK, [$id]);
if ($next !== false) {
wp_unschedule_event($next, self::CRON_HOOK, [$id]);
}
}
}
public function add_weekly_cron($s) {
if (!isset($s['weekly'])) {
$s['weekly'] = ['interval' => 7*24*60*60, 'display' => __('Weekly')];
}
return $s;
}
public function admin_menu() {
add_menu_page('PulseCast', 'PulseCast', 'manage_options', 'pulsecast', [$this, 'page_main'], 'dashicons-megaphone', 55);
}
public function page_main() {
if (!current_user_can('manage_options')) wp_die('Keine Berechtigung.');
$settings = get_option(self::OPTION_KEY, []);
$schedules = get_option(self::SCHEDULES_KEY, []);
// Feedback Nachrichten
if (isset($_GET['pulsecast_status'])) {
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html($_GET['pulsecast_status']) . '</p></div>';
}
if (isset($_GET['pulsecast_error'])) {
echo '<div class="notice notice-error is-dismissible"><p>' . esc_html($_GET['pulsecast_error']) . '</p></div>';
}
$current_server_time = current_time('Y-m-d H:i:s');
$current_utc_time = gmdate('Y-m-d H:i:s');
?>
<div class="wrap">
<h1>PulseCast — Broadcasts</h1>
<div class="notice notice-info">
<p><strong>Aktuelle Zeit (Server-Zeitzone):</strong> <?php echo esc_html($current_server_time); ?></p>
<p><strong>Aktuelle Zeit (UTC):</strong> <?php echo esc_html($current_utc_time); ?></p>
<p class="description">Zeitgeplante Broadcasts werden in UTC an die StatusAPI gesendet.</p>
</div>
<h2>Einstellungen</h2>
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
<?php wp_nonce_field('pulsecast_save_settings'); ?>
<input type="hidden" name="action" value="pulsecast_schedule">
<table class="form-table">
<tr>
<th scope="row"><label for="api_url">StatusAPI Adresse</label></th>
<td>
<input name="api_url" id="api_url" type="url" class="regular-text"
value="<?php echo esc_attr($settings['api_url'] ?? ''); ?>"
placeholder="http://mc.viper.ipv64.net"
required>
<p class="description">Gib die Serveradresse an — Port (<code>9191</code>) und Pfad (<code>/broadcast</code>) werden automatisch ergänzt.</p>
</td>
</tr>
<tr>
<th scope="row"><label for="api_key">API Key (optional)</label></th>
<td><input name="api_key" id="api_key" type="text" class="regular-text" value="<?php echo esc_attr($settings['api_key'] ?? ''); ?>"></td>
</tr>
<tr>
<th scope="row"><label for="broadcast_prefix">Broadcast Prefix</label></th>
<td>
<input name="broadcast_prefix" id="broadcast_prefix" type="text" class="regular-text"
value="<?php echo esc_attr($settings['broadcast_prefix'] ?? '[Broadcast]'); ?>">
<p class="description">Beispiel: <code>Broadcast</code> oder <code>[Broadcast]</code>. Die Klammern werden bei Bedarf automatisch mit der Klammer-Farbe eingefärbt.</p>
</td>
</tr>
<tr>
<th scope="row"><label for="broadcast_prefix_color">Prefix Text Farbe</label></th>
<td>
<input name="broadcast_prefix_color" id="broadcast_prefix_color" type="text" class="regular-text"
value="<?php echo esc_attr($settings['broadcast_prefix_color'] ?? '&c'); ?>">
<p class="description">Farbe für den Text INNENHALB der Klammern (z. B. <code>&amp;c</code> Rot).</p>
</td>
</tr>
<tr>
<th scope="row"><label for="broadcast_bracket_color">Klammer Farbe (optional)</label></th>
<td>
<input name="broadcast_bracket_color" id="broadcast_bracket_color" type="text" class="regular-text"
value="<?php echo esc_attr($settings['broadcast_bracket_color'] ?? '&8'); ?>">
<p class="description">Farbe für die Klammern [ ] (z. B. <code>&amp;8</code> Dunkelgrau). Leer lassen für Standardfarbe.</p>
</td>
</tr>
<tr>
<th scope="row"><label for="broadcast_message_color">Nachrichten Farbe</label></th>
<td>
<input name="broadcast_message_color" id="broadcast_message_color" type="text" class="regular-text"
value="<?php echo esc_attr($settings['broadcast_message_color'] ?? '&f'); ?>">
<p class="description">Farbcodes mit <code>&amp;</code> (z. B. <code>&amp;f</code>).</p>
</td>
</tr>
</table>
<p class="submit"><button type="submit" class="button button-primary">Einstellungen speichern</button></p>
</form>
<hr>
<h2>Sofortiger Broadcast</h2>
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
<?php wp_nonce_field('pulsecast_send_now'); ?>
<input type="hidden" name="action" value="pulsecast_send">
<table class="form-table">
<tr>
<th><label for="message">Nachricht</label></th>
<td><textarea name="message" id="message" rows="3" class="large-text" required placeholder="Hier Nachricht eingeben..."></textarea></td>
</tr>
</table>
<p><button class="button button-primary">Senden</button></p>
</form>
<hr>
<h2>Geplante Broadcasts (serverseitig)</h2>
<div style="background: #fff; padding: 10px; border: 1px solid #ccc; margin-bottom: 20px; display:flex; justify-content:space-between; align-items:center;">
<div>
<p style="margin:0;">Geplante Broadcasts verwenden automatisch die Standard-Einstellungen für Prefix und Farben.</p>
</div>
<div>
<form style="display:inline;" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
<?php wp_nonce_field('pulsecast_resync_action'); ?>
<input type="hidden" name="action" value="pulsecast_resync">
<button type="submit" class="button" onclick="return confirm('Alle gespeicherten Pläne erneut an den Server senden?');">↻ Synchronisation mit Server erzwingen</button>
</form>
</div>
</div>
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
<?php wp_nonce_field('pulsecast_schedule_new'); ?>
<input type="hidden" name="action" value="pulsecast_schedule">
<table class="form-table">
<tr>
<th><label for="sched_message">Nachricht</label></th>
<td><textarea name="sched_message" id="sched_message" rows="3" class="large-text" required></textarea></td>
</tr>
<tr>
<th><label for="sched_time">Zeit (YYYY-MM-DD HH:MM, Server-Zeitzone)</label></th>
<td>
<input name="sched_time" id="sched_time" type="datetime-local" class="regular-text" required>
<p class="description">Beispiel: <?php echo esc_html(date('Y-m-d\TH:i', strtotime('+1 hour'))); ?> (in einer Stunde)</p>
</td>
</tr>
<tr>
<th><label for="sched_recur">Wiederholung</label></th>
<td>
<select name="sched_recur" id="sched_recur">
<option value="none">Keine</option>
<option value="hourly">Stündlich</option>
<option value="daily">Täglich</option>
<option value="weekly">Wöchentlich</option>
</select>
</td>
</tr>
</table>
<p><button class="button">Planen (serverseitig)</button></p>
</form>
<h3>Aktuelle Zeitgeplante Nachrichten</h3>
<?php if (empty($schedules)): ?>
<p>Keine geplanten Broadcasts.</p>
<?php else: ?>
<table class="widefat">
<thead><tr><th>ID</th><th>Nachricht</th><th>Sendezeit (Lokal)</th><th>Sendezeit (UTC)</th><th>Status</th><th>Wiederholung</th><th>Aktionen</th></tr></thead>
<tbody>
<?php foreach ($schedules as $id => $s):
$local_time = get_date_from_gmt(gmdate('Y-m-d H:i:s', $s['time']), 'Y-m-d H:i:s');
$utc_time = gmdate('Y-m-d H:i:s', $s['time']);
$now = time();
$is_past = $s['time'] <= $now;
$status = $is_past ? '⚠️ Verpasst/Verarbeitet' : '⏰ Geplant';
?>
<tr style="<?php echo $is_past ? 'opacity: 0.6;' : ''; ?>">
<td><?php echo esc_html($id); ?></td>
<td><?php echo esc_html($s['message']); ?></td>
<td><?php echo esc_html($local_time); ?></td>
<td><?php echo esc_html($utc_time); ?></td>
<td><?php echo esc_html($status); ?></td>
<td><?php echo esc_html($s['recur']); ?></td>
<td>
<form style="display:inline" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
<?php wp_nonce_field('pulsecast_delete_schedule_'.$id); ?>
<input type="hidden" name="action" value="pulsecast_delete_schedule">
<input type="hidden" name="id" value="<?php echo esc_attr($id); ?>">
<button class="button button-small" onclick="return confirm('Schedule löschen?');">Löschen</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<p class="description">Hinweis: Alle Broadcasts werden global gesendet.</p>
</div>
<?php
}
public function handle_send_post() {
if (!current_user_can('manage_options')) wp_die('Forbidden');
check_admin_referer('pulsecast_send_now');
$settings = get_option(self::OPTION_KEY, []);
$message = sanitize_textarea_field($_POST['message'] ?? '');
$type = 'global';
$prefix = $settings['broadcast_prefix'] ?? '[Broadcast]';
$prefix_color = $settings['broadcast_prefix_color'] ?? '&c';
$bracket_color = $settings['broadcast_bracket_color'] ?? '&8'; // Neu
$message_color = $settings['broadcast_message_color'] ?? '&f';
if (empty($message)) {
wp_redirect(add_query_arg('pulsecast_error', 'empty_message', wp_get_referer()));
exit;
}
$res = $this->send_to_api($message, $type, $prefix, $prefix_color, $bracket_color, $message_color);
$code = is_wp_error($res) ? 'error' : 'ok';
wp_redirect(add_query_arg('pulsecast_status', $code, wp_get_referer()));
exit;
}
public function handle_schedule_post() {
if (!current_user_can('manage_options')) wp_die('Forbidden');
if (isset($_POST['_wpnonce']) && wp_verify_nonce($_POST['_wpnonce'], 'pulsecast_save_settings')) {
check_admin_referer('pulsecast_save_settings');
$settings = get_option(self::OPTION_KEY, []);
$settings['api_url'] = esc_url_raw($_POST['api_url'] ?? '');
$settings['api_key'] = sanitize_text_field($_POST['api_key'] ?? '');
$settings['broadcast_prefix'] = sanitize_text_field($_POST['broadcast_prefix'] ?? '[Broadcast]');
$settings['broadcast_prefix_color'] = sanitize_text_field($_POST['broadcast_prefix_color'] ?? '&c');
$settings['broadcast_bracket_color'] = sanitize_text_field($_POST['broadcast_bracket_color'] ?? '&8'); // Neu
$settings['broadcast_message_color'] = sanitize_text_field($_POST['broadcast_message_color'] ?? '&f');
update_option(self::OPTION_KEY, $settings);
wp_redirect(add_query_arg('pulsecast_status', 'settings_saved', wp_get_referer()));
exit;
}
check_admin_referer('pulsecast_schedule_new');
$message = sanitize_textarea_field($_POST['sched_message'] ?? '');
$timeRaw = sanitize_text_field($_POST['sched_time'] ?? '');
$recur = sanitize_text_field($_POST['sched_recur'] ?? 'none');
$type = 'global';
$settings = get_option(self::OPTION_KEY, []);
$prefix = sanitize_text_field($_POST['sched_prefix'] ?? '');
$prefix_color = sanitize_text_field($_POST['sched_prefix_color'] ?? '');
$bracket_color = sanitize_text_field($_POST['sched_bracket_color'] ?? ''); // Neu
$message_color = sanitize_text_field($_POST['sched_message_color'] ?? '');
if (empty($prefix)) $prefix = $settings['broadcast_prefix'] ?? '[Broadcast]';
if (empty($prefix_color)) $prefix_color = $settings['broadcast_prefix_color'] ?? '&c';
if (empty($bracket_color)) $bracket_color = $settings['broadcast_bracket_color'] ?? '&8'; // Neu
if (empty($message_color)) $message_color = $settings['broadcast_message_color'] ?? '&f';
if (empty($message) || empty($timeRaw)) {
wp_redirect(add_query_arg('pulsecast_error', 'empty_fields', wp_get_referer()));
exit;
}
$timeRaw = str_replace('T', ' ', $timeRaw);
$local_timestamp = strtotime($timeRaw);
if ($local_timestamp === false || $local_timestamp <= 0) {
wp_redirect(add_query_arg('pulsecast_error', 'bad_time', wp_get_referer()));
exit;
}
$utc_datetime = get_gmt_from_date(date('Y-m-d H:i:s', $local_timestamp), 'Y-m-d H:i:s');
$timestamp_utc = strtotime($utc_datetime . ' UTC');
$schedules = get_option(self::SCHEDULES_KEY, []);
$id = (string) time() . rand(1000,9999);
$schedules[$id] = [
'message' => $message,
'time' => $timestamp_utc,
'recur' => $recur,
'type' => $type,
'prefix' => $prefix,
'prefix_color' => $prefix_color,
'bracket_color' => $bracket_color, // Neu
'message_color' => $message_color,
];
update_option(self::SCHEDULES_KEY, $schedules);
$sent = $this->send_schedule_to_api($id, $schedules[$id]);
if (is_wp_error($sent)) {
wp_redirect(add_query_arg('pulsecast_error', 'register_failed', wp_get_referer()));
} else {
wp_redirect(add_query_arg('pulsecast_status', 'scheduled_server', wp_get_referer()));
}
exit;
}
public function handle_resync_post() {
if (!current_user_can('manage_options')) wp_die('Forbidden');
check_admin_referer('pulsecast_resync_action');
$schedules = get_option(self::SCHEDULES_KEY, []);
$count = 0;
$errors = 0;
foreach ($schedules as $id => $s) {
$res = $this->send_schedule_to_api($id, $s);
if (is_wp_error($res)) {
$errors++;
} else {
$count++;
}
}
$msg = "$count Broadcasts synchronisiert.";
if ($errors > 0) {
$msg .= " $errors Fehler sind aufgetreten.";
}
wp_redirect(add_query_arg('pulsecast_status', $msg, wp_get_referer()));
exit;
}
public function handle_delete_schedule() {
if (!current_user_can('manage_options')) wp_die('Forbidden');
$id = sanitize_text_field($_POST['id'] ?? '');
check_admin_referer('pulsecast_delete_schedule_'.$id);
$schedules = get_option(self::SCHEDULES_KEY, []);
if (isset($schedules[$id])) {
$this->send_cancel_schedule_to_api($id);
unset($schedules[$id]);
update_option(self::SCHEDULES_KEY, $schedules);
}
wp_redirect(remove_query_arg(['pulsecast_error','pulsecast_status'], wp_get_referer()));
exit;
}
public function cron_send_broadcast($id) {
$schedules = get_option(self::SCHEDULES_KEY, []);
if (!isset($schedules[$id])) return;
$s = $schedules[$id];
$res = $this->send_to_api(
$s['message'],
$s['type'] ?? 'global',
$s['prefix'] ?? '',
$s['prefix_color'] ?? '',
$s['bracket_color'] ?? '', // Neu
$s['message_color'] ?? ''
);
$log = get_option(self::OPTION_KEY . '_last_logs', []);
$entry = [
'time' => time(),
'id' => $id,
'result' => is_wp_error($res) ? $res->get_error_message() : 'ok'
];
$log[] = $entry;
if (count($log) > 50) array_shift($log);
update_option(self::OPTION_KEY . '_last_logs', $log);
if (($s['recur'] ?? 'none') !== 'none') {
$next = $this->compute_next_timestamp($s['time'], $s['recur']);
if ($next !== null) {
$schedules[$id]['time'] = $next;
update_option(self::SCHEDULES_KEY, $schedules);
}
} else {
unset($schedules[$id]);
update_option(self::SCHEDULES_KEY, $schedules);
}
}
private function compute_next_timestamp($currentTimestamp, $recur) {
switch ($recur) {
case 'hourly': return $currentTimestamp + HOUR_IN_SECONDS;
case 'daily': return $currentTimestamp + DAY_IN_SECONDS;
case 'weekly': return $currentTimestamp + WEEK_IN_SECONDS;
default: return null;
}
}
private function build_final_api_url($raw_url) {
$raw = trim($raw_url);
if ($raw === '') return '';
if (!preg_match('#^https?://#i', $raw)) {
$raw = 'http://' . $raw;
}
$parts = parse_url($raw);
if ($parts === false || empty($parts['host'])) return '';
$scheme = $parts['scheme'] ?? 'http';
$host = $parts['host'];
$port = $parts['port'] ?? 9191;
$path = $parts['path'] ?? '/broadcast';
if (substr($path, -1) === '/') $path = rtrim($path, '/');
if ($path === '') $path = '/broadcast';
$url = $scheme . '://' . $host . ($port ? ':' . $port : '') . $path;
return $url;
}
private function send_to_api($message, $type = 'global', $prefix_override = '', $prefix_color = '', $bracket_color = '', $message_color = '') {
$settings = get_option(self::OPTION_KEY, []);
$raw = rtrim($settings['api_url'] ?? '', '/');
$api_key = $settings['api_key'] ?? '';
$default_prefix = $settings['broadcast_prefix'] ?? '';
$default_prefix_color = $settings['broadcast_prefix_color'] ?? '&c';
$default_bracket_color = $settings['broadcast_bracket_color'] ?? '&8'; // Neu
$default_message_color = $settings['broadcast_message_color'] ?? '&f';
if (empty($raw)) {
return new WP_Error('no_url', 'StatusAPI URL ist nicht konfiguriert.');
}
$final_url = $this->build_final_api_url($raw);
if (empty($final_url)) {
return new WP_Error('bad_url', 'StatusAPI URL ist ungültig.');
}
$payload_prefix = ($prefix_override !== '' ? $prefix_override : $default_prefix);
$payload_prefix_color = ($prefix_color !== '' ? $prefix_color : $default_prefix_color);
$payload_bracket_color = ($bracket_color !== '' ? $bracket_color : $default_bracket_color); // Neu
$payload_message_color = ($message_color !== '' ? $message_color : $default_message_color);
$payload = [
'message' => $message,
'type' => $type,
'prefix' => $payload_prefix,
'prefixColor' => $payload_prefix_color,
'bracketColor' => $payload_bracket_color, // Neu
'messageColor' => $payload_message_color,
'meta' => [
'source' => 'PulseCast-WordPress',
'time' => gmdate('c'),
],
];
$args = [
'body' => wp_json_encode($payload),
'headers' => [
'Content-Type' => 'application/json',
],
'timeout' => 15,
];
if (!empty($api_key)) {
$args['headers']['X-Api-Key'] = $api_key;
}
$response = wp_remote_post($final_url, $args);
if (is_wp_error($response)) {
return $response;
}
$code = wp_remote_retrieve_response_code($response);
if ($code < 200 || $code >= 300) {
return new WP_Error('http_error', 'HTTP ' . $code . ': ' . wp_remote_retrieve_response_message($response));
}
return true;
}
private function send_schedule_to_api($localId, $schedule) {
$settings = get_option(self::OPTION_KEY, []);
$raw = rtrim($settings['api_url'] ?? '', '/');
$api_key = $settings['api_key'] ?? '';
if (empty($raw)) {
return new WP_Error('no_url', 'StatusAPI URL ist nicht konfiguriert.');
}
$final_url = $this->build_final_api_url($raw);
if (empty($final_url)) {
return new WP_Error('bad_url', 'StatusAPI URL ist ungültig.');
}
$timeSec = intval($schedule['time'] ?? 0);
$timeMs = $timeSec * 1000;
$payload = [
'message' => $schedule['message'] ?? '',
'type' => 'global',
'prefix' => $schedule['prefix'] ?? '',
'prefixColor' => $schedule['prefix_color'] ?? '',
'bracketColor' => $schedule['bracket_color'] ?? '', // Neu
'messageColor' => $schedule['message_color'] ?? '',
'scheduleTime' => $timeMs,
'recur' => $schedule['recur'] ?? 'none',
'clientScheduleId' => $localId,
'meta' => [
'source' => 'PulseCast-WordPress',
'time' => gmdate('c'),
'timezone' => 'UTC',
],
];
$args = [
'body' => wp_json_encode($payload),
'headers' => [
'Content-Type' => 'application/json',
],
'timeout' => 15,
];
if (!empty($api_key)) $args['headers']['X-Api-Key'] = $api_key;
$response = wp_remote_post($final_url, $args);
if (is_wp_error($response)) {
return $response;
}
$code = wp_remote_retrieve_response_code($response);
if ($code < 200 || $code >= 300) {
return new WP_Error('http_error', 'HTTP ' . $code . ': ' . wp_remote_retrieve_response_message($response));
}
return true;
}
private function send_cancel_schedule_to_api($localId) {
$settings = get_option(self::OPTION_KEY, []);
$raw = rtrim($settings['api_url'] ?? '', '/');
$api_key = $settings['api_key'] ?? '';
if (empty($raw)) return new WP_Error('no_url', 'no api');
$base = $this->build_final_api_url($raw);
if (empty($base)) return new WP_Error('bad_url', 'bad');
$cancelUrl = rtrim($base, '/') . '/cancel';
$payload = [
'clientScheduleId' => $localId,
'meta' => ['source' => 'PulseCast-WordPress', 'time' => gmdate('c')],
];
$args = [
'body' => wp_json_encode($payload),
'headers' => ['Content-Type' => 'application/json'],
'timeout' => 10,
];
if (!empty($api_key)) $args['headers']['X-Api-Key'] = $api_key;
return wp_remote_post($cancelUrl, $args);
}
}
new PulseCast();