From 243cb0608c48c19499a75cedc8ab60e4dfef2bf6 Mon Sep 17 00:00:00 2001 From: Akurosia Kamo Date: Sun, 24 May 2026 09:31:57 +0200 Subject: [PATCH] mark tankbuster as purple (superbolide is broken) move stuff to env file and recommit config.php --- .env.example | 6 ++++ .gitignore | 2 +- config.php | 87 +++++++++++++++++++++++++++++++++++++++++++++---- css/planner.css | 16 +++++++++ index.php | 5 --- js/planner.js | 8 +++-- 6 files changed, 109 insertions(+), 15 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ebb33b6 --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ +DEV_MODE=true +CLIENT_ID=your-fflogs-client-id +REDIRECT_URI=http://localhost:8080/auth/callback.php +AUTHORIZE_URI=https://www.fflogs.com/oauth/authorize +TOKEN_URI=https://www.fflogs.com/oauth/token +GRAPHQL_URI=https://www.fflogs.com/api/v2/user diff --git a/.gitignore b/.gitignore index 6eb1281..1540607 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .claude/ debug/ cached_logs/ +.env fflogs-schema.json -config.php diff --git a/config.php b/config.php index 148ba52..29ee653 100644 --- a/config.php +++ b/config.php @@ -1,11 +1,51 @@ = 2 + && (($value[0] === '"' && $value[-1] === '"') || ($value[0] === "'" && $value[-1] === "'")) + ) { + $value = substr($value, 1, -1); + } + + $_ENV[$key] = $value; + putenv($key . '=' . $value); + } +} + +function env_value(string $key, ?string $default = null): string { + $value = $_ENV[$key] ?? getenv($key); + if ($value === false || $value === null || $value === '') { + if ($default !== null) return $default; + throw new RuntimeException('Missing required environment value: ' . $key); + } + return (string)$value; +} + +function env_bool(string $key, bool $default = false): bool { + $value = strtolower(env_value($key, $default ? 'true' : 'false')); + return in_array($value, ['1', 'true', 'yes', 'on'], true); +} + +load_env_file(__DIR__ . '/.env'); + +define('DEV_MODE', env_bool('DEV_MODE')); +define('CLIENT_ID', env_value('CLIENT_ID')); +define('REDIRECT_URI', env_value('REDIRECT_URI')); +define('AUTHORIZE_URI', env_value('AUTHORIZE_URI')); +define('TOKEN_URI', env_value('TOKEN_URI')); +define('GRAPHQL_URI', env_value('GRAPHQL_URI')); function session_start_safe(): void { if (session_status() === PHP_SESSION_NONE) { @@ -19,3 +59,38 @@ function session_start_safe(): void { session_start(); } } + +function default_return_path(): string { + $script = str_replace('\\', '/', $_SERVER['SCRIPT_NAME'] ?? '/index.php'); + $base = rtrim(dirname(dirname($script)), '/'); + return ($base === '' ? '' : $base) . '/index.php'; +} + +function safe_return_path(?string $value): string { + $value = trim((string)$value); + if ($value === '') return default_return_path(); + + $parts = parse_url($value); + if ($parts === false) return default_return_path(); + if (isset($parts['host'])) { + $currentHost = strtolower(explode(':', $_SERVER['HTTP_HOST'] ?? '')[0]); + if (strtolower($parts['host']) !== $currentHost) return default_return_path(); + } elseif (str_starts_with($value, '//')) { + return default_return_path(); + } + + $path = $parts['path'] ?? ''; + if ($path === '') $path = default_return_path(); + if ($path[0] !== '/') $path = '/' . ltrim($path, '/'); + + $query = isset($parts['query']) ? '?' . $parts['query'] : ''; + return $path . $query; +} + +function current_return_path(): string { + return safe_return_path($_SERVER['REQUEST_URI'] ?? null); +} + +function auth_start_href(?string $returnPath = null): string { + return 'auth/start.php?return=' . rawurlencode($returnPath ?? current_return_path()); +} diff --git a/css/planner.css b/css/planner.css index 00627e9..1dcb3ec 100644 --- a/css/planner.css +++ b/css/planner.css @@ -797,6 +797,11 @@ z-index: 1; } +.timeline-hit-line--tankbuster { + width: 2px; + background: rgba(177,112,255,.62); +} + .timeline-player-row .timeline-track { background-color: rgba(255,255,255,0.015); } @@ -874,6 +879,17 @@ background: rgba(224,92,92,.22); } +.timeline-boss-action--tankbuster { + border-color: rgba(177,112,255,.55); + background: rgba(177,112,255,.18); + color: #dbc7ff; +} + +.timeline-boss-action--tankbuster:hover { + border-color: rgba(177,112,255,.85); + background: rgba(177,112,255,.28); +} + .timeline-mitigation { position: absolute; top: 6px; diff --git a/index.php b/index.php index 14ce54d..46fe07d 100644 --- a/index.php +++ b/index.php @@ -2,11 +2,6 @@ require_once __DIR__ . '/config.php'; session_start_safe(); -function auth_start_href(): string { - $return = $_SERVER['REQUEST_URI'] ?? '/'; - return 'auth/start.php?return=' . urlencode($return); -} - $authenticated = !empty($_SESSION['access_token']) && ($_SESSION['token_expires'] ?? 0) > time(); diff --git a/js/planner.js b/js/planner.js index c746a4e..5e0f560 100644 --- a/js/planner.js +++ b/js/planner.js @@ -920,14 +920,14 @@ function renderTimelineHtml(plan) { const bossActions = layoutBossActions(mechanics, duration); const laneCount = Math.max(1, ...bossActions.map(item => item.lane + 1)); const hitLines = mechanics.map(m => ` - + `).join(''); const bossItems = bossActions.map(({ mechanic: m, left, lane }) => ` - `).join(''); @@ -1869,6 +1869,7 @@ function aoeEventsToMechanics(aoeEvents, fightStart, phases, players, withMitiga timestamp: relTs, phase: phase?.name ?? '', unmitigatedDamage: avgUnmit, + isHeavyTankbuster: !!ev.isHeavyTankbuster, notes: '', assignments, }; @@ -1991,6 +1992,7 @@ async function refreshPlanLanguage(planId) { ...mechanic, name: match.abilityName ?? mechanic.name, abilityId: match.abilityId ?? mechanic.abilityId, + isHeavyTankbuster: !!match.isHeavyTankbuster, assignments, }; });