Implement base notifications support (#77)

* initial implementation of notifications
* typehint UUID returns. Fixes that notifications bug
This commit is contained in:
Dane Everitt 2016-09-05 12:00:56 -04:00 committed by GitHub
parent b3ca8a3732
commit b02df8e610
11 changed files with 176 additions and 28 deletions

View file

@ -176,7 +176,7 @@ class ServerController extends Controller
$download = new Models\Download; $download = new Models\Download;
$download->token = Uuid::generate(4); $download->token = (string) Uuid::generate(4);
$download->server = $server->uuid; $download->server = $server->uuid;
$download->path = str_replace('../', '', $file); $download->path = str_replace('../', '', $file);

View file

@ -137,5 +137,4 @@ class User extends Model implements AuthenticatableContract,
$this->notify(new ResetPasswordNotification($token)); $this->notify(new ResetPasswordNotification($token));
} }
} }

View file

@ -0,0 +1,90 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2016 Dane Everitt <dane@daneeveritt.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace Pterodactyl\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class AccountCreated extends Notification implements ShouldQueue
{
use Queueable;
/**
* The password reset token to send.
*
* @var string
*/
public $token;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($token)
{
$this->token = $token;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail', 'database'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('You are recieving this email because an account has been created for you on Pterodactyl Panel.')
->line('Email: ' . $notifiable->email)
->action('Setup Your Account', url('/auth/password/reset/' . $this->token . '?email=' . $notifiable->email));
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
'email' => $notifiable->email,
'token' => $this->token
];
}
}

View file

@ -1,5 +1,26 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2016 Dane Everitt <dane@daneeveritt.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace Pterodactyl\Notifications; namespace Pterodactyl\Notifications;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
@ -7,7 +28,7 @@ use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
class SendPasswordReset extends Notification class SendPasswordReset extends Notification implements ShouldQueue
{ {
use Queueable; use Queueable;

View file

@ -29,9 +29,11 @@ use Settings;
use Hash; use Hash;
use Validator; use Validator;
use Mail; use Mail;
use Carbon;
use Pterodactyl\Models; use Pterodactyl\Models;
use Pterodactyl\Services\UuidService; use Pterodactyl\Services\UuidService;
use Pterodactyl\Notifications\AccountCreated;
use Pterodactyl\Exceptions\DisplayValidationException; use Pterodactyl\Exceptions\DisplayValidationException;
use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayException;
@ -48,10 +50,10 @@ class UserRepository
* Creates a user on the panel. Returns the created user's ID. * Creates a user on the panel. Returns the created user's ID.
* *
* @param string $email * @param string $email
* @param string $password An unhashed version of the user's password. * @param string|null $password An unhashed version of the user's password.
* @return bool|integer * @return bool|integer
*/ */
public function create($email, $password, $admin = false) public function create($email, $password = null, $admin = false)
{ {
$validator = Validator::make([ $validator = Validator::make([
'email' => $email, 'email' => $email,
@ -59,7 +61,7 @@ class UserRepository
'root_admin' => $admin 'root_admin' => $admin
], [ ], [
'email' => 'required|email|unique:users,email', 'email' => 'required|email|unique:users,email',
'password' => 'required|regex:((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})', 'password' => 'nullable|regex:((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})',
'root_admin' => 'required|boolean' 'root_admin' => 'required|boolean'
]); ]);
@ -77,25 +79,26 @@ class UserRepository
$user->uuid = $uuid->generate('users', 'uuid'); $user->uuid = $uuid->generate('users', 'uuid');
$user->email = $email; $user->email = $email;
$user->password = Hash::make($password); $user->password = Hash::make((is_null($password)) ? str_random(30) : $password);
$user->language = 'en'; $user->language = 'en';
$user->root_admin = ($admin) ? 1 : 0; $user->root_admin = ($admin) ? 1 : 0;
$user->save(); $user->save();
Mail::queue('emails.new-account', [ // Setup a Password Reset to use when they set a password.
$token = str_random(32);
DB::table('password_resets')->insert([
'email' => $user->email, 'email' => $user->email,
'forgot' => route('auth.password'), 'token' => $token,
'login' => route('auth.login') 'created_at' => Carbon::now()->toDateTimeString()
], function ($message) use ($email) { ]);
$message->to($email);
$message->from(Settings::get('email_from', env('MAIL_FROM')), Settings::get('email_sender_name', env('MAIL_FROM_NAME', 'Pterodactyl Panel'))); $user->notify((new AccountCreated($token)));
$message->subject(Settings::get('company') . ' - New Account');
});
DB::commit(); DB::commit();
return $user->id; return $user->id;
} catch (\Exception $ex) { } catch (\Exception $ex) {
DB::rollBack(); DB::rollBack();
throw $e; throw $ex;
} }
} }

