Webbserver - Love Blomberg

Show sourcecode

The following files exists in this folder. Click to view.

public_html/GYA2/api/

admin_data.php
complete_session.php
export_csv.php
save_maze.php
save_reaction.php
save_simon.php
start_session.php

admin_data.php

173 lines ASCII Unix (LF)
<?php
session_start
();
if (empty(
$_SESSION['admin_logged_in'])) {
    
http_response_code(403);
    
header('Content-Type: application/json');
    echo 
json_encode(['error' => 'Unauthorized']);
    exit;
}

require 
__DIR__ '/../config.php';

$pdo getDB();

// --- Fetch all data ---

$participants $pdo->query("
    SELECT p.id, p.email, p.group_type, p.created_at, p.completed_at
    FROM participants p
    ORDER BY p.created_at DESC
"
)->fetchAll();

$reactions $pdo->query("
    SELECT r.participant_id, p.group_type, r.round_number, r.reaction_ms, r.was_premature, r.delay_ms
    FROM reaction_times r
    JOIN participants p ON p.id = r.participant_id
    ORDER BY r.participant_id, r.round_number
"
)->fetchAll();

$mazes $pdo->query("
    SELECT m.participant_id, p.group_type, m.total_time_ms, m.total_moves
    FROM maze_results m
    JOIN participants p ON p.id = m.participant_id
    ORDER BY m.participant_id
"
)->fetchAll();

$simons $pdo->query("
    SELECT s.participant_id, p.group_type, s.max_level, s.total_time_ms
    FROM simon_results s
    JOIN participants p ON p.id = s.participant_id
    ORDER BY s.participant_id
"
)->fetchAll();

$simonRounds $pdo->query("
    SELECT sr.participant_id, sr.level_number, sr.success, sr.response_times_json
    FROM simon_rounds sr
    ORDER BY sr.participant_id, sr.level_number
"
)->fetchAll();

// --- Build per-participant data structure ---
$participantData = [];
foreach (
$participants as $p) {
    
$participantData[$p['id']] = [
        
'id' => $p['id'],
        
'email' => $p['email'],
        
'group' => $p['group_type'],
        
'created_at' => $p['created_at'],
        
'completed_at' => $p['completed_at'],
        
'reaction_rounds' => [],
        
'reaction_avg' => null,
        
'reaction_best' => null,
        
'maze' => null,
        
'simon' => null,
        
'simon_rounds' => [],
    ];
}

foreach (
$reactions as $r) {
    
$pid $r['participant_id'];
    if (!isset(
$participantData[$pid])) continue;
    
$participantData[$pid]['reaction_rounds'][] = $r;
}

foreach (
$participantData as $pid => &$pd) {
    
$valid array_filter($pd['reaction_rounds'], fn($r) => !$r['was_premature']);
    if (
count($valid) > 0) {
        
$times array_column($valid'reaction_ms');
        
$pd['reaction_avg'] = round(array_sum($times) / count($times));
        
$pd['reaction_best'] = min($times);
    }
}
unset(
$pd);

foreach (
$mazes as $m) {
    
$pid $m['participant_id'];
    if (!isset(
$participantData[$pid])) continue;
    
$participantData[$pid]['maze'] = $m;
}

foreach (
$simons as $s) {
    
$pid $s['participant_id'];
    if (!isset(
$participantData[$pid])) continue;
    
$participantData[$pid]['simon'] = $s;
}

foreach (
$simonRounds as $sr) {
    
$pid $sr['participant_id'];
    if (!isset(
$participantData[$pid])) continue;
    
$participantData[$pid]['simon_rounds'][] = $sr;
}

// --- Build chart data ---
$reactionByGroup = ['placebo' => [], 'control' => []];
$mazeTimeByGroup = ['placebo' => [], 'control' => []];
$mazeMovesByGroup = ['placebo' => [], 'control' => []];
$simonByGroup = ['placebo' => [], 'control' => []];

foreach (
$participantData as $pid => $pd) {
    
$g $pd['group'];
    if (
$pd['reaction_avg'] !== null) {
        
$reactionByGroup[$g][] = $pd['reaction_avg'];
    }
    if (
$pd['maze']) {
        
$mazeTimeByGroup[$g][] = round($pd['maze']['total_time_ms'] / 10001);
        
$mazeMovesByGroup[$g][] = (int)$pd['maze']['total_moves'];
    }
    if (
$pd['simon']) {
        
$simonByGroup[$g][] = (int)$pd['simon']['max_level'];
    }
}

function 
groupAvg($arr) {
    return 
count($arr) > round(array_sum($arr) / count($arr), 1) : 0;
}

// Leaderboards
$leaderboardPlacebo = [];
$leaderboardControl = [];
foreach (
$participantData as $pid => $pd) {
    if (
$pd['reaction_avg'] === null) continue;
    
$entry = ['email' => $pd['email'], 'avg' => $pd['reaction_avg']];
    if (
$pd['group'] === 'placebo') {
        
$leaderboardPlacebo[] = $entry;
    } else {
        
$leaderboardControl[] = $entry;
    }
}
usort($leaderboardPlacebo, fn($a$b) => $a['avg'] - $b['avg']);
usort($leaderboardControl, fn($a$b) => $a['avg'] - $b['avg']);

// Groups for participant lists
$groups = ['placebo' => [], 'control' => []];
foreach (
$participantData as $pid => $pd) {
    
$groups[$pd['group']][] = $pd;
}

$totalParticipants count($participants);
$completedCount count(array_filter($participants, fn($p) => $p['completed_at'] !== null));

header('Content-Type: application/json');
echo 
json_encode([
    
'summary' => [
        
'total_participants' => $totalParticipants,
        
'completed' => $completedCount,
        
'reaction_avg_placebo' => groupAvg($reactionByGroup['placebo']),
        
'reaction_avg_control' => groupAvg($reactionByGroup['control']),
        
'simon_avg_placebo' => groupAvg($simonByGroup['placebo']),
        
'simon_avg_control' => groupAvg($simonByGroup['control']),
        
'maze_time_avg_placebo' => groupAvg($mazeTimeByGroup['placebo']),
        
'maze_time_avg_control' => groupAvg($mazeTimeByGroup['control']),
        
'maze_moves_avg_placebo' => groupAvg($mazeMovesByGroup['placebo']),
        
'maze_moves_avg_control' => groupAvg($mazeMovesByGroup['control']),
    ],
    
'charts' => [
        
'reaction_by_group' => $reactionByGroup,
        
'maze_time_by_group' => $mazeTimeByGroup,
        
'maze_moves_by_group' => $mazeMovesByGroup,
        
'simon_by_group' => $simonByGroup,
    ],
    
'leaderboard_placebo' => array_values($leaderboardPlacebo),
    
'leaderboard_control' => array_values($leaderboardControl),
    
'groups' => $groups,
]);