feat(admin): IP pool allocation, billing exports, service attachments
- IP pool: sheet import (xlsx/csv) matched by address, bulk allocate/revoke with notification email (ip_allocated/ip_revoked), ip_pool_logs history. - Orders/invoices: Excel export on branded template (BrandedReportWriter), shared billing filters, order item service info in list responses. - Web design quote Excel export; activity log export. - Service attachments with copy-to-invoice; deployment invoice attachments. - Customer email attachments stored on disk and attached by path. - Admin password change endpoint; user.fullname backfill migration; orders.user_id backfill from logs. - Disable deploy workflow until CI/CD is set up. - Ignore stored customer email and service attachment uploads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ea5697cb81
commit
46aa138eec
@@ -2,84 +2,23 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Http\Services\SignRSA;
|
||||
use App\Models\Setting;
|
||||
use App\Support\Cache\CacheKey;
|
||||
use App\Support\MailSettings;
|
||||
use Illuminate\Mail\MailManager;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class MailConfigServiceProvider extends ServiceProvider
|
||||
{
|
||||
private static ?array $resolved = null;
|
||||
|
||||
public function register()
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
if (!App::runningInConsole()) {
|
||||
MailSettings::apply();
|
||||
|
||||
public function boot()
|
||||
{
|
||||
if (App::runningInConsole()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self::$resolved !== null) {
|
||||
Config::set('mail', self::$resolved);
|
||||
return;
|
||||
}
|
||||
|
||||
$config = Cache::remember(CacheKey::build('settings', 'mail'), 3600, function () {
|
||||
if (!Schema::hasTable('setting')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$mail = Setting::where('key', 'smtp')->first();
|
||||
$setting = Setting::where('key', 'setting')->first();
|
||||
|
||||
if (!$mail || !$setting) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$mail = json_decode($mail->value);
|
||||
$company = json_decode($setting->value)->company ?? 'Your Company';
|
||||
|
||||
$password = '';
|
||||
if (isset($mail->password)) {
|
||||
$decrypted = (new SignRSA())->DecryptFunc($mail->password);
|
||||
$password = $decrypted ?: $mail->password;
|
||||
}
|
||||
|
||||
$transport = $mail->transport ?? 'smtp';
|
||||
$encryption = $mail->encryption ?? config('mail.mailers.smtp.encryption');
|
||||
|
||||
if ($encryption === 0 || $encryption === '0' || $encryption === 'starttls') {
|
||||
$encryption = 'tls';
|
||||
}
|
||||
|
||||
$config = config('mail');
|
||||
$config['default'] = $transport;
|
||||
$config['from'] = [
|
||||
'address' => $mail->from_address ?? $mail->user ?? config('mail.from.address', 'no-reply@example.com'),
|
||||
'name' => $mail->from_name ?? $company,
|
||||
];
|
||||
$config['mailers'][$transport] = array_merge($config['mailers'][$transport] ?? [], [
|
||||
'transport' => $transport,
|
||||
'host' => $mail->host ?? '',
|
||||
'port' => $mail->port ?? 587,
|
||||
'encryption' => $encryption,
|
||||
'username' => $mail->user ?? '',
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
return $config;
|
||||
});
|
||||
|
||||
if ($config) {
|
||||
self::$resolved = $config;
|
||||
Config::set('mail', $config);
|
||||
}
|
||||
$this->app->afterResolving('mail.manager', fn () => MailSettings::apply());
|
||||
Queue::before(fn () => MailSettings::refresh($this->app->make('mail.manager')));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user