diff --git a/admin/Controllers/Auth/AdminForgotPasswordController.php b/admin/Controllers/Auth/AdminForgotPasswordController.php new file mode 100644 index 0000000..ba0c44d --- /dev/null +++ b/admin/Controllers/Auth/AdminForgotPasswordController.php @@ -0,0 +1,43 @@ +middleware('guest:admin'); + } + + protected function broker() + { + return Password::broker('admins'); + } + + public function showLinkRequestForm() + { + + return view('admin.passwords.email'); + } +} diff --git a/admin/Controllers/Auth/AdminLoginController.php b/admin/Controllers/Auth/AdminLoginController.php new file mode 100644 index 0000000..bdd8d2a --- /dev/null +++ b/admin/Controllers/Auth/AdminLoginController.php @@ -0,0 +1,43 @@ +middleware('guest:admin', ['except' => ['logout']]); + } + + public function showLoginForm() + { + return view('admin.auth.login'); + } + + public function login(Request $request) + { + // Validate the form data + $this->validate($request, [ + 'email' => 'required|email', + 'password' => 'required|min:6' + ]); + + // Attempt to log the user in + if (Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password], $request->remember)) { + // if successful, then redirect to their intended location + return redirect()->intended(route('admin.dashboard')); + } + + // if unsuccessful, then redirect back to the login with the form data + return redirect()->back()->withInput($request->only('email', 'remember')); + } + + public function logout() + { + Auth::guard('admin')->logout(); + return redirect('/'); + } +} diff --git a/admin/Controllers/Auth/AdminResetPasswordController.php b/admin/Controllers/Auth/AdminResetPasswordController.php new file mode 100644 index 0000000..0dbede5 --- /dev/null +++ b/admin/Controllers/Auth/AdminResetPasswordController.php @@ -0,0 +1,116 @@ +middleware('guest:admin'); + } + + protected function guard() + { + return Auth::guard('admin'); + } + + protected function broker() + { + return Password::broker('admins'); + } + + public function showResetForm(Request $request, $token = null) + { + return view('admin.passwords.reset')->with( + ['token' => $token, 'email' => $request->email] + ); + } + + protected function rules() + { + return [ + 'token' => 'required', + 'email' => 'required|email', + 'password' => 'required|confirmed|min:6', + ]; + } + + protected function validationErrorMessages() + { + return []; + } + public function reset(Request $request) + { + $this->validate($request, $this->rules(), $this->validationErrorMessages()); + + // Here we will attempt to reset the user's password. If it is successful we + // will update the password on an actual user model and persist it to the + // database. Otherwise we will parse the error and return the response. + $response = $this->broker()->reset( + $this->credentials($request), function ($user, $password) { + $this->resetPassword($user, $password); + } + ); + + // If the password was successfully reset, we will redirect the user back to + // the application's home authenticated view. If there is an error we can + // redirect them back to where they came from with their error message. + return $response == Password::PASSWORD_RESET + ? $this->sendResetResponse($response) + : $this->sendResetFailedResponse($request, $response); + } + + protected function credentials(Request $request) + { + return $request->only( + 'email', 'password', 'password_confirmation', 'token' + ); + } + + protected function resetPassword($user, $password) + { + $user->forceFill([ + 'password' => bcrypt($password), + 'remember_token' => Str::random(60), + ])->save(); + + $this->guard()->login($user); + } + + protected function sendResetResponse($response) + { + return redirect('admin.'.config('app.domain').'/dashboard') + ->with('status', trans($response)); + } + + protected function sendResetFailedResponse(Request $request, $response) + { + return redirect()->back() + ->withInput($request->only('email')) + ->withErrors(['email' => trans($response)]); + } +} diff --git a/admin/Controllers/Auth/Controller.php b/admin/Controllers/Auth/Controller.php new file mode 100644 index 0000000..8ec4b8c --- /dev/null +++ b/admin/Controllers/Auth/Controller.php @@ -0,0 +1,13 @@ +middleware('auth:admin'); + } + + /** + * Show the application dashboard. + * + * @return \Illuminate\Http\Response + */ + public function index() + { + return view('admin.dashboard'); + } +} diff --git a/admin/Models/Auth/Admin.php b/admin/Models/Auth/Admin.php new file mode 100644 index 0000000..e09e199 --- /dev/null +++ b/admin/Models/Auth/Admin.php @@ -0,0 +1,44 @@ +notify(new AdminResetPasswordNotification($token)); + } +} diff --git a/admin/Notifications/AdminResetPasswordNotification.php b/admin/Notifications/AdminResetPasswordNotification.php new file mode 100644 index 0000000..7af1c98 --- /dev/null +++ b/admin/Notifications/AdminResetPasswordNotification.php @@ -0,0 +1,63 @@ +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) + { + return (new MailMessage) + ->line('You are receiving this email because we received a password reset request for your account.') + ->action('Reset Password', route('admin.password.reset', $this->token)) + ->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 [ + // + ]; + } +} diff --git a/admin/Observers/AdminObserver.php b/admin/Observers/AdminObserver.php new file mode 100644 index 0000000..35efc09 --- /dev/null +++ b/admin/Observers/AdminObserver.php @@ -0,0 +1,36 @@ +id) && !is_numeric($admin->id)){ + $admin->id = Admin::generateUniqueID(); + } + } + + /** + * Listen to the Admin deleting event. + * + * @param Admin $admin + * @return void + */ + public function deleting(Admin $admin) + { + // + } + +} \ No newline at end of file diff --git a/api/V1/Auth/Controllers/FBloginController.php b/api/V1/Auth/Controllers/FBLoginController.php similarity index 100% rename from api/V1/Auth/Controllers/FBloginController.php rename to api/V1/Auth/Controllers/FBLoginController.php diff --git a/api/V1/Auth/Controllers/ResetPasswordController.php b/api/V1/Auth/Controllers/ResetPasswordController.php index a65ca97..df6b029 100644 --- a/api/V1/Auth/Controllers/ResetPasswordController.php +++ b/api/V1/Auth/Controllers/ResetPasswordController.php @@ -11,7 +11,7 @@ class ResetPasswordController extends Controller { // Redirect to Dashboard if Authenticated - protected $redirectTo = '/dashboard'; + protected $redirectTo = '/'; public function __construct() { diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index a747e31..8978268 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -60,6 +60,17 @@ protected function unauthenticated($request, AuthenticationException $exception) return response()->json(['error' => 'Unauthenticated.'], 401); } - return redirect()->guest(route('login')); + $guard = array_get($exception->guards(), 0); + + switch ($guard) { + case 'admin': + $login = 'admin.login'; + break; + + default: + $login = 'login'; + break; + } + return redirect()->guest(route($login)); } } diff --git a/app/Http/Controllers/DomainController.php b/app/Http/Controllers/DomainController.php new file mode 100644 index 0000000..d63b11b --- /dev/null +++ b/app/Http/Controllers/DomainController.php @@ -0,0 +1,17 @@ +route('app'); + } + + public function vueRouterCatcher() + { + return view('app'); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index e4cec9c..479c415 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -17,10 +17,20 @@ class RedirectIfAuthenticated */ public function handle($request, Closure $next, $guard = null) { - if (Auth::guard($guard)->check()) { - return redirect('/home'); - } + switch ($guard) { + case 'admin': + if (Auth::guard($guard)->check()) { + return redirect()->route('admin.dashboard'); + } + break; - return $next($request); + default: + if (Auth::guard($guard)->check()) { + return redirect('/home'); + } + break; + } + + return $next($request); } } diff --git a/app/Models/Auth/User.php b/app/Models/Auth/User.php index 4f78590..7a4df69 100644 --- a/app/Models/Auth/User.php +++ b/app/Models/Auth/User.php @@ -8,10 +8,11 @@ use Silber\Bouncer\Database\HasRolesAndAbilities; use Tymon\JWTAuth\Contracts\JWTSubject as AuthenticatableUserContract; use App\Notifications\PasswordResetNotification; +use Illuminate\Database\Eloquent\SoftDeletes; class User extends Authenticatable implements AuthenticatableUserContract { - use Notifiable, UserMutator, HasRolesAndAbilities; + use Notifiable, UserMutator, HasRolesAndAbilities, SoftDeletes; protected $table = 'users'; diff --git a/app/Observers/UserObserver.php b/app/Observers/UserObserver.php index 78debf0..43ff3f5 100644 --- a/app/Observers/UserObserver.php +++ b/app/Observers/UserObserver.php @@ -21,8 +21,6 @@ public function creating(User $user) $user->id = User::generateUniqueID(); } $user->code = User::generateUniqueCode(); - - } /** diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index a811766..db80cb2 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -5,6 +5,8 @@ use Illuminate\Support\ServiceProvider; use App\Models\Auth\User; use App\Observers\UserObserver; +use Admin\Models\Auth\Admin; +use Admin\Observers\AdminObserver; class AppServiceProvider extends ServiceProvider { @@ -16,6 +18,7 @@ class AppServiceProvider extends ServiceProvider public function boot() { User::observe(UserObserver::class); + Admin::observe(AdminObserver::class); } /** diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 5ea48d3..d0e2c80 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -16,6 +16,8 @@ class RouteServiceProvider extends ServiceProvider */ protected $namespace = 'App\Http\Controllers'; + protected $admin_namespace = 'Admin\Controllers'; + /** * Define your route model bindings, pattern filters, etc. * @@ -23,8 +25,9 @@ class RouteServiceProvider extends ServiceProvider */ public function boot() { - // - + Route::pattern('vue', '[\/\w\.-]*'); + Route::pattern('nonwww', '[\/\w\.-]*'); + Route::pattern('subdomain', '^(?!.*(admin|api|www)).*$'); parent::boot(); } @@ -39,6 +42,8 @@ public function map() $this->mapWebRoutes(); + $this->mapAdminRoutes(); + // } @@ -56,6 +61,13 @@ protected function mapWebRoutes() ->group(base_path('routes/web.php')); } + protected function mapAdminRoutes() + { + Route::middleware('web') + ->namespace($this->admin_namespace) + ->group(base_path('routes/admin.php')); + } + /** * Define the "api" routes for the application. * diff --git a/composer.json b/composer.json index 225fdf2..b275384 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,8 @@ ], "psr-4": { "App\\": "app/", - "Api\\": "api/" + "Api\\": "api/", + "Admin\\": "admin/" } }, "autoload-dev": { diff --git a/config/app.php b/config/app.php index 6515b2b..9b0043c 100644 --- a/config/app.php +++ b/config/app.php @@ -53,6 +53,8 @@ 'url' => env('APP_URL', 'http://localhost'), + 'domain' => env('APP_DOMAIN', 'laravel.dev'), + /* |-------------------------------------------------------------------------- | Application Timezone diff --git a/config/auth.php b/config/auth.php index 4b11132..8541cf8 100644 --- a/config/auth.php +++ b/config/auth.php @@ -45,6 +45,10 @@ 'driver' => 'jwt', 'provider' => 'users', ], + 'admin' => [ + 'driver' => 'session', + 'provider' => 'admins', + ], ], /* @@ -69,6 +73,10 @@ 'driver' => 'eloquent', 'model' => App\Models\Auth\User::class, ], + 'admins' => [ + 'driver' => 'eloquent', + 'model' => Admin\Models\Auth\Admin::class, + ], // 'users' => [ // 'driver' => 'database', @@ -97,6 +105,11 @@ 'table' => 'password_resets', 'expire' => 60, ], + 'admins' => [ + 'provider' => 'admins', + 'table' => 'password_resets', + 'expire' => 15, + ], ], ]; diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php index 6bd3b2a..bea8970 100644 --- a/database/migrations/2014_10_12_000000_create_users_table.php +++ b/database/migrations/2014_10_12_000000_create_users_table.php @@ -16,7 +16,6 @@ public function up() Schema::create('users', function (Blueprint $table) { $table->unsignedBigInteger('id'); // Allows Us to use Facebook ID $table->unsignedBigInteger('sp_id')->nullable(); // Sponsor ID - $table->foreign('sp_id')->references('id')->on('users'); $table->string('code',24); $table->string('first_name',32); $table->string('last_name',32); @@ -31,6 +30,7 @@ public function up() $table->unsignedTinyInteger('resent')->default(0); // For Sending Password Reset Email $table->json('settings')->nullable(); $table->rememberToken(); + $table->softDeletes(); $table->timestamps(); }); } diff --git a/database/migrations/2017_03_18_021252_create_bouncer_tables.php b/database/migrations/2017_03_18_021252_create_bouncer_tables.php index 714c845..3bdd20c 100644 --- a/database/migrations/2017_03_18_021252_create_bouncer_tables.php +++ b/database/migrations/2017_03_18_021252_create_bouncer_tables.php @@ -18,7 +18,7 @@ public function up() $table->increments('id'); $table->string('name', 150); $table->string('title')->nullable(); - $table->integer('entity_id')->unsigned()->nullable(); + $table->unsignedBigInteger('entity_id')->unsigned()->nullable(); $table->string('entity_type', 150)->nullable(); $table->boolean('only_owned')->default(false); $table->timestamps(); @@ -39,7 +39,8 @@ public function up() Schema::create(Models::table('assigned_roles'), function (Blueprint $table) { $table->integer('role_id')->unsigned()->index(); - $table->morphs('entity'); + $table->unsignedBigInteger('entity_id')->unsigned()->nullable(); + $table->string('entity_type', 150)->nullable(); $table->foreign('role_id')->references('id')->on(Models::table('roles')) ->onUpdate('cascade')->onDelete('cascade'); @@ -47,7 +48,8 @@ public function up() Schema::create(Models::table('permissions'), function (Blueprint $table) { $table->integer('ability_id')->unsigned()->index(); - $table->morphs('entity'); + $table->unsignedBigInteger('entity_id')->unsigned()->nullable(); + $table->string('entity_type', 150)->nullable(); $table->boolean('forbidden')->default(false); $table->foreign('ability_id')->references('id')->on(Models::table('abilities')) diff --git a/database/migrations/2017_06_08_070222_create_admins_table.php b/database/migrations/2017_06_08_070222_create_admins_table.php new file mode 100644 index 0000000..cf9e9fb --- /dev/null +++ b/database/migrations/2017_06_08_070222_create_admins_table.php @@ -0,0 +1,37 @@ +unsignedBigInteger('id'); + $table->string('name'); + $table->string('email')->unique(); + $table->string('job_title'); + $table->string('password'); + $table->rememberToken(); + $table->softDeletes(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('admins'); + } +} diff --git a/database/seeds/AdminTableSeeder.php b/database/seeds/AdminTableSeeder.php new file mode 100644 index 0000000..fbbdc2c --- /dev/null +++ b/database/seeds/AdminTableSeeder.php @@ -0,0 +1,25 @@ + 'admin@example.com', + 'job_title' => 'CEO', + 'name' => 'admin', + 'password' => 'password' + ]); + + } +} diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 2399bf1..cfb1fa5 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -12,5 +12,6 @@ class DatabaseSeeder extends Seeder public function run() { $this->call(UsersTableSeeder::class); + $this->call(AdminTableSeeder::class); } } diff --git a/database/seeds/UsersTableSeeder.php b/database/seeds/UsersTableSeeder.php index eb3abb2..17b7b91 100644 --- a/database/seeds/UsersTableSeeder.php +++ b/database/seeds/UsersTableSeeder.php @@ -15,19 +15,21 @@ public function run() { \Bouncer::seeder(function () { // List All the Abilities of Each Roles - \Bouncer::allow('admin')->to(['ban-user', 'add-user', 'delete-user', 'view-user', 'edit-user']); - \Bouncer::allow('user')->to('update-profile'); + \Bouncer::allow('tenant')->to(['manage_users']); + \Bouncer::allow('manager')->to('manage_projects','manage_comment','manage_files'); + \Bouncer::allow('worker')->to('update_task','edit_profile', 'comment','upload_files'); + \Bouncer::allow('client')->to('edit_profile', 'edit_profile', 'comment' ,'upload_files'); }); $user = User::create([ - 'email' => 'admin@laravel.dev', - 'username' => 'superadmin', + 'email' => 'user@example.com', + 'username' => 'user', 'first_name' => 'John', 'last_name' => 'Doe', 'password' => 'password' ]); - \Bouncer::assign('admin')->to($user); + \Bouncer::assign('tenant')->to($user); // Gives All Abilities \Bouncer::allow($user)->everything(); diff --git a/resources/views/admin/auth/login.blade.php b/resources/views/admin/auth/login.blade.php new file mode 100644 index 0000000..13b40a7 --- /dev/null +++ b/resources/views/admin/auth/login.blade.php @@ -0,0 +1,60 @@ +@extends('layouts.admin') @section('content') +
+ You are Logged In as a USER +
+@else ++ You are Logged Out as a USER +
+@endif @if (Auth::guard('admin')->check()) ++ You are Logged In as a ADMIN +
+@else ++ You are Logged Out as a ADMIN +
+@endif \ No newline at end of file diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php new file mode 100644 index 0000000..28487b4 --- /dev/null +++ b/resources/views/home.blade.php @@ -0,0 +1,15 @@ +@extends('layouts.admin') @section('content') +