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\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\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\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\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\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\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\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\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\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\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\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);