Skip to content

Commit a01c934

Browse files
authored
Merge pull request pterodactyl#1328 from ayan4m1/feature/1233
Add mail tester
2 parents cf54fc3 + a415b6c commit a01c934

File tree

7 files changed

+242
-9
lines changed

7 files changed

+242
-9
lines changed

app/Http/Controllers/Admin/Settings/MailController.php

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22

33
namespace Pterodactyl\Http\Controllers\Admin\Settings;
44

5+
use Exception;
56
use Illuminate\View\View;
6-
use Illuminate\Http\RedirectResponse;
7+
use Illuminate\Http\Request;
8+
use Illuminate\Http\Response;
79
use Prologue\Alerts\AlertsMessageBag;
810
use Illuminate\Contracts\Console\Kernel;
11+
use Pterodactyl\Notifications\MailTested;
12+
use Illuminate\Support\Facades\Notification;
913
use Pterodactyl\Exceptions\DisplayException;
1014
use Pterodactyl\Http\Controllers\Controller;
1115
use Illuminate\Contracts\Encryption\Encrypter;
@@ -81,13 +85,13 @@ public function index(): View
8185
* Handle request to update SMTP mail settings.
8286
*
8387
* @param \Pterodactyl\Http\Requests\Admin\Settings\MailSettingsFormRequest $request
84-
* @return \Illuminate\Http\RedirectResponse
88+
* @return \Illuminate\Http\Response
8589
*
8690
* @throws DisplayException
8791
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
8892
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
8993
*/
90-
public function update(MailSettingsFormRequest $request): RedirectResponse
94+
public function update(MailSettingsFormRequest $request): Response
9195
{
9296
if ($this->config->get('mail.driver') !== 'smtp') {
9397
throw new DisplayException('This feature is only available if SMTP is the selected email driver for the Panel.');
@@ -107,8 +111,25 @@ public function update(MailSettingsFormRequest $request): RedirectResponse
107111
}
108112

109113
$this->kernel->call('queue:restart');
110-
$this->alert->success('Mail settings have been updated successfully and the queue worker was restarted to apply these changes.')->flash();
111114

112-
return redirect()->route('admin.settings.mail');
115+
return response('', 204);
116+
}
117+
118+
/**
119+
* Submit a request to send a test mail message.
120+
*
121+
* @param Request $request
122+
* @return \Illuminate\Http\Response
123+
*/
124+
public function test(Request $request): Response
125+
{
126+
try {
127+
Notification::route('mail', $request->user()->email)
128+
->notify(new MailTested($request->user()));
129+
} catch (Exception $exception) {
130+
return response($exception->getMessage(), 500);
131+
}
132+
133+
return response('', 204);
113134
}
114135
}

app/Notifications/MailTested.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Pterodactyl\Notifications;
4+
5+
use Pterodactyl\Models\User;
6+
use Illuminate\Notifications\Notification;
7+
use Illuminate\Notifications\Messages\MailMessage;
8+
9+
class MailTested extends Notification
10+
{
11+
/**
12+
* @var \Pterodactyl\Models\User
13+
*/
14+
private $user;
15+
16+
public function __construct(User $user)
17+
{
18+
$this->user = $user;
19+
}
20+
21+
public function via()
22+
{
23+
return ['mail'];
24+
}
25+
26+
public function toMail()
27+
{
28+
return (new MailMessage)
29+
->subject('Pterodactyl Test Message')
30+
->greeting('Hello ' . $this->user->name . '!')
31+
->line('This is a test of the Pterodactyl mail system. You\'re good to go!');
32+
}
33+
}

public/js/laroute.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/themes/pterodactyl/js/plugins/minecraft/eula.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ $(document).ready(function () {
5555
console.error(jqXHR);
5656
swal({
5757
title: 'Whoops!',
58-
text: 'An error occured while attempting to set the EULA as accepted: ' . jqXHR.responseJSON.error,
58+
text: 'An error occurred while attempting to set the EULA as accepted: ' + jqXHR.responseJSON.error,
5959
type: 'error'
6060
})
6161
});

