Files
Workshop-Wahlen/includes/api.php
ProgrammGamer 73ad38423d
All checks were successful
Deploy Workshop-Wahlen (DEV / PROD) / deploy (push) Successful in 12s
Implement feature X to enhance user experience and fix bug Y in module Z
2026-02-25 18:51:54 +01:00

1484 lines
56 KiB
PHP

<?php
if (!defined('ABSPATH')) exit;
function kc_api_permission_check() {
if (!is_user_logged_in()) {
return new WP_Error(
'kc_api_auth_required',
'Authentifizierung erforderlich.',
['status' => 401]
);
}
if (!current_user_can('manage_options')) {
return new WP_Error(
'kc_api_forbidden',
'Keine Berechtigung für diese API.',
['status' => 403]
);
}
return true;
}
function kc_api_owner_permission_check() {
$base = kc_api_permission_check();
if (is_wp_error($base)) {
return $base;
}
$current = wp_get_current_user();
if (!$current || intval($current->ID) !== 1) {
return new WP_Error('kc_api_owner_only', 'Nur Owner (User ID 1) erlaubt.', ['status' => 403]);
}
return true;
}
function kc_api_request_data(WP_REST_Request $request) {
$json = $request->get_json_params();
if (is_array($json) && !empty($json)) {
return $json;
}
$params = $request->get_params();
return is_array($params) ? $params : [];
}
function kc_api_bool($value) {
if (is_bool($value)) return $value;
if (is_numeric($value)) return intval($value) === 1;
if (is_string($value)) {
$v = strtolower(trim($value));
return in_array($v, ['1', 'true', 'yes', 'ja', 'on'], true);
}
return false;
}
function kc_api_ensure_workshop_teamer_columns() {
global $wpdb;
$prefix = $wpdb->prefix;
$columns = $wpdb->get_col("SHOW COLUMNS FROM {$prefix}kc_workshop_teamer");
if (!in_array('wahl_id', $columns, true)) {
$wpdb->query("ALTER TABLE {$prefix}kc_workshop_teamer ADD COLUMN wahl_id INT(11) NULL DEFAULT NULL");
}
if (!in_array('phase', $columns, true)) {
$wpdb->query("ALTER TABLE {$prefix}kc_workshop_teamer ADD COLUMN phase INT(11) NULL DEFAULT NULL");
}
}
function kc_api_validate_teilnehmer_payload($data, $exclude_id = 0) {
global $wpdb;
$prefix = $wpdb->prefix;
$vorname = sanitize_text_field($data['vorname'] ?? '');
$nachname = sanitize_text_field($data['nachname'] ?? '');
$wahl_id = intval($data['wahl_id'] ?? 0);
$phase = intval($data['phase'] ?? 0);
$w1 = intval($data['wunsch1'] ?? 0);
$w2 = intval($data['wunsch2'] ?? 0);
$w3 = intval($data['wunsch3'] ?? 0);
if ($vorname === '' || $nachname === '' || $wahl_id <= 0 || $phase <= 0 || $w1 <= 0 || $w2 <= 0 || $w3 <= 0) {
return new WP_Error('kc_api_invalid_input', 'Pflichtfelder fehlen oder sind ungültig.', ['status' => 400]);
}
if (count(array_unique([$w1, $w2, $w3])) !== 3) {
return new WP_Error('kc_api_duplicate_wishes', 'Wünsche müssen unterschiedlich sein.', ['status' => 400]);
}
$wahl_row = $wpdb->get_row($wpdb->prepare("SELECT id, anzahl_einheiten FROM {$prefix}kc_wahlen WHERE id=%d AND deleted=0", $wahl_id));
if (!$wahl_row) {
return new WP_Error('kc_api_wahl_not_found', 'Wahl nicht gefunden.', ['status' => 404]);
}
$max_ph = max(1, intval($wahl_row->anzahl_einheiten));
if ($phase < 1 || $phase > $max_ph) {
return new WP_Error('kc_api_invalid_phase', 'Ungültige Phase für diese Wahl.', ['status' => 400]);
}
$norm_v = mb_strtolower(trim($vorname));
$norm_n = mb_strtolower(trim($nachname));
if ($exclude_id > 0) {
$exists = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$prefix}kc_teilnehmer WHERE LOWER(TRIM(vorname))=%s AND LOWER(TRIM(nachname))=%s AND wahl_id=%d AND id<>%d",
$norm_v,
$norm_n,
$wahl_id,
$exclude_id
));
} else {
$exists = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$prefix}kc_teilnehmer WHERE LOWER(TRIM(vorname))=%s AND LOWER(TRIM(nachname))=%s AND wahl_id=%d",
$norm_v,
$norm_n,
$wahl_id
));
}
if (intval($exists) > 0) {
return new WP_Error('kc_api_duplicate_participant', 'Diese Kombination aus Vorname/Nachname existiert bereits in der Wahl.', ['status' => 409]);
}
$allowed = $wpdb->get_col($wpdb->prepare("SELECT workshop_id FROM {$prefix}kc_wahl_workshops WHERE wahl_id=%d", $wahl_id));
$allowed = array_map('intval', (array) $allowed);
if (!empty($allowed)) {
foreach ([$w1, $w2, $w3] as $wid) {
if (!in_array(intval($wid), $allowed, true)) {
return new WP_Error('kc_api_invalid_workshop_for_wahl', 'Mindestens ein Wunsch gehört nicht zur Wahl.', ['status' => 400]);
}
}
}
return [
'vorname' => $vorname,
'nachname' => $nachname,
'wahl_id' => $wahl_id,
'phase' => $phase,
'wunsch1' => $w1,
'wunsch2' => $w2,
'wunsch3' => $w3,
];
}
function kc_api_get_status(WP_REST_Request $request) {
$user = wp_get_current_user();
return rest_ensure_response([
'success' => true,
'authenticated' => is_user_logged_in(),
'authorized' => current_user_can('manage_options'),
'user' => [
'id' => intval($user->ID),
'login' => (string) $user->user_login,
'display_name' => (string) $user->display_name,
],
]);
}
function kc_api_get_wahlen(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$rows = $wpdb->get_results("SELECT * FROM {$prefix}kc_wahlen WHERE deleted=0 ORDER BY id DESC");
$items = [];
foreach ((array) $rows as $row) {
$items[] = [
'id' => intval($row->id),
'name' => (string) $row->name,
'beschreibung' => (string) $row->beschreibung,
'anzahl_einheiten' => max(1, intval($row->anzahl_einheiten)),
'min_kapazitaet' => intval($row->min_kapazitaet),
'max_kapazitaet' => intval($row->max_kapazitaet),
'freigegeben' => intval($row->freigegeben) === 1,
];
}
return rest_ensure_response(['success' => true, 'count' => count($items), 'items' => $items]);
}
function kc_api_get_wahl(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wahl_id = intval($request->get_param('id'));
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$prefix}kc_wahlen WHERE id=%d AND deleted=0", $wahl_id));
if (!$row) {
return new WP_Error('kc_api_wahl_not_found', 'Wahl nicht gefunden.', ['status' => 404]);
}
return rest_ensure_response([
'success' => true,
'item' => [
'id' => intval($row->id),
'name' => (string) $row->name,
'beschreibung' => (string) $row->beschreibung,
'anzahl_einheiten' => max(1, intval($row->anzahl_einheiten)),
'min_kapazitaet' => intval($row->min_kapazitaet),
'max_kapazitaet' => intval($row->max_kapazitaet),
'freigegeben' => intval($row->freigegeben) === 1,
]
]);
}
function kc_api_create_wahl(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$data = kc_api_request_data($request);
$name = sanitize_text_field($data['name'] ?? '');
if ($name === '') {
return new WP_Error('kc_api_invalid_name', 'Name ist erforderlich.', ['status' => 400]);
}
$insert = [
'name' => $name,
'beschreibung' => sanitize_textarea_field($data['beschreibung'] ?? ''),
'anzahl_einheiten' => max(1, intval($data['anzahl_einheiten'] ?? 1)),
'freigegeben' => kc_api_bool($data['freigegeben'] ?? false) ? 1 : 0,
'deleted' => 0,
];
if (isset($data['min_kapazitaet'])) $insert['min_kapazitaet'] = intval($data['min_kapazitaet']);
if (isset($data['max_kapazitaet'])) $insert['max_kapazitaet'] = intval($data['max_kapazitaet']);
$wpdb->insert("{$prefix}kc_wahlen", $insert);
return rest_ensure_response([
'success' => true,
'id' => intval($wpdb->insert_id),
'message' => 'Wahl angelegt.'
]);
}
function kc_api_update_wahl(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wahl_id = intval($request->get_param('id'));
$data = kc_api_request_data($request);
$exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$prefix}kc_wahlen WHERE id=%d AND deleted=0", $wahl_id));
if (!$exists) {
return new WP_Error('kc_api_wahl_not_found', 'Wahl nicht gefunden.', ['status' => 404]);
}
$update = [];
if (array_key_exists('name', $data)) $update['name'] = sanitize_text_field($data['name']);
if (array_key_exists('beschreibung', $data)) $update['beschreibung'] = sanitize_textarea_field($data['beschreibung']);
if (array_key_exists('anzahl_einheiten', $data)) $update['anzahl_einheiten'] = max(1, intval($data['anzahl_einheiten']));
if (array_key_exists('freigegeben', $data)) $update['freigegeben'] = kc_api_bool($data['freigegeben']) ? 1 : 0;
if (array_key_exists('min_kapazitaet', $data)) $update['min_kapazitaet'] = intval($data['min_kapazitaet']);
if (array_key_exists('max_kapazitaet', $data)) $update['max_kapazitaet'] = intval($data['max_kapazitaet']);
if (empty($update)) {
return new WP_Error('kc_api_empty_update', 'Keine Felder zum Aktualisieren übergeben.', ['status' => 400]);
}
$wpdb->update("{$prefix}kc_wahlen", $update, ['id' => $wahl_id]);
return rest_ensure_response(['success' => true, 'message' => 'Wahl aktualisiert.']);
}
function kc_api_delete_wahl(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wahl_id = intval($request->get_param('id'));
$exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$prefix}kc_wahlen WHERE id=%d AND deleted=0", $wahl_id));
if (!$exists) {
return new WP_Error('kc_api_wahl_not_found', 'Wahl nicht gefunden.', ['status' => 404]);
}
$wpdb->delete("{$prefix}kc_zuteilung", ['wahl_id' => $wahl_id]);
$wpdb->delete("{$prefix}kc_force_zuteilung", ['wahl_id' => $wahl_id]);
$wpdb->delete("{$prefix}kc_teilnehmer", ['wahl_id' => $wahl_id]);
$wpdb->delete("{$prefix}kc_wahl_workshops", ['wahl_id' => $wahl_id]);
$wpdb->update("{$prefix}kc_wahlen", ['deleted' => 1], ['id' => $wahl_id]);
return rest_ensure_response(['success' => true, 'message' => 'Wahl gelöscht (soft delete + Cascade).']);
}
function kc_api_get_wahl_workshops(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wahl_id = intval($request->get_param('id'));
$wahl = $wpdb->get_row($wpdb->prepare("SELECT id, name, anzahl_einheiten FROM {$prefix}kc_wahlen WHERE id=%d AND deleted=0", $wahl_id));
if (!$wahl) {
return new WP_Error('kc_api_wahl_not_found', 'Wahl nicht gefunden.', ['status' => 404]);
}
$rows = $wpdb->get_results($wpdb->prepare(
"SELECT ww.phase, ww.workshop_id, ws.name
FROM {$prefix}kc_wahl_workshops ww
JOIN {$prefix}kc_workshops ws ON ws.id = ww.workshop_id
WHERE ww.wahl_id = %d
ORDER BY ww.phase ASC, ws.name ASC",
$wahl_id
));
$phases = [];
foreach ((array) $rows as $row) {
$phase = intval($row->phase ?: 1);
if (!isset($phases[$phase])) $phases[$phase] = [];
$phases[$phase][] = [
'workshop_id' => intval($row->workshop_id),
'workshop_name' => (string) $row->name,
];
}
return rest_ensure_response([
'success' => true,
'wahl' => ['id' => intval($wahl->id), 'name' => (string) $wahl->name, 'anzahl_einheiten' => max(1, intval($wahl->anzahl_einheiten))],
'phases' => $phases,
]);
}
function kc_api_set_wahl_workshops(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wahl_id = intval($request->get_param('id'));
$body = kc_api_request_data($request);
$wahl = $wpdb->get_row($wpdb->prepare("SELECT id, anzahl_einheiten FROM {$prefix}kc_wahlen WHERE id=%d AND deleted=0", $wahl_id));
if (!$wahl) {
return new WP_Error('kc_api_wahl_not_found', 'Wahl nicht gefunden.', ['status' => 404]);
}
$anzahl_einheiten = max(1, intval($wahl->anzahl_einheiten));
$assignments = isset($body['phases']) && is_array($body['phases']) ? $body['phases'] : [];
if (empty($assignments) && !empty($body['workshop_ids']) && is_array($body['workshop_ids'])) {
$assignments = [1 => $body['workshop_ids']];
}
if (empty($assignments)) {
return new WP_Error('kc_api_invalid_assignments', 'phases-Map oder workshop_ids erforderlich.', ['status' => 400]);
}
$wpdb->delete("{$prefix}kc_wahl_workshops", ['wahl_id' => $wahl_id]);
foreach ($assignments as $phase => $workshop_ids) {
$phase_num = max(1, intval($phase));
if ($phase_num > $anzahl_einheiten) continue;
if (!is_array($workshop_ids)) continue;
foreach ($workshop_ids as $wid) {
$wid = intval($wid);
if ($wid <= 0) continue;
$wpdb->insert("{$prefix}kc_wahl_workshops", [
'wahl_id' => $wahl_id,
'workshop_id' => $wid,
'phase' => $anzahl_einheiten > 1 ? $phase_num : 1,
]);
}
}
return rest_ensure_response(['success' => true, 'message' => 'Workshop-Zuordnung gespeichert.']);
}
function kc_api_get_workshops(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$rows = $wpdb->get_results("SELECT * FROM {$prefix}kc_workshops ORDER BY name ASC");
$items = [];
foreach ((array) $rows as $row) {
$items[] = [
'id' => intval($row->id),
'name' => (string) $row->name,
'beschreibung' => (string) $row->beschreibung,
'max_teilnehmer' => intval($row->max_teilnehmer),
'min_teilnehmer' => isset($row->min_teilnehmer) ? intval($row->min_teilnehmer) : 0,
];
}
return rest_ensure_response(['success' => true, 'count' => count($items), 'items' => $items]);
}
function kc_api_get_workshop(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wid = intval($request->get_param('id'));
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$prefix}kc_workshops WHERE id=%d", $wid));
if (!$row) {
return new WP_Error('kc_api_workshop_not_found', 'Workshop nicht gefunden.', ['status' => 404]);
}
return rest_ensure_response([
'success' => true,
'item' => [
'id' => intval($row->id),
'name' => (string) $row->name,
'beschreibung' => (string) $row->beschreibung,
'max_teilnehmer' => intval($row->max_teilnehmer),
'min_teilnehmer' => isset($row->min_teilnehmer) ? intval($row->min_teilnehmer) : 0,
]
]);
}
function kc_api_create_workshop(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$data = kc_api_request_data($request);
$name = sanitize_text_field($data['name'] ?? '');
if ($name === '') {
return new WP_Error('kc_api_invalid_name', 'Name ist erforderlich.', ['status' => 400]);
}
$col = $wpdb->get_var("SHOW COLUMNS FROM {$prefix}kc_workshops LIKE 'min_teilnehmer'");
if (empty($col)) {
$wpdb->query("ALTER TABLE {$prefix}kc_workshops ADD COLUMN min_teilnehmer INT NOT NULL DEFAULT 0");
}
$wpdb->insert("{$prefix}kc_workshops", [
'name' => $name,
'beschreibung' => sanitize_text_field($data['beschreibung'] ?? ''),
'max_teilnehmer' => intval($data['max_teilnehmer'] ?? 0),
'min_teilnehmer' => intval($data['min_teilnehmer'] ?? 0),
]);
return rest_ensure_response(['success' => true, 'id' => intval($wpdb->insert_id), 'message' => 'Workshop angelegt.']);
}
function kc_api_update_workshop(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wid = intval($request->get_param('id'));
$data = kc_api_request_data($request);
$exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$prefix}kc_workshops WHERE id=%d", $wid));
if (!$exists) {
return new WP_Error('kc_api_workshop_not_found', 'Workshop nicht gefunden.', ['status' => 404]);
}
$update = [];
if (array_key_exists('name', $data)) $update['name'] = sanitize_text_field($data['name']);
if (array_key_exists('beschreibung', $data)) $update['beschreibung'] = sanitize_text_field($data['beschreibung']);
if (array_key_exists('max_teilnehmer', $data)) $update['max_teilnehmer'] = intval($data['max_teilnehmer']);
if (array_key_exists('min_teilnehmer', $data)) $update['min_teilnehmer'] = intval($data['min_teilnehmer']);
if (empty($update)) {
return new WP_Error('kc_api_empty_update', 'Keine Felder zum Aktualisieren übergeben.', ['status' => 400]);
}
$wpdb->update("{$prefix}kc_workshops", $update, ['id' => $wid]);
return rest_ensure_response(['success' => true, 'message' => 'Workshop aktualisiert.']);
}
function kc_api_delete_workshop(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wid = intval($request->get_param('id'));
$exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$prefix}kc_workshops WHERE id=%d", $wid));
if (!$exists) {
return new WP_Error('kc_api_workshop_not_found', 'Workshop nicht gefunden.', ['status' => 404]);
}
$wpdb->delete("{$prefix}kc_workshops", ['id' => $wid]);
return rest_ensure_response(['success' => true, 'message' => 'Workshop gelöscht.']);
}
function kc_api_get_workshop_teamer(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wid = intval($request->get_param('id'));
kc_api_ensure_workshop_teamer_columns();
$rows = $wpdb->get_results($wpdb->prepare(
"SELECT wt.id, wt.teamer_id, wt.wahl_id, wt.phase, t.vorname, t.nachname
FROM {$prefix}kc_workshop_teamer wt
JOIN {$prefix}kc_teamer t ON t.id = wt.teamer_id
WHERE wt.workshop_id=%d
ORDER BY wt.wahl_id ASC, wt.phase ASC, t.vorname ASC",
$wid
));
$fixed = [];
$scoped = [];
foreach ((array) $rows as $row) {
$entry = [
'teamer_id' => intval($row->teamer_id),
'name' => trim($row->vorname . ' ' . $row->nachname),
'wahl_id' => $row->wahl_id !== null ? intval($row->wahl_id) : null,
'phase' => $row->phase !== null ? intval($row->phase) : null,
];
if ($entry['wahl_id'] === null && $entry['phase'] === null) {
$fixed[] = $entry;
} else {
$scoped[] = $entry;
}
}
return rest_ensure_response(['success' => true, 'workshop_id' => $wid, 'fixed' => $fixed, 'scoped' => $scoped]);
}
function kc_api_set_workshop_teamer(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wid = intval($request->get_param('id'));
$data = kc_api_request_data($request);
kc_api_ensure_workshop_teamer_columns();
$teamer_ids = isset($data['teamer_ids']) && is_array($data['teamer_ids']) ? array_map('intval', $data['teamer_ids']) : [];
$teamer_ids = array_values(array_unique(array_filter($teamer_ids, function($v) { return $v > 0; })));
$is_fixed = kc_api_bool($data['fixed'] ?? false);
$wahl_id = array_key_exists('wahl_id', $data) ? intval($data['wahl_id']) : null;
$phase = array_key_exists('phase', $data) ? intval($data['phase']) : null;
if ($is_fixed) {
$wpdb->query($wpdb->prepare(
"DELETE FROM {$prefix}kc_workshop_teamer WHERE workshop_id=%d AND wahl_id IS NULL AND phase IS NULL",
$wid
));
} else {
if ($wahl_id === null || $wahl_id <= 0) {
return new WP_Error('kc_api_invalid_scope', 'Für scoped-Zuordnung ist wahl_id erforderlich.', ['status' => 400]);
}
if ($phase !== null && $phase > 0) {
$wpdb->delete("{$prefix}kc_workshop_teamer", [
'workshop_id' => $wid,
'wahl_id' => $wahl_id,
'phase' => $phase,
]);
} else {
$wpdb->query($wpdb->prepare(
"DELETE FROM {$prefix}kc_workshop_teamer WHERE workshop_id=%d AND wahl_id=%d AND phase IS NULL",
$wid,
$wahl_id
));
$phase = null;
}
}
foreach ($teamer_ids as $tid) {
$wpdb->insert("{$prefix}kc_workshop_teamer", [
'workshop_id' => $wid,
'teamer_id' => $tid,
'wahl_id' => $is_fixed ? null : $wahl_id,
'phase' => $is_fixed ? null : $phase,
]);
}
return rest_ensure_response(['success' => true, 'message' => 'Teamer-Zuordnung gespeichert.', 'count' => count($teamer_ids)]);
}
function kc_api_get_teamer(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$id = intval($request->get_param('id'));
if ($id > 0) {
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$prefix}kc_teamer WHERE id=%d", $id));
if (!$row) return new WP_Error('kc_api_teamer_not_found', 'Teamer nicht gefunden.', ['status' => 404]);
return rest_ensure_response(['success' => true, 'item' => ['id' => intval($row->id), 'vorname' => (string) $row->vorname, 'nachname' => (string) $row->nachname]]);
}
$rows = $wpdb->get_results("SELECT * FROM {$prefix}kc_teamer ORDER BY vorname ASC");
$items = [];
foreach ((array) $rows as $row) {
$items[] = ['id' => intval($row->id), 'vorname' => (string) $row->vorname, 'nachname' => (string) $row->nachname];
}
return rest_ensure_response(['success' => true, 'count' => count($items), 'items' => $items]);
}
function kc_api_create_teamer(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$data = kc_api_request_data($request);
$vorname = sanitize_text_field($data['vorname'] ?? '');
$nachname = sanitize_text_field($data['nachname'] ?? '');
if ($vorname === '') {
return new WP_Error('kc_api_invalid_input', 'Vorname ist erforderlich.', ['status' => 400]);
}
$existing = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$prefix}kc_teamer WHERE vorname=%s AND nachname=%s",
$vorname,
$nachname
));
if (intval($existing) > 0) {
return new WP_Error('kc_api_duplicate_teamer', 'Teamer existiert bereits.', ['status' => 409]);
}
$wpdb->insert("{$prefix}kc_teamer", ['vorname' => $vorname, 'nachname' => $nachname]);
return rest_ensure_response(['success' => true, 'id' => intval($wpdb->insert_id), 'message' => 'Teamer angelegt.']);
}
function kc_api_update_teamer(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$id = intval($request->get_param('id'));
$data = kc_api_request_data($request);
$exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$prefix}kc_teamer WHERE id=%d", $id));
if (!$exists) return new WP_Error('kc_api_teamer_not_found', 'Teamer nicht gefunden.', ['status' => 404]);
$update = [];
if (array_key_exists('vorname', $data)) $update['vorname'] = sanitize_text_field($data['vorname']);
if (array_key_exists('nachname', $data)) $update['nachname'] = sanitize_text_field($data['nachname']);
if (empty($update)) return new WP_Error('kc_api_empty_update', 'Keine Felder zum Aktualisieren übergeben.', ['status' => 400]);
$wpdb->update("{$prefix}kc_teamer", $update, ['id' => $id]);
return rest_ensure_response(['success' => true, 'message' => 'Teamer aktualisiert.']);
}
function kc_api_delete_teamer(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$id = intval($request->get_param('id'));
$exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$prefix}kc_teamer WHERE id=%d", $id));
if (!$exists) return new WP_Error('kc_api_teamer_not_found', 'Teamer nicht gefunden.', ['status' => 404]);
$wpdb->delete("{$prefix}kc_teamer", ['id' => $id]);
return rest_ensure_response(['success' => true, 'message' => 'Teamer gelöscht.']);
}
function kc_api_set_teamer_password(WP_REST_Request $request) {
$data = kc_api_request_data($request);
$password = trim((string)($data['password'] ?? ''));
if ($password === '') {
delete_option('kc_teamer_password_hash');
return rest_ensure_response(['success' => true, 'message' => 'Teamer-Passwort entfernt.']);
}
update_option('kc_teamer_password_hash', wp_hash_password($password));
return rest_ensure_response(['success' => true, 'message' => 'Teamer-Passwort gespeichert.']);
}
function kc_api_get_teilnehmer(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$id = intval($request->get_param('id'));
if ($id > 0) {
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$prefix}kc_teilnehmer WHERE id=%d", $id));
if (!$row) return new WP_Error('kc_api_tn_not_found', 'Teilnehmer nicht gefunden.', ['status' => 404]);
return rest_ensure_response(['success' => true, 'item' => $row]);
}
$wahl_id = intval($request->get_param('wahl_id'));
$phase = intval($request->get_param('phase'));
$sql = "SELECT * FROM {$prefix}kc_teilnehmer";
$where = [];
$args = [];
if ($wahl_id > 0) {
$where[] = 'wahl_id=%d';
$args[] = $wahl_id;
}
if ($phase > 0) {
$where[] = 'phase=%d';
$args[] = $phase;
}
if (!empty($where)) {
$sql .= ' WHERE ' . implode(' AND ', $where);
$sql = $wpdb->prepare($sql, $args);
}
$sql .= ' ORDER BY wahl_id, phase, nachname, vorname';
$rows = $wpdb->get_results($sql);
return rest_ensure_response(['success' => true, 'count' => count((array)$rows), 'items' => $rows]);
}
function kc_api_create_teilnehmer(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$data = kc_api_request_data($request);
$validated = kc_api_validate_teilnehmer_payload($data, 0);
if (is_wp_error($validated)) return $validated;
$wpdb->insert("{$prefix}kc_teilnehmer", $validated);
return rest_ensure_response(['success' => true, 'id' => intval($wpdb->insert_id), 'message' => 'Teilnehmer angelegt.']);
}
function kc_api_update_teilnehmer(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$id = intval($request->get_param('id'));
$exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$prefix}kc_teilnehmer WHERE id=%d", $id));
if (!$exists) return new WP_Error('kc_api_tn_not_found', 'Teilnehmer nicht gefunden.', ['status' => 404]);
$data = kc_api_request_data($request);
$validated = kc_api_validate_teilnehmer_payload($data, $id);
if (is_wp_error($validated)) return $validated;
$wpdb->update("{$prefix}kc_teilnehmer", $validated, ['id' => $id]);
return rest_ensure_response(['success' => true, 'message' => 'Teilnehmer aktualisiert.']);
}
function kc_api_delete_teilnehmer(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$id = intval($request->get_param('id'));
$exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$prefix}kc_teilnehmer WHERE id=%d", $id));
if (!$exists) return new WP_Error('kc_api_tn_not_found', 'Teilnehmer nicht gefunden.', ['status' => 404]);
$wpdb->delete("{$prefix}kc_teilnehmer", ['id' => $id]);
return rest_ensure_response(['success' => true, 'message' => 'Teilnehmer gelöscht.']);
}
function kc_api_submit_wahl_anmeldung(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wahl_id = intval($request->get_param('id'));
$wahl = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$prefix}kc_wahlen WHERE id=%d", $wahl_id));
if (!$wahl) {
return new WP_Error('kc_api_wahl_not_found', 'Wahl nicht gefunden.', ['status' => 404]);
}
$data = kc_api_request_data($request);
$vorname = sanitize_text_field($data['vorname'] ?? '');
$nachname = sanitize_text_field($data['nachname'] ?? '');
$wishes = isset($data['wishes']) && is_array($data['wishes']) ? $data['wishes'] : [];
if ($vorname === '' || $nachname === '') {
return new WP_Error('kc_api_invalid_input', 'Vorname und Nachname sind erforderlich.', ['status' => 400]);
}
$norm_v = mb_strtolower(trim($vorname));
$norm_n = mb_strtolower(trim($nachname));
$exists = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$prefix}kc_teilnehmer WHERE LOWER(TRIM(vorname))=%s AND LOWER(TRIM(nachname))=%s AND wahl_id=%d",
$norm_v,
$norm_n,
$wahl_id
));
if (intval($exists) > 0) {
return new WP_Error('kc_api_duplicate_participant', 'Diese Kombination aus Vorname/Nachname existiert bereits für diese Wahl.', ['status' => 409]);
}
$phasen = max(1, intval($wahl->anzahl_einheiten));
$inserted_ids = [];
for ($phase = 1; $phase <= $phasen; $phase++) {
if (empty($wishes[$phase]) || !is_array($wishes[$phase])) {
return new WP_Error('kc_api_missing_phase_wishes', 'Wünsche für jede Phase erforderlich.', ['status' => 400]);
}
$w1 = intval($wishes[$phase][0] ?? 0);
$w2 = intval($wishes[$phase][1] ?? 0);
$w3 = intval($wishes[$phase][2] ?? 0);
if ($w1 <= 0 || $w2 <= 0 || $w3 <= 0 || count(array_unique([$w1, $w2, $w3])) !== 3) {
return new WP_Error('kc_api_invalid_wishes', 'Jede Phase benötigt 3 unterschiedliche Wünsche.', ['status' => 400]);
}
$allowed = $wpdb->get_col($wpdb->prepare("SELECT workshop_id FROM {$prefix}kc_wahl_workshops WHERE wahl_id=%d AND phase=%d", $wahl_id, $phase));
$allowed = array_map('intval', (array)$allowed);
if (!empty($allowed)) {
foreach ([$w1, $w2, $w3] as $wid) {
if (!in_array($wid, $allowed, true)) {
return new WP_Error('kc_api_invalid_workshop_for_phase', 'Ungültige Workshop-Auswahl für Phase ' . intval($phase), ['status' => 400]);
}
}
}
$wpdb->insert("{$prefix}kc_teilnehmer", [
'vorname' => $vorname,
'nachname' => $nachname,
'wahl_id' => $wahl_id,
'phase' => $phase,
'wunsch1' => $w1,
'wunsch2' => $w2,
'wunsch3' => $w3,
'deleted' => 0,
]);
$inserted_ids[] = intval($wpdb->insert_id);
}
return rest_ensure_response([
'success' => true,
'message' => 'Anmeldung gespeichert.',
'participant_ids' => $inserted_ids,
]);
}
function kc_api_get_force_zuteilungen(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$id = intval($request->get_param('id'));
if ($id > 0) {
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$prefix}kc_force_zuteilung WHERE id=%d", $id));
if (!$row) return new WP_Error('kc_api_force_not_found', 'Force-Zuteilung nicht gefunden.', ['status' => 404]);
return rest_ensure_response(['success' => true, 'item' => $row]);
}
$rows = $wpdb->get_results("SELECT * FROM {$prefix}kc_force_zuteilung ORDER BY id DESC");
return rest_ensure_response(['success' => true, 'count' => count((array)$rows), 'items' => $rows]);
}
function kc_api_create_force_zuteilung(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$data = kc_api_request_data($request);
$insert = [
'teilnehmer_id' => intval($data['teilnehmer_id'] ?? 0),
'wahl_id' => intval($data['wahl_id'] ?? 0),
'phase' => intval($data['phase'] ?? 1),
'workshop_id' => intval($data['workshop_id'] ?? 0),
'kommentar' => sanitize_text_field($data['kommentar'] ?? ''),
];
if ($insert['teilnehmer_id'] <= 0 || $insert['wahl_id'] <= 0 || $insert['phase'] <= 0 || $insert['workshop_id'] <= 0) {
return new WP_Error('kc_api_invalid_input', 'Ungültige Force-Zuteilung.', ['status' => 400]);
}
$wpdb->insert("{$prefix}kc_force_zuteilung", $insert);
return rest_ensure_response(['success' => true, 'id' => intval($wpdb->insert_id), 'message' => 'Force-Zuteilung angelegt.']);
}
function kc_api_update_force_zuteilung(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$id = intval($request->get_param('id'));
$data = kc_api_request_data($request);
$exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$prefix}kc_force_zuteilung WHERE id=%d", $id));
if (!$exists) return new WP_Error('kc_api_force_not_found', 'Force-Zuteilung nicht gefunden.', ['status' => 404]);
$update = [];
if (array_key_exists('teilnehmer_id', $data)) $update['teilnehmer_id'] = intval($data['teilnehmer_id']);
if (array_key_exists('wahl_id', $data)) $update['wahl_id'] = intval($data['wahl_id']);
if (array_key_exists('phase', $data)) $update['phase'] = intval($data['phase']);
if (array_key_exists('workshop_id', $data)) $update['workshop_id'] = intval($data['workshop_id']);
if (array_key_exists('kommentar', $data)) $update['kommentar'] = sanitize_text_field($data['kommentar']);
if (empty($update)) return new WP_Error('kc_api_empty_update', 'Keine Felder zum Aktualisieren übergeben.', ['status' => 400]);
$wpdb->update("{$prefix}kc_force_zuteilung", $update, ['id' => $id]);
return rest_ensure_response(['success' => true, 'message' => 'Force-Zuteilung aktualisiert.']);
}
function kc_api_delete_force_zuteilung(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$id = intval($request->get_param('id'));
$exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$prefix}kc_force_zuteilung WHERE id=%d", $id));
if (!$exists) return new WP_Error('kc_api_force_not_found', 'Force-Zuteilung nicht gefunden.', ['status' => 404]);
$wpdb->delete("{$prefix}kc_force_zuteilung", ['id' => $id]);
return rest_ensure_response(['success' => true, 'message' => 'Force-Zuteilung gelöscht.']);
}
function kc_api_get_wahl_zuteilungen(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wahl_id = intval($request->get_param('id'));
if ($wahl_id <= 0) {
return new WP_Error('kc_api_invalid_id', 'Ungültige Wahl-ID.', ['status' => 400]);
}
$wahl = $wpdb->get_row($wpdb->prepare(
"SELECT id, name, anzahl_einheiten FROM {$prefix}kc_wahlen WHERE id=%d AND deleted=0",
$wahl_id
));
if (!$wahl) {
return new WP_Error('kc_api_wahl_not_found', 'Wahl nicht gefunden.', ['status' => 404]);
}
$rows = $wpdb->get_results($wpdb->prepare(
"SELECT z.id, z.teilnehmer_id, z.vorname, z.nachname, z.phase, z.workshop_id, z.wunsch_rang, ws.name AS workshop_name
FROM {$prefix}kc_zuteilung z
LEFT JOIN {$prefix}kc_workshops ws ON ws.id = z.workshop_id
WHERE z.wahl_id = %d
ORDER BY z.phase ASC, z.nachname ASC, z.vorname ASC",
$wahl_id
));
$items = [];
foreach ((array) $rows as $row) {
$items[] = [
'id' => intval($row->id),
'teilnehmer_id' => intval($row->teilnehmer_id),
'vorname' => (string) $row->vorname,
'nachname' => (string) $row->nachname,
'phase' => intval($row->phase),
'workshop_id' => $row->workshop_id !== null ? intval($row->workshop_id) : null,
'workshop_name' => $row->workshop_name !== null ? (string) $row->workshop_name : null,
'wunsch_rang' => $row->wunsch_rang !== null ? intval($row->wunsch_rang) : null,
];
}
return rest_ensure_response([
'success' => true,
'wahl' => [
'id' => intval($wahl->id),
'name' => (string) $wahl->name,
'anzahl_einheiten' => max(1, intval($wahl->anzahl_einheiten)),
],
'count' => count($items),
'items' => $items,
]);
}
function kc_api_run_wahl_zuteilung(WP_REST_Request $request) {
$wahl_id = intval($request->get_param('id'));
if ($wahl_id <= 0) {
return new WP_Error('kc_api_invalid_id', 'Ungültige Wahl-ID.', ['status' => 400]);
}
if (!function_exists('kc_run_zuteilung')) {
return new WP_Error('kc_api_zuteilung_missing', 'Zuteilungsfunktion nicht verfügbar.', ['status' => 500]);
}
kc_run_zuteilung($wahl_id);
return rest_ensure_response(['success' => true, 'message' => 'Zuteilung ausgeführt.', 'wahl_id' => $wahl_id]);
}
function kc_api_delete_wahl_zuteilungen(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wahl_id = intval($request->get_param('id'));
$wpdb->delete("{$prefix}kc_zuteilung", ['wahl_id' => $wahl_id]);
return rest_ensure_response(['success' => true, 'message' => 'Zuteilungen gelöscht.', 'wahl_id' => $wahl_id]);
}
function kc_api_get_wahl_ergebnis(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$wahl_id = intval($request->get_param('id'));
$wahl = $wpdb->get_row($wpdb->prepare("SELECT id, name, freigegeben FROM {$prefix}kc_wahlen WHERE id=%d AND deleted=0", $wahl_id));
if (!$wahl) {
return new WP_Error('kc_api_wahl_not_found', 'Wahl nicht gefunden.', ['status' => 404]);
}
$workshops = $wpdb->get_results($wpdb->prepare(
"SELECT ws.id, ws.name
FROM {$prefix}kc_workshops ws
JOIN {$prefix}kc_wahl_workshops ww ON ws.id = ww.workshop_id
WHERE ww.wahl_id=%d",
$wahl_id
));
$ws_names = [];
foreach ((array) $workshops as $ws) $ws_names[intval($ws->id)] = (string)$ws->name;
$rows = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$prefix}kc_zuteilung WHERE wahl_id=%d", $wahl_id));
$grouped = [];
$not_assigned = [];
foreach ((array) $rows as $row) {
$phase = intval($row->phase);
if ($phase <= 0) continue;
if (!isset($grouped[$phase])) $grouped[$phase] = [];
if (!empty($row->workshop_id) && isset($ws_names[intval($row->workshop_id)])) {
$wid = intval($row->workshop_id);
if (!isset($grouped[$phase][$wid])) {
$grouped[$phase][$wid] = [
'workshop_id' => $wid,
'workshop_name' => $ws_names[$wid],
'teilnehmer' => [],
];
}
$grouped[$phase][$wid]['teilnehmer'][] = [
'id' => intval($row->id),
'teilnehmer_id' => intval($row->teilnehmer_id),
'vorname' => (string)$row->vorname,
'nachname' => (string)$row->nachname,
'wunsch_rang' => intval($row->wunsch_rang),
];
} else {
$not_assigned[] = [
'id' => intval($row->id),
'teilnehmer_id' => intval($row->teilnehmer_id),
'vorname' => (string)$row->vorname,
'nachname' => (string)$row->nachname,
'phase' => $phase,
];
}
}
return rest_ensure_response([
'success' => true,
'wahl' => [
'id' => intval($wahl->id),
'name' => (string)$wahl->name,
'freigegeben' => intval($wahl->freigegeben) === 1,
],
'phases' => $grouped,
'not_assigned' => $not_assigned,
]);
}
function kc_api_create_workshop_by_teamer_password(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$data = kc_api_request_data($request);
$pw = trim((string)($data['teamer_password'] ?? ''));
$vorname = sanitize_text_field($data['vorname'] ?? '');
$nachname = sanitize_text_field($data['nachname'] ?? '');
$ws_name = sanitize_text_field($data['workshop_name'] ?? '');
$min_t = max(0, intval($data['min_teilnehmer'] ?? 0));
$max_t = max(1, intval($data['max_teilnehmer'] ?? 10));
$saved_hash = get_option('kc_teamer_password_hash', '');
if ($pw === '' || empty($saved_hash) || !wp_check_password($pw, $saved_hash)) {
return new WP_Error('kc_api_invalid_teamer_password', 'Teamer-Passwort ungültig.', ['status' => 403]);
}
if ($vorname === '' || $nachname === '' || $ws_name === '') {
return new WP_Error('kc_api_invalid_input', 'Vorname, Nachname und Workshop-Name sind erforderlich.', ['status' => 400]);
}
if ($min_t > $max_t) {
return new WP_Error('kc_api_invalid_capacity', 'min_teilnehmer darf nicht größer als max_teilnehmer sein.', ['status' => 400]);
}
$existing = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$prefix}kc_teamer WHERE vorname=%s AND nachname=%s", $vorname, $nachname));
if ($existing) {
$tid = intval($existing->id);
} else {
$wpdb->insert("{$prefix}kc_teamer", ['vorname' => $vorname, 'nachname' => $nachname]);
$tid = intval($wpdb->insert_id);
}
$col = $wpdb->get_var("SHOW COLUMNS FROM {$prefix}kc_workshops LIKE 'min_teilnehmer'");
if (empty($col)) {
$wpdb->query("ALTER TABLE {$prefix}kc_workshops ADD COLUMN min_teilnehmer INT NOT NULL DEFAULT 0");
}
$wpdb->insert("{$prefix}kc_workshops", [
'name' => $ws_name,
'beschreibung' => '',
'max_teilnehmer' => $max_t,
'min_teilnehmer' => $min_t,
]);
$wid = intval($wpdb->insert_id);
if ($wid <= 0) {
return new WP_Error('kc_api_create_workshop_failed', 'Fehler beim Anlegen des Workshops.', ['status' => 500]);
}
$wpdb->insert("{$prefix}kc_workshop_teamer", ['workshop_id' => $wid, 'teamer_id' => $tid]);
return rest_ensure_response(['success' => true, 'workshop_id' => $wid, 'teamer_id' => $tid, 'message' => 'Workshop angelegt und Teamer zugeordnet.']);
}
function kc_api_generate_testdata(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$data = kc_api_request_data($request);
$num_workshops = max(1, intval($data['num_workshops'] ?? 3));
$num_part_per_phase = max(1, intval($data['num_part_per_phase'] ?? 10));
$phases = max(1, min(4, intval($data['phases'] ?? 2)));
$min_cap = max(1, intval($data['min_capacity'] ?? 4));
$max_cap = max($min_cap, intval($data['max_capacity'] ?? 8));
$created = ['wahlen' => 0, 'workshops' => 0, 'ww' => 0, 'teilnehmer' => 0];
$wahl_name = 'TEST - Zufallswahl ' . time();
$wpdb->insert("{$prefix}kc_wahlen", [
'name' => $wahl_name,
'beschreibung' => 'Automatisch erzeugte zufällige Testdaten',
'anzahl_einheiten' => $phases,
'freigegeben' => 1,
'deleted' => 0,
]);
$wahl_id = intval($wpdb->insert_id);
if ($wahl_id) $created['wahlen']++;
$ws_ids = [];
for ($i = 0; $i < $num_workshops; $i++) {
$cap = rand($min_cap, $max_cap);
$wn = 'TEST - WS ' . ($i + 1) . ' #' . rand(1000, 9999);
$wpdb->insert("{$prefix}kc_workshops", [
'name' => $wn,
'beschreibung' => 'Auto-generated',
'max_teilnehmer' => $cap,
]);
$wid = intval($wpdb->insert_id);
if ($wid) {
$ws_ids[] = $wid;
$created['workshops']++;
for ($ph = 1; $ph <= $phases; $ph++) {
$wpdb->insert("{$prefix}kc_wahl_workshops", ['wahl_id' => $wahl_id, 'workshop_id' => $wid, 'phase' => $ph]);
$created['ww']++;
}
}
}
$firsts = ['Lukas', 'Mia', 'Jonas', 'Emma', 'Noah', 'Hannah', 'Paul', 'Lea', 'Tim', 'Lina', 'Max', 'Sara'];
$lasts = ['Müller', 'Schmidt', 'Schneider', 'Fischer', 'Weber', 'Mayer', 'Wagner', 'Becker', 'Hoffmann', 'Schulz'];
for ($n = 0; $n < $num_part_per_phase; $n++) {
for ($ph = 1; $ph <= $phases; $ph++) {
$fn = $firsts[array_rand($firsts)] . rand(1, 999);
$ln = $lasts[array_rand($lasts)];
$w1 = $ws_ids[array_rand($ws_ids)];
$w2 = $ws_ids[array_rand($ws_ids)];
$w3 = $ws_ids[array_rand($ws_ids)];
$wpdb->insert("{$prefix}kc_teilnehmer", [
'vorname' => $fn,
'nachname' => $ln,
'wahl_id' => $wahl_id,
'phase' => $ph,
'wunsch1' => intval($w1),
'wunsch2' => intval($w2),
'wunsch3' => intval($w3),
'deleted' => 0,
]);
if (intval($wpdb->insert_id)) $created['teilnehmer']++;
}
}
return rest_ensure_response(['success' => true, 'created' => $created, 'wahl_id' => $wahl_id]);
}
function kc_api_clear_testdata(WP_REST_Request $request) {
global $wpdb;
$prefix = $wpdb->prefix;
$test_ws = $wpdb->get_col($wpdb->prepare("SELECT id FROM {$prefix}kc_workshops WHERE name LIKE %s", 'TEST - %'));
if (!empty($test_ws)) {
foreach ($test_ws as $tw) {
$wpdb->delete("{$prefix}kc_workshop_teamer", ['workshop_id' => $tw]);
}
$wpdb->query("DELETE FROM {$prefix}kc_wahl_workshops WHERE workshop_id IN (" . implode(',', array_map('intval', $test_ws)) . ")");
$wpdb->query("DELETE FROM {$prefix}kc_workshops WHERE id IN (" . implode(',', array_map('intval', $test_ws)) . ")");
}
$test_wahlen = $wpdb->get_col($wpdb->prepare("SELECT id FROM {$prefix}kc_wahlen WHERE name LIKE %s", 'TEST - %'));
if (!empty($test_wahlen)) {
$ids = implode(',', array_map('intval', $test_wahlen));
$wpdb->query("DELETE FROM {$prefix}kc_zuteilung WHERE wahl_id IN (" . $ids . ")");
$wpdb->query("DELETE FROM {$prefix}kc_force_zuteilung WHERE wahl_id IN (" . $ids . ")");
$wpdb->query("DELETE FROM {$prefix}kc_teilnehmer WHERE wahl_id IN (" . $ids . ")");
$wpdb->query("DELETE FROM {$prefix}kc_wahl_workshops WHERE wahl_id IN (" . $ids . ")");
$wpdb->query("DELETE FROM {$prefix}kc_wahlen WHERE id IN (" . $ids . ")");
}
return rest_ensure_response(['success' => true, 'message' => 'Alle TEST-Daten wurden entfernt.']);
}
function kc_api_reset_plugin_data(WP_REST_Request $request) {
if (!function_exists('kc_uninstall_tables') || !function_exists('kc_install_tables')) {
return new WP_Error('kc_api_reset_unavailable', 'Reset-Funktionen nicht verfügbar.', ['status' => 500]);
}
kc_uninstall_tables();
kc_install_tables();
return rest_ensure_response(['success' => true, 'message' => 'Plugin-Daten zurückgesetzt (Tabellen neu erstellt).']);
}
add_action('rest_api_init', function() {
register_rest_route('kc-internal/v1', '/status', [
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_status',
'permission_callback' => 'kc_api_permission_check',
]);
register_rest_route('kc-internal/v1', '/wahlen', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_wahlen',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_create_wahl',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/wahlen/(?P<id>\d+)', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_wahl',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => 'kc_api_update_wahl',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::DELETABLE,
'callback' => 'kc_api_delete_wahl',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/wahlen/(?P<id>\d+)/workshops', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_wahl_workshops',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => 'kc_api_set_wahl_workshops',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/wahlen/(?P<id>\d+)/anmeldung', [
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_submit_wahl_anmeldung',
'permission_callback' => 'kc_api_permission_check',
]);
register_rest_route('kc-internal/v1', '/wahlen/(?P<id>\d+)/zuteilungen', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_wahl_zuteilungen',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::DELETABLE,
'callback' => 'kc_api_delete_wahl_zuteilungen',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/wahlen/(?P<id>\d+)/zuteilung/run', [
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_run_wahl_zuteilung',
'permission_callback' => 'kc_api_permission_check',
]);
register_rest_route('kc-internal/v1', '/wahlen/(?P<id>\d+)/ergebnis', [
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_wahl_ergebnis',
'permission_callback' => 'kc_api_permission_check',
]);
register_rest_route('kc-internal/v1', '/workshops', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_workshops',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_create_workshop',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/workshops/(?P<id>\d+)', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_workshop',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => 'kc_api_update_workshop',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::DELETABLE,
'callback' => 'kc_api_delete_workshop',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/workshops/(?P<id>\d+)/teamer', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_workshop_teamer',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => 'kc_api_set_workshop_teamer',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/teamer', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_teamer',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_create_teamer',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/teamer/(?P<id>\d+)', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_teamer',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => 'kc_api_update_teamer',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::DELETABLE,
'callback' => 'kc_api_delete_teamer',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/teamer/password', [
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_set_teamer_password',
'permission_callback' => 'kc_api_permission_check',
]);
register_rest_route('kc-internal/v1', '/teilnehmer', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_teilnehmer',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_create_teilnehmer',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/teilnehmer/(?P<id>\d+)', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_teilnehmer',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => 'kc_api_update_teilnehmer',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::DELETABLE,
'callback' => 'kc_api_delete_teilnehmer',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/force-zuteilungen', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_force_zuteilungen',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_create_force_zuteilung',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/force-zuteilungen/(?P<id>\d+)', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => 'kc_api_get_force_zuteilungen',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => 'kc_api_update_force_zuteilung',
'permission_callback' => 'kc_api_permission_check',
],
[
'methods' => WP_REST_Server::DELETABLE,
'callback' => 'kc_api_delete_force_zuteilung',
'permission_callback' => 'kc_api_permission_check',
],
]);
register_rest_route('kc-internal/v1', '/teamer/workshop-create', [
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_create_workshop_by_teamer_password',
'permission_callback' => 'kc_api_permission_check',
]);
register_rest_route('kc-internal/v1', '/data/test/generate', [
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_generate_testdata',
'permission_callback' => 'kc_api_owner_permission_check',
]);
register_rest_route('kc-internal/v1', '/data/test/clear', [
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_clear_testdata',
'permission_callback' => 'kc_api_owner_permission_check',
]);
register_rest_route('kc-internal/v1', '/data/reset', [
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'kc_api_reset_plugin_data',
'permission_callback' => 'kc_api_owner_permission_check',
]);
});
add_filter('rest_index', function($response) {
if (current_user_can('manage_options')) {
return $response;
}
if (!($response instanceof WP_REST_Response)) {
return $response;
}
$data = $response->get_data();
if (!is_array($data)) {
return $response;
}
if (!empty($data['namespaces']) && is_array($data['namespaces'])) {
$data['namespaces'] = array_values(array_filter($data['namespaces'], function($ns) {
return $ns !== 'kc-internal/v1';
}));
}
if (!empty($data['routes']) && is_array($data['routes'])) {
foreach ($data['routes'] as $route => $route_config) {
if (strpos($route, '/kc-internal/v1/') === 0) {
unset($data['routes'][$route]);
}
}
}
$response->set_data($data);
return $response;
});
add_filter('rest_post_dispatch', function($response, $server, $request) {
if (!($response instanceof WP_REST_Response) || !($request instanceof WP_REST_Request)) {
return $response;
}
$route = $request->get_route();
if (strpos($route, '/kc-internal/v1/') !== 0) {
return $response;
}
if (intval($response->get_status()) === 401) {
$response->header('WWW-Authenticate', 'Basic realm="KC Internal API"');
$response->header('Cache-Control', 'no-store');
}
return $response;
}, 10, 3);