diff --git a/.gitignore b/.gitignore index b6a4b86..46369c4 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ Homestead.yaml npm-debug.log yarn-error.log .env +/360-dev.iml diff --git a/app/Concern/Admin/TraitAdminController.php b/app/Concern/Admin/TraitAdminController.php new file mode 100644 index 0000000..b4af979 --- /dev/null +++ b/app/Concern/Admin/TraitAdminController.php @@ -0,0 +1,117 @@ +model = self::__MODEL; + } + + /** + * Display a listing of the resource. + * + * @return \Illuminate\Http\Response + */ + public function index() + { + $items = $this->model::all(); + return view('admin.' . $this->view . '.index', compact('items')); + } + + /** + * Show the form for creating a new resource. + * + * @return \Illuminate\Http\Response + */ + public function create() + { + $this->authorize('create', $this->model); + $item = new $this->model; + return view('admin.' . $this->view . '.form', compact('item')); + } + + /** + * Store a newly created resource in storage. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function store(Request $request) + { + $this->authorize('create', $this->model); + Validator::make($request->all(), $this->validator)->validate(); + $this->model::create($request->all()); + return $this->index()->with('success', 'Nouvel entité créé'); + } + + /** + * Display the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function show(int $id) + { + $this->authorize('view', $this->model); + $item = $this->model::where('id', $id)->first(); + return view('admin.' . $this->view . '.show', compact('item')); + } + + /** + * Show the form for editing the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function edit(int $id) + { + $this->authorize('update', $this->model); + $item = $this->model::where('id', $id)->first(); + return view('admin.' . $this->view . '.form', compact('item')); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, int $id) + { + $this->authorize('update', $this->model); + $item = $this->model::where('id', $id)->first(); + $item->update($request->all()); + return $this->index()->with('success', 'Entité modifié avec succès'); + } + + /** + * @param int $id + * @return mixed + */ + public function destroy(int $id) + { + $this->authorize('delete', $this->model); + $item = $this->model::where('id', $id)->first(); + $item->delete(); + return $this->index()->with('success', 'Entité supprimé'); + } +} diff --git a/app/Http/Controllers/Admin/PostController.php b/app/Http/Controllers/Admin/PostController.php new file mode 100644 index 0000000..f0f1fee --- /dev/null +++ b/app/Http/Controllers/Admin/PostController.php @@ -0,0 +1,17 @@ +authorize('view', self::__MODEL); + $items = User::with('roles')->get(); + return view('admin.' . $this->view . '.index', compact('items')); + } + + public function destroy(User $user) + { + $this->authorize('delete', $user); + $user->roles()->detach(); + $user->delete(); + return $this->index()->with('success', 'Utilisateur supprimé'); + } +} diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index 6a247fe..1326cf9 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -4,6 +4,10 @@ use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\SendsPasswordResetEmails; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Password; class ForgotPasswordController extends Controller { @@ -23,10 +27,34 @@ class ForgotPasswordController extends Controller /** * Create a new controller instance. * - * @return void */ public function __construct() { $this->middleware('guest'); } + + /** + * Send a reset link to the given user. + * + * @param Request $request + * @return RedirectResponse|JsonResponse + */ + public function sendResetLinkEmail(Request $request) + { + $this->validateEmail($request); + + // We will send the password reset link to this user. Once we have attempted + // to send the link, we will examine the response then see the message we + // need to show to the user. Finally, we'll send out a proper response. + $response = $this->broker()->sendResetLink( + array_merge( + $request->only('email'), + ['verify_token' => null] + ) + ); + + return $response == Password::RESET_LINK_SENT + ? $this->sendResetLinkResponse($response) + : $this->sendResetLinkFailedResponse($request, $response); + } } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index b2ea669..69f2f36 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -4,6 +4,7 @@ use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\AuthenticatesUsers; +use Illuminate\Http\Request; class LoginController extends Controller { @@ -30,10 +31,23 @@ class LoginController extends Controller /** * Create a new controller instance. * - * @return void */ public function __construct() { $this->middleware('guest')->except('logout'); } + + /** + * Get the needed authorization credentials from the request. + * + * @param Request $request + * @return array + */ + protected function credentials(Request $request) + { + return array_merge( + $request->only($this->username(), 'password'), + ['verify_token' => null] + ); + } } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index f77265a..0ccefd1 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -2,8 +2,13 @@ namespace App\Http\Controllers\Auth; -use App\User; +use App\Model\Role; +use App\Model\User; use App\Http\Controllers\Controller; +use App\Notifications\RegisteredUser; +use Illuminate\Auth\Events\Registered; +use Illuminate\Http\Request; +use Illuminate\Routing\Redirector; use Illuminate\Support\Facades\Validator; use Illuminate\Foundation\Auth\RegistersUsers; @@ -32,13 +37,48 @@ class RegisterController extends Controller /** * Create a new controller instance. * - * @return void */ public function __construct() { $this->middleware('guest'); } + /** + * Handle a registration request for the application. + * + * @param Request $request + * @return \Illuminate\Http\Response + */ + public function register(Request $request) + { + $this->validator($request->all())->validate(); + event(new Registered($user = $this->create($request->all()))); + $user->notify(new RegisteredUser()); + return $this->registered($request, $user) + ?: redirect($this->redirectPath()); + } + + /** + * Verify the email adress with token + * + * @param int $id + * @param string $token + * @return Redirector + */ + public function confirm(int $id, string $token) + { + $user = User::where([['id', $id], ['verify_token', $token]])->first(); + if ($user) { + $role = Role::where('name', 'user')->first(); + $user->roles()->attach($role); + $user->update(['veriffy_token' => null]); + $this->guard()->login($user); + return redirect($this->redirectPath()); + } else { + return redirect('/login')->with('error', 'Ce lien n\'est pas valide'); + } + } + /** * Get a validator for an incoming registration request. * @@ -58,14 +98,25 @@ protected function validator(array $data) * Create a new user instance after a valid registration. * * @param array $data - * @return \App\User + * @return \App\Model\User */ protected function create(array $data) { + $default = null; + $size = 40; + $avatar = "https://www.gravatar.com/avatar/"; + $avatar .= md5(strtolower(trim($data['email']))); + $avatar .= "?d="; + $avatar .= urlencode($default); + $avatar .= "&s="; + $avatar .= $size; + return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => bcrypt($data['password']), + 'verify_token' => str_replace('/', '', bcrypt(str_random(16))), + 'avatar' => $avatar ]); } } diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php new file mode 100644 index 0000000..a3af7dd --- /dev/null +++ b/app/Http/Controllers/HomeController.php @@ -0,0 +1,28 @@ +middleware('auth'); + } + + /** + * Show the application dashboard. + * + * @return \Illuminate\Http\Response + */ + public function index() + { + return view('home'); + } +} diff --git a/app/Http/Controllers/PostsController.php b/app/Http/Controllers/PostsController.php index 5ade670..000a73f 100644 --- a/app/Http/Controllers/PostsController.php +++ b/app/Http/Controllers/PostsController.php @@ -1,8 +1,8 @@ [ - \App\Http\Middleware\EncryptCookies::class, - \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, - \Illuminate\Session\Middleware\StartSession::class, + EncryptCookies::class, + AddQueuedCookiesToResponse::class, + StartSession::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, - \Illuminate\View\Middleware\ShareErrorsFromSession::class, - \App\Http\Middleware\VerifyCsrfToken::class, - \Illuminate\Routing\Middleware\SubstituteBindings::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + SubstituteBindings::class, ], 'api' => [ @@ -51,11 +70,14 @@ class Kernel extends HttpKernel * @var array */ protected $routeMiddleware = [ - 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, - 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, - 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, - 'can' => \Illuminate\Auth\Middleware\Authorize::class, - 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, - 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, + 'auth' => Authenticate::class, + 'auth.basic' => AuthenticateWithBasicAuth::class, + 'bindings' => SubstituteBindings::class, + 'can' => Authorize::class, + 'guest' => RedirectIfAuthenticated::class, + 'throttle' => ThrottleRequests::class, + 'role' => EntrustRole::class, + 'permission' => EntrustPermission::class, + 'ability' => EntrustAbility::class ]; } diff --git a/app/Category.php b/app/Model/Category.php similarity index 60% rename from app/Category.php rename to app/Model/Category.php index 52ecfc0..fd07183 100644 --- a/app/Category.php +++ b/app/Model/Category.php @@ -1,10 +1,16 @@ belongsToMany(User::class); + } +} diff --git a/app/Model/User.php b/app/Model/User.php new file mode 100644 index 0000000..64e6966 --- /dev/null +++ b/app/Model/User.php @@ -0,0 +1,54 @@ +hasMany(Post::class); + } + + /** + * @return BelongsToMany + */ + public function roles(): BelongsToMany + { + return $this->belongsToMany(Role::class); + } +} diff --git a/app/Notifications/RegisteredUser.php b/app/Notifications/RegisteredUser.php new file mode 100644 index 0000000..595f6f2 --- /dev/null +++ b/app/Notifications/RegisteredUser.php @@ -0,0 +1,67 @@ +success() + ->subject('Inscription sur ' . env('APP_NAME')) + ->line( + 'Votre compte à bien été créé, ' . + 'merci de confirmer votre adresse mail en cliquant sur le bouton suivant' + ) + ->action( + 'Confirmer mon adresse mail', + route('auth.confirm', [$notifiable->id, urlencode($notifiable->verify_token)]) + ) + ->line('Merci de votre inscrption'); + } + + /** + * Get the array representation of the notification + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable): array + { + return [ + // + ]; + } +} diff --git a/app/Policies/CategoryPolicy.php b/app/Policies/CategoryPolicy.php new file mode 100644 index 0000000..e0b479d --- /dev/null +++ b/app/Policies/CategoryPolicy.php @@ -0,0 +1,68 @@ +roles->name === 'root') { + return true; + } + } + + /** + * Determine whether the user can view the category. + * + * @param \App\Model\User $user + * @param \App\Model\Category $category + * @return mixed + */ + public function view(User $user, Category $category) + { + return true; + } + + /** + * Determine whether the user can create categories. + * + * @param \App\Model\User $user + * @return mixed + */ + public function create(User $user) + { + return $user->roles->name === 'admin' || $user->roles->name === 'redactor'; + } + + /** + * Determine whether the user can update the category. + * + * @param \App\Model\User $user + * @param \App\Model\Category $category + * @return mixed + */ + public function update(User $user, Category $category) + { + return $user->roles->name === 'admin' || + $user->roles->name === 'redactor' || + $user->posts->category_id === $category->id; + } + + /** + * Determine whether the user can delete the category. + * + * @param \App\Model\User $user + * @param \App\Model\Category $category + * @return mixed + */ + public function delete(User $user, Category $category) + { + return $user->roles->name === 'admin' || $user->posts->category_id === $category->id; + } +} diff --git a/app/Policies/PostPolicy.php b/app/Policies/PostPolicy.php new file mode 100644 index 0000000..f7a1ab2 --- /dev/null +++ b/app/Policies/PostPolicy.php @@ -0,0 +1,66 @@ +roles->name === 'root') { + return true; + } + } + + /** + * Determine whether the user can view the post. + * + * @param \App\Model\User $user + * @param \App\Model\Post $post + * @return mixed + */ + public function view(User $user, Post $post) + { + return true; + } + + /** + * Determine whether the user can create posts. + * + * @param \App\Model\User $user + * @return mixed + */ + public function create(User $user) + { + return $user->roles->name === 'admin' || $user->roles->name === 'redactor'; + } + + /** + * Determine whether the user can update the post. + * + * @param \App\Model\User $user + * @param \App\Model\Post $post + * @return mixed + */ + public function update(User $user, Post $post) + { + return $user->roles->name === 'admin' || $user->roles->name === 'redactor' || $user->id === $post->user_id; + } + + /** + * Determine whether the user can delete the post. + * + * @param \App\Model\User $user + * @param \App\Model\Post $post + * @return mixed + */ + public function delete(User $user, Post $post) + { + return $user->roles->name === 'admin' || $user->roles->name === 'redactor'; + } +} diff --git a/app/Policies/RolePolicy.php b/app/Policies/RolePolicy.php new file mode 100644 index 0000000..a665fd6 --- /dev/null +++ b/app/Policies/RolePolicy.php @@ -0,0 +1,66 @@ +roles->name === 'root') { + return true; + } + } + + /** + * Determine whether the user can view the role. + * + * @param \App\Model\User $user + * @param \App\Model\Role $role + * @return mixed + */ + public function view(User $user, Role $role) + { + return false; + } + + /** + * Determine whether the user can create roles. + * + * @param \App\Model\User $user + * @return mixed + */ + public function create(User $user) + { + return false; + } + + /** + * Determine whether the user can update the role. + * + * @param \App\Model\User $user + * @param \App\Model\Role $role + * @return mixed + */ + public function update(User $user, Role $role) + { + return false; + } + + /** + * Determine whether the user can delete the role. + * + * @param \App\Model\User $user + * @param \App\Model\Role $role + * @return mixed + */ + public function delete(User $user, Role $role) + { + return false; + } +} diff --git a/app/Policies/UserPolicy.php b/app/Policies/UserPolicy.php new file mode 100644 index 0000000..b4ea5fe --- /dev/null +++ b/app/Policies/UserPolicy.php @@ -0,0 +1,65 @@ +roles->name === 'root') { + return true; + } + } + + /** + * Determine whether the user can view the model. + * + * @param \App\Model\User $user + * @param \App\Model\User $model + * @return mixed + */ + public function view(User $user, User $model) + { + return $user->roles->name === 'moderator' || $user->id === $model->id; + } + + /** + * Determine whether the user can create models. + * + * @param \App\Model\User $user + * @return mixed + */ + public function create(User $user) + { + return true; + } + + /** + * Determine whether the user can update the model. + * + * @param \App\Model\User $user + * @param \App\Model\User $model + * @return mixed + */ + public function update(User $user, User $model) + { + return $user->id === $model->id || $user->roles->name === 'admin'; + } + + /** + * Determine whether the user can delete the model. + * + * @param \App\Model\User $user + * @param \App\Model\User $model + * @return mixed + */ + public function delete(User $user, User $model) + { + return $user->id === $model->id; + } +} diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 9784b1a..6cb6be0 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -2,7 +2,14 @@ namespace App\Providers; -use Illuminate\Support\Facades\Gate; +use App\Model\Category; +use App\Model\Post; +use App\Model\Role; +use App\Model\User; +use App\Policies\CategoryPolicy; +use App\Policies\PostPolicy; +use App\Policies\RolePolicy; +use App\Policies\UserPolicy; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; class AuthServiceProvider extends ServiceProvider @@ -13,7 +20,10 @@ class AuthServiceProvider extends ServiceProvider * @var array */ protected $policies = [ - 'App\Model' => 'App\Policies\ModelPolicy', + Category::class => CategoryPolicy::class, + Post::class => PostPolicy::class, + Role::class => RolePolicy::class, + User::class => UserPolicy::class ]; /** diff --git a/app/User.php b/app/User.php deleted file mode 100644 index bd1d184..0000000 --- a/app/User.php +++ /dev/null @@ -1,38 +0,0 @@ -hasMany(Post::class); - } -} diff --git a/composer.json b/composer.json index 0d1b1a8..dcb7975 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,8 @@ "php": ">=7.0.0", "fideloper/proxy": "~3.3", "laravel/framework": "5.5.*", - "laravel/tinker": "~1.0" + "laravel/tinker": "~1.0", + "zizaco/entrust": "^1.8" }, "require-dev": { "barryvdh/laravel-debugbar": "^3.1", diff --git a/composer.lock b/composer.lock index cd6d2a3..cdf01fb 100644 --- a/composer.lock +++ b/composer.lock @@ -405,16 +405,16 @@ }, { "name": "laravel/framework", - "version": "v5.5.18", + "version": "v5.5.19", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "1cc21baac11551377734b8c17ead17db4c34fe21" + "reference": "c678100e84934ec85c9f8bc26bd0a60222682719" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/1cc21baac11551377734b8c17ead17db4c34fe21", - "reference": "1cc21baac11551377734b8c17ead17db4c34fe21", + "url": "https://api.github.com/repos/laravel/framework/zipball/c678100e84934ec85c9f8bc26bd0a60222682719", + "reference": "c678100e84934ec85c9f8bc26bd0a60222682719", "shasum": "" }, "require": { @@ -532,7 +532,7 @@ "framework", "laravel" ], - "time": "2017-10-19T12:50:26+00:00" + "time": "2017-10-25T19:10:45+00:00" }, { "name": "laravel/tinker", diff --git a/config/app.php b/config/app.php index b81fb73..1d73888 100644 --- a/config/app.php +++ b/config/app.php @@ -168,6 +168,7 @@ * Package Service Providers... */ + /* * Application Service Providers... */ @@ -228,7 +229,7 @@ 'View' => Illuminate\Support\Facades\View::class, // Project aliases - 'Menu' => \App\Helpers\MenuHelper::class + 'Menu' => \App\Helpers\MenuHelper::class, ], ]; diff --git a/config/auth.php b/config/auth.php index 7817501..1d25fe7 100644 --- a/config/auth.php +++ b/config/auth.php @@ -67,7 +67,8 @@ 'providers' => [ 'users' => [ 'driver' => 'eloquent', - 'model' => App\User::class, + 'model' => App\Model\User::class, + 'table' => 'users' ], // 'users' => [ diff --git a/config/services.php b/config/services.php index 4460f0e..2a2f05d 100644 --- a/config/services.php +++ b/config/services.php @@ -30,7 +30,7 @@ ], 'stripe' => [ - 'model' => App\User::class, + 'model' => App\Model\User::class, 'key' => env('STRIPE_KEY'), 'secret' => env('STRIPE_SECRET'), ], diff --git a/database/factories/CategoryFactory.php b/database/factories/CategoryFactory.php index f2c0835..e301454 100644 --- a/database/factories/CategoryFactory.php +++ b/database/factories/CategoryFactory.php @@ -13,7 +13,7 @@ | */ -$factory->define(App\Category::class, function (Faker $faker) { +$factory->define(App\Model\Category::class, function (Faker $faker) { return [ 'name' => $faker->name, diff --git a/database/factories/PostsFactory.php b/database/factories/PostsFactory.php index 25a72b4..e899e9d 100644 --- a/database/factories/PostsFactory.php +++ b/database/factories/PostsFactory.php @@ -13,7 +13,7 @@ | */ -$factory->define(App\Post::class, function (Faker $faker) { +$factory->define(App\Model\Post::class, function (Faker $faker) { return [ 'name' => $faker->name, @@ -21,10 +21,10 @@ 'content' => $faker->text(1000), 'image' => $faker->imageUrl(), 'category_id' => function () { - return factory(\App\Category::class)->create()->id; + return factory(\App\Model\Category::class)->create()->id; }, 'user_id' => function () { - return factory(\App\User::class)->create()->id; + return factory(\App\Model\User::class)->create()->id; } ]; }); diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 008e952..9712f8c 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -13,7 +13,7 @@ | */ -$factory->define(App\User::class, function (Faker $faker) { +$factory->define(App\Model\User::class, function (Faker $faker) { static $password; return [ @@ -21,5 +21,6 @@ 'email' => $faker->unique()->safeEmail, 'password' => $password ?: $password = bcrypt('secret'), 'remember_token' => str_random(10), + 'avatar' => $faker->imageUrl() ]; }); diff --git a/database/migrations/2017_10_21_112415_create_posts_table.php b/database/migrations/2017_10_21_112415_create_posts_table.php index b71a62d..7805a8c 100644 --- a/database/migrations/2017_10_21_112415_create_posts_table.php +++ b/database/migrations/2017_10_21_112415_create_posts_table.php @@ -37,11 +37,6 @@ public function up() $table->index(['category_id', 'user_id']); $table->timestamps(); }); - - Schema::create('roles', function(Blueprint $table) { - $table->increments('id'); - $table->string('name'); - }); } /** @@ -53,6 +48,5 @@ public function down() { Schema::dropIfExists('posts'); Schema::dropIfExists('categories'); - Schema::dropIfExists('roles'); } } diff --git a/database/migrations/2017_10_24_195320_add_avatar_to_users_table.php b/database/migrations/2017_10_24_195320_add_avatar_to_users_table.php new file mode 100644 index 0000000..47486e9 --- /dev/null +++ b/database/migrations/2017_10_24_195320_add_avatar_to_users_table.php @@ -0,0 +1,32 @@ +string('avatar')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('avatar'); + }); + } +} diff --git a/database/migrations/2017_10_26_035256_add_verify_token_to_users_table.php b/database/migrations/2017_10_26_035256_add_verify_token_to_users_table.php new file mode 100644 index 0000000..1174dd7 --- /dev/null +++ b/database/migrations/2017_10_26_035256_add_verify_token_to_users_table.php @@ -0,0 +1,32 @@ +string('verify_token')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('verify_token'); + }); + } +} diff --git a/database/migrations/2017_10_31_000239_create_roles_table.php b/database/migrations/2017_10_31_000239_create_roles_table.php new file mode 100644 index 0000000..4d213f0 --- /dev/null +++ b/database/migrations/2017_10_31_000239_create_roles_table.php @@ -0,0 +1,49 @@ +increments('id'); + $table->string('name')->unique(); + $table->string('display_name')->nullable(); + $table->string('description')->nullable(); + $table->timestamps(); + }); + + // Create table for associating roles to users (Many-to-Many) + Schema::create('role_user', function (Blueprint $table) { + $table->integer('user_id')->unsigned(); + $table->integer('role_id')->unsigned(); + + $table->foreign('user_id')->references('id')->on('users') + ->onUpdate('cascade')->onDelete('cascade'); + $table->foreign('role_id')->references('id')->on('roles') + ->onUpdate('cascade')->onDelete('cascade'); + + $table->primary(['user_id', 'role_id']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('roles'); + Schema::drop('role_user'); + } +} diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index b96ae0a..141ff8f 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -12,5 +12,7 @@ class DatabaseSeeder extends Seeder public function run() { $this->call(PostsTableSeeder::class); + $this->call(RoleTableSeeder::class); + $this->call(UserTableSeeder::class); } } diff --git a/database/seeds/PostsTableSeeder.php b/database/seeds/PostsTableSeeder.php index 903637b..e2e630f 100644 --- a/database/seeds/PostsTableSeeder.php +++ b/database/seeds/PostsTableSeeder.php @@ -14,6 +14,6 @@ class PostsTableSeeder extends Seeder */ public function run() { - factory(\App\Post::class, 50)->create(); + factory(\App\Model\Post::class, 50)->create(); } } diff --git a/database/seeds/RoleTableSeeder.php b/database/seeds/RoleTableSeeder.php new file mode 100644 index 0000000..c09c510 --- /dev/null +++ b/database/seeds/RoleTableSeeder.php @@ -0,0 +1,39 @@ + 'user', + 'display_name' => 'Simple user', + 'description' => 'Just a simple user' + ], [ + 'name' => 'moderator', + 'display_name' => 'Moderator', + 'description' => 'User can moderate comments and forum' + ], [ + 'name' => 'redactor', + 'display_name' => 'Redactor', + 'description' => 'User can write post' + ], [ + 'name' => 'admin', + 'display_name' => 'Admin', + 'description' => 'User can moderate all and can write/edit post' + ], [ + 'name' => 'root', + 'display_name' => 'Super Admin', + 'description' => 'Full access' + ] + ]); + } +} diff --git a/database/seeds/UserTableSeeder.php b/database/seeds/UserTableSeeder.php new file mode 100644 index 0000000..f454548 --- /dev/null +++ b/database/seeds/UserTableSeeder.php @@ -0,0 +1,34 @@ +create(); + + $users = User::all(); + + $user = Role::where('name', 'user')->first(); + $admin = Role::where('name', 'admin')->first(); + $redactor = Role::where('name', 'redactor')->first(); + $moderator = Role::where('name', 'moderator')->first(); + $root = Role::where('name', 'root')->first(); + + for ($i = 0; $i < 10; $i++) { + $users[$i]->roles()->save($user); + $users[$i + 10]->roles()->save($admin); + $users[$i + 20]->roles()->save($redactor); + $users[$i + 30]->roles()->save($moderator); + $users[$i + 40]->roles()->save($root); + } + } +} diff --git a/package-lock.json b/package-lock.json index 7088372..9789b69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9670,15 +9670,6 @@ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "dev": true }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, "string-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", @@ -9699,6 +9690,15 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", diff --git a/resources/assets/js/app.js b/resources/assets/js/app.js index c1620c1..35b3584 100644 --- a/resources/assets/js/app.js +++ b/resources/assets/js/app.js @@ -5,7 +5,7 @@ * building robust, powerful web applications using Vue and Laravel. */ -require('./bootstrap'); +require('./bootstrap') window.Vue = require('vue'); diff --git a/resources/views/admin/permission/form.blade.php b/resources/views/admin/permission/form.blade.php new file mode 100644 index 0000000..61a26eb --- /dev/null +++ b/resources/views/admin/permission/form.blade.php @@ -0,0 +1,11 @@ +@extends('layout') + +@section('content') +

Administration

+

Les roles

+ @if($item->id) +

Editer

+ @else +

Créer

+ @endif +@endsection \ No newline at end of file diff --git a/resources/views/admin/permission/index.blade.php b/resources/views/admin/permission/index.blade.php new file mode 100644 index 0000000..6bca689 --- /dev/null +++ b/resources/views/admin/permission/index.blade.php @@ -0,0 +1,53 @@ +@extends('layout') + +@section('content') +
+

Administration

+
+

Permissions

+

+ Créer une nouvel permission +

+ + + + + + + + + + + + + + @foreach($items as $item) + + + + + + + + + + + @endforeach + +
IDNameDisplay NameDescriptionCreated AtUpdated AtAction
{{ $item->id }}{{ $item->name }}{{ $item->display_name }} + + {{ $item->description }} + + {{ $item->created_at }}{{ $item->updated_at }} + + Editer + + +
+ {{ csrf_field() }} + {{ method_field('DELETE') }} + +
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/admin/permission/show.blade.php b/resources/views/admin/permission/show.blade.php new file mode 100644 index 0000000..405a0b7 --- /dev/null +++ b/resources/views/admin/permission/show.blade.php @@ -0,0 +1,8 @@ +@extends('layout') + +@section('content') +

Administration

+

Les roles

+

{{ $item->name }}

+

{{ $item->description }}

+@endsection \ No newline at end of file diff --git a/resources/views/admin/role/form.blade.php b/resources/views/admin/role/form.blade.php new file mode 100644 index 0000000..61a26eb --- /dev/null +++ b/resources/views/admin/role/form.blade.php @@ -0,0 +1,11 @@ +@extends('layout') + +@section('content') +

Administration

+

Les roles

+ @if($item->id) +

Editer

+ @else +

Créer

+ @endif +@endsection \ No newline at end of file diff --git a/resources/views/admin/role/index.blade.php b/resources/views/admin/role/index.blade.php new file mode 100644 index 0000000..1af9ec5 --- /dev/null +++ b/resources/views/admin/role/index.blade.php @@ -0,0 +1,53 @@ +@extends('layout') + +@section('content') +
+

Administration

+
+

Roles

+

+ Créer un nouveau role +

+ + + + + + + + + + + + + + @foreach($items as $item) + + + + + + + + + + + @endforeach + +
IDNameDisplay NameDescriptionCreated AtUpdated AtAction
{{ $item->id }}{{ $item->name }}{{ $item->display_name }} + + {{ $item->description }} + + {{ $item->created_at }}{{ $item->updated_at }} + + Editer + + +
+ {{ csrf_field() }} + {{ method_field('DELETE') }} + +
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/admin/role/show.blade.php b/resources/views/admin/role/show.blade.php new file mode 100644 index 0000000..405a0b7 --- /dev/null +++ b/resources/views/admin/role/show.blade.php @@ -0,0 +1,8 @@ +@extends('layout') + +@section('content') +

Administration

+

Les roles

+

{{ $item->name }}

+

{{ $item->description }}

+@endsection \ No newline at end of file diff --git a/resources/views/admin/user/form.blade.php b/resources/views/admin/user/form.blade.php new file mode 100644 index 0000000..61a26eb --- /dev/null +++ b/resources/views/admin/user/form.blade.php @@ -0,0 +1,11 @@ +@extends('layout') + +@section('content') +

Administration

+

Les roles

+ @if($item->id) +

Editer

+ @else +

Créer

+ @endif +@endsection \ No newline at end of file diff --git a/resources/views/admin/user/index.blade.php b/resources/views/admin/user/index.blade.php new file mode 100644 index 0000000..56dcf36 --- /dev/null +++ b/resources/views/admin/user/index.blade.php @@ -0,0 +1,59 @@ +@extends('layout') + +@section('content') +
+

Administration

+
+

Users

+

+ Créer un nouveau user +

+ + + + + + + + + + + + + + + @foreach($items as $item) + + + + + + + + + + + + @endforeach + +
IDNameEmailAvatarCreated AtUpdated AtRoleAction
{{ $item->id }}{{ $item->name }}{{ $item->email }} + + Avatar de {{ $item->name }} + + {{ $item->created_at }}{{ $item->updated_at }} + @foreach($item->roles as $role) + {{ ucfirst($role->name) }} + @endforeach + + + Editer + + +
+ {{ csrf_field() }} + {{ method_field('DELETE') }} + +
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/admin/user/show.blade.php b/resources/views/admin/user/show.blade.php new file mode 100644 index 0000000..405a0b7 --- /dev/null +++ b/resources/views/admin/user/show.blade.php @@ -0,0 +1,8 @@ +@extends('layout') + +@section('content') +

Administration

+

Les roles

+

{{ $item->name }}

+

{{ $item->description }}

+@endsection \ No newline at end of file diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php new file mode 100644 index 0000000..1831af5 --- /dev/null +++ b/resources/views/auth/login.blade.php @@ -0,0 +1,69 @@ +@extends('layout') +{{-- TODO: Transformer le style en bootstrap4 --}} +@section('content') +
+
+
+
+
Login
+ +
+
+ {{ csrf_field() }} + +
+ + +
+ + + @if ($errors->has('email')) + + {{ $errors->first('email') }} + + @endif +
+
+ +
+ + +
+ + + @if ($errors->has('password')) + + {{ $errors->first('password') }} + + @endif +
+
+ +
+
+
+ +
+
+
+ +
+
+ + + + Forgot Your Password? + +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/passwords/email.blade.php b/resources/views/auth/passwords/email.blade.php new file mode 100644 index 0000000..33a265f --- /dev/null +++ b/resources/views/auth/passwords/email.blade.php @@ -0,0 +1,47 @@ +@extends('layout') +{{-- TODO: Transformer le style en bootstrap4 --}} +@section('content') +
+
+
+
+
Reset Password
+ +
+ @if (session('status')) +
+ {{ session('status') }} +
+ @endif + +
+ {{ csrf_field() }} + +
+ + +
+ + + @if ($errors->has('email')) + + {{ $errors->first('email') }} + + @endif +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/passwords/reset.blade.php b/resources/views/auth/passwords/reset.blade.php new file mode 100644 index 0000000..b4621f1 --- /dev/null +++ b/resources/views/auth/passwords/reset.blade.php @@ -0,0 +1,70 @@ +@extends('layout') +{{-- TODO: Transformer le style en bootstrap4 --}} +@section('content') +
+
+
+
+
Reset Password
+ +
+
+ {{ csrf_field() }} + + + +
+ + +
+ + + @if ($errors->has('email')) + + {{ $errors->first('email') }} + + @endif +
+
+ +
+ + +
+ + + @if ($errors->has('password')) + + {{ $errors->first('password') }} + + @endif +
+
+ +
+ +
+ + + @if ($errors->has('password_confirmation')) + + {{ $errors->first('password_confirmation') }} + + @endif +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php new file mode 100644 index 0000000..170e476 --- /dev/null +++ b/resources/views/auth/register.blade.php @@ -0,0 +1,77 @@ +@extends('layout') +{{-- TODO: Transformer le style en bootstrap4 --}} +@section('content') +
+
+
+
+
Register
+ +
+
+ {{ csrf_field() }} + +
+ + +
+ + + @if ($errors->has('name')) + + {{ $errors->first('name') }} + + @endif +
+
+ +
+ + +
+ + + @if ($errors->has('email')) + + {{ $errors->first('email') }} + + @endif +
+
+ +
+ + +
+ + + @if ($errors->has('password')) + + {{ $errors->first('password') }} + + @endif +
+
+ +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php new file mode 100644 index 0000000..4498f5a --- /dev/null +++ b/resources/views/home.blade.php @@ -0,0 +1,23 @@ +@extends('layout') + +@section('content') +
+
+
+
+
Dashboard
+ +
+ @if (session('status')) +
+ {{ session('status') }} +
+ @endif + + You are logged in! +
+
+
+
+
+@endsection diff --git a/resources/views/layout.blade.php b/resources/views/layout.blade.php index 206f768..59af604 100644 --- a/resources/views/layout.blade.php +++ b/resources/views/layout.blade.php @@ -1,4 +1,3 @@ - @@ -7,9 +6,12 @@ + + 360 dev - + + @@ -25,8 +27,9 @@ - + +{{----}} - +{{----}} diff --git a/resources/views/partials/navbar.blade.php b/resources/views/partials/navbar.blade.php index 3bd1e29..fe708b1 100644 --- a/resources/views/partials/navbar.blade.php +++ b/resources/views/partials/navbar.blade.php @@ -10,9 +10,56 @@ Blog -
- - -
+ \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 2164b9f..843b732 100644 --- a/routes/web.php +++ b/routes/web.php @@ -11,10 +11,45 @@ | */ +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Route; + +function namesRouteRessource (string $name): array +{ + return ['names' => [ + 'index' => 'admin.' . $name . '.index', + 'edit' => 'admin.' . $name . '.edit', + 'update' => 'admin.' . $name . '.update', + 'show' => 'admin.' . $name . '.show', + 'create' => 'admin.' . $name . '.create', + 'store' => 'admin.' . $name . '.store', + 'destroy' => 'admin.' . $name . '.destroy' + ]]; +} + Route::get('/', function () { // TODO Create home controller return view('welcome'); })->name('root'); Route::resource('blog', 'PostsController'); -Route::get('blog/categorie/{slug}', 'PostsController@category')->name('blog.category'); \ No newline at end of file +Route::get('blog/categorie/{slug}', 'PostsController@category')->name('blog.category'); + +// Authentication +Auth::routes(); +Route::get('/verify/{id}/{token}', 'Auth\RegisterController@confirm')->name('auth.confirm'); + +Route::get('/home', 'HomeController@index')->name('home'); + +Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function () { + Route::resource('blog', 'PostController', namesRouteRessource('blog')); + Route::resource('role', 'RoleController', namesRouteRessource('role')); + Route::resource('permission', 'PermissionController', namesRouteRessource('permission')); + Route::resource('user', 'UserController', namesRouteRessource('user')); + /*Route::resources([ + 'blog' => 'PostController', + 'role' => 'RoleController', + 'permission' => 'PermissionController', + 'user' => 'UserController' + ]);*/ +});