Skip to content

Commit

Permalink
Update for Hyn 5.2 and Laravel 5.6
Browse files Browse the repository at this point in the history
  • Loading branch information
colinmackinlay committed Sep 1, 2018
1 parent da862a5 commit d56d7b1
Show file tree
Hide file tree
Showing 42 changed files with 752 additions and 443 deletions.
11 changes: 9 additions & 2 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,14 @@ MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

LIMIT_UUID_LENGTH_32=true
AUTO_DELETE_TENANT_DIRECTORY=true
AUTO_DELETE_TENANT_DATABASE=true
TENANCY_DEFAULT_HOSTNAME=townhouse.test
TENANCY_EARLY_IDENTIFICATION=true
TENANCY_DATABASE_AUTO_DELETE=true
TENANCY_DATABASE_AUTO_DELETE_USER=true
ABORT_WITHOUT_IDENTIFIED_HOSTNAME=false
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
Expand Down Expand Up @@ -32,3 +34,7 @@ MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
20 changes: 7 additions & 13 deletions app/Console/Commands/CreateTenant.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,30 @@

use App\Notifications\TenantCreated;
use App\Tenant;
use Hyn\Tenancy\Models\Customer;
use Illuminate\Console\Command;

class CreateTenant extends Command
{
protected $signature = 'tenant:create {name} {email}';
protected $signature = 'tenant:create {name} {password} {email}';

protected $description = 'Creates a tenant with the provided name and email address e.g. php artisan tenant:create boise [email protected]';
protected $description = 'Creates a tenant with the provided name and email address e.g. php artisan tenant:create boise test [email protected]';

public function handle()
{
$name = $this->argument('name');
$email = $this->argument('email');
$password = $this->argument('password');

if ($this->tenantExists($name, $email)) {
$this->error("A tenant with name '{$name}' and/or '{$email}' already exists.");

if (Tenant::tenantExists($name)) {
$this->error("A tenant with name '{$name}' already exists.");
return;
}

$tenant = Tenant::createFrom($name, $email);
$tenant = Tenant::registerTenant($name, $email, $password);
$this->info("Tenant '{$name}' is created and is now accessible at {$tenant->hostname->fqdn}");

// invite admin
$tenant->admin->notify(new TenantCreated($tenant->hostname));
$this->info("Admin {$email} has been invited!");
}

private function tenantExists($name, $email): bool
{
return Customer::where('name', $name)->orWhere('email', $email)->exists();
$this->info("Admin {$email} can log in using password {$password}");
}
}
14 changes: 5 additions & 9 deletions app/Console/Commands/DeleteTenant.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,15 @@ class DeleteTenant extends Command
public function handle()
{
// because this is a destructive command, we'll only allow to run this command
// if the environment is local or testing
if (!(app()->isLocal() || app()->runningUnitTests())) {
$this->error('This command is only avilable on the local environment.');
// if you are on the local environment or testing
if (!app()->isLocal() && !app()->runningUnitTests()) {
$this->error('This command is only available on the local environment.');

return;
}

$name = $this->argument('name');
if ($tenant = Tenant::retrieveBy($name)) {
$tenant->delete();
$this->info("Tenant {$name} successfully deleted.");
} else {
$this->error("Couldn't find tenant {$name}");
}
$result = Tenant::delete($name);
$this->info($result);
}
}
3 changes: 2 additions & 1 deletion app/Http/Controllers/Auth/RegisterController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;

Expand Down Expand Up @@ -65,7 +66,7 @@ protected function create(array $data)
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'password' => Hash::make($data['password']),
]);
}
}
6 changes: 4 additions & 2 deletions app/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Kernel extends HttpKernel
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
Expand Down Expand Up @@ -54,9 +54,11 @@ class Kernel extends HttpKernel
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'tenancy.enforce' => \App\Http\Middleware\EnforceTenancy::class
'tenancy.enforce' => \App\Http\Middleware\EnforceTenancy::class,
];
}
17 changes: 17 additions & 0 deletions app/Http/Middleware/CheckForMaintenanceMode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;

class CheckForMaintenanceMode extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.
*
* @var array
*/
protected $except = [
//
];
}
4 changes: 2 additions & 2 deletions app/Http/Middleware/TrustProxies.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ class TrustProxies extends Middleware
protected $proxies;

/**
* The current proxy header mappings.
* The headers that should be used to detect proxies.
*
* @var array
* @var int
*/
protected $headers = Request::HEADER_X_FORWARDED_ALL;
}
77 changes: 77 additions & 0 deletions app/Notifications/MailResetPasswordToken.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Support\Facades\Log;

