diff --git a/app/Bus/Commands/System/Config/UpdateConfigCommand.php b/app/Bus/Commands/System/Config/UpdateConfigCommand.php new file mode 100644 index 00000000..c0c9b12b --- /dev/null +++ b/app/Bus/Commands/System/Config/UpdateConfigCommand.php @@ -0,0 +1,39 @@ + + */ +class UpdateConfigCommand +{ + /** + * This is the config key/values array. + * + * @var array + */ + public $values; + + /** + * Create a new update config command instance. + * + * @param array $values + * + * @return void + */ + public function __construct($values) + { + $this->values = $values; + } +} diff --git a/app/Bus/Commands/System/Mail/TestMailCommand.php b/app/Bus/Commands/System/Mail/TestMailCommand.php new file mode 100644 index 00000000..131d864e --- /dev/null +++ b/app/Bus/Commands/System/Mail/TestMailCommand.php @@ -0,0 +1,41 @@ + + */ +class TestMailCommand +{ + /** + * The user to send the notification to. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * Create a new test mail command. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Bus/Handlers/Commands/System/Config/UpdateConfigCommandHandler.php b/app/Bus/Handlers/Commands/System/Config/UpdateConfigCommandHandler.php new file mode 100644 index 00000000..924d4397 --- /dev/null +++ b/app/Bus/Handlers/Commands/System/Config/UpdateConfigCommandHandler.php @@ -0,0 +1,68 @@ + + */ +class UpdateConfigCommandHandler +{ + /** + * Handle update config command handler instance. + * + * @param \CachetHQ\Cachet\Bus\Commands\System\Config\UpdateConfigCommand $command + * + * @return void + */ + public function handle(UpdateConfigCommand $command) + { + foreach ($command->values as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Writes to the .env file with given parameters. + * + * @param string $key + * @param mixed $value + * + * @return void + */ + protected function writeEnv($key, $value) + { + $dir = app()->environmentPath(); + $file = app()->environmentFile(); + $path = "{$dir}/{$file}"; + + try { + (new Dotenv($dir, $file))->load(); + + $envKey = strtoupper($key); + $envValue = env($envKey) ?: 'null'; + + file_put_contents($path, str_replace( + "{$envKey}={$envValue}", + "{$envKey}={$value}", + file_get_contents($path) + )); + } catch (InvalidPathException $e) { + throw $e; + } + } +} diff --git a/app/Bus/Handlers/Commands/System/Mail/TestMailCommandHandler.php b/app/Bus/Handlers/Commands/System/Mail/TestMailCommandHandler.php new file mode 100644 index 00000000..09d052c2 --- /dev/null +++ b/app/Bus/Handlers/Commands/System/Mail/TestMailCommandHandler.php @@ -0,0 +1,64 @@ + + */ +class TestMailCommandHandler +{ + /** + * The mailer instance. + * + * @var \Illuminate\Contracts\Mail\Mailer + */ + protected $mailer; + + /** + * Create a test mail command handler. + * + * @param \Illuminate\Contracts\Mail\Mailer $mailer + * + * @return void + */ + public function __construct(MailQueue $mailer) + { + $this->mailer = $mailer; + } + + /** + * Handle the test mail command. + * + * @param \CachetHQ\Cachet\Bus\Commands\System\Mail\TestMailCommand $command + * + * @return void + */ + public function handle(TestMailCommand $command) + { + $mail = [ + 'email' => $command->user->email, + 'subject' => trans('dashboard.settings.mail.email.subject'), + ]; + + $this->mailer->queue([ + 'html' => 'emails.system.test-html', + 'text' => 'emails.system.test-text', + ], $mail, function ($message) use ($mail) { + $message->to($mail['email'])->subject($mail['subject']); + }); + } +} diff --git a/app/Composers/SettingsComposer.php b/app/Composers/SettingsComposer.php new file mode 100644 index 00000000..1c20941d --- /dev/null +++ b/app/Composers/SettingsComposer.php @@ -0,0 +1,85 @@ + + */ +class SettingsComposer +{ + /** + * Array of cache drivers. + * + * @var string[] + */ + protected $cacheDrivers = [ + 'apc' => 'APC(u)', + 'array' => 'Array', + 'database' => 'Database', + 'file' => 'File', + 'memcached' => 'Memcached', + 'redis' => 'Redis', + ]; + + /** + * Array of cache drivers. + * + * @var string[] + */ + protected $mailDrivers = [ + 'smtp' => 'SMTP', + 'mail' => 'Mail', + 'sendmail' => 'Sendmail', + 'mailgun' => 'Mailgun', + 'mandrill' => 'Mandrill', + // 'ses' => 'Amazon SES', this will be available only if aws/aws-sdk-php is installed + 'sparkpost' => 'SparkPost', + 'log' => 'Log (Testing)', + ]; + + /** + * Array of queue drivers. + * + * @var string[] + */ + protected $queueDrivers = [ + 'null' => 'None', + 'sync' => 'Synchronous', + 'database' => 'Database', + 'beanstalkd' => 'Beanstalk', + 'sqs' => 'Amazon SQS', + 'redis' => 'Redis', + ]; + + /** + * Bind data to the view. + * + * @param \Illuminate\Contracts\View\View $view + * + * @return void + */ + public function compose(View $view) + { + $view->withCacheDrivers($this->cacheDrivers); + $view->withMailDrivers($this->mailDrivers); + $view->withQueueDrivers($this->queueDrivers); + } +} diff --git a/app/Foundation/Providers/ComposerServiceProvider.php b/app/Foundation/Providers/ComposerServiceProvider.php index 9bb13534..5ca975cb 100644 --- a/app/Foundation/Providers/ComposerServiceProvider.php +++ b/app/Foundation/Providers/ComposerServiceProvider.php @@ -21,6 +21,7 @@ use CachetHQ\Cachet\Composers\Modules\ScheduledComposer as ScheduledModuleCompos use CachetHQ\Cachet\Composers\Modules\StatusComposer as StatusModuleComposer; use CachetHQ\Cachet\Composers\Modules\StickiedComposer as StickiedModuleComposer; use CachetHQ\Cachet\Composers\Modules\TimelineComposer as TimelineModuleComposer; +use CachetHQ\Cachet\Composers\SettingsComposer; use CachetHQ\Cachet\Composers\ThemeComposer; use CachetHQ\Cachet\Composers\TimezoneLocaleComposer; use Illuminate\Contracts\View\Factory; @@ -48,6 +49,7 @@ class ComposerServiceProvider extends ServiceProvider $factory->composer('partials.modules.scheduled', ScheduledModuleComposer::class); $factory->composer('partials.modules.status', StatusModuleComposer::class); $factory->composer('partials.modules.timeline', TimelineModuleComposer::class); + $factory->composer(['dashboard.settings.mail', 'setup.*'], SettingsComposer::class); } /** diff --git a/app/Http/Controllers/Dashboard/SettingsController.php b/app/Http/Controllers/Dashboard/SettingsController.php index 999a377a..bba21992 100644 --- a/app/Http/Controllers/Dashboard/SettingsController.php +++ b/app/Http/Controllers/Dashboard/SettingsController.php @@ -11,12 +11,15 @@ namespace CachetHQ\Cachet\Http\Controllers\Dashboard; +use CachetHQ\Cachet\Bus\Commands\System\Config\UpdateConfigCommand; +use CachetHQ\Cachet\Bus\Commands\System\Mail\TestMailCommand; use CachetHQ\Cachet\Integrations\Contracts\Credits; use CachetHQ\Cachet\Models\User; use CachetHQ\Cachet\Settings\Repository; use Exception; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Lang; use Illuminate\Support\Facades\Log; @@ -96,6 +99,12 @@ class SettingsController extends Controller 'icon' => 'ion-ios-list', 'active' => false, ], + 'mail' => [ + 'title' => trans('dashboard.settings.mail.mail'), + 'url' => cachet_route('dashboard.settings.mail'), + 'icon' => 'ion-paper-airplane', + 'active' => false, + ], 'about' => [ 'title' => CACHET_VERSION, 'url' => 'javascript: void(0);', @@ -266,6 +275,47 @@ class SettingsController extends Controller return View::make('dashboard.settings.log')->withLog($logContents)->withSubMenu($this->subMenu); } + /** + * Show the mail settings view. + * + * @return \Illuminate\View\View + */ + public function showMailView() + { + $this->subMenu['mail']['active'] = true; + + return View::make('dashboard.settings.mail')->withConfig(Config::get('mail')); + } + + /** + * Test the mail config. + * + * @return \Illuminate\Http\RedirectResponse + */ + public function testMail() + { + dispatch(new TestMailCommand(Auth::user())); + + return cachet_redirect('dashboard.settings.mail') + ->withSuccess(trans('dashboard.notifications.awesome'));; + } + + /** + * Handle updating of the settings. + * + * @return \Illuminate\Http\RedirectResponse + */ + public function postMail() + { + $config = Binput::get('config'); + + dispatch(new UpdateConfigCommand($config)); + + return cachet_redirect('dashboard.settings.mail') + ->withInput(Binput::all()) + ->withSuccess(trans('dashboard.notifications.awesome')); + } + /** * Updates the status page settings. * diff --git a/app/Http/Routes/Dashboard/SettingRoutes.php b/app/Http/Routes/Dashboard/SettingRoutes.php index 4370a750..a963470d 100644 --- a/app/Http/Routes/Dashboard/SettingRoutes.php +++ b/app/Http/Routes/Dashboard/SettingRoutes.php @@ -78,6 +78,18 @@ class SettingRoutes 'as' => 'get:dashboard.settings.log', 'uses' => 'SettingsController@showLogView', ]); + $router->get('mail', [ + 'as' => 'get:dashboard.settings.mail', + 'uses' => 'SettingsController@showMailView', + ]); + $router->post('mail', [ + 'as' => 'post:dashboard.settings.mail', + 'uses' => 'SettingsController@postMail', + ]); + $router->post('mail/test', [ + 'as' => 'post:dashboard.settings.mail.test', + 'uses' => 'SettingsController@testMail', + ]); $router->post('/', [ 'as' => 'post:dashboard.settings', diff --git a/resources/lang/en/dashboard.php b/resources/lang/en/dashboard.php index b4e2f6b2..6f4bf5c8 100644 --- a/resources/lang/en/dashboard.php +++ b/resources/lang/en/dashboard.php @@ -214,6 +214,14 @@ return [ 'header' => 'Custom Header HTML', 'footer' => 'Custom Footer HTML', ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], 'security' => [ 'security' => 'Security', 'two-factor' => 'Users without two-factor authentication', diff --git a/resources/views/dashboard/settings/mail.blade.php b/resources/views/dashboard/settings/mail.blade.php new file mode 100644 index 00000000..c8217632 --- /dev/null +++ b/resources/views/dashboard/settings/mail.blade.php @@ -0,0 +1,60 @@ +@extends('layout.dashboard') + +@section('content') +