Files
InvoiceShelf/app/Http/Controllers/V1/Admin/Settings/MailConfigurationController.php
Darko Gjorgjijoski a38f09cf7b Installer reliability improvements (#593)
* docs: add CLAUDE.md for Claude Code guidance

* fix: handle missing settings table in installation middlewares

RedirectIfInstalled crashed with "no such table: settings" when the
database_created marker file existed but the database was empty.
Changed to use isDbCreated() which verifies actual tables, and added
try-catch around Setting queries in both middlewares.

* feat: pre-select database driver from env in installation wizard

The database step now reads DB_CONNECTION from the environment and
pre-selects the matching driver on load, including correct defaults
for hostname and port.

* feat: pre-select mail driver and config from env in installation wizard

The email step now fetches the current mail configuration on load
instead of hardcoding the driver to 'mail'. SMTP fields fall back
to Laravel config values from the environment.

* refactor: remove file-based DB marker in favor of direct DB checks

The database_created marker file was a second source of truth that
could drift out of sync with the actual database. InstallUtils now
checks the database directly via Schema::hasTable which is cached
per-request and handles all error cases gracefully.
2026-04-02 14:48:08 +02:00

258 lines
8.4 KiB
PHP
Executable File

<?php
namespace App\Http\Controllers\V1\Admin\Settings;
use App\Http\Controllers\Controller;
use App\Http\Requests\MailEnvironmentRequest;
use App\Mail\TestMail;
use App\Models\Setting;
use App\Space\EnvironmentManager;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Mail;
class MailConfigurationController extends Controller
{
/**
* The environment manager
*
* @var EnvironmentManager
*/
protected $environmentManager;
/**
* The constructor
*/
public function __construct(EnvironmentManager $environmentManager)
{
$this->environmentManager = $environmentManager;
}
/**
* Save the mail environment variables
*
* @return JsonResponse
*
* @throws AuthorizationException
*/
public function saveMailEnvironment(MailEnvironmentRequest $request)
{
$this->authorize('manage email config');
$setting = Setting::getSetting('profile_complete');
// Prepare mail settings for database storage
$mailSettings = $this->prepareMailSettingsForDatabase($request);
// Save mail settings to database
Setting::setSettings($mailSettings);
if ($setting !== 'COMPLETED') {
Setting::setSetting('profile_complete', 4);
}
return response()->json([
'success' => 'mail_variables_save_successfully',
]);
}
/**
* Prepare mail settings for database storage
*
* @return array
*/
private function prepareMailSettingsForDatabase(MailEnvironmentRequest $request)
{
$driver = $request->get('mail_driver');
// Base settings that are always saved
$settings = [
'mail_driver' => $driver,
'from_name' => $request->get('from_name'),
'from_mail' => $request->get('from_mail'),
];
// Driver-specific settings
switch ($driver) {
case 'smtp':
$settings = array_merge($settings, [
'mail_host' => $request->get('mail_host'),
'mail_port' => $request->get('mail_port'),
'mail_username' => $request->get('mail_username'),
'mail_password' => $request->get('mail_password'),
'mail_encryption' => $request->get('mail_encryption', 'none'),
'mail_scheme' => $request->get('mail_scheme'),
'mail_url' => $request->get('mail_url'),
'mail_timeout' => $request->get('mail_timeout'),
'mail_local_domain' => $request->get('mail_local_domain'),
]);
break;
case 'mailgun':
$settings = array_merge($settings, [
'mail_mailgun_domain' => $request->get('mail_mailgun_domain'),
'mail_mailgun_secret' => $request->get('mail_mailgun_secret'),
'mail_mailgun_endpoint' => $request->get('mail_mailgun_endpoint', 'api.mailgun.net'),
'mail_mailgun_scheme' => $request->get('mail_mailgun_scheme', 'https'),
]);
break;
case 'ses':
$settings = array_merge($settings, [
'mail_ses_key' => $request->get('mail_ses_key'),
'mail_ses_secret' => $request->get('mail_ses_secret'),
'mail_ses_region' => $request->get('mail_ses_region', 'us-east-1'),
]);
break;
case 'sendmail':
$settings = array_merge($settings, [
'mail_sendmail_path' => $request->get('mail_sendmail_path', '/usr/sbin/sendmail -bs -i'),
]);
break;
}
return $settings;
}
/**
* Return the mail environment variables
*
* @return JsonResponse
*
* @throws AuthorizationException
*/
public function getMailEnvironment()
{
$this->authorize('manage email config');
// Get mail settings from database
$mailSettings = Setting::getSettings([
'mail_driver',
'mail_host',
'mail_port',
'mail_username',
'mail_password',
'mail_encryption',
'mail_scheme',
'mail_url',
'mail_timeout',
'mail_local_domain',
'from_name',
'from_mail',
'mail_mailgun_domain',
'mail_mailgun_secret',
'mail_mailgun_endpoint',
'mail_mailgun_scheme',
'mail_ses_key',
'mail_ses_secret',
'mail_ses_region',
'mail_sendmail_path',
]);
$driver = $mailSettings['mail_driver'] ?? config('mail.default');
// Base data that's always available
$MailData = [
'mail_driver' => $driver,
'from_name' => $mailSettings['from_name'] ?? config('mail.from.name'),
'from_mail' => $mailSettings['from_mail'] ?? config('mail.from.address'),
];
// Driver-specific configuration
switch ($driver) {
case 'smtp':
$MailData = array_merge($MailData, [
'mail_host' => $mailSettings['mail_host'] ?? config('mail.mailers.smtp.host', ''),
'mail_port' => $mailSettings['mail_port'] ?? config('mail.mailers.smtp.port', ''),
'mail_username' => $mailSettings['mail_username'] ?? config('mail.mailers.smtp.username', ''),
'mail_password' => $mailSettings['mail_password'] ?? config('mail.mailers.smtp.password', ''),
'mail_encryption' => $mailSettings['mail_encryption'] ?? config('mail.mailers.smtp.encryption', 'none'),
'mail_scheme' => $mailSettings['mail_scheme'] ?? '',
'mail_url' => $mailSettings['mail_url'] ?? '',
'mail_timeout' => $mailSettings['mail_timeout'] ?? '',
'mail_local_domain' => $mailSettings['mail_local_domain'] ?? '',
]);
break;
case 'mailgun':
$MailData = array_merge($MailData, [
'mail_mailgun_domain' => $mailSettings['mail_mailgun_domain'] ?? '',
'mail_mailgun_secret' => $mailSettings['mail_mailgun_secret'] ?? '',
'mail_mailgun_endpoint' => $mailSettings['mail_mailgun_endpoint'] ?? 'api.mailgun.net',
'mail_mailgun_scheme' => $mailSettings['mail_mailgun_scheme'] ?? 'https',
]);
break;
case 'ses':
$MailData = array_merge($MailData, [
'mail_ses_key' => $mailSettings['mail_ses_key'] ?? '',
'mail_ses_secret' => $mailSettings['mail_ses_secret'] ?? '',
'mail_ses_region' => $mailSettings['mail_ses_region'] ?? 'us-east-1',
]);
break;
case 'sendmail':
$MailData = array_merge($MailData, [
'mail_sendmail_path' => $mailSettings['mail_sendmail_path'] ?? '/usr/sbin/sendmail -bs -i',
]);
break;
default:
// For unknown drivers, return minimal configuration
break;
}
return response()->json($MailData);
}
/**
* Return the available mail drivers
*
* @return JsonResponse
*
* @throws AuthorizationException
*/
public function getMailDrivers()
{
$this->authorize('manage email config');
$drivers = [
'smtp',
'mail',
'sendmail',
'mailgun',
'ses',
];
return response()->json($drivers);
}
/**
* Test the email configuration
*
* @return JsonResponse
*
* @throws AuthorizationException
* @throws ValidationException
*/
public function testEmailConfig(Request $request)
{
$this->authorize('manage email config');
$this->validate($request, [
'to' => 'required|email',
'subject' => 'required',
'message' => 'required',
]);
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
return response()->json([
'success' => true,
]);
}
}