class MailResetPasswordToken extends Notification
{
use Queueable;

/**
* The password reset token.
*
* @var string
*/
public $token;

/**
* Create a notification instance.
*
* @param string $token
* @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'];
}

/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
// Get current Hostname
$hostname = app(\Hyn\Tenancy\Environment::class)->hostname();

// Get FQDN (Fully-Qualified Domain Name) by current hostname
$fqdn = $hostname->fqdn;

return (new MailMessage)
->subject('Reset Password Notification')
->line('You are receiving this email because we received a password reset request for your account.')
->action('Reset Password', $fqdn.route('password.reset', $this->token, false))
->line('If you did not request a password reset, no further action is required.');
}

/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
62 changes: 32 additions & 30 deletions app/Tenant.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,68 @@
namespace App;

use Hyn\Tenancy\Environment;
use Hyn\Tenancy\Models\Customer;
use Hyn\Tenancy\Models\Hostname;
use Hyn\Tenancy\Models\Website;
use Illuminate\Support\Facades\Hash;
use Hyn\Tenancy\Contracts\Repositories\CustomerRepository;
use Hyn\Tenancy\Contracts\Repositories\HostnameRepository;
use Hyn\Tenancy\Contracts\Repositories\WebsiteRepository;

/**
* @property Customer customer
* @property Website website
* @property Hostname hostname
* @property User admin
*/
class Tenant
{
public function __construct(Customer $customer, Website $website = null, Hostname $hostname = null, User $admin = null)
public function __construct(Website $website = null, Hostname $hostname = null, User $admin = null)
{
$this->customer = $customer;
$this->website = $website ?? $customer->websites->first();
$this->hostname = $hostname ?? $customer->hostnames->first();
$this->website = $website;
$this->hostname = $hostname;
$this->admin = $admin;
}

public function delete()
public static function delete($name)
{
app(HostnameRepository::class)->delete($this->hostname, true);
app(WebsiteRepository::class)->delete($this->website, true);
app(CustomerRepository::class)->delete($this->customer, true);
$baseUrl = env('APP_URL_BASE');
$name = "{$name}.{$baseUrl}";
if ($tenant = Hostname::where('fqdn', $name)->firstOrFail()) {
app(HostnameRepository::class)->delete($tenant, true);
app(WebsiteRepository::class)->delete($tenant->website, true);
return "Tenant {$name} successfully deleted.";
}
}

public static function createFrom($name, $email, $password = null): Tenant
public static function deleteByFqdn($fqdn)
{
// create a customer
$customer = new Customer;
$customer->name = $name;
$customer->email = $email;
if ($tenant = Hostname::where('fqdn', $fqdn)->firstOrFail()) {
app(HostnameRepository::class)->delete($tenant, true);
app(WebsiteRepository::class)->delete($tenant->website, true);
return "Tenant {$fqdn} successfully deleted.";
}
}

app(CustomerRepository::class)->create($customer);
public static function registerTenant($name, $email, $password): Tenant
{
// Convert all to lowercase
$name = strtolower($name);
$email = strtolower($email);

// associate the customer with a website
$website = new Website;
$website->customer()->associate($customer);
app(WebsiteRepository::class)->create($website);

// associate the website with a hostname
$hostname = new Hostname;
$baseUrl = config('app.url_base');
$baseUrl = env('APP_URL_BASE');
$hostname->fqdn = "{$name}.{$baseUrl}";
$hostname->customer()->associate($customer);
app(HostnameRepository::class)->attach($hostname, $website);

// make hostname current
app(Environment::class)->hostname($hostname);
app(Environment::class)->tenant($hostname->website);

$admin = static::makeAdmin($name, $email, $password ?: str_random());
// Make the registered user the default Admin of the site.
$admin = static::makeAdmin($name, $email, $password);

return new Tenant($customer, $website, $hostname, $admin);
return new Tenant($website, $hostname, $admin);
}

private static function makeAdmin($name, $email, $password): User
Expand All @@ -71,12 +76,9 @@ private static function makeAdmin($name, $email, $password): User
return $admin;
}

public static function retrieveBy($name): ?Tenant
public static function tenantExists($name)
{
if ($customer = Customer::where('name', $name)->with(['websites', 'hostnames'])->first()) {
return new Tenant($customer);
}

return null;
$name = $name . '.' . env('APP_URL_BASE');
return Hostname::where('fqdn', $name)->exists();
}
}
9 changes: 9 additions & 0 deletions app/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
use App\Notifications\MailResetPasswordToken;

class User extends Authenticatable
{
Expand All @@ -28,4 +29,12 @@ class User extends Authenticatable
protected $hidden = [
'password', 'remember_token',
];

/**
* Send a password reset email to the user
*/
public function sendPasswordResetNotification($token)
{
$this->notify(new MailResetPasswordToken($token));
}
}
3 changes: 2 additions & 1 deletion config/broadcasting.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
//
'cluster' => env('PUSHER_APP_CLUSTER'),
'encrypted' => true,
],
],

Expand Down
Loading

3 comments on commit d56d7b1

@sevillaarvin
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I'm wondering why the commit message is:

Update for Hyn 5.2 and Laravel 5.6

With all the references to Models\Customer and CustomerRepository removed, but the multi-tenant package is still at 5.1.2?

@colinmackinlay
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it still have 5.1.2 in composer.json? Sorry if it does. Just run composer update. This commit works fine with 5.3 and Laravel 5.7 too.

@sevillaarvin
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, just recently read issue #16 as well. Thank you.

Please sign in to comment.