View file

@ -59,7 +59,7 @@ class UuidService
} while (!$return); } while (!$return);
return $return; return (string) $return;
} }
@ -85,7 +85,7 @@ class UuidService
} while (!$return); } while (!$return);
return $return; return (string) $return;
} }

View file

@ -17,7 +17,7 @@
], ],
"require": { "require": {
"php": ">=5.6.4", "php": ">=5.6.4",
"laravel/framework": "5.3.*", "laravel/framework": "5.3.6",
"barryvdh/laravel-debugbar": "^2.2.3", "barryvdh/laravel-debugbar": "^2.2.3",
"doctrine/dbal": "^2.5.4", "doctrine/dbal": "^2.5.4",
"guzzlehttp/guzzle": "^6.2.1", "guzzlehttp/guzzle": "^6.2.1",
@ -35,7 +35,8 @@
"mockery/mockery": "0.9.*", "mockery/mockery": "0.9.*",
"phpunit/phpunit": "~5.0", "phpunit/phpunit": "~5.0",
"symfony/css-selector": "3.1.*", "symfony/css-selector": "3.1.*",
"symfony/dom-crawler": "3.1.*" "symfony/dom-crawler": "3.1.*",
"laravel/homestead": "3.0.*"
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [

View file

@ -39,14 +39,14 @@ return [
'driver' => 'database', 'driver' => 'database',
'table' => 'jobs', 'table' => 'jobs',
'queue' => 'default', 'queue' => 'default',
'expire' => 60, 'retry_after' => 60,
], ],
'beanstalkd' => [ 'beanstalkd' => [
'driver' => 'beanstalkd', 'driver' => 'beanstalkd',
'host' => 'localhost', 'host' => 'localhost',
'queue' => 'default', 'queue' => 'default',
'ttr' => 60, 'retry_after' => 60,
], ],
'sqs' => [ 'sqs' => [
@ -70,7 +70,7 @@ return [
'driver' => 'redis', 'driver' => 'redis',
'connection' => 'default', 'connection' => 'default',
'queue' => 'default', 'queue' => 'default',
'expire' => 60, 'retry_after' => 60,
], ],
], ],

View file

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateNotificationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('notifications', function (Blueprint $table) {
$table->string('id')->primary();
$table->string('type');
$table->morphs('notifiable');
$table->text('data');
$table->timestamp('read_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('notifications');
}
}

View file

@ -19,4 +19,4 @@ if (! empty($outroLines)) {
} }
echo 'Regards,', "\n"; echo 'Regards,', "\n";
echo config('app.name'), "\n"; echo Settings::get('company'), "\n";

View file

@ -71,7 +71,7 @@ $style = [
<tr> <tr>
<td style="{{ $style['email-masthead'] }}"> <td style="{{ $style['email-masthead'] }}">
<a style="{{ $fontFamily }} {{ $style['email-masthead_name'] }}" href="{{ url('/') }}" target="_blank"> <a style="{{ $fontFamily }} {{ $style['email-masthead_name'] }}" href="{{ url('/') }}" target="_blank">
{{ config('app.name') }} {{ Settings::get('company') }}
</a> </a>
</td> </td>
</tr> </tr>
@ -140,7 +140,7 @@ $style = [
<!-- Salutation --> <!-- Salutation -->
<p style="{{ $style['paragraph'] }}"> <p style="{{ $style['paragraph'] }}">
Regards,<br>{{ config('app.name') }} Regards,<br>{{ Settings::get('company') }}
</p> </p>
<!-- Sub Copy --> <!-- Sub Copy -->
@ -176,7 +176,7 @@ $style = [
<td style="{{ $fontFamily }} {{ $style['email-footer_cell'] }}"> <td style="{{ $fontFamily }} {{ $style['email-footer_cell'] }}">
<p style="{{ $style['paragraph-sub'] }}"> <p style="{{ $style['paragraph-sub'] }}">
&copy; {{ date('Y') }} &copy; {{ date('Y') }}
<a style="{{ $style['anchor'] }}" href="{{ url('/') }}" target="_blank">{{ config('app.name') }}</a>. <a style="{{ $style['anchor'] }}" href="{{ url('/') }}" target="_blank">{{ Settings::get('company') }}</a>.
All rights reserved. All rights reserved.
</p> </p>
</td> </td>