771 lines
34 KiB
PHP
771 lines
34 KiB
PHP
<?php
|
||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||
|
||
/**
|
||
* MC_Gallery_Forum_Bridge
|
||
*
|
||
* Optionale Integration zwischen MC MultiServer Gallery PRO und WP Business Forum.
|
||
* Wird nur initialisiert wenn beide Plugins aktiv sind (class_exists-Check).
|
||
*
|
||
* Features:
|
||
* - Forum-User können ihren Minecraft-Account im Profil verknüpfen
|
||
* - Verknüpfte + verifizierte User können in der Galerie ohne Ingame-Token hochladen
|
||
* - Admin kann Verknüpfungen in der Forum-Benutzerverwaltung einsehen & bestätigen
|
||
* - Automatische Verifikation wenn ein gültiger Ingame-Token für diesen MC-Namen vorliegt
|
||
*
|
||
* Datenspeicherung: forum_user_meta (bereits vorhanden im Forum-Schema)
|
||
*/
|
||
class MC_Gallery_Forum_Bridge {
|
||
|
||
// Meta-Keys (gespeichert in forum_user_meta)
|
||
const META_MC_USER = 'mc_linked_username';
|
||
const META_MC_SERVER = 'mc_linked_server';
|
||
const META_VERIFIED = 'mc_link_verified';
|
||
|
||
const NONCE_ACTION = 'mc_gallery_forum_bridge';
|
||
|
||
// ── Bootstrap ─────────────────────────────────────────────────────────────
|
||
|
||
public static function init() {
|
||
// Nur laden wenn beide Plugins aktiv sind
|
||
if ( ! class_exists( 'WBF_Auth' ) || ! class_exists( 'MC_Gallery_Helpers' ) ) {
|
||
return;
|
||
}
|
||
|
||
// AJAX-Handler
|
||
add_action( 'wp_ajax_mc_forum_link_account', [ __CLASS__, 'ajax_link_account' ] );
|
||
add_action( 'wp_ajax_mc_forum_unlink_account', [ __CLASS__, 'ajax_unlink_account' ] );
|
||
add_action( 'wp_ajax_mc_forum_verify_upload', [ __CLASS__, 'ajax_verify_upload' ] );
|
||
add_action( 'wp_ajax_nopriv_mc_forum_verify_upload', [ __CLASS__, 'ajax_verify_upload' ] );
|
||
add_action( 'wp_ajax_mc_forum_admin_approve', [ __CLASS__, 'ajax_admin_approve' ] );
|
||
|
||
// Hooks in die Gallery-Ausgabe (sofern vorhanden)
|
||
add_filter( 'mc_gallery_verify_ui_extra', [ __CLASS__, 'render_verify_panel' ], 10, 2 );
|
||
add_filter( 'mc_gallery_can_upload', [ __CLASS__, 'filter_upload_permission' ], 10, 3 );
|
||
|
||
// Hooks ins Forum
|
||
add_filter( 'wbf_profile_tabs', [ __CLASS__, 'add_profile_tab' ], 10, 2 );
|
||
add_filter( 'wbf_profile_tab_content', [ __CLASS__, 'render_profile_tab' ], 10, 3 );
|
||
add_action( 'wbf_admin_user_row_extra',[ __CLASS__, 'render_admin_user_col' ] );
|
||
|
||
// CSS laden
|
||
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'enqueue_assets' ] );
|
||
add_action( 'admin_enqueue_scripts', [ __CLASS__, 'enqueue_assets' ] );
|
||
}
|
||
|
||
public static function enqueue_assets() {
|
||
wp_enqueue_style(
|
||
'mc-gallery-forum-bridge',
|
||
MCGALLERY_PRO_URL . 'assets/css/mc-gallery-forum-bridge.css',
|
||
[],
|
||
MCGALLERY_PRO_VERSION
|
||
);
|
||
}
|
||
|
||
// ── Forum-Profil: Minecraft-Tab ───────────────────────────────────────────
|
||
|
||
/**
|
||
* Neuen Tab "Minecraft" zum Forum-Profil hinzufügen.
|
||
* Erwartet dass WBF einen `wbf_profile_tabs`-Filter anbietet.
|
||
* Falls nicht: Tab wird ignoriert, kein Fehler.
|
||
*/
|
||
public static function add_profile_tab( $tabs, $profile_user ) {
|
||
$tabs['minecraft'] = [
|
||
'label' => '<i class="fas fa-cubes"></i> Minecraft',
|
||
'order' => 50,
|
||
];
|
||
return $tabs;
|
||
}
|
||
|
||
public static function render_profile_tab( $content, $tab, $profile_user ) {
|
||
if ( $tab !== 'minecraft' ) return $content;
|
||
|
||
$current = WBF_Auth::get_current_user();
|
||
$is_own = $current && (int) $current->id === (int) $profile_user->id;
|
||
$is_mod = $current && WBF_Roles::can( $current, 'manage_users' );
|
||
|
||
$mc_user = self::get_mc_username( $profile_user->id );
|
||
$verified = self::is_verified( $profile_user->id );
|
||
$servers = self::get_server_list();
|
||
|
||
ob_start();
|
||
?>
|
||
<div class="mc-bridge-profile-tab">
|
||
|
||
<?php if ( $mc_user ) : ?>
|
||
<div class="mc-bridge-linked-card <?php echo $verified ? 'is-verified' : 'is-pending'; ?>">
|
||
<img class="mc-bridge-head"
|
||
src="https://mc-heads.net/avatar/<?php echo esc_attr( $mc_user ); ?>/48"
|
||
alt="" loading="lazy">
|
||
<div class="mc-bridge-linked-info">
|
||
<span class="mc-bridge-mc-name"><?php echo esc_html( $mc_user ); ?></span>
|
||
<?php if ( $verified ) : ?>
|
||
<span class="mc-bridge-badge mc-bridge-badge--ok">
|
||
<i class="fas fa-check-circle"></i> Verifiziert
|
||
</span>
|
||
<?php else : ?>
|
||
<span class="mc-bridge-badge mc-bridge-badge--wait">
|
||
<i class="fas fa-clock"></i> Ausstehend
|
||
</span>
|
||
<?php endif; ?>
|
||
<?php
|
||
$sv = self::get_mc_server( $profile_user->id );
|
||
if ( $sv ) echo '<span class="mc-bridge-server-hint"><i class="fas fa-server"></i> ' . esc_html( $sv ) . '</span>';
|
||
?>
|
||
</div>
|
||
<?php if ( $is_own || $is_mod ) : ?>
|
||
<div class="mc-bridge-actions">
|
||
<?php if ( ! $verified && $is_own ) : ?>
|
||
<button type="button" class="mc-bridge-btn mc-bridge-btn--self-verify"
|
||
data-server="<?php echo esc_attr( $sv ); ?>"
|
||
data-nonce="<?php echo wp_create_nonce( self::NONCE_ACTION ); ?>">
|
||
<i class="fas fa-shield-check"></i> Jetzt verifizieren
|
||
</button>
|
||
<?php endif; ?>
|
||
<?php if ( ! $verified && $is_mod ) : ?>
|
||
<button type="button" class="mc-bridge-btn mc-bridge-btn--approve"
|
||
data-uid="<?php echo (int) $profile_user->id; ?>"
|
||
data-nonce="<?php echo wp_create_nonce( self::NONCE_ACTION ); ?>">
|
||
<i class="fas fa-check"></i> Bestätigen
|
||
</button>
|
||
<?php endif; ?>
|
||
<?php if ( $is_own ) : ?>
|
||
<button type="button" class="mc-bridge-btn mc-bridge-btn--unlink"
|
||
data-nonce="<?php echo wp_create_nonce( self::NONCE_ACTION ); ?>">
|
||
<i class="fas fa-unlink"></i> Trennen
|
||
</button>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
<?php if ( $is_own && ! $verified ) : ?>
|
||
<div class="mc-bridge-pending-hint">
|
||
<i class="fas fa-info-circle"></i>
|
||
Noch nicht verifiziert. Du kannst entweder auf Admin-Bestätigung warten
|
||
oder deinen Ingame-Token normal in der Galerie eingeben — dann wird
|
||
die Verknüpfung automatisch bestätigt.
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php elseif ( $is_own ) : ?>
|
||
|
||
<p class="mc-bridge-intro">
|
||
Verknüpfe deinen Minecraft-Account mit deinem Forum-Profil.
|
||
Danach kannst du Bilder in der Galerie ohne Ingame-Token hochladen.
|
||
</p>
|
||
<div class="mc-bridge-link-form">
|
||
<label>
|
||
<span>Minecraft-Benutzername</span>
|
||
<input type="text" id="mc-bridge-username"
|
||
placeholder="z. B. MvViper123" maxlength="32" autocomplete="off">
|
||
</label>
|
||
<?php if ( count( $servers ) > 1 ) : ?>
|
||
<label>
|
||
<span>Server</span>
|
||
<select id="mc-bridge-server">
|
||
<?php foreach ( $servers as $sid => $sname ) : ?>
|
||
<option value="<?php echo esc_attr( $sid ); ?>">
|
||
<?php echo esc_html( $sname ); ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</label>
|
||
<?php else :
|
||
$first_key = array_key_first( $servers );
|
||
echo '<input type="hidden" id="mc-bridge-server" value="' . esc_attr( $first_key ) . '">';
|
||
endif; ?>
|
||
<button type="button" class="mc-bridge-btn mc-bridge-btn--link"
|
||
data-nonce="<?php echo wp_create_nonce( self::NONCE_ACTION ); ?>">
|
||
<i class="fas fa-link"></i> Verknüpfen
|
||
</button>
|
||
</div>
|
||
|
||
<?php else : ?>
|
||
<p class="mc-bridge-intro">Kein Minecraft-Account verknüpft.</p>
|
||
<?php endif; ?>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
(function($){
|
||
// Account verknüpfen
|
||
$('.mc-bridge-btn--link').on('click', function(){
|
||
var mc = $('#mc-bridge-username').val().trim();
|
||
var sv = $('#mc-bridge-server').val() || '';
|
||
if ( ! mc ) { alert('Bitte einen Minecraft-Namen eingeben.'); return; }
|
||
var $btn = $(this).prop('disabled', true).text('Bitte warten…');
|
||
$.post(<?php echo json_encode( admin_url('admin-ajax.php') ); ?>, {
|
||
action: 'mc_forum_link_account',
|
||
mc_username: mc,
|
||
server_id: sv,
|
||
nonce: $btn.data('nonce')
|
||
})
|
||
.done(function(r){
|
||
if ( r.success ) location.reload();
|
||
else { alert(r.data || 'Fehler beim Verknüpfen.'); $btn.prop('disabled', false).html('<i class="fas fa-link"></i> Verknüpfen'); }
|
||
})
|
||
.fail(function(){ alert('Netzwerkfehler.'); $btn.prop('disabled', false).html('<i class="fas fa-link"></i> Verknüpfen'); });
|
||
});
|
||
|
||
// Trennen
|
||
$('.mc-bridge-btn--unlink').on('click', function(){
|
||
if ( ! confirm('Minecraft-Konto wirklich trennen?') ) return;
|
||
$.post(<?php echo json_encode( admin_url('admin-ajax.php') ); ?>, {
|
||
action: 'mc_forum_unlink_account',
|
||
nonce: $(this).data('nonce')
|
||
})
|
||
.done(function(r){
|
||
if ( r.success ) location.reload();
|
||
else alert(r.data || 'Fehler.');
|
||
});
|
||
});
|
||
|
||
// Eigene Verknüpfung verifizieren (ohne Admin-Button)
|
||
$('.mc-bridge-btn--self-verify').on('click', function(){
|
||
var $btn = $(this).prop('disabled', true);
|
||
var nonce = $btn.data('nonce');
|
||
var sv = $btn.data('server') || '';
|
||
var old = $btn.html();
|
||
|
||
$btn.html('<i class="fas fa-spinner fa-spin"></i> Prüfe...');
|
||
|
||
$.post(<?php echo json_encode( admin_url('admin-ajax.php') ); ?>, {
|
||
action: 'mc_forum_verify_upload',
|
||
nonce: nonce,
|
||
server_id: sv
|
||
})
|
||
.done(function(r){
|
||
if ( r && r.success ) {
|
||
location.reload();
|
||
} else {
|
||
alert((r && r.data && r.data.message) ? r.data.message : 'Verifizierung nicht möglich.');
|
||
$btn.prop('disabled', false).html(old);
|
||
}
|
||
})
|
||
.fail(function(){
|
||
alert('Netzwerkfehler. Bitte erneut versuchen.');
|
||
$btn.prop('disabled', false).html(old);
|
||
});
|
||
});
|
||
|
||
// Admin: Bestätigen
|
||
$('.mc-bridge-btn--approve').on('click', function(){
|
||
var uid = $(this).data('uid');
|
||
var nonce = $(this).data('nonce');
|
||
var $btn = $(this).prop('disabled', true);
|
||
$.post(<?php echo json_encode( admin_url('admin-ajax.php') ); ?>, {
|
||
action: 'mc_forum_admin_approve',
|
||
user_id: uid,
|
||
nonce: nonce
|
||
})
|
||
.done(function(r){
|
||
if ( r.success ) location.reload();
|
||
else { alert(r.data || 'Fehler.'); $btn.prop('disabled', false); }
|
||
});
|
||
});
|
||
})(jQuery);
|
||
</script>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
// ── AJAX-Handler ──────────────────────────────────────────────────────────
|
||
|
||
/** Account verknüpfen (eigenes Profil) */
|
||
public static function ajax_link_account() {
|
||
check_ajax_referer( self::NONCE_ACTION, 'nonce' );
|
||
|
||
$user = WBF_Auth::get_current_user();
|
||
if ( ! $user ) wp_send_json_error( 'Nicht eingeloggt.' );
|
||
|
||
$mc_user = sanitize_text_field( $_POST['mc_username'] ?? '' );
|
||
$server = sanitize_text_field( $_POST['server_id'] ?? '' );
|
||
|
||
// Validierung
|
||
if ( strlen( $mc_user ) < 2 || strlen( $mc_user ) > 32 ) {
|
||
wp_send_json_error( 'Ungültiger Minecraft-Name (2–32 Zeichen).' );
|
||
}
|
||
if ( ! preg_match( '/^[a-zA-Z0-9_]+$/', $mc_user ) ) {
|
||
wp_send_json_error( 'Nur Buchstaben, Zahlen und _ erlaubt.' );
|
||
}
|
||
|
||
// Doppelte Verknüpfung verhindern
|
||
if ( self::mc_user_taken( $mc_user, $user->id ) ) {
|
||
wp_send_json_error( 'Dieser Minecraft-Name ist bereits mit einem anderen Forum-Konto verknüpft.' );
|
||
}
|
||
|
||
self::set_mc_username( $user->id, $mc_user );
|
||
self::set_mc_server( $user->id, $server );
|
||
// Verifizierung: automatisch wenn gültiger Ingame-Token vorliegt
|
||
$auto_verified = self::check_active_token_for( $mc_user );
|
||
self::set_verified( $user->id, $auto_verified );
|
||
|
||
wp_send_json_success( [
|
||
'mc_username' => $mc_user,
|
||
'verified' => $auto_verified,
|
||
] );
|
||
}
|
||
|
||
/** Account-Verknüpfung trennen */
|
||
public static function ajax_unlink_account() {
|
||
check_ajax_referer( self::NONCE_ACTION, 'nonce' );
|
||
|
||
$user = WBF_Auth::get_current_user();
|
||
if ( ! $user ) wp_send_json_error( 'Nicht eingeloggt.' );
|
||
|
||
self::delete_mc_link( $user->id );
|
||
wp_send_json_success();
|
||
}
|
||
|
||
/** Admin bestätigt eine ausstehende Verknüpfung */
|
||
public static function ajax_admin_approve() {
|
||
check_ajax_referer( self::NONCE_ACTION, 'nonce' );
|
||
|
||
$current = WBF_Auth::get_current_user();
|
||
if ( ! $current || ! WBF_Roles::can( $current, 'manage_users' ) ) {
|
||
wp_send_json_error( 'Keine Berechtigung.' );
|
||
}
|
||
|
||
$target_id = (int) ( $_POST['user_id'] ?? 0 );
|
||
if ( ! $target_id ) wp_send_json_error( 'Ungültige Benutzer-ID.' );
|
||
|
||
self::set_verified( $target_id, true );
|
||
wp_send_json_success();
|
||
}
|
||
|
||
/**
|
||
* Galerie-Verify via Forum-Login.
|
||
* Wird vom Frontend aufgerufen wenn der User auf "Mit Forum-Login verifizieren" klickt.
|
||
* Gibt bei Erfolg MC-Username + Server zurück, die das Gallery-JS dann als würden
|
||
* sie aus einem Token-Verify stammen weiterverarbeiten kann.
|
||
*/
|
||
public static function ajax_verify_upload() {
|
||
check_ajax_referer( self::NONCE_ACTION, 'nonce' );
|
||
|
||
$forum_user = WBF_Auth::get_current_user();
|
||
if ( ! $forum_user ) {
|
||
wp_send_json_error( [
|
||
'code' => 'not_logged_in',
|
||
'message' => 'Du musst im Forum eingeloggt sein.',
|
||
] );
|
||
}
|
||
|
||
$mc_user = self::get_mc_username( $forum_user->id );
|
||
$verified = self::is_verified( $forum_user->id );
|
||
|
||
if ( ! $mc_user ) {
|
||
wp_send_json_error( [
|
||
'code' => 'no_mc_link',
|
||
'message' => 'Kein Minecraft-Konto verknüpft. Bitte zuerst im Profil verknüpfen.',
|
||
] );
|
||
}
|
||
|
||
// Noch nicht verifiziert → Ingame-Token als letzten Ausweg prüfen
|
||
if ( ! $verified ) {
|
||
if ( self::check_active_token_for( $mc_user ) ) {
|
||
self::set_verified( $forum_user->id, true );
|
||
$verified = true;
|
||
}
|
||
}
|
||
|
||
if ( ! $verified ) {
|
||
wp_send_json_error( [
|
||
'code' => 'not_verified',
|
||
'message' => 'Dein Account ist noch nicht verifiziert. Bitte einen Admin um Bestätigung oder nutze einmalig das Ingame-Token.',
|
||
] );
|
||
}
|
||
|
||
$server_id = self::get_mc_server( $forum_user->id )
|
||
?: sanitize_text_field( $_POST['server_id'] ?? '' );
|
||
|
||
if ( empty( $server_id ) ) {
|
||
$servers = self::get_server_list();
|
||
if ( ! empty( $servers ) ) {
|
||
$first = array_key_first( $servers );
|
||
if ( $first !== null ) {
|
||
$server_id = (string) $first;
|
||
}
|
||
}
|
||
}
|
||
|
||
wp_send_json_success( [
|
||
'mc_username' => $mc_user,
|
||
'server_id' => $server_id,
|
||
'display_name' => $forum_user->display_name,
|
||
'verify_type' => 'forum_login',
|
||
] );
|
||
}
|
||
|
||
// ── Filter: Gallery-Upload-Berechtigung ───────────────────────────────────
|
||
|
||
/**
|
||
* Gibt true zurück wenn ein eingeloggter Forum-User einen verifizierten
|
||
* Link zu $mc_username hat — ersetzt dann die normale Token-Prüfung.
|
||
* Wird nur aufgerufen wenn die Gallery `apply_filters('mc_gallery_can_upload', …)` nutzt.
|
||
*/
|
||
public static function filter_upload_permission( $allowed, $mc_username, $server_id ) {
|
||
if ( $allowed ) return true; // schon erlaubt, nicht überschreiben
|
||
|
||
$forum_user = WBF_Auth::get_current_user();
|
||
if ( ! $forum_user ) return false;
|
||
|
||
$linked = self::get_mc_username( $forum_user->id );
|
||
if ( ! $linked ) return false;
|
||
if ( strtolower( $linked ) !== strtolower( $mc_username ) ) return false;
|
||
|
||
return self::is_verified( $forum_user->id );
|
||
}
|
||
|
||
// ── Filter: Zusätzliche Verify-UI in der Gallery ──────────────────────────
|
||
|
||
/**
|
||
* Hängt unter das normale Verify-Formular einen "Mit Forum-Login"-Bereich.
|
||
* Funktioniert wenn die Gallery `apply_filters('mc_gallery_verify_ui_extra', '', $server_id)` aufruft.
|
||
*
|
||
* Falls der Hook nicht existiert: eigenen Shortcode [mc_gallery_forum_login] nutzen.
|
||
*/
|
||
public static function render_verify_panel( $html, $server_id ) {
|
||
return $html . self::build_verify_panel( $server_id );
|
||
}
|
||
|
||
/**
|
||
* Shortcode [mc_gallery_forum_login server_id="survival"]
|
||
* Kann manuell auf der Upload-Seite eingebettet werden falls der Hook-Ansatz
|
||
* nicht greift.
|
||
*/
|
||
public static function shortcode_verify_panel( $atts ) {
|
||
$atts = shortcode_atts( [ 'server_id' => '' ], $atts );
|
||
return self::build_verify_panel( sanitize_text_field( $atts['server_id'] ) );
|
||
}
|
||
|
||
/** Eigentliches HTML für das Verify-Panel */
|
||
public static function build_verify_panel( $server_id ) {
|
||
$forum_user = WBF_Auth::get_current_user();
|
||
$nonce = wp_create_nonce( self::NONCE_ACTION );
|
||
$ajax_url = admin_url( 'admin-ajax.php' );
|
||
|
||
ob_start();
|
||
?>
|
||
<div class="mc-bridge-verify-wrap" data-server="<?php echo esc_attr( $server_id ); ?>">
|
||
<div class="mc-bridge-divider"><span>oder</span></div>
|
||
|
||
<?php if ( ! $forum_user ) :
|
||
$forum_url = function_exists('wbf_get_forum_url') ? wbf_get_forum_url() : '#';
|
||
$register_url = function_exists('wbf_get_forum_url') ? wbf_get_forum_url() . '?register=1' : '#';
|
||
?>
|
||
<div class="mc-bridge-card">
|
||
<div class="mc-bridge-card-inner">
|
||
<div class="mc-bridge-card-icon">
|
||
<i class="fas fa-comments"></i>
|
||
</div>
|
||
<div class="mc-bridge-card-text">
|
||
<div class="mc-bridge-card-label">Forum-Login</div>
|
||
<div class="mc-bridge-card-desc">
|
||
Direkt hochladen ohne Ingame-Token – wenn dein <strong>Minecraft-Account</strong> mit dem Forum verknüpft ist.
|
||
</div>
|
||
</div>
|
||
<div class="mc-bridge-card-actions">
|
||
<a href="<?php echo esc_url( $forum_url ); ?>" class="mc-bridge-action-btn">
|
||
<i class="fas fa-sign-in-alt"></i> Einloggen
|
||
</a>
|
||
<a href="<?php echo esc_url( $register_url ); ?>" class="mc-bridge-action-btn-ghost">
|
||
<i class="fas fa-external-link-alt"></i> Konto erstellen
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<?php else :
|
||
$mc_user = self::get_mc_username( $forum_user->id );
|
||
$verified = self::is_verified( $forum_user->id );
|
||
$forum_url = function_exists('wbf_get_forum_url')
|
||
? wbf_get_forum_url() . '?forum_profile=' . (int) $forum_user->id . '#tab-minecraft'
|
||
: '#';
|
||
?>
|
||
|
||
<?php if ( $mc_user && $verified ) : ?>
|
||
<div class="mc-bridge-success">
|
||
<i class="fas fa-check-circle"></i>
|
||
Verifiziert als <strong><?php echo esc_html( $mc_user ); ?></strong>
|
||
</div>
|
||
|
||
<?php elseif ( $mc_user ) : ?>
|
||
<div class="mc-bridge-card mc-bridge-card--warn">
|
||
<div class="mc-bridge-card-inner">
|
||
<img class="mc-bridge-head-sm"
|
||
src="https://mc-heads.net/avatar/<?php echo esc_attr( $mc_user ); ?>/44"
|
||
alt="" loading="lazy">
|
||
<div class="mc-bridge-card-text">
|
||
<div class="mc-bridge-card-label">Verknüpft · ausstehend</div>
|
||
<div class="mc-bridge-card-desc">
|
||
<strong><?php echo esc_html( $mc_user ); ?></strong>
|
||
· Noch nicht bestätigt
|
||
</div>
|
||
</div>
|
||
<button type="button"
|
||
class="mc-bridge-verify-trigger"
|
||
data-ajax="<?php echo esc_attr( $ajax_url ); ?>"
|
||
data-nonce="<?php echo esc_attr( $nonce ); ?>"
|
||
data-server="<?php echo esc_attr( $server_id ); ?>">
|
||
<i class="fas fa-sign-in-alt"></i> Mit Forum verifizieren
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<?php else : ?>
|
||
<div class="mc-bridge-card">
|
||
<div class="mc-bridge-card-inner">
|
||
<div class="mc-bridge-card-icon">
|
||
<i class="fas fa-user-circle"></i>
|
||
</div>
|
||
<div class="mc-bridge-card-text">
|
||
<div class="mc-bridge-card-label">Eingeloggt als <?php echo esc_html( $forum_user->display_name ); ?></div>
|
||
<div class="mc-bridge-card-desc">
|
||
Noch kein Minecraft-Konto verknüpft.
|
||
</div>
|
||
</div>
|
||
<div class="mc-bridge-card-actions">
|
||
<a href="<?php echo esc_url( $forum_url ); ?>" class="mc-bridge-action-btn">
|
||
<i class="fas fa-link"></i> Konto verknüpfen
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php endif; ?>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
(function($){
|
||
$(document).on('click', '.mc-bridge-verify-trigger', function(){
|
||
console.log('[MC-Gallery] Forum-Login Button geklickt!');
|
||
if (typeof $ === 'undefined') { alert('jQuery nicht geladen!'); return; }
|
||
var $btn = $(this).prop('disabled', true);
|
||
var ajax = $btn.data('ajax');
|
||
var nonce = $btn.data('nonce');
|
||
var server = $btn.data('server') || $btn.closest('[data-server]').data('server') || '';
|
||
|
||
$btn.html('<i class="fas fa-spinner fa-spin"></i> Prüfe…');
|
||
|
||
$.post(ajax, {
|
||
action: 'mc_forum_verify_upload',
|
||
nonce: nonce,
|
||
server_id: server
|
||
})
|
||
.done(function(r){
|
||
if ( r.success ) {
|
||
if (!r.data.server_id) {
|
||
r.data.server_id = server || '';
|
||
}
|
||
|
||
// Galerie-JS über erfolgreiche Verify informieren
|
||
// Standard-Event — Gallery-JS kann darauf lauschen
|
||
$(document).trigger('mc_gallery_forum_verified', [ r.data ]);
|
||
|
||
// Falls Gallery eigenes globales Callback hat
|
||
if ( typeof window.mcGalleryOnVerified === 'function' ) {
|
||
window.mcGalleryOnVerified( r.data );
|
||
}
|
||
|
||
// Statusanzeige aktualisieren
|
||
$btn.closest('.mc-bridge-verify-wrap')
|
||
.html('<div class="mc-bridge-success">'
|
||
+ '<i class="fas fa-check-circle"></i> Verifiziert als <strong>'
|
||
+ $('<span>').text(r.data.mc_username).html()
|
||
+ '</strong></div>');
|
||
} else {
|
||
var msg = (r.data && r.data.message) ? r.data.message : 'Fehler bei der Verifikation.';
|
||
var $wrap = $btn.closest('.mc-bridge-verify-wrap');
|
||
$wrap.find('.mc-bridge-error').remove();
|
||
$wrap.append('<p class="mc-bridge-error"><i class="fas fa-times-circle"></i> ' + msg + '</p>');
|
||
$btn.prop('disabled', false).html('<i class="fas fa-sign-in-alt"></i> Mit Forum-Login verifizieren');
|
||
}
|
||
})
|
||
.fail(function(){
|
||
$btn.prop('disabled', false).html('<i class="fas fa-sign-in-alt"></i> Mit Forum-Login verifizieren');
|
||
alert('Netzwerkfehler. Bitte erneut versuchen.');
|
||
});
|
||
});
|
||
})(jQuery);
|
||
</script>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
// ── Admin: Spalte in Forum-Benutzertabelle ────────────────────────────────
|
||
|
||
/**
|
||
* Zeigt verknüpfte MC-Accounts in der Forum-Admin-Usertabelle.
|
||
* Voraussetzung: Forum rendert `do_action('wbf_admin_user_row_extra', $user)`.
|
||
*/
|
||
public static function render_admin_user_col( $user ) {
|
||
$mc_user = self::get_mc_username( $user->id );
|
||
if ( ! $mc_user ) return;
|
||
|
||
$verified = self::is_verified( $user->id );
|
||
$nonce = wp_create_nonce( self::NONCE_ACTION );
|
||
?>
|
||
<span class="mc-bridge-admin-mc-badge"
|
||
title="Verknüpfter Minecraft-Account<?php echo $verified ? ' (verifiziert)' : ' (ausstehend)'; ?>">
|
||
<img src="https://mc-heads.net/avatar/<?php echo esc_attr( $mc_user ); ?>/20" alt="">
|
||
<?php echo esc_html( $mc_user ); ?>
|
||
<?php if ( $verified ) : ?>
|
||
<i class="fas fa-check" style="color:#22c55e"></i>
|
||
<?php else : ?>
|
||
<a href="#"
|
||
class="mc-bridge-btn--approve"
|
||
style="color:#f59e0b;margin-left:4px"
|
||
data-uid="<?php echo (int) $user->id; ?>"
|
||
data-nonce="<?php echo esc_attr( $nonce ); ?>"
|
||
title="Verknüpfung bestätigen">
|
||
<i class="fas fa-check-circle"></i>
|
||
</a>
|
||
<script>
|
||
(function($){
|
||
$(document).on('click', '.mc-bridge-btn--approve[data-uid]', function(e){
|
||
e.preventDefault();
|
||
var $a = $(this);
|
||
var uid = $a.data('uid');
|
||
var nonce = $a.data('nonce');
|
||
$.post(<?php echo json_encode( admin_url('admin-ajax.php') ); ?>, {
|
||
action: 'mc_forum_admin_approve',
|
||
user_id: uid,
|
||
nonce: nonce
|
||
}).done(function(r){
|
||
if ( r.success ) location.reload();
|
||
else alert(r.data || 'Fehler.');
|
||
});
|
||
});
|
||
})(jQuery);
|
||
</script>
|
||
<?php endif; ?>
|
||
</span>
|
||
<?php
|
||
}
|
||
|
||
// ── Hilfsmethoden: forum_user_meta Zugriff ────────────────────────────────
|
||
|
||
private static function get_meta( $user_id, $key ) {
|
||
global $wpdb;
|
||
return $wpdb->get_var( $wpdb->prepare(
|
||
"SELECT meta_value FROM {$wpdb->prefix}forum_user_meta
|
||
WHERE user_id = %d AND meta_key = %s
|
||
LIMIT 1",
|
||
(int) $user_id, $key
|
||
) );
|
||
}
|
||
|
||
private static function set_meta( $user_id, $key, $value ) {
|
||
global $wpdb;
|
||
$table = $wpdb->prefix . 'forum_user_meta';
|
||
|
||
$exists = $wpdb->get_var( $wpdb->prepare(
|
||
"SELECT id FROM {$table} WHERE user_id = %d AND meta_key = %s",
|
||
(int) $user_id, $key
|
||
) );
|
||
|
||
if ( $exists ) {
|
||
$wpdb->update( $table,
|
||
[ 'meta_value' => $value ],
|
||
[ 'user_id' => (int) $user_id, 'meta_key' => $key ]
|
||
);
|
||
} else {
|
||
$wpdb->insert( $table, [
|
||
'user_id' => (int) $user_id,
|
||
'meta_key' => $key,
|
||
'meta_value' => $value,
|
||
] );
|
||
}
|
||
}
|
||
|
||
private static function delete_meta( $user_id, $key ) {
|
||
global $wpdb;
|
||
$wpdb->delete( $wpdb->prefix . 'forum_user_meta',
|
||
[ 'user_id' => (int) $user_id, 'meta_key' => $key ]
|
||
);
|
||
}
|
||
|
||
// Öffentliche Getter/Setter
|
||
public static function get_mc_username( $user_id ) { return self::get_meta( $user_id, self::META_MC_USER ); }
|
||
public static function get_mc_server ( $user_id ) { return self::get_meta( $user_id, self::META_MC_SERVER ); }
|
||
public static function is_verified ( $user_id ) { return '1' === self::get_meta( $user_id, self::META_VERIFIED ); }
|
||
|
||
public static function set_mc_username( $user_id, $val ) { self::set_meta( $user_id, self::META_MC_USER, $val ); }
|
||
public static function set_mc_server ( $user_id, $val ) { self::set_meta( $user_id, self::META_MC_SERVER, $val ); }
|
||
public static function set_verified ( $user_id, $bool ) { self::set_meta( $user_id, self::META_VERIFIED, $bool ? '1' : '0' ); }
|
||
|
||
public static function delete_mc_link( $user_id ) {
|
||
self::delete_meta( $user_id, self::META_MC_USER );
|
||
self::delete_meta( $user_id, self::META_MC_SERVER );
|
||
self::delete_meta( $user_id, self::META_VERIFIED );
|
||
}
|
||
|
||
// Prüft ob ein MC-Name schon einem anderen Forum-User gehört
|
||
private static function mc_user_taken( $mc_user, $exclude_user_id ) {
|
||
global $wpdb;
|
||
return (bool) $wpdb->get_var( $wpdb->prepare(
|
||
"SELECT m.id FROM {$wpdb->prefix}forum_user_meta m
|
||
WHERE m.meta_key = %s
|
||
AND m.meta_value = %s
|
||
AND m.user_id != %d
|
||
LIMIT 1",
|
||
self::META_MC_USER, $mc_user, (int) $exclude_user_id
|
||
) );
|
||
}
|
||
|
||
/**
|
||
* Markiert den verknüpften Forum-Account zu einem MC-Namen als verifiziert.
|
||
* Gibt true zurück, wenn ein Account gefunden und aktualisiert wurde.
|
||
*/
|
||
public static function verify_linked_user_by_mc_username( $mc_username ) {
|
||
$mc_username = trim( (string) $mc_username );
|
||
if ( $mc_username === '' ) return false;
|
||
|
||
global $wpdb;
|
||
$user_id = (int) $wpdb->get_var( $wpdb->prepare(
|
||
"SELECT user_id FROM {$wpdb->prefix}forum_user_meta
|
||
WHERE meta_key = %s AND LOWER(meta_value) = LOWER(%s)
|
||
LIMIT 1",
|
||
self::META_MC_USER,
|
||
$mc_username
|
||
) );
|
||
|
||
if ( ! $user_id ) return false;
|
||
|
||
self::set_verified( $user_id, true );
|
||
return true;
|
||
}
|
||
|
||
// Gibt true zurück wenn ein gültiger und bereits verifizierter Ingame-Token für diesen MC-Namen existiert
|
||
private static function check_active_token_for( $mc_username ) {
|
||
if ( ! class_exists( 'MC_Gallery_Helpers' ) ) return false;
|
||
$tokens = MC_Gallery_Helpers::get_tokens();
|
||
$now = time();
|
||
|
||
$wanted = strtolower( trim( (string) $mc_username ) );
|
||
if ( $wanted === '' ) return false;
|
||
|
||
foreach ( $tokens as $token => $data ) {
|
||
if ( ! is_array( $data ) ) continue;
|
||
if ( ( $data['expires'] ?? 0 ) < $now ) continue;
|
||
if ( empty( $data['claimed'] ) ) continue;
|
||
|
||
// Unterschiedliche Payload-Feldnamen aus Java/WP-Versionen tolerieren
|
||
$name = $data['claimed_by'] ?? $data['username'] ?? $data['player'] ?? '';
|
||
if ( strtolower( trim( (string) $name ) ) === $wanted ) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// Server-Liste aus Gallery-Config laden
|
||
private static function get_server_list() {
|
||
$servers = get_option( 'mc_gallery_servers', [] );
|
||
if ( ! empty( $servers ) && is_array( $servers ) ) return $servers;
|
||
return [ 'default' => 'Standard-Server' ];
|
||
}
|
||
}
|