diff --git a/.env.example b/.env.example index 8a5ad36..a4b04fd 100644 --- a/.env.example +++ b/.env.example @@ -45,4 +45,7 @@ PUSHER_APP_CLUSTER=mt1 MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" -ADMIN_EMAIL_FOR_NOTIFICATIONS = 'example@mail.ru' +ADMIN_EMAIL_FOR_NOTIFICATIONS=example@mail.ru + +PUSH_ALL_API_KEY= +PUSH_ALL_API_ID= diff --git a/app/Console/Commands/SendNewPosts.php b/app/Console/Commands/SendNewPosts.php new file mode 100644 index 0000000..4ba6e9f --- /dev/null +++ b/app/Console/Commands/SendNewPosts.php @@ -0,0 +1,47 @@ +=', $this->argument('since'))->latest()->take(5)->get(); + + if ($posts->isNotEmpty() && $users->isNotEmpty()) { + $this->alert('Письма отправляются...'); + + $bar = $this->output->createProgressBar(count($users)); + + $bar->start(); + + foreach ($users as $user) { + $user->notify(new PostsForPeriod($posts)); + + $bar->advance(); + } + + $bar->finish(); + $this->info(PHP_EOL . 'Письма успешно отправленны'); + } else { + $this->info(PHP_EOL . 'Письма не были отправлены. Проверьте введенные параметры.'); + } + + return 0; + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 69914e9..944dba0 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,6 +2,8 @@ namespace App\Console; +use App\Console\Commands\SendNewPosts; +use Carbon\Carbon; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -24,7 +26,9 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule) { - // $schedule->command('inspire')->hourly(); + $now = Carbon::now()->format('Y-m-d'); + + $schedule->command(SendNewPosts::class, [$now])->weekly()->mondays()->at('09:00'); } /** diff --git a/app/Http/Controllers/AdministrationController.php b/app/Http/Controllers/AdministrationController.php new file mode 100644 index 0000000..c796560 --- /dev/null +++ b/app/Http/Controllers/AdministrationController.php @@ -0,0 +1,23 @@ +middleware('role:admin'); + } + + public function index() { + return view('admin.index'); + } + + public function posts() { + $posts = Post::with('tags')->latest()->get(); + return view('/admin.posts', compact('posts')); + } +} diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index dbac62c..c6a6de6 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -52,7 +52,7 @@ protected function validator(array $data) return Validator::make($data, [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], - 'password' => ['required', 'string', 'min:1', 'confirmed'], + 'password' => ['required', 'string', 'min:8', 'confirmed'], ]); } diff --git a/app/Http/Controllers/FeedbacksController.php b/app/Http/Controllers/FeedbacksController.php index f2ba7c5..2482d35 100644 --- a/app/Http/Controllers/FeedbacksController.php +++ b/app/Http/Controllers/FeedbacksController.php @@ -9,7 +9,7 @@ class FeedbacksController extends Controller { public function __construct() { - $this->middleware('auth'); + $this->middleware('role:admin'); } public function index() diff --git a/app/Http/Controllers/PostsController.php b/app/Http/Controllers/PostsController.php index 723ecbf..2d183d2 100644 --- a/app/Http/Controllers/PostsController.php +++ b/app/Http/Controllers/PostsController.php @@ -16,7 +16,6 @@ class PostsController extends Controller public function __construct() { $this->middleware('auth'); - $this->middleware('can:update,post')->except(['index', 'userPosts', 'adminIndex', 'create', 'store']); } public function validateRequest($request, $post) @@ -31,7 +30,7 @@ public function validateRequest($request, $post) public function index() { - $posts = Post::with('tags')->latest()->get(); + $posts = Post::with('tags')->where('published', 1)->latest()->get(); return view('/index', compact('posts')); } @@ -41,11 +40,6 @@ public function userPosts() return view('/posts.index', compact('posts')); } - public function adminIndex() { - $posts = Post::with('tags')->latest()->get(); - return view('/posts.admin-index', compact('posts')); - } - public function create() { return view('/posts.create'); @@ -73,24 +67,33 @@ public function store(Request $request) sendMailNotifyToAdmin(new PostCreated($post)); flash( 'Post created successfully'); + pushNotification('Post created successfully', 'New Notification'); return redirect('/'); } public function show(Post $post) { + $this->authorize('view', $post); + return view('/posts.show', compact('post')); } public function edit(Post $post) { + $this->authorize('update', $post); + return view('/posts.edit', compact('post')); } public function update(Request $request, Post $post) { + $this->authorize('update', $post); + $values = $this->validateRequest($request, $post); + $values['published'] = $request->has('published'); + $post->update($values); $postTags = $post->tags->keyBy('name'); @@ -121,17 +124,21 @@ public function update(Request $request, Post $post) sendMailNotifyToAdmin(new PostEdited($post)); flash( 'Post edited successfully'); + pushNotification('Post edited successfully', 'New Notification'); return back(); } public function destroy(Post $post) { + $this->authorize('delete', $post); + $post->delete(); sendMailNotifyToAdmin(new PostDeleted($post)); - flash( 'Post delete successfully'); + flash( 'Post deleted successfully'); + pushNotification('Post deleted successfully', 'New Notification'); - return redirect('/posts'); + return back(); } } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 36ced13..b704d04 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -63,5 +63,6 @@ class Kernel extends HttpKernel 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, + 'role' => \App\Http\Middleware\RoleMiddleware::class, ]; } diff --git a/app/Http/Middleware/RoleMiddleware.php b/app/Http/Middleware/RoleMiddleware.php new file mode 100644 index 0000000..0764c0f --- /dev/null +++ b/app/Http/Middleware/RoleMiddleware.php @@ -0,0 +1,26 @@ +user()) { + if (!auth()->user()->hasRole($role)) { + abort(403, 'THIS ACTION IS UNAUTHORIZED.'); + } + + if ($permission !== null && !auth()->user()->hasPermissionTo($permission)) { + abort(403, 'THIS ACTION IS UNAUTHORIZED.'); + } + } else { + return redirect('/'); + } + + return $next($request); + } +} diff --git a/app/Notifications/PostsForPeriod.php b/app/Notifications/PostsForPeriod.php new file mode 100644 index 0000000..4f73b32 --- /dev/null +++ b/app/Notifications/PostsForPeriod.php @@ -0,0 +1,37 @@ +posts = $posts; + } + + public function via($notifiable) + { + return ['mail']; + } + + public function toMail($notifiable) + { + return (new MailMessage)->markdown('mail.posts-for-period', ['posts' => $this->posts]); + } + + public function toArray($notifiable) + { + return [ + // + ]; + } +} diff --git a/app/Permission.php b/app/Permission.php new file mode 100644 index 0000000..1dc414c --- /dev/null +++ b/app/Permission.php @@ -0,0 +1,25 @@ +belongsToMany(Role::class); + } + + public function users() + { + return $this->belongsToMany(User::class); + } +} diff --git a/app/Policies/PostPolicy.php b/app/Policies/PostPolicy.php index 6275d0d..f2be6fe 100644 --- a/app/Policies/PostPolicy.php +++ b/app/Policies/PostPolicy.php @@ -10,8 +10,18 @@ class PostPolicy { use HandlesAuthorization; + public function view(User $user, Post $post) + { + return $post->owner_id == $user->id; + } + public function update(User $user, Post $post) { return $post->owner_id == $user->id; } + + public function delete(User $user, Post $post) + { + return $post->owner_id == $user->id; + } } diff --git a/app/Post.php b/app/Post.php index a8c2092..90c29ac 100644 --- a/app/Post.php +++ b/app/Post.php @@ -3,10 +3,13 @@ namespace App; use App\Events\PostCreated; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Post extends Model { + use HasFactory; + protected $table = 'posts'; protected $guarded = []; diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 4671263..e4f261f 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -2,6 +2,8 @@ namespace App\Providers; +use App\Policies\PostPolicy; +use App\Post; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Contracts\Auth\Access\Gate; @@ -14,7 +16,7 @@ class AuthServiceProvider extends ServiceProvider */ protected $policies = [ // 'App\Model' => 'App\Policies\ModelPolicy', - 'App\Post' => 'App\Policies\PostPolicy', + Post::class => PostPolicy::class ]; /** @@ -28,7 +30,7 @@ public function boot(Gate $gate) $this->registerPolicies(); $gate->before(function ($user) { - if ($user->email == 'admin@mail.ru') { + if ($user->email == env('ADMIN_EMAIL_FOR_NOTIFICATIONS')) { return true; } }); diff --git a/app/Providers/PushNotificationServiceProvider.php b/app/Providers/PushNotificationServiceProvider.php new file mode 100644 index 0000000..470fd14 --- /dev/null +++ b/app/Providers/PushNotificationServiceProvider.php @@ -0,0 +1,21 @@ +app->singleton(PushNotificationsService::class, function() { + return new PushNotificationsService(env('PUSH_ALL_API_ID'), env('PUSH_ALL_API_KEY')); + }); + } +} diff --git a/app/Providers/TelescopeServiceProvider.php b/app/Providers/TelescopeServiceProvider.php index 75f53ee..3ed290a 100644 --- a/app/Providers/TelescopeServiceProvider.php +++ b/app/Providers/TelescopeServiceProvider.php @@ -16,7 +16,7 @@ class TelescopeServiceProvider extends TelescopeApplicationServiceProvider */ public function register() { - // Telescope::night(); +// Telescope::night(); $this->hideSensitiveRequestDetails(); @@ -64,7 +64,7 @@ protected function gate() { Gate::define('viewTelescope', function ($user) { return in_array($user->email, [ - 'ap.sky@yandex.ru' + env('ADMIN_EMAIL_FOR_NOTIFICATIONS') ]); }); } diff --git a/app/Role.php b/app/Role.php new file mode 100644 index 0000000..6b52b31 --- /dev/null +++ b/app/Role.php @@ -0,0 +1,25 @@ +belongsToMany(Permission::class); + } + + public function users() + { + return $this->belongsToMany(User::class); + } +} diff --git a/app/Services/PushNotificationsService.php b/app/Services/PushNotificationsService.php new file mode 100644 index 0000000..6a4f6b5 --- /dev/null +++ b/app/Services/PushNotificationsService.php @@ -0,0 +1,38 @@ +apiID = $api_id; + $this->apiKey= $api_key; + } + + public function send($text, $title) + { + $data = [ + 'type' => 'self', + 'id' => $this->apiID, + 'key' => $this->apiKey, + 'text' => $text, + 'title' => $title + ]; + + $client = new Client([ + 'base_uri' => 'https://pushall.ru/api.php', + ]); + + $response = $client->request('POST', '', [ + 'form_params' => $data + ]); + + return $response; + } +} diff --git a/app/Tag.php b/app/Tag.php index aee6777..8df7266 100644 --- a/app/Tag.php +++ b/app/Tag.php @@ -2,10 +2,13 @@ namespace App; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Tag extends Model { + use HasFactory; + protected $table = 'tags'; protected $guarded = []; diff --git a/app/Traits/HasRolesAndPermissions.php b/app/Traits/HasRolesAndPermissions.php new file mode 100644 index 0000000..54e40b6 --- /dev/null +++ b/app/Traits/HasRolesAndPermissions.php @@ -0,0 +1,81 @@ +belongsToMany(Role::class); + } + + public function permissions() + { + return $this->belongsToMany(Permission::class); + } + + public function hasRole(... $roles) + { + foreach ($roles as $role) { + if ($this->roles->contains('slug', $role)) { + return true; + } + } + return false; + } + + public function hasPermission($permission) + { + return (bool) $this->permissions->where('slug', $permission)->count(); + } + + public function hasPermissionThroughRole($permission) + { + foreach ($permission->roles as $role){ + if($this->roles->contains($role)) { + return true; + } + } + return false; + } + + public function hasPermissionTo($permission) + { + return $this->hasPermissionThroughRole($permission) || $this->hasPermission($permission->slug); + } + + public function getAllPermissions(array $permissions) + { + return Permission::whereIn('slug', $permissions)->get(); + } + + public function givePermissionsTo(... $permissions) + { + $permissions = $this->getAllPermissions($permissions); + + if ($permissions === null) { + return $this; + } + + $this->permissions()->saveMany($permissions); + return $this; + } + + public function deletePermissions(... $permissions ) + { + $permissions = $this->getAllPermissions($permissions); + + $this->permissions()->detach($permissions); + return $this; + } + + public function refreshPermissions(... $permissions ) + { + $this->permissions()->detach(); + + return $this->givePermissionsTo($permissions); + } +} diff --git a/app/User.php b/app/User.php index 0a98446..26ee71b 100644 --- a/app/User.php +++ b/app/User.php @@ -2,37 +2,26 @@ namespace App; +use App\Traits\HasRolesAndPermissions; use Illuminate\Contracts\Auth\MustVerifyEmail; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; + use HasFactory; + use HasRolesAndPermissions; - /** - * The attributes that are mass assignable. - * - * @var array - */ protected $fillable = [ 'name', 'email', 'password', ]; - /** - * The attributes that should be hidden for arrays. - * - * @var array - */ protected $hidden = [ 'password', 'remember_token', ]; - /** - * The attributes that should be cast to native types. - * - * @var array - */ protected $casts = [ 'email_verified_at' => 'datetime', ]; diff --git a/app/helpers.php b/app/helpers.php index 927b22b..b7f9ca0 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -1,14 +1,45 @@ flash('message', $message); - session()->flash('message_type', $type); +if (! function_exists('flash')) { + /** + * @param $message + * @param string $type + */ + function flash($message, $type = 'success') { + session()->flash('message', $message); + session()->flash('message_type', $type); + } +} + + +if (! function_exists('sendMailNotifyToAdmin')) { + + /** + * @param $mailView + */ + + function sendMailNotifyToAdmin($mailView) { + $admin = \App\User::where('email', env('ADMIN_EMAIL_FOR_NOTIFICATIONS'))->first(); + + if ($admin) { + $admin->notify($mailView); + } + } } -function sendMailNotifyToAdmin($mailView) { - $admin = \App\User::where('email', env('ADMIN_EMAIL_FOR_NOTIFICATIONS'))->first(); - if ($admin) { - $admin->notify($mailView); +if (! function_exists('pushNotification')) { + + /** + * @param null $text + * @param null $title + * @return \App\Services\PushNotificationsService|mixed + */ + function pushNotification($text = null, $title = null) { + if (is_null($text) || is_null($title)) { + return app(\App\Services\PushNotificationsService::class); + } + + return app(\App\Services\PushNotificationsService::class)->send($text, $title); } } diff --git a/composer.lock b/composer.lock index c7b1a37..6725f08 100644 --- a/composer.lock +++ b/composer.lock @@ -802,16 +802,16 @@ }, { "name": "laravel/framework", - "version": "v8.2.0", + "version": "v8.4.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "846d4dad13ed8cb535bf4058d53b2770647f9301" + "reference": "1c57ab5e375d0a897c22b29e8352453be514131e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/846d4dad13ed8cb535bf4058d53b2770647f9301", - "reference": "846d4dad13ed8cb535bf4058d53b2770647f9301", + "url": "https://api.github.com/repos/laravel/framework/zipball/1c57ab5e375d0a897c22b29e8352453be514131e", + "reference": "1c57ab5e375d0a897c22b29e8352453be514131e", "shasum": "" }, "require": { @@ -841,7 +841,7 @@ "symfony/routing": "^5.1", "symfony/var-dumper": "^5.1", "tijsverkoyen/css-to-inline-styles": "^2.2.2", - "vlucas/phpdotenv": "^5.0", + "vlucas/phpdotenv": "^5.2", "voku/portable-ascii": "^1.4.8" }, "conflict": { @@ -961,7 +961,7 @@ "framework", "laravel" ], - "time": "2020-09-14T13:36:13+00:00" + "time": "2020-09-16T16:13:13+00:00" }, { "name": "laravel/helpers", @@ -1524,16 +1524,16 @@ }, { "name": "nesbot/carbon", - "version": "2.39.2", + "version": "2.40.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "326efde1bc09077a26cb77f6e2e32e13f06c27f2" + "reference": "6c7646154181013ecd55e80c201b9fd873c6ee5d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/326efde1bc09077a26cb77f6e2e32e13f06c27f2", - "reference": "326efde1bc09077a26cb77f6e2e32e13f06c27f2", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/6c7646154181013ecd55e80c201b9fd873c6ee5d", + "reference": "6c7646154181013ecd55e80c201b9fd873c6ee5d", "shasum": "" }, "require": { @@ -1609,7 +1609,7 @@ "type": "tidelift" } ], - "time": "2020-09-10T12:16:42+00:00" + "time": "2020-09-11T19:00:58+00:00" }, { "name": "nikic/php-parser", @@ -4812,16 +4812,16 @@ }, { "name": "facade/flare-client-php", - "version": "1.3.5", + "version": "1.3.6", "source": { "type": "git", "url": "https://github.com/facade/flare-client-php.git", - "reference": "25907a113bfc212a38d458ae365bfb902b4e7fb8" + "reference": "451fadf38e9f635e7f8e1f5b3cf5c9eb82f11799" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/25907a113bfc212a38d458ae365bfb902b4e7fb8", - "reference": "25907a113bfc212a38d458ae365bfb902b4e7fb8", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/451fadf38e9f635e7f8e1f5b3cf5c9eb82f11799", + "reference": "451fadf38e9f635e7f8e1f5b3cf5c9eb82f11799", "shasum": "" }, "require": { @@ -4834,7 +4834,6 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", - "larapack/dd": "^1.1", "phpunit/phpunit": "^7.5.16", "spatie/phpunit-snapshot-assertions": "^2.0" }, @@ -4870,7 +4869,7 @@ "type": "github" } ], - "time": "2020-08-26T18:06:23+00:00" + "time": "2020-09-18T06:35:11+00:00" }, { "name": "facade/ignition", @@ -5510,16 +5509,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.2.1", + "version": "5.2.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44" + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d870572532cd70bc3fab58f2e23ad423c8404c44", - "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", "shasum": "" }, "require": { @@ -5558,20 +5557,20 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2020-08-15T11:14:08+00:00" + "time": "2020-09-03T19:13:55+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "e878a14a65245fbe78f8080eba03b47c3b705651" + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e878a14a65245fbe78f8080eba03b47c3b705651", - "reference": "e878a14a65245fbe78f8080eba03b47c3b705651", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", "shasum": "" }, "require": { @@ -5603,7 +5602,7 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2020-06-27T10:12:23+00:00" + "time": "2020-09-17T18:55:26+00:00" }, { "name": "phpspec/prophecy", diff --git a/config/app.php b/config/app.php index 79f1db5..37a68bb 100644 --- a/config/app.php +++ b/config/app.php @@ -175,7 +175,7 @@ App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, App\Providers\TelescopeServiceProvider::class, - + App\Providers\PushNotificationServiceProvider::class, ], /* diff --git a/database/factories/PermissionFactory.php b/database/factories/PermissionFactory.php new file mode 100644 index 0000000..01ae47b --- /dev/null +++ b/database/factories/PermissionFactory.php @@ -0,0 +1,19 @@ +isEmpty()) { + $activeUsers = collect([User::factory()->create()]); + } + + return [ + 'code' => $this->faker->unique()->regexify('[a-zA-Z0-9_-]+'), + 'owner_id' => $activeUsers->random(1)->first(), + 'name' => $this->faker->words(2, true), + 'description' => $this->faker->words(3, true), + 'text' => $this->faker->text, + 'published' => boolval(rand(0,1)) + ]; + } +} diff --git a/database/factories/RoleFactory.php b/database/factories/RoleFactory.php new file mode 100644 index 0000000..ddc5c04 --- /dev/null +++ b/database/factories/RoleFactory.php @@ -0,0 +1,19 @@ + $this->faker->unique()->word + ]; + } +} diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 741edea..0f2c8aa 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -1,28 +1,24 @@ define(User::class, function (Faker $faker) { - return [ - 'name' => $faker->name, - 'email' => $faker->unique()->safeEmail, - 'email_verified_at' => now(), - 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password - 'remember_token' => Str::random(10), - ]; -}); + public function definition() + { + return [ + 'name' => $this->faker->name, + 'email' => $this->faker->unique()->safeEmail, + 'email_verified_at' => now(), + 'password' => Hash::make(1), + 'remember_token' => Str::random(10), + ]; + } +} diff --git a/database/migrations/2020_09_18_134638_create_roles_table.php b/database/migrations/2020_09_18_134638_create_roles_table.php new file mode 100644 index 0000000..56cd593 --- /dev/null +++ b/database/migrations/2020_09_18_134638_create_roles_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('name')->unique(); + $table->string('slug')->unique(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('roles'); + } +} diff --git a/database/migrations/2020_09_18_134809_create_permissions_table.php b/database/migrations/2020_09_18_134809_create_permissions_table.php new file mode 100644 index 0000000..c60db6b --- /dev/null +++ b/database/migrations/2020_09_18_134809_create_permissions_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('name')->unique(); + $table->string('slug')->unique();; + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('permissions'); + } +} diff --git a/database/migrations/2020_09_18_141922_create_permission_role_table.php b/database/migrations/2020_09_18_141922_create_permission_role_table.php new file mode 100644 index 0000000..a170483 --- /dev/null +++ b/database/migrations/2020_09_18_141922_create_permission_role_table.php @@ -0,0 +1,33 @@ +primary(['permission_id', 'role_id']); + + $table->foreignId('permission_id')->constrained('permissions')->onDelete('Cascade'); + $table->foreignId('role_id')->constrained('roles')->onDelete('Cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('permission_role'); + } +} diff --git a/database/migrations/2020_09_18_151207_create_role_user_table.php b/database/migrations/2020_09_18_151207_create_role_user_table.php new file mode 100644 index 0000000..09cbd9d --- /dev/null +++ b/database/migrations/2020_09_18_151207_create_role_user_table.php @@ -0,0 +1,33 @@ +primary(['role_id', 'user_id']); + + $table->foreignId('role_id')->constrained('roles')->onDelete('Cascade'); + $table->foreignId('user_id')->constrained('users')->onDelete('Cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('role_user'); + } +} diff --git a/database/migrations/2020_09_23_202223_create_permission_user_table.php b/database/migrations/2020_09_23_202223_create_permission_user_table.php new file mode 100644 index 0000000..ce5c8fa --- /dev/null +++ b/database/migrations/2020_09_23_202223_create_permission_user_table.php @@ -0,0 +1,33 @@ +primary(['permission_id', 'user_id']); + + $table->foreignId('permission_id')->constrained('permissions')->onDelete('Cascade'); + $table->foreignId('user_id')->constrained('users')->onDelete('Cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('permission_user'); + } +} diff --git a/database/migrations/2020_09_29_201917_create_user_admin.php b/database/migrations/2020_09_29_201917_create_user_admin.php new file mode 100644 index 0000000..0a599b7 --- /dev/null +++ b/database/migrations/2020_09_29_201917_create_user_admin.php @@ -0,0 +1,40 @@ +run(); + + $rolesSeeder = new RolesTableSeeder(); + $rolesSeeder->run(); + + $adminRole = Role::where('slug', 'admin')->first(); + $adminPermissions = Permission::all(); + $adminRole->permissions()->attach($adminPermissions); + + $admin = User::factory() + ->create([ + 'name' => 'Pavel', + 'email' => 'admin@mail.ru', + 'password' => Hash::make('1') + ]); + + $admin->roles()->attach($adminRole); + $admin->permissions()->attach($adminPermissions); + } + + public function down() + { + + } +} diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 237dfc5..0b25e0f 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -1,6 +1,10 @@ call(UserSeeder::class); + $this->call(\Database\Seeders\UsersTableSeeder::class); } } diff --git a/database/seeds/PermissionsTableSeeder.php b/database/seeds/PermissionsTableSeeder.php new file mode 100644 index 0000000..f7e7b09 --- /dev/null +++ b/database/seeds/PermissionsTableSeeder.php @@ -0,0 +1,39 @@ + 'view posts', + 'slug' => 'view-posts' + ], + [ + 'name' => 'create posts', + 'slug' => 'create-posts' + ], + [ + 'name' => 'update posts', + 'slug' => 'update-posts' + ], + [ + 'name' => 'delete posts', + 'slug' => 'delete-posts' + ], + ]; + + foreach ($permissions as $permission) { + Permission::factory()->create([ + 'name' => $permission['name'], + 'slug' => $permission['slug'] + ]); + } + } +} diff --git a/database/seeds/RolesTableSeeder.php b/database/seeds/RolesTableSeeder.php new file mode 100644 index 0000000..d437fe7 --- /dev/null +++ b/database/seeds/RolesTableSeeder.php @@ -0,0 +1,35 @@ + 'admin', + 'slug' => 'admin' + ], + [ + 'name' => 'site manager', + 'slug' => 'site-manager' + ], + [ + 'name' => 'registered', + 'slug' => 'registered' + ] + ]; + + foreach ($roles as $role) { + Role::factory()->create([ + 'name' => $role['name'], + 'slug' => $role['slug'] + ]); + } + } +} diff --git a/database/seeds/UsersTableSeeder.php b/database/seeds/UsersTableSeeder.php new file mode 100644 index 0000000..2f4ab8a --- /dev/null +++ b/database/seeds/UsersTableSeeder.php @@ -0,0 +1,47 @@ +get(); + + $registeredRole = Role::where('slug', 'registered')->first(); + $registeredRole->permissions()->attach(Permission::all()); + + $tags = Tag::factory()->count(10)->create(); + + $admin = User::where('email', env('ADMIN_EMAIL_FOR_NOTIFICATIONS'))->first(); + + $admin->posts()->saveMany(Post::factory()->count(2)->create()); + + $admin->posts()->each(function ($post) use ($tags) { + $post->tags()->attach($tags->random(random_int(0, 2))); + }); + + User::factory() + ->has(Post::factory() + ->count(9)) + ->count(2) + ->create() + ->each(function (User $user) use ($registeredRole, $registeredPermissions, $tags) { + $user->roles()->attach($registeredRole); + $user->permissions()->attach($registeredPermissions); + $user->posts()->each(function ($post) use ($tags) { + $post->tags()->attach($tags->random(random_int(1, 2))); + }); + }) + ; + } +} diff --git a/resources/views/posts/admin-index.blade.php b/resources/views/admin/posts.blade.php similarity index 98% rename from resources/views/posts/admin-index.blade.php rename to resources/views/admin/posts.blade.php index 3cb7e40..0b1ca96 100644 --- a/resources/views/posts/admin-index.blade.php +++ b/resources/views/admin/posts.blade.php @@ -38,7 +38,7 @@
Edit -
+ @csrf @method('DELETE') diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 80108b6..b6a1409 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -5,8 +5,8 @@ @endsection @section('content') -
-
+
+
{{ __('Login') }}
diff --git a/resources/views/layouts/admin/admin-header.blade.php b/resources/views/layouts/admin/admin-header.blade.php index c9776df..2d84ef7 100644 --- a/resources/views/layouts/admin/admin-header.blade.php +++ b/resources/views/layouts/admin/admin-header.blade.php @@ -25,7 +25,7 @@ diff --git a/resources/views/layouts/base/header.blade.php b/resources/views/layouts/base/header.blade.php index 5fe9989..8dca032 100644 --- a/resources/views/layouts/base/header.blade.php +++ b/resources/views/layouts/base/header.blade.php @@ -11,21 +11,27 @@ @@ -38,7 +38,7 @@
@@ -54,7 +54,7 @@
@@ -70,7 +70,7 @@
diff --git a/routes/web.php b/routes/web.php index d89879f..a96340d 100644 --- a/routes/web.php +++ b/routes/web.php @@ -8,15 +8,12 @@ Route::get('/posts', 'PostsController@userPosts')->name('user.posts'); Route::resource('posts', PostsController::class)->except(['index']); -Route::get('/admin/posts', 'PostsController@adminIndex')->name('admin-post-index'); - Route::get('/about', 'StaticPagesController@aboutIndex')->name('about'); Route::get('/contacts', 'StaticPagesController@contactsIndex')->name('contacts'); -Route::get('/admin', function () { - return view('admin.index'); -})->name('admin'); +Route::get('/admin', 'AdministrationController@index')->name('admin'); +Route::get('/admin/posts', 'AdministrationController@posts')->name('admin.posts'); Route::get('/admin/feedbacks', 'FeedbacksController@index')->name('feedback');; Route::post('/admin/feedbacks', 'FeedbacksController@store');