Skip to content

Commit c62bfc6

Browse files
syropianclaude
andcommitted
Gates legacy migration behind a legacy-database check
New users were always prompted to migrate, even on fresh or self-hosted installs. Now a newly created user is only sent to /migrate when an off-by-default config (CHECK_FOR_MIGRATION) is on and a matching github_id exists in the legacy database; everyone else starts migrated. Adds a read-only legacy connection and a LegacyMigration service mirroring the sponsorship check, with a logged failure path so a legacy-database hiccup never blocks sign-in. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent bad9ce6 commit c62bfc6

5 files changed

Lines changed: 75 additions & 1 deletion

File tree

.env.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ GITHUB_SPONSOREE_LOGIN=syropian
6363

6464
CHECK_FOR_SPONSORSHIP=true
6565

66+
# Legacy migration (hosted instance only — leave off for local/self-hosted)
67+
CHECK_FOR_MIGRATION=false
68+
LEGACY_DB_HOST=127.0.0.1
69+
LEGACY_DB_PORT=3306
70+
LEGACY_DB_DATABASE=
71+
LEGACY_DB_USERNAME=
72+
LEGACY_DB_PASSWORD=
73+
6674
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
6775
VITE_PUSHER_HOST="${PUSHER_HOST}"
6876
VITE_PUSHER_PORT="${PUSHER_PORT}"

app/Http/Controllers/AuthController.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace App\Http\Controllers;
66

7+
use App\Lib\LegacyMigration;
78
use App\Lib\Sponsorship;
89
use App\Models\User;
910
use Illuminate\Http\Request;
@@ -33,7 +34,7 @@ public function redirectToProvider(Request $request)
3334
->redirect();
3435
}
3536

36-
public function handleProviderCallback(Request $request, Sponsorship $sponsorship)
37+
public function handleProviderCallback(Request $request, Sponsorship $sponsorship, LegacyMigration $migration)
3738
{
3839
$scope = $request->session()->pull('auth_scope', 'read:user');
3940

@@ -50,6 +51,16 @@ public function handleProviderCallback(Request $request, Sponsorship $sponsorshi
5051

5152
$user->save();
5253

54+
if ($user->wasRecentlyCreated) {
55+
try {
56+
$migration->markAsMigratedUnlessLegacy($user);
57+
} catch (Throwable $e) {
58+
// A legacy lookup failure must never block sign-in; the user stays
59+
// gated to /migrate, which is harmless when they have no data.
60+
Log::warning('Legacy migration check failed during login', ['user_id' => $user->id, 'exception' => $e]);
61+
}
62+
}
63+
5364
if (config('app.check_for_sponsorship')) {
5465
try {
5566
$sponsorship->updateUserSponsorshipStatus($user);

app/Lib/LegacyMigration.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Lib;
6+
7+
use App\Models\User;
8+
use Illuminate\Support\Facades\DB;
9+
10+
class LegacyMigration
11+
{
12+
public function isEnabled(): bool
13+
{
14+
return (bool) config('app.check_for_migration');
15+
}
16+
17+
public function hasLegacyAccount(User $user): bool
18+
{
19+
return DB::connection('legacy')
20+
->table('users')
21+
->where('github_id', $user->github_id)
22+
->exists();
23+
}
24+
25+
public function markAsMigratedUnlessLegacy(User $user): void
26+
{
27+
if ($this->isEnabled() && $this->hasLegacyAccount($user)) {
28+
return;
29+
}
30+
31+
$user->markAsMigrated();
32+
}
33+
}

config/app.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@
138138

139139
'check_for_sponsorship' => env('CHECK_FOR_SPONSORSHIP', false),
140140

141+
// Only the shared hosted instance has a legacy database to migrate from;
142+
// local runners and self-hosters leave this off.
143+
'check_for_migration' => env('CHECK_FOR_MIGRATION', false),
144+
141145
/*
142146
|--------------------------------------------------------------------------
143147
| Maintenance Mode Driver

config/database.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,24 @@
9595
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
9696
],
9797

98+
// Read-only connection to the previous-generation Astral database, used
99+
// by the hosted instance to detect which users have data to migrate.
100+
'legacy' => [
101+
'driver' => env('LEGACY_DB_CONNECTION', 'mysql'),
102+
'url' => env('LEGACY_DATABASE_URL'),
103+
'host' => env('LEGACY_DB_HOST', '127.0.0.1'),
104+
'port' => env('LEGACY_DB_PORT', '3306'),
105+
'database' => env('LEGACY_DB_DATABASE'),
106+
'username' => env('LEGACY_DB_USERNAME'),
107+
'password' => env('LEGACY_DB_PASSWORD', ''),
108+
'charset' => 'utf8mb4',
109+
'collation' => 'utf8mb4_unicode_ci',
110+
'prefix' => '',
111+
'prefix_indexes' => true,
112+
'strict' => true,
113+
'engine' => null,
114+
],
115+
98116
],
99117

100118
/*

0 commit comments

Comments
 (0)