Skip to content

Commit 61a638e

Browse files
Add installer support for configuring app, database, and API keys
Co-authored-by: bixmatech <bixmatech@gmail.com>
1 parent 91bdb39 commit 61a638e

File tree

3 files changed

+102
-1
lines changed

3 files changed

+102
-1
lines changed

app/Http/Controllers/InstallerController.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Models\Setting;
66
use App\Models\User;
7+
use App\Support\EnvWriter;
78
use Illuminate\Http\Request;
89
use Illuminate\Support\Facades\Artisan;
910
use Illuminate\Support\Facades\Hash;
@@ -26,11 +27,32 @@ public function index(): View
2627
public function store(Request $request): RedirectResponse
2728
{
2829
$data = $request->validate([
30+
'app_url' => 'nullable|url',
31+
'db_host' => 'nullable|string',
32+
'db_database' => 'nullable|string',
33+
'db_username' => 'nullable|string',
34+
'db_password' => 'nullable|string',
35+
'openai' => 'nullable|string',
36+
'stripe_public' => 'nullable|string',
37+
'stripe_secret' => 'nullable|string',
2938
'name' => 'required|string|max:255',
3039
'email' => 'required|email',
3140
'password' => 'required|string|min:8',
3241
]);
3342

43+
EnvWriter::set(array_filter([
44+
'APP_URL' => $data['app_url'] ?? null,
45+
'DB_HOST' => $data['db_host'] ?? null,
46+
'DB_DATABASE' => $data['db_database'] ?? null,
47+
'DB_USERNAME' => $data['db_username'] ?? null,
48+
'DB_PASSWORD' => $data['db_password'] ?? null,
49+
'OPENAI_API_KEY' => $data['openai'] ?? null,
50+
'STRIPE_PUBLIC' => $data['stripe_public'] ?? null,
51+
'STRIPE_SECRET' => $data['stripe_secret'] ?? null,
52+
]));
53+
54+
Artisan::call('config:clear');
55+
3456
if (!config('app.key')) {
3557
Artisan::call('key:generate', ['--ansi' => true]);
3658
}
@@ -49,6 +71,8 @@ public function store(Request $request): RedirectResponse
4971

5072
Setting::updateOrCreate(['key' => 'installed'], ['value' => now()->toDateTimeString()]);
5173

74+
Artisan::call('config:cache');
75+
5276
return redirect()->route('dashboard')->with('status', 'Installed');
5377
}
5478
}

app/Support/EnvWriter.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace App\Support;
4+
5+
class EnvWriter
6+
{
7+
public static function set(array $pairs): void
8+
{
9+
$envPath = base_path('.env');
10+
if (!file_exists($envPath)) {
11+
if (file_exists(base_path('.env.example'))) {
12+
copy(base_path('.env.example'), $envPath);
13+
} else {
14+
file_put_contents($envPath, "\n");
15+
}
16+
}
17+
$content = file_get_contents($envPath);
18+
foreach ($pairs as $key => $value) {
19+
$value = self::escape($value);
20+
if (preg_match("/^{$key}=.*/m", $content)) {
21+
$content = preg_replace("/^{$key}=.*/m", "{$key}={$value}", $content);
22+
} else {
23+
$content .= PHP_EOL."{$key}={$value}";
24+
}
25+
}
26+
file_put_contents($envPath, $content);
27+
}
28+
29+
protected static function escape($value): string
30+
{
31+
if ($value === null) return '';
32+
$needsQuotes = str_contains($value, ' ') || str_contains($value, '#') || str_contains($value, '"');
33+
$escaped = str_replace(["\n", "\r"], ['', ''], $value);
34+
if ($needsQuotes) {
35+
return '"'.str_replace('"', '\\"', $escaped).'"';
36+
}
37+
return $escaped;
38+
}
39+
}

resources/views/install/index.blade.php

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,49 @@
1414
@endif
1515
@endif
1616
<div class="mb-6 p-3 border rounded">
17-
<div>Env file: <strong>{{ $hasEnv ? 'Found' : 'Missing (using .env.example)'}} </strong></div>
17+
<div>Env file: <strong>{{ $hasEnv ? 'Found' : 'Missing (will create)'}} </strong></div>
1818
<div>App key: <strong>{{ $hasKey ? 'Set' : 'Not set (will be generated)'}} </strong></div>
1919
</div>
2020
<form method="POST" action="{{ route('install.store') }}" class="space-y-4">
2121
@csrf
22+
<h2 class="text-lg font-medium">App & Database</h2>
23+
<div>
24+
<label class="block">APP_URL</label>
25+
<input name="app_url" class="w-full p-2 border rounded" placeholder="https://example.com">
26+
</div>
27+
<div class="grid grid-cols-2 gap-3">
28+
<div>
29+
<label class="block">DB_HOST</label>
30+
<input name="db_host" class="w-full p-2 border rounded" placeholder="127.0.0.1">
31+
</div>
32+
<div>
33+
<label class="block">DB_DATABASE</label>
34+
<input name="db_database" class="w-full p-2 border rounded">
35+
</div>
36+
<div>
37+
<label class="block">DB_USERNAME</label>
38+
<input name="db_username" class="w-full p-2 border rounded">
39+
</div>
40+
<div>
41+
<label class="block">DB_PASSWORD</label>
42+
<input name="db_password" class="w-full p-2 border rounded">
43+
</div>
44+
</div>
45+
<h2 class="text-lg font-medium">API Keys</h2>
46+
<div>
47+
<label class="block">OpenAI API Key</label>
48+
<input name="openai" class="w-full p-2 border rounded" placeholder="sk-...">
49+
</div>
50+
<div class="grid grid-cols-2 gap-3">
51+
<div>
52+
<label class="block">Stripe Public Key</label>
53+
<input name="stripe_public" class="w-full p-2 border rounded" placeholder="pk_live_...">
54+
</div>
55+
<div>
56+
<label class="block">Stripe Secret Key</label>
57+
<input name="stripe_secret" class="w-full p-2 border rounded" placeholder="sk_live_...">
58+
</div>
59+
</div>
2260
<h2 class="text-lg font-medium">Create Admin User</h2>
2361
<div>
2462
<label class="block">Name</label>

0 commit comments

Comments
 (0)