resources/themes/pterodactyl/admin/settings/mail.blade.php

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
</div>
3333
</div>
3434
@else
35-
<form action="{{ route('admin.settings.mail') }}" method="POST">
35+
<form>
3636
<div class="box-body">
3737
<div class="row">
3838
<div class="form-group col-md-6">
@@ -98,11 +98,107 @@
9898
</div>
9999
<div class="box-footer">
100100
{{ csrf_field() }}
101-
<button type="submit" name="_method" value="PATCH" class="btn btn-sm btn-primary pull-right">Save</button>
101+
<div class="pull-right">
102+
<button type="button" id="testButton" class="btn btn-sm btn-success">Test</button>
103+
<button type="button" id="saveButton" class="btn btn-sm btn-primary">Save</button>
104+
</div>
102105
</div>
103106
</form>
104107
@endif
105108
</div>
106109
</div>
107110
</div>
108111
@endsection
112+
113+
@section('footer-scripts')
114+
{!! Theme::js('js/laroute.js?t={cache-version}') !!}
115+
{!! Theme::js('vendor/jquery/jquery.min.js?t={cache-version}') !!}
116+
{!! Theme::js('vendor/sweetalert/sweetalert.min.js?t={cache-version}') !!}
117+
118+
<script>
119+
function saveSettings() {
120+
return $.ajax({
121+
method: 'PATCH',
122+
url: Router.route('admin.settings.mail'),
123+
contentType: 'application/json',
124+
data: JSON.stringify({
125+
'mail:host': $('input[name="mail:host"]').val(),
126+
'mail:port': $('input[name="mail:port"]').val(),
127+
'mail:encryption': $('select[name="mail:encryption"]').val(),
128+
'mail:username': $('input[name="mail:username"]').val(),
129+
'mail:password': $('input[name="mail:password"]').val(),
130+
'mail:from:address': $('input[name="mail:from:address"]').val(),
131+
'mail:from:name': $('input[name="mail:from:name"]').val()
132+
}),
133+
headers: { 'X-CSRF-Token': $('input[name="_token"]').val() }
134+
}).fail(function (jqXHR) {
135+
showErrorDialog(jqXHR, 'save');
136+
});
137+
}
138+
139+
function testSettings() {
140+
swal({
141+
type: 'info',
142+
title: 'Test Mail Settings',
143+
text: 'Click "Test" to begin the test.',
144+
showCancelButton: true,
145+
confirmButtonText: 'Test',
146+
closeOnConfirm: false,
147+
showLoaderOnConfirm: true
148+
}, function () {
149+
$.ajax({
150+
method: 'GET',
151+
url: Router.route('admin.settings.mail.test'),
152+
headers: { 'X-CSRF-Token': $('input[name="_token"]').val() }
153+
}).fail(function (jqXHR) {
154+
showErrorDialog(jqXHR, 'test');
155+
}).done(function () {
156+
swal({
157+
title: 'Success',
158+
text: 'The test message was sent successfully.',
159+
type: 'success'
160+
});
161+
});
162+
});
163+
}
164+
165+
function saveAndTestSettings() {
166+
saveSettings().done(testSettings);
167+
}
168+
169+
function showErrorDialog(jqXHR, verb) {
170+
console.error(jqXHR);
171+
var errorText = '';
172+
if (!jqXHR.responseJSON) {
173+
errorText = jqXHR.responseText;
174+
} else if (jqXHR.responseJSON.error) {
175+
errorText = jqXHR.responseJSON.error;
176+
} else if (jqXHR.responseJSON.errors) {
177+
$.each(jqXHR.responseJSON.errors, function (i, v) {
178+
if (v.detail) {
179+
errorText += v.detail + ' ';
180+
}
181+
});
182+
}
183+
184+
swal({
185+
title: 'Whoops!',
186+
text: 'An error occurred while attempting to ' + verb + ' mail settings: ' + errorText,
187+
type: 'error'
188+
});
189+
}
190+
191+
$(document).ready(function () {
192+
$('#testButton').on('click', saveAndTestSettings);
193+
$('#saveButton').on('click', function () {
194+
saveSettings().done(function () {
195+
swal({
196+
title: 'Success',
197+
text: 'Mail settings have been updated successfully and the queue worker was restarted to apply these changes.',
198+
type: 'success'
199+
});
200+
});
201+
});
202+
});
203+
</script>
204+
@endsection

routes/admin.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
Route::group(['prefix' => 'settings'], function () {
6565
Route::get('/', 'Settings\IndexController@index')->name('admin.settings');
6666
Route::get('/mail', 'Settings\MailController@index')->name('admin.settings.mail');
67+
Route::get('/mail/test', 'Settings\MailController@test')->name('admin.settings.mail.test');
6768
Route::get('/advanced', 'Settings\AdvancedController@index')->name('admin.settings.advanced');
6869

6970
Route::patch('/', 'Settings\IndexController@update');
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
namespace Tests\Unit\Http\Controllers;
4+
5+
use Mockery as m;
6+
use Prologue\Alerts\AlertsMessageBag;
7+
use Illuminate\Contracts\Console\Kernel;
8+
use Illuminate\Contracts\Encryption\Encrypter;
9+
use Illuminate\Contracts\Config\Repository as ConfigRepository;
10+
use Pterodactyl\Http\Controllers\Admin\Settings\MailController;
11+
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
12+
13+
class MailControllerTest extends ControllerTestCase
14+
{
15+
/**
16+
* @var \Prologue\Alerts\AlertsMessageBag
17+
*/
18+
private $alert;
19+
20+
/**
21+
* @var \Illuminate\Contracts\Config\Repository
22+
*/
23+
private $configRepository;
24+
25+
/**
26+
* @var \Illuminate\Contracts\Encryption\Encrypter
27+
*/
28+
private $encrypter;
29+
30+
/**
31+
* @var \Illuminate\Contracts\Console\Kernel
32+
*/
33+
private $kernel;
34+
35+
/**
36+
* @var \Pterodactyl\Contracts\Repository\SettingsRepositoryInterface
37+
*/
38+
private $settingsRepositoryInterface;
39+
40+
/**
41+
* Setup tests.
42+
*/
43+
public function setUp()
44+
{
45+
parent::setUp();
46+
47+
$this->alert = m::mock(AlertsMessageBag::class);
48+
$this->configRepository = m::mock(ConfigRepository::class);
49+
$this->encrypter = m::mock(Encrypter::class);
50+
$this->kernel = m::mock(Kernel::class);
51+
$this->settingsRepositoryInterface = m::mock(SettingsRepositoryInterface::class);
52+
}
53+
54+
/**
55+
* Test the mail controller for viewing mail settings page.
56+
*/
57+
public function testIndex()
58+
{
59+
$this->configRepository->shouldReceive('get');
60+
61+
$response = $this->getController()->index();
62+
63+
$this->assertIsViewResponse($response);
64+
$this->assertViewNameEquals('admin.settings.mail', $response);
65+
}
66+
67+
/**
68+
* Prepare a MailController using our mocks.
69+
*
70+
* @return MailController
71+
*/
72+
public function getController()
73+
{
74+
return new MailController(
75+
$this->alert,
76+
$this->configRepository,
77+
$this->encrypter,
78+
$this->kernel,
79+
$this->settingsRepositoryInterface
80+
);
81+
}
82+
}

0 commit comments

Comments
 (0)