mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-07 05:31:24 +00:00
Configurations cleanup & database configurations for mail and pdfs (#479)
* Move Mail, PDF configuration to Database, standardize configurations * Set default currency to USD on install * Pint code
This commit is contained in:
committed by
GitHub
parent
3da86965e1
commit
18d63a3375
46
.env.example
46
.env.example
@@ -1,19 +1,11 @@
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_KEY=base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=
|
||||
APP_DEBUG=true
|
||||
|
||||
APP_NAME="InvoiceShelf"
|
||||
APP_LOG_LEVEL=debug
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
DB_HOST=
|
||||
@@ -22,38 +14,6 @@ DB_DATABASE=
|
||||
DB_USERNAME=
|
||||
DB_PASSWORD=
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
CACHE_STORE=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=1440
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=
|
||||
MAIL_PORT=
|
||||
MAIL_USERNAME=
|
||||
MAIL_PASSWORD=
|
||||
MAIL_ENCRYPTION=
|
||||
|
||||
MAIL_FROM_NAME=
|
||||
MAIL_FROM_ADDRESS=
|
||||
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_KEY=
|
||||
PUSHER_SECRET=
|
||||
|
||||
SANCTUM_STATEFUL_DOMAIN=
|
||||
TRUSTED_PROXIES="*"
|
||||
|
||||
CRON_JOB_AUTH_TOKEN=""
|
||||
LOG_STACK=single
|
||||
|
||||
PDF_DRIVER=dompdf
|
||||
GOTENBERG_HOST=
|
||||
GOTENBERG_PAPERSIZE=
|
||||
|
||||
@@ -41,13 +41,79 @@ class MailConfigurationController extends Controller
|
||||
$this->authorize('manage email config');
|
||||
|
||||
$setting = Setting::getSetting('profile_complete');
|
||||
$results = $this->environmentManager->saveMailVariables($request);
|
||||
|
||||
// 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($results);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,51 +127,75 @@ class MailConfigurationController extends Controller
|
||||
{
|
||||
$this->authorize('manage email config');
|
||||
|
||||
$driver = config('mail.default');
|
||||
// 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' => config('mail.from.name'),
|
||||
'from_mail' => config('mail.from.address'),
|
||||
'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' => config('mail.mailers.smtp.host'),
|
||||
'mail_port' => config('mail.mailers.smtp.port'),
|
||||
'mail_username' => config('mail.mailers.smtp.username'),
|
||||
'mail_password' => config('mail.mailers.smtp.password'),
|
||||
'mail_encryption' => config('mail.mailers.smtp.scheme') ?? 'none',
|
||||
'mail_scheme' => config('mail.mailers.smtp.scheme'),
|
||||
'mail_url' => config('mail.mailers.smtp.url'),
|
||||
'mail_timeout' => config('mail.mailers.smtp.timeout'),
|
||||
'mail_local_domain' => config('mail.mailers.smtp.local_domain'),
|
||||
'mail_host' => $mailSettings['mail_host'] ?? '',
|
||||
'mail_port' => $mailSettings['mail_port'] ?? '',
|
||||
'mail_username' => $mailSettings['mail_username'] ?? '',
|
||||
'mail_password' => $mailSettings['mail_password'] ?? '',
|
||||
'mail_encryption' => $mailSettings['mail_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' => config('mail.mailers.mailgun.domain'),
|
||||
'mail_mailgun_secret' => config('mail.mailers.mailgun.secret'),
|
||||
'mail_mailgun_endpoint' => config('mail.mailers.mailgun.endpoint'),
|
||||
'mail_mailgun_scheme' => config('mail.mailers.mailgun.scheme'),
|
||||
'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' => config('services.ses.key'),
|
||||
'mail_ses_secret' => config('services.ses.secret'),
|
||||
'mail_ses_region' => config('services.ses.region'),
|
||||
'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' => config('mail.mailers.sendmail.path'),
|
||||
'mail_sendmail_path' => $mailSettings['mail_sendmail_path'] ?? '/usr/sbin/sendmail -bs -i',
|
||||
]);
|
||||
break;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\V1\Admin\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\PDFConfigurationRequest;
|
||||
use App\Models\Setting;
|
||||
use App\Space\EnvironmentManager;
|
||||
|
||||
class PDFConfigurationController extends Controller
|
||||
@@ -34,11 +35,19 @@ class PDFConfigurationController extends Controller
|
||||
{
|
||||
$this->authorize('manage pdf config');
|
||||
|
||||
// Get PDF settings from database
|
||||
$pdfSettings = Setting::getSettings([
|
||||
'pdf_driver',
|
||||
'gotenberg_host',
|
||||
'gotenberg_papersize',
|
||||
'gotenberg_margins',
|
||||
]);
|
||||
|
||||
$config = [
|
||||
'pdf_driver' => config('pdf.driver'),
|
||||
'gotenberg_host' => config('pdf.gotenberg.host'),
|
||||
'gotenberg_margins' => config('pdf.gotenberg.margins'),
|
||||
'gotenberg_papersize' => config('pdf.gotenberg.papersize'),
|
||||
'pdf_driver' => $pdfSettings['pdf_driver'] ?? config('pdf.driver'),
|
||||
'gotenberg_host' => $pdfSettings['gotenberg_host'] ?? config('pdf.connections.gotenberg.host'),
|
||||
'gotenberg_margins' => $pdfSettings['gotenberg_margins'] ?? config('pdf.connections.gotenberg.margins'),
|
||||
'gotenberg_papersize' => $pdfSettings['gotenberg_papersize'] ?? config('pdf.connections.gotenberg.papersize'),
|
||||
];
|
||||
|
||||
return response()->json($config);
|
||||
@@ -47,8 +56,47 @@ class PDFConfigurationController extends Controller
|
||||
public function saveEnvironment(PDFConfigurationRequest $request)
|
||||
{
|
||||
$this->authorize('manage pdf config');
|
||||
$results = $this->environmentManager->savePDFVariables($request);
|
||||
|
||||
return response()->json($results);
|
||||
// Prepare PDF settings for database storage
|
||||
$pdfSettings = $this->preparePDFSettingsForDatabase($request);
|
||||
|
||||
// Save PDF settings to database
|
||||
Setting::setSettings($pdfSettings);
|
||||
|
||||
return response()->json([
|
||||
'success' => 'pdf_variables_save_successfully',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare PDF settings for database storage
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function preparePDFSettingsForDatabase(PDFConfigurationRequest $request)
|
||||
{
|
||||
$driver = $request->get('pdf_driver');
|
||||
|
||||
// Base settings that are always saved
|
||||
$settings = [
|
||||
'pdf_driver' => $driver,
|
||||
];
|
||||
|
||||
// Driver-specific settings
|
||||
switch ($driver) {
|
||||
case 'gotenberg':
|
||||
$settings = array_merge($settings, [
|
||||
'gotenberg_host' => $request->get('gotenberg_host'),
|
||||
'gotenberg_papersize' => $request->get('gotenberg_papersize'),
|
||||
'gotenberg_margins' => $request->get('gotenberg_margins'),
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'dompdf':
|
||||
// dompdf doesn't have additional configuration in the current setup
|
||||
break;
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,15 +18,15 @@ class ConfigMiddleware
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (InstallUtils::isDbCreated()) {
|
||||
// Only handle dynamic file disk switching when file_disk_id is provided
|
||||
if ($request->has('file_disk_id')) {
|
||||
$file_disk = FileDisk::find($request->file_disk_id);
|
||||
} else {
|
||||
$file_disk = FileDisk::whereSetAsDefault(true)->first();
|
||||
}
|
||||
|
||||
if ($file_disk) {
|
||||
$file_disk->setConfig();
|
||||
if ($file_disk) {
|
||||
$file_disk->setConfig();
|
||||
}
|
||||
}
|
||||
// Default file disk is now handled by AppConfigProvider during boot
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
||||
@@ -33,10 +33,34 @@ class MailEnvironmentRequest extends FormRequest
|
||||
'mail_port' => [
|
||||
'required',
|
||||
],
|
||||
'mail_username' => [
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
'mail_password' => [
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
'mail_encryption' => [
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
'mail_scheme' => [
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
'mail_url' => [
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
'mail_timeout' => [
|
||||
'nullable',
|
||||
'integer',
|
||||
],
|
||||
'mail_local_domain' => [
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
'from_name' => [
|
||||
'required',
|
||||
'string',
|
||||
@@ -44,11 +68,10 @@ class MailEnvironmentRequest extends FormRequest
|
||||
'from_mail' => [
|
||||
'required',
|
||||
'string',
|
||||
'email',
|
||||
],
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case 'mailgun':
|
||||
return [
|
||||
'mail_driver' => [
|
||||
@@ -64,43 +87,10 @@ class MailEnvironmentRequest extends FormRequest
|
||||
'string',
|
||||
],
|
||||
'mail_mailgun_endpoint' => [
|
||||
'required',
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
'from_name' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'from_mail' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case 'ses':
|
||||
return [
|
||||
'mail_driver' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'mail_host' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'mail_port' => [
|
||||
'required',
|
||||
],
|
||||
'mail_ses_key' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'mail_ses_secret' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'mail_encryption' => [
|
||||
'mail_mailgun_scheme' => [
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
@@ -111,13 +101,28 @@ class MailEnvironmentRequest extends FormRequest
|
||||
'from_mail' => [
|
||||
'required',
|
||||
'string',
|
||||
'email',
|
||||
],
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case 'mail':
|
||||
case 'ses':
|
||||
return [
|
||||
'mail_driver' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'mail_ses_key' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'mail_ses_secret' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'mail_ses_region' => [
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
'from_name' => [
|
||||
'required',
|
||||
'string',
|
||||
@@ -125,13 +130,20 @@ class MailEnvironmentRequest extends FormRequest
|
||||
'from_mail' => [
|
||||
'required',
|
||||
'string',
|
||||
'email',
|
||||
],
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case 'sendmail':
|
||||
return [
|
||||
'mail_driver' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'mail_sendmail_path' => [
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
'from_name' => [
|
||||
'required',
|
||||
'string',
|
||||
@@ -139,10 +151,26 @@ class MailEnvironmentRequest extends FormRequest
|
||||
'from_mail' => [
|
||||
'required',
|
||||
'string',
|
||||
'email',
|
||||
],
|
||||
];
|
||||
|
||||
break;
|
||||
default:
|
||||
return [
|
||||
'mail_driver' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'from_name' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'from_mail' => [
|
||||
'required',
|
||||
'string',
|
||||
'email',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ class PDFConfigurationRequest extends FormRequest
|
||||
'string',
|
||||
],
|
||||
];
|
||||
break;
|
||||
|
||||
case 'gotenberg':
|
||||
return [
|
||||
@@ -40,18 +39,28 @@ class PDFConfigurationRequest extends FormRequest
|
||||
'url',
|
||||
],
|
||||
'gotenberg_papersize' => [
|
||||
'required',
|
||||
'string',
|
||||
function ($attribute, $value, $fail) {
|
||||
($attribute); // unused
|
||||
$reg = "/^\d+(pt|px|pc|mm|cm|in) \d+(pt|px|pc|mm|cm|in)$/";
|
||||
if (! preg_match($reg, $value)) {
|
||||
$fail('Invalid papersize, must be in format "210mm 297mm". Accepts: pt,px,pc,mm,cm,in');
|
||||
}
|
||||
},
|
||||
],
|
||||
'gotenberg_margins' => [
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
];
|
||||
|
||||
break;
|
||||
default:
|
||||
return [
|
||||
'pdf_driver' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
];
|
||||
}
|
||||
throw new \InvalidArgumentException('Invalid PDFDriver requested');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Carbon;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
|
||||
176
app/Providers/AppConfigProvider.php
Normal file
176
app/Providers/AppConfigProvider.php
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Setting;
|
||||
use App\Space\InstallUtils;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppConfigProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
// Check if database is available
|
||||
if (! InstallUtils::isDbCreated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->configureMailFromDatabase();
|
||||
$this->configurePDFFromDatabase();
|
||||
$this->configureFileSystemFromDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure mail settings from database
|
||||
*/
|
||||
protected function configureMailFromDatabase(): void
|
||||
{
|
||||
try {
|
||||
// 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',
|
||||
]);
|
||||
|
||||
if (! empty($mailSettings['mail_driver'])) {
|
||||
$driver = $mailSettings['mail_driver'];
|
||||
|
||||
// Set default mailer
|
||||
Config::set('mail.default', $driver);
|
||||
|
||||
// Configure based on driver
|
||||
switch ($driver) {
|
||||
case 'smtp':
|
||||
Config::set('mail.mailers.smtp.host', $mailSettings['mail_host'] ?? '127.0.0.1');
|
||||
Config::set('mail.mailers.smtp.port', $mailSettings['mail_port'] ?? 2525);
|
||||
Config::set('mail.mailers.smtp.username', $mailSettings['mail_username'] ?? null);
|
||||
Config::set('mail.mailers.smtp.password', $mailSettings['mail_password'] ?? null);
|
||||
Config::set('mail.mailers.smtp.encryption', $mailSettings['mail_encryption'] ?? 'none');
|
||||
Config::set('mail.mailers.smtp.scheme', $mailSettings['mail_scheme'] ?? null);
|
||||
Config::set('mail.mailers.smtp.url', $mailSettings['mail_url'] ?? null);
|
||||
Config::set('mail.mailers.smtp.timeout', $mailSettings['mail_timeout'] ?? null);
|
||||
Config::set('mail.mailers.smtp.local_domain', $mailSettings['mail_local_domain'] ?? null);
|
||||
break;
|
||||
|
||||
case 'mailgun':
|
||||
Config::set('mail.mailers.mailgun.domain', $mailSettings['mail_mailgun_domain'] ?? null);
|
||||
Config::set('mail.mailers.mailgun.secret', $mailSettings['mail_mailgun_secret'] ?? null);
|
||||
Config::set('mail.mailers.mailgun.endpoint', $mailSettings['mail_mailgun_endpoint'] ?? 'api.mailgun.net');
|
||||
Config::set('mail.mailers.mailgun.scheme', $mailSettings['mail_mailgun_scheme'] ?? 'https');
|
||||
|
||||
// Also set services config for mailgun
|
||||
Config::set('services.mailgun.domain', $mailSettings['mail_mailgun_domain'] ?? null);
|
||||
Config::set('services.mailgun.secret', $mailSettings['mail_mailgun_secret'] ?? null);
|
||||
Config::set('services.mailgun.endpoint', $mailSettings['mail_mailgun_endpoint'] ?? 'api.mailgun.net');
|
||||
break;
|
||||
|
||||
case 'ses':
|
||||
Config::set('services.ses.key', $mailSettings['mail_ses_key'] ?? null);
|
||||
Config::set('services.ses.secret', $mailSettings['mail_ses_secret'] ?? null);
|
||||
Config::set('services.ses.region', $mailSettings['mail_ses_region'] ?? 'us-east-1');
|
||||
break;
|
||||
|
||||
case 'sendmail':
|
||||
Config::set('mail.mailers.sendmail.path', $mailSettings['mail_sendmail_path'] ?? '/usr/sbin/sendmail -bs -i');
|
||||
break;
|
||||
}
|
||||
|
||||
// Set global from address and name
|
||||
if (! empty($mailSettings['from_mail'])) {
|
||||
Config::set('mail.from.address', $mailSettings['from_mail']);
|
||||
}
|
||||
if (! empty($mailSettings['from_name'])) {
|
||||
Config::set('mail.from.name', $mailSettings['from_name']);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Silently fail if database is not available (during installation, migrations, etc.)
|
||||
// This prevents the application from breaking during setup
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure PDF settings from database
|
||||
*/
|
||||
protected function configurePDFFromDatabase(): void
|
||||
{
|
||||
try {
|
||||
// Get PDF settings from database
|
||||
$pdfSettings = Setting::getSettings([
|
||||
'pdf_driver',
|
||||
'gotenberg_host',
|
||||
'gotenberg_papersize',
|
||||
'gotenberg_margins',
|
||||
]);
|
||||
|
||||
if (! empty($pdfSettings['pdf_driver'])) {
|
||||
$driver = $pdfSettings['pdf_driver'];
|
||||
|
||||
// Set PDF driver
|
||||
Config::set('pdf.driver', $driver);
|
||||
|
||||
// Configure based on driver
|
||||
switch ($driver) {
|
||||
case 'gotenberg':
|
||||
if (! empty($pdfSettings['gotenberg_host'])) {
|
||||
Config::set('pdf.connections.gotenberg.host', $pdfSettings['gotenberg_host']);
|
||||
}
|
||||
if (! empty($pdfSettings['gotenberg_papersize'])) {
|
||||
Config::set('pdf.connections.gotenberg.papersize', $pdfSettings['gotenberg_papersize']);
|
||||
}
|
||||
if (! empty($pdfSettings['gotenberg_margins'])) {
|
||||
Config::set('pdf.connections.gotenberg.margins', $pdfSettings['gotenberg_margins']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'dompdf':
|
||||
// dompdf doesn't have additional configuration in the current setup
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Silently fail if database is not available (during installation, migrations, etc.)
|
||||
// This prevents the application from breaking during setup
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure file system settings from database
|
||||
*/
|
||||
protected function configureFileSystemFromDatabase(): void
|
||||
{
|
||||
try {
|
||||
// Get the default file disk from database
|
||||
$fileDisk = \App\Models\FileDisk::whereSetAsDefault(true)->first();
|
||||
|
||||
if ($fileDisk) {
|
||||
$fileDisk->setConfig();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Silently fail if database is not available (during installation, migrations, etc.)
|
||||
// This prevents the application from breaking during setup
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,12 +36,12 @@ class GotenbergPDFDriver
|
||||
{
|
||||
public function loadView(string $viewname): GotenbergPDFResponse
|
||||
{
|
||||
$papersize = explode(' ', config('pdf.gotenberg.papersize'));
|
||||
$papersize = explode(' ', config('pdf.connections.gotenberg.papersize'));
|
||||
if (count($papersize) != 2) {
|
||||
throw new \InvalidArgumentException('Invalid Gotenberg Papersize specified');
|
||||
}
|
||||
|
||||
$host = config('pdf.gotenberg.host');
|
||||
$host = config('pdf.connections.gotenberg.host');
|
||||
$request = Gotenberg::chromium($host)
|
||||
->pdf()
|
||||
->margins(0, 0, 0, 0) // Margins can be set using CSS
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
namespace App\Space;
|
||||
|
||||
use App\Http\Requests\DatabaseEnvironmentRequest;
|
||||
use App\Http\Requests\DiskEnvironmentRequest;
|
||||
use App\Http\Requests\DomainEnvironmentRequest;
|
||||
use App\Http\Requests\MailEnvironmentRequest;
|
||||
use App\Http\Requests\PDFConfigurationRequest;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
@@ -238,29 +236,6 @@ class EnvironmentManager
|
||||
return DB::connection()->getPdo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the mail content to the .env file.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function saveMailVariables(MailEnvironmentRequest $request)
|
||||
{
|
||||
$mailEnv = $this->getMailConfiguration($request);
|
||||
|
||||
try {
|
||||
|
||||
$this->updateEnv($mailEnv);
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'error' => 'mail_variables_save_error',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => 'mail_variables_save_successfully',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the pdf generation content to the .env file.
|
||||
*
|
||||
@@ -315,169 +290,6 @@ class EnvironmentManager
|
||||
return $pdfEnv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mail configuration
|
||||
*
|
||||
* @param MailEnvironmentRequest $request
|
||||
* @return array
|
||||
*/
|
||||
private function getMailConfiguration($request)
|
||||
{
|
||||
$mailEnv = [];
|
||||
|
||||
$driver = $request->get('mail_driver');
|
||||
|
||||
switch ($driver) {
|
||||
case 'smtp':
|
||||
|
||||
$mailEnv = [
|
||||
'MAIL_MAILER' => $request->get('mail_driver'),
|
||||
'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_SCHEME' => $request->get('mail_encryption') !== 'none' ? $request->get('mail_encryption') : 'null',
|
||||
'MAIL_FROM_ADDRESS' => $request->get('from_mail'),
|
||||
'MAIL_FROM_NAME' => $request->get('from_name'),
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case 'mailgun':
|
||||
|
||||
$mailEnv = [
|
||||
'MAIL_MAILER' => $request->get('mail_driver'),
|
||||
'MAIL_HOST' => $request->get('mail_host'),
|
||||
'MAIL_PORT' => $request->get('mail_port'),
|
||||
'MAIL_USERNAME' => config('mail.username'),
|
||||
'MAIL_PASSWORD' => config('mail.password'),
|
||||
'MAIL_FROM_ADDRESS' => $request->get('from_mail'),
|
||||
'MAIL_FROM_NAME' => $request->get('from_name'),
|
||||
'MAILGUN_DOMAIN' => $request->get('mail_mailgun_domain'),
|
||||
'MAILGUN_SECRET' => $request->get('mail_mailgun_secret'),
|
||||
'MAILGUN_ENDPOINT' => $request->get('mail_mailgun_endpoint'),
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case 'ses':
|
||||
|
||||
$mailEnv = [
|
||||
'MAIL_MAILER' => $request->get('mail_driver'),
|
||||
'MAIL_HOST' => $request->get('mail_host'),
|
||||
'MAIL_PORT' => $request->get('mail_port'),
|
||||
'MAIL_USERNAME' => config('mail.username'),
|
||||
'MAIL_PASSWORD' => config('mail.password'),
|
||||
'MAIL_ENCRYPTION' => $request->get('mail_encryption'),
|
||||
'MAIL_FROM_ADDRESS' => $request->get('from_mail'),
|
||||
'MAIL_FROM_NAME' => $request->get('from_name'),
|
||||
'SES_KEY' => $request->get('mail_ses_key'),
|
||||
'SES_SECRET' => $request->get('mail_ses_secret'),
|
||||
'SES_REGION' => $request->get('mail_ses_region'),
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case 'sendmail':
|
||||
case 'mail':
|
||||
|
||||
$mailEnv = [
|
||||
'MAIL_MAILER' => $request->get('mail_driver'),
|
||||
'MAIL_HOST' => config('mail.host'),
|
||||
'MAIL_PORT' => config('mail.port'),
|
||||
'MAIL_USERNAME' => config('mail.username'),
|
||||
'MAIL_PASSWORD' => config('mail.password'),
|
||||
'MAIL_ENCRYPTION' => config('mail.encryption'),
|
||||
'MAIL_FROM_ADDRESS' => $request->get('from_mail'),
|
||||
'MAIL_FROM_NAME' => $request->get('from_name'),
|
||||
];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return $mailEnv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the disk content to the .env file.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function saveDiskVariables(DiskEnvironmentRequest $request)
|
||||
{
|
||||
$diskEnv = $this->getDiskConfiguration($request);
|
||||
|
||||
try {
|
||||
|
||||
$this->updateEnv($diskEnv);
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'error' => 'disk_variables_save_error',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => 'disk_variables_save_successfully',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the disk configuration
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getDiskConfiguration(DiskEnvironmentRequest $request)
|
||||
{
|
||||
$diskEnv = [];
|
||||
|
||||
$driver = $request->get('app_domain');
|
||||
|
||||
if ($driver) {
|
||||
$diskEnv['FILESYSTEM_DRIVER'] = $driver;
|
||||
}
|
||||
|
||||
switch ($request->get('selected_driver')) {
|
||||
case 's3':
|
||||
|
||||
$diskEnv = [
|
||||
'AWS_KEY' => $request->get('aws_key'),
|
||||
'AWS_SECRET' => $request->get('aws_secret'),
|
||||
'AWS_REGION' => $request->get('aws_region'),
|
||||
'AWS_BUCKET' => $request->get('aws_bucket'),
|
||||
'AWS_ROOT' => $request->get('aws_root'),
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case 'doSpaces':
|
||||
|
||||
$diskEnv = [
|
||||
'DO_SPACES_KEY' => $request->get('do_spaces_key'),
|
||||
'DO_SPACES_SECRET' => $request->get('do_spaces_secret'),
|
||||
'DO_SPACES_REGION' => $request->get('do_spaces_region'),
|
||||
'DO_SPACES_BUCKET' => $request->get('do_spaces_bucket'),
|
||||
'DO_SPACES_ENDPOINT' => $request->get('do_spaces_endpoint'),
|
||||
'DO_SPACES_ROOT' => $request->get('do_spaces_root'),
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case 'dropbox':
|
||||
|
||||
$diskEnv = [
|
||||
'DROPBOX_TOKEN' => $request->get('dropbox_token'),
|
||||
'DROPBOX_KEY' => $request->get('dropbox_key'),
|
||||
'DROPBOX_SECRET' => $request->get('dropbox_secret'),
|
||||
'DROPBOX_APP' => $request->get('dropbox_app'),
|
||||
'DROPBOX_ROOT' => $request->get('dropbox_root'),
|
||||
];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return $diskEnv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save sanctum stateful domain to the .env file.
|
||||
*
|
||||
@@ -507,35 +319,6 @@ class EnvironmentManager
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Order the env contents
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reoderEnv()
|
||||
{
|
||||
$contents = $this->getEnvContents();
|
||||
$contents = explode($this->delimiter, $contents);
|
||||
if (empty($contents)) {
|
||||
return;
|
||||
}
|
||||
natsort($contents);
|
||||
|
||||
$formatted = '';
|
||||
$previous = '';
|
||||
foreach ($contents as $current) {
|
||||
$parts_line = explode('_', $current);
|
||||
$parts_last = explode('_', $previous);
|
||||
if ($parts_line[0] != $parts_last[0]) {
|
||||
$formatted .= $this->delimiter;
|
||||
}
|
||||
$formatted .= $current.$this->delimiter;
|
||||
$previous = $current;
|
||||
}
|
||||
|
||||
file_put_contents($this->envPath, trim($formatted));
|
||||
}
|
||||
|
||||
private function getDomains(string $requestDomain): array
|
||||
{
|
||||
$appUrl = config('app.url');
|
||||
|
||||
@@ -6,4 +6,5 @@ return [
|
||||
App\Providers\DropboxServiceProvider::class,
|
||||
App\Providers\ViewServiceProvider::class,
|
||||
App\Providers\PDFServiceProvider::class,
|
||||
App\Providers\AppConfigProvider::class,
|
||||
];
|
||||
|
||||
@@ -13,6 +13,19 @@ use App\Models\RecurringInvoice;
|
||||
use App\Models\TaxType;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Abilities Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is for defining the abilities used in the application. Each
|
||||
| ability includes a name, a unique identifier (ability), the associated
|
||||
| model, and any dependencies on other abilities. This configuration helps
|
||||
| manage user permissions and access control throughout the application.
|
||||
|
|
||||
*/
|
||||
|
||||
'abilities' => [
|
||||
|
||||
// Customer
|
||||
|
||||
@@ -4,11 +4,19 @@ use Illuminate\Support\Facades\Facade;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Class Aliases
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This array of class aliases will be registered when this application
|
||||
| is started. You may add any additional class aliases which should
|
||||
| be loaded to the array. For speed, all aliases are lazy loaded.
|
||||
|
|
||||
*/
|
||||
|
||||
'aliases' => Facade::defaultAliases()->merge([
|
||||
'Flash' => Laracasts\Flash\Flash::class,
|
||||
'Menu' => Lavary\Menu\Facade::class,
|
||||
'Pusher' => Pusher\Pusher::class,
|
||||
'Redis' => Illuminate\Support\Facades\Redis::class,
|
||||
])->toArray(),
|
||||
|
||||
];
|
||||
|
||||
@@ -2,13 +2,49 @@
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Defaults
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option defines the default authentication "guard" and password
|
||||
| reset "broker" for your application. You may change these values
|
||||
| as required, but they're a perfect start for most applications.
|
||||
|
|
||||
*/
|
||||
|
||||
'defaults' => [
|
||||
'guard' => env('AUTH_GUARD', 'web'),
|
||||
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Guards
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Next, you may define every authentication guard for your application.
|
||||
| Of course, a great default configuration has been defined for you
|
||||
| which utilizes session storage plus the Eloquent user provider.
|
||||
|
|
||||
| All authentication guards have a user provider, which defines how the
|
||||
| users are actually retrieved out of your database or other storage
|
||||
| system used by the application. Typically, Eloquent is utilized.
|
||||
|
|
||||
| Supported: "session"
|
||||
|
|
||||
*/
|
||||
|
||||
'guards' => [
|
||||
'web' => [
|
||||
'driver' => 'session',
|
||||
'provider' => 'users',
|
||||
],
|
||||
'api' => [
|
||||
'driver' => 'token',
|
||||
'provider' => 'users',
|
||||
'hash' => false,
|
||||
],
|
||||
|
||||
'customer' => [
|
||||
'driver' => 'session',
|
||||
'provider' => 'customers',
|
||||
@@ -17,13 +53,42 @@ return [
|
||||
],
|
||||
|
||||
'providers' => [
|
||||
'users' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => \App\Models\User::class,
|
||||
],
|
||||
'customers' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => \App\Models\Customer::class,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Resetting Passwords
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These configuration options specify the behavior of Laravel's password
|
||||
| reset functionality, including the table utilized for token storage
|
||||
| and the user provider that is invoked to actually retrieve users.
|
||||
|
|
||||
| The expiry time is the number of minutes that each reset token will be
|
||||
| considered valid. This security feature keeps tokens short-lived so
|
||||
| they have less time to be guessed. You may change this as needed.
|
||||
|
|
||||
| The throttle setting is the number of seconds a user must wait before
|
||||
| generating more password reset tokens. This prevents the user from
|
||||
| quickly generating a very large amount of password reset tokens.
|
||||
|
|
||||
*/
|
||||
|
||||
'passwords' => [
|
||||
'users' => [
|
||||
'provider' => 'users',
|
||||
'table' => 'password_reset_tokens',
|
||||
'expire' => 60,
|
||||
'throttle' => 60,
|
||||
],
|
||||
'customers' => [
|
||||
'provider' => 'customers',
|
||||
'table' => 'password_reset_tokens',
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Cache Store
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default cache store that will be used by the
|
||||
| framework. This connection is utilized if another isn't explicitly
|
||||
| specified when running a cache operation inside the application.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('CACHE_STORE', 'file'),
|
||||
];
|
||||
|
||||
@@ -2,9 +2,41 @@
|
||||
|
||||
return [
|
||||
|
||||
'cloud' => env('FILESYSTEM_CLOUD', 's3'),
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Filesystem Disk
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the default filesystem disk that should be used
|
||||
| by the framework. The "local" disk, as well as a variety of cloud
|
||||
| based disks are available to your application for file storage.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('FILESYSTEM_DISK', 'local'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Filesystem Disks
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Below you may configure as many filesystem disks as necessary, and you
|
||||
| may even configure multiple disks for the same driver. Examples for
|
||||
| most supported storage drivers are configured here for reference.
|
||||
|
|
||||
| Supported drivers: "local", "ftp", "sftp", "s3"
|
||||
|
|
||||
*/
|
||||
|
||||
'disks' => [
|
||||
|
||||
'local' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app'),
|
||||
'throw' => false,
|
||||
'report' => false,
|
||||
],
|
||||
|
||||
's3' => [
|
||||
'driver' => 's3',
|
||||
'key' => env('AWS_KEY'),
|
||||
@@ -24,11 +56,6 @@ return [
|
||||
'bucket' => env('S3_COMPAT_BUCKET'),
|
||||
],
|
||||
|
||||
'media' => [
|
||||
'driver' => 'local',
|
||||
'root' => public_path('media'),
|
||||
],
|
||||
|
||||
'doSpaces' => [
|
||||
'type' => 'AwsS3',
|
||||
'driver' => 's3',
|
||||
@@ -51,6 +78,11 @@ return [
|
||||
'root' => env('DROPBOX_ROOT'),
|
||||
],
|
||||
|
||||
'media' => [
|
||||
'driver' => 'local',
|
||||
'root' => public_path('media'),
|
||||
],
|
||||
|
||||
'views' => [
|
||||
'driver' => 'local',
|
||||
'root' => resource_path('views'),
|
||||
@@ -60,13 +92,6 @@ return [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/templates/pdf'),
|
||||
],
|
||||
|
||||
'local' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app'),
|
||||
'throw' => false,
|
||||
'report' => false,
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -2,13 +2,35 @@
|
||||
|
||||
return [
|
||||
|
||||
'driver' => env('PDF_DRIVER', 'gotenberg'),
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default PDF Driver
|
||||
|--------------------------------------------------------------------------
|
||||
| Here you may specify which of the PDF drivers below you wish to use as
|
||||
| your default driver for all PDF generation.
|
||||
|
|
||||
*/
|
||||
|
||||
'gotenberg' => [
|
||||
'host' => env('GOTENBERG_HOST', 'http://pdf:3000'),
|
||||
'papersize' => env('GOTENBERG_PAPERSIZE', '210mm 297mm'),
|
||||
'driver' => env('PDF_DRIVER', 'dompdf'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| PDF Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here are each of the connections setup for your application. Example
|
||||
| configuration has been included, but you may add as many connections as
|
||||
| you would like.
|
||||
|
|
||||
*/
|
||||
'connections' => [
|
||||
|
||||
'dompdf' => [],
|
||||
|
||||
'gotenberg' => [
|
||||
'host' => env('GOTENBERG_HOST', 'http://pdf:3000'),
|
||||
'papersize' => env('GOTENBERG_PAPERSIZE', '210mm 297mm'),
|
||||
],
|
||||
],
|
||||
|
||||
'dompdf' => [],
|
||||
|
||||
];
|
||||
|
||||
107
config/queue.php
107
config/queue.php
@@ -1,5 +1,112 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Queue Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Laravel's queue supports a variety of backends via a single, unified
|
||||
| API, giving you convenient access to each backend using identical
|
||||
| syntax for each. The default queue connection is defined below.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('QUEUE_CONNECTION', 'sync'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the connection options for every queue backend
|
||||
| used by your application. An example configuration is provided for
|
||||
| each backend supported by Laravel. You're also free to add more.
|
||||
|
|
||||
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'sync' => [
|
||||
'driver' => 'sync',
|
||||
],
|
||||
|
||||
'database' => [
|
||||
'driver' => 'database',
|
||||
'connection' => env('DB_QUEUE_CONNECTION'),
|
||||
'table' => env('DB_QUEUE_TABLE', 'jobs'),
|
||||
'queue' => env('DB_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90),
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'beanstalkd' => [
|
||||
'driver' => 'beanstalkd',
|
||||
'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'),
|
||||
'queue' => env('BEANSTALKD_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90),
|
||||
'block_for' => 0,
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'sqs' => [
|
||||
'driver' => 'sqs',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
|
||||
'queue' => env('SQS_QUEUE', 'default'),
|
||||
'suffix' => env('SQS_SUFFIX'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
|
||||
'queue' => env('REDIS_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90),
|
||||
'block_for' => null,
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Job Batching
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following options configure the database and table that store job
|
||||
| batching information. These options can be updated to any database
|
||||
| connection and table which has been defined by your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'batching' => [
|
||||
'database' => env('DB_CONNECTION', 'sqlite'),
|
||||
'table' => 'job_batches',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Failed Queue Jobs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These options configure the behavior of failed queue job logging so you
|
||||
| can control how and where failed jobs are stored. Laravel ships with
|
||||
| support for storing failed jobs in a simple file or in a database.
|
||||
|
|
||||
| Supported drivers: "database-uuids", "dynamodb", "file", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'failed' => [
|
||||
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
|
||||
'database' => env('DB_CONNECTION', 'sqlite'),
|
||||
'table' => 'failed_jobs',
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -2,6 +2,18 @@
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Third Party Services
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is for storing the credentials for third party services such
|
||||
| as Mailgun, Postmark, AWS and more. This file provides the de facto
|
||||
| location for this type of information, allowing packages to have
|
||||
| a conventional file to locate the various service credentials.
|
||||
|
|
||||
*/
|
||||
|
||||
'mailgun' => [
|
||||
'domain' => env('MAILGUN_DOMAIN'),
|
||||
'secret' => env('MAILGUN_SECRET'),
|
||||
@@ -26,28 +38,6 @@ return [
|
||||
],
|
||||
],
|
||||
|
||||
'facebook' => [
|
||||
'client_id' => env('FACEBOOK_CLIENT_ID'),
|
||||
'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
|
||||
'redirect' => env('FACEBOOK_REDIRECT_URL'),
|
||||
],
|
||||
|
||||
'google' => [
|
||||
'client_id' => env('GOOGLE_CLIENT_ID'),
|
||||
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
|
||||
'redirect' => env('GOOGLE_REDIRECT_URL'),
|
||||
],
|
||||
|
||||
'github' => [
|
||||
'client_id' => env('GITHUB_CLIENT_ID'),
|
||||
'client_secret' => env('GITHUB_CLIENT_SECRET'),
|
||||
'redirect' => env('GITHUB_REDIRECT_URL'),
|
||||
],
|
||||
|
||||
'cron_job' => [
|
||||
'auth_token' => env('CRON_JOB_AUTH_TOKEN', 0),
|
||||
],
|
||||
|
||||
'ses' => [
|
||||
'key' => env('SES_KEY'),
|
||||
'secret' => env('SES_SECRET'),
|
||||
|
||||
217
config/session.php
Normal file
217
config/session.php
Normal file
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Session Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option determines the default session driver that is utilized for
|
||||
| incoming requests. Laravel supports a variety of storage options to
|
||||
| persist session data. Database storage is a great default choice.
|
||||
|
|
||||
| Supported: "file", "cookie", "database", "apc",
|
||||
| "memcached", "redis", "dynamodb", "array"
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => env('SESSION_DRIVER', 'file'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Lifetime
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the number of minutes that you wish the session
|
||||
| to be allowed to remain idle before it expires. If you want them
|
||||
| to expire immediately when the browser is closed then you may
|
||||
| indicate that via the expire_on_close configuration option.
|
||||
|
|
||||
*/
|
||||
|
||||
'lifetime' => (int) env('SESSION_LIFETIME', 1440),
|
||||
|
||||
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Encryption
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to easily specify that all of your session data
|
||||
| should be encrypted before it's stored. All encryption is performed
|
||||
| automatically by Laravel and you may use the session like normal.
|
||||
|
|
||||
*/
|
||||
|
||||
'encrypt' => env('SESSION_ENCRYPT', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session File Location
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When utilizing the "file" session driver, the session files are placed
|
||||
| on disk. The default storage location is defined here; however, you
|
||||
| are free to provide another location where they should be stored.
|
||||
|
|
||||
*/
|
||||
|
||||
'files' => storage_path('framework/sessions'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Database Connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using the "database" or "redis" session drivers, you may specify a
|
||||
| connection that should be used to manage these sessions. This should
|
||||
| correspond to a connection in your database configuration options.
|
||||
|
|
||||
*/
|
||||
|
||||
'connection' => env('SESSION_CONNECTION'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Database Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using the "database" session driver, you may specify the table to
|
||||
| be used to store sessions. Of course, a sensible default is defined
|
||||
| for you; however, you're welcome to change this to another table.
|
||||
|
|
||||
*/
|
||||
|
||||
'table' => env('SESSION_TABLE', 'sessions'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cache Store
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using one of the framework's cache driven session backends, you may
|
||||
| define the cache store which should be used to store the session data
|
||||
| between requests. This must match one of your defined cache stores.
|
||||
|
|
||||
| Affects: "apc", "dynamodb", "memcached", "redis"
|
||||
|
|
||||
*/
|
||||
|
||||
'store' => env('SESSION_STORE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Sweeping Lottery
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Some session drivers must manually sweep their storage location to get
|
||||
| rid of old sessions from storage. Here are the chances that it will
|
||||
| happen on a given request. By default, the odds are 2 out of 100.
|
||||
|
|
||||
*/
|
||||
|
||||
'lottery' => [2, 100],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may change the name of the session cookie that is created by
|
||||
| the framework. Typically, you should not need to change this value
|
||||
| since doing so does not grant a meaningful security improvement.
|
||||
|
|
||||
*/
|
||||
|
||||
'cookie' => env(
|
||||
'SESSION_COOKIE',
|
||||
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
|
||||
),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The session cookie path determines the path for which the cookie will
|
||||
| be regarded as available. Typically, this will be the root path of
|
||||
| your application, but you're free to change this when necessary.
|
||||
|
|
||||
*/
|
||||
|
||||
'path' => env('SESSION_PATH', '/'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the domain and subdomains the session cookie is
|
||||
| available to. By default, the cookie will be available to the root
|
||||
| domain and all subdomains. Typically, this shouldn't be changed.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => env('SESSION_DOMAIN'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| HTTPS Only Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By setting this option to true, session cookies will only be sent back
|
||||
| to the server if the browser has a HTTPS connection. This will keep
|
||||
| the cookie from being sent to you when it can't be done securely.
|
||||
|
|
||||
*/
|
||||
|
||||
'secure' => env('SESSION_SECURE_COOKIE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| HTTP Access Only
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Setting this value to true will prevent JavaScript from accessing the
|
||||
| value of the cookie and the cookie will only be accessible through
|
||||
| the HTTP protocol. It's unlikely you should disable this option.
|
||||
|
|
||||
*/
|
||||
|
||||
'http_only' => env('SESSION_HTTP_ONLY', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Same-Site Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option determines how your cookies behave when cross-site requests
|
||||
| take place, and can be used to mitigate CSRF attacks. By default, we
|
||||
| will set this value to "lax" to permit secure cross-site requests.
|
||||
|
|
||||
| See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value
|
||||
|
|
||||
| Supported: "lax", "strict", "none", null
|
||||
|
|
||||
*/
|
||||
|
||||
'same_site' => env('SESSION_SAME_SITE', 'lax'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Partitioned Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Setting this value to true will tie the cookie to the top-level site for
|
||||
| a cross-site context. Partitioned cookies are accepted by the browser
|
||||
| when flagged "secure" and the Same-Site attribute is set to "none".
|
||||
|
|
||||
*/
|
||||
|
||||
'partitioned' => env('SESSION_PARTITIONED_COOKIE', false),
|
||||
|
||||
];
|
||||
@@ -46,13 +46,6 @@ services:
|
||||
- SESSION_LIFETIME=240
|
||||
- SESSION_DOMAIN=localhost
|
||||
- SANCTUM_STATEFUL_DOMAINS=localhost:8090
|
||||
#- MAIL_MAILER=smtp
|
||||
#- MAIL_HOST=smtp.mailtrap.io
|
||||
#- MAIL_PORT=2525
|
||||
#- MAIL_USERNAME=null
|
||||
#- MAIL_PASSWORD=null
|
||||
#- MAIL_PASSWORD_FILE=<filename>
|
||||
#- MAIL_ENCRYPTION=null
|
||||
volumes:
|
||||
- invoiceshelf_storage:/var/www/html/storage/
|
||||
ports:
|
||||
|
||||
@@ -27,13 +27,6 @@ services:
|
||||
- SESSION_LIFETIME=240
|
||||
- SESSION_DOMAIN=localhost
|
||||
- SANCTUM_STATEFUL_DOMAINS=localhost:8090
|
||||
#- MAIL_DRIVER=smtp
|
||||
#- MAIL_HOST=smtp.mailtrap.io
|
||||
#- MAIL_PORT=2525
|
||||
#- MAIL_USERNAME=null
|
||||
#- MAIL_PASSWORD=null
|
||||
#- MAIL_PASSWORD_FILE=<filename>
|
||||
#- MAIL_ENCRYPTION=null
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
invoiceshelf:
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
#!/bin/bash
|
||||
function replace_or_insert() {
|
||||
# Voodoo magic: https://superuser.com/a/976712
|
||||
@@ -71,36 +69,6 @@ fi
|
||||
if [ "$BROADCAST_CONNECTION" != '' ]; then
|
||||
replace_or_insert "BROADCAST_CONNECTION" "$BROADCAST_CONNECTION"
|
||||
fi
|
||||
if [ "$MAIL_DRIVER" != '' ]; then
|
||||
replace_or_insert "MAIL_MAILER" "$MAIL_DRIVER"
|
||||
fi
|
||||
if [ "$MAIL_MAILER" != '' ]; then
|
||||
replace_or_insert "MAIL_MAILER" "$MAIL_MAILER"
|
||||
fi
|
||||
if [ "$MAIL_HOST" != '' ]; then
|
||||
replace_or_insert "MAIL_HOST" "$MAIL_HOST"
|
||||
fi
|
||||
if [ "$MAIL_PORT" != '' ]; then
|
||||
replace_or_insert "MAIL_PORT" "$MAIL_PORT"
|
||||
fi
|
||||
if [ "$MAIL_USERNAME" != '' ]; then
|
||||
replace_or_insert "MAIL_USERNAME" "$MAIL_USERNAME"
|
||||
fi
|
||||
if [ "$MAIL_PASSWORD" != '' ]; then
|
||||
replace_or_insert "MAIL_PASSWORD" "$MAIL_PASSWORD"
|
||||
elif [ "$MAIL_PASSWORD_FILE" != '' ]; then
|
||||
value=$(<$MAIL_PASSWORD_FILE)
|
||||
replace_or_insert "MAIL_PASSWORD" "$value"
|
||||
fi
|
||||
if [ "$MAIL_SCHEME" != '' ]; then
|
||||
replace_or_insert "MAIL_SCHEME" "$MAIL_SCHEME"
|
||||
fi
|
||||
if [ "$MAIL_FROM_NAME" != '' ]; then
|
||||
replace_or_insert "MAIL_FROM_NAME" "$MAIL_FROM_NAME"
|
||||
fi
|
||||
if [ "$MAIL_FROM_ADDRESS" != '' ]; then
|
||||
replace_or_insert "MAIL_FROM_ADDRESS" "$MAIL_FROM_ADDRESS"
|
||||
fi
|
||||
if [ "$TRUSTED_PROXIES" != '' ]; then
|
||||
replace_or_insert "TRUSTED_PROXIES" "$TRUSTED_PROXIES"
|
||||
fi
|
||||
|
||||
@@ -162,7 +162,7 @@ const isSaving = ref(false)
|
||||
let isFetchingInitialData = ref(false)
|
||||
|
||||
let currentPreferences = reactive({
|
||||
currency: 1,
|
||||
currency: 3,
|
||||
language: 'en',
|
||||
carbon_date_format: 'd M Y',
|
||||
time_zone: 'UTC',
|
||||
|
||||
Reference in New Issue
Block a user