├── public ├── favicon.ico ├── robots.txt ├── assets │ ├── css │ │ └── app.css │ └── js │ │ └── admin │ │ └── color-modes.js ├── .htaccess └── index.php ├── database ├── .gitignore ├── seeders │ └── DatabaseSeeder.php ├── migrations │ ├── 2024_10_08_000001_create_tags_table.php │ ├── 2024_10_06_000001_create_categories_table.php │ ├── 2024_10_06_000002_create_category_post_table.php │ ├── 2024_10_05_000001_create_posts_table.php │ ├── 2024_10_04_000001_create_cache_table.php │ ├── 2024_10_08_000002_create_post_tags_table.php │ ├── 2024_10_07_000001_create_comments_table.php │ ├── 2024_10_09_000001_create_likes_table.php │ ├── 2024_10_04_000000_create_users_table.php │ └── 2024_10_04_000002_create_jobs_table.php └── factories │ ├── PostFactory.php │ └── UserFactory.php ├── bootstrap ├── cache │ └── .gitignore ├── providers.php └── app.php ├── storage ├── logs │ └── .gitignore ├── app │ ├── public │ │ └── .gitignore │ └── .gitignore └── framework │ ├── testing │ └── .gitignore │ ├── views │ └── .gitignore │ ├── cache │ ├── data │ │ └── .gitignore │ └── .gitignore │ ├── sessions │ └── .gitignore │ └── .gitignore ├── phpstan.neon.dist ├── docs ├── social-preview-en.png ├── screenshot-main-page.png ├── social-preview-en.curve ├── translations.md └── https.md ├── resources └── views │ ├── mail │ └── user │ │ └── password.blade.php │ ├── post │ ├── index.blade.php │ └── index │ │ └── liked_posts.blade.php │ ├── category │ ├── index.blade.php │ └── post │ │ └── index.blade.php │ ├── admin │ ├── post │ │ ├── show.blade.php │ │ └── index.blade.php │ ├── tag │ │ ├── create.blade.php │ │ ├── edit.blade.php │ │ └── show.blade.php │ ├── category │ │ ├── create.blade.php │ │ ├── edit.blade.php │ │ └── show.blade.php │ ├── main │ │ └── index.blade.php │ └── user │ │ ├── show.blade.php │ │ └── create.blade.php │ ├── layouts │ ├── wrapper-admin │ │ ├── navbar.blade.php │ │ └── toggle_theme.blade.php │ ├── wrapper-personal.blade.php │ ├── wrapper.blade.php │ ├── wrapper-admin.blade.php │ ├── wrapper-personal │ │ └── sidebar.blade.php │ └── wrapper │ │ └── _navbar.blade.php │ ├── about │ └── index.blade.php │ ├── personal │ ├── comment │ │ ├── edit.blade.php │ │ └── index.blade.php │ ├── liked │ │ └── index.blade.php │ └── main │ │ └── index.blade.php │ ├── auth │ └── passwords │ │ ├── email.blade.php │ │ ├── confirm.blade.php │ │ └── reset.blade.php │ └── contact │ └── index.blade.php ├── lang ├── en │ ├── pagination.php │ ├── auth.php │ └── passwords.php └── ru │ ├── pagination.php │ ├── auth.php │ └── passwords.php ├── tests ├── TestCase.php ├── Unit │ └── ExampleTest.php └── Feature │ ├── ExampleTest.php │ └── ProfileXest.php ├── .gitattributes ├── .editorconfig ├── .gitignore ├── app ├── Http │ ├── Controllers │ │ ├── Admin │ │ │ ├── Post │ │ │ │ ├── DeleteController.php │ │ │ │ ├── BaseController.php │ │ │ │ ├── ShowController.php │ │ │ │ ├── StoreController.php │ │ │ │ ├── IndexController.php │ │ │ │ ├── UpdateController.php │ │ │ │ ├── CreateController.php │ │ │ │ └── EditController.php │ │ │ ├── Tag │ │ │ │ ├── DeleteController.php │ │ │ │ ├── CreateController.php │ │ │ │ ├── EditController.php │ │ │ │ ├── ShowController.php │ │ │ │ ├── IndexController.php │ │ │ │ ├── StoreController.php │ │ │ │ └── UpdateController.php │ │ │ ├── User │ │ │ │ ├── DeleteController.php │ │ │ │ ├── CreateController.php │ │ │ │ ├── EditController.php │ │ │ │ ├── ShowController.php │ │ │ │ ├── IndexController.php │ │ │ │ ├── StoreController.php │ │ │ │ └── UpdateController.php │ │ │ ├── Category │ │ │ │ ├── CreateController.php │ │ │ │ ├── DeleteController.php │ │ │ │ ├── EditController.php │ │ │ │ ├── ShowController.php │ │ │ │ ├── IndexController.php │ │ │ │ ├── UpdateController.php │ │ │ │ └── StoreController.php │ │ │ └── Main │ │ │ │ └── IndexController.php │ │ ├── Controller.php │ │ ├── AboutController.php │ │ ├── ContactsController.php │ │ ├── Personal │ │ │ ├── Comment │ │ │ │ ├── DeleteController.php │ │ │ │ ├── EditController.php │ │ │ │ ├── UpdateController.php │ │ │ │ └── IndexController.php │ │ │ ├── Liked │ │ │ │ ├── DeleteController.php │ │ │ │ └── IndexController.php │ │ │ └── Main │ │ │ │ └── IndexController.php │ │ ├── Category │ │ │ ├── IndexController.php │ │ │ └── Post │ │ │ │ └── IndexController.php │ │ ├── Post │ │ │ ├── Like │ │ │ │ └── StoreController.php │ │ │ └── Comment │ │ │ │ └── StoreController.php │ │ ├── Auth │ │ │ ├── ForgotPasswordController.php │ │ │ ├── ResetPasswordController.php │ │ │ ├── ConfirmPasswordController.php │ │ │ ├── LoginController.php │ │ │ ├── VerificationController.php │ │ │ └── RegisterController.php │ │ ├── PlaceholderController.php │ │ └── PostController.php │ ├── Middleware │ │ └── AdminMiddleware.php │ └── Requests │ │ ├── Admin │ │ ├── Tag │ │ │ ├── StoreRequest.php │ │ │ └── UpdateRequest.php │ │ ├── Category │ │ │ ├── StoreRequest.php │ │ │ └── UpdateRequest.php │ │ ├── User │ │ │ ├── StoreRequest.php │ │ │ └── UpdateRequest.php │ │ └── Post │ │ │ ├── StoreRequest.php │ │ │ └── UpdateRequest.php │ │ ├── Post │ │ └── Comment │ │ │ └── StoreRequest.php │ │ └── Personal │ │ └── Comment │ │ └── UpdateRequest.php ├── Models │ ├── CategoryPost.php │ ├── Tag.php │ ├── PostTag.php │ ├── PostUserLike.php │ ├── Category.php │ └── Comment.php ├── Providers │ └── AppServiceProvider.php ├── Jobs │ └── StoreUserJob.php ├── Mail │ └── User │ │ └── PasswordMail.php └── Service │ └── PostService.php ├── .php-cs-fixer.dist.php ├── routes └── console.php ├── docker-compose └── nginx │ └── blog.conf ├── Dockerfile ├── config ├── services.php └── filesystems.php ├── rector.php ├── LICENSE ├── .env.ci ├── phpunit.xml ├── .env.local ├── docker-compose.yml ├── artisan ├── translations ├── README.zh-cn.md ├── README.zh-tw.md ├── README.ko.md ├── README.ja.md ├── README.am.md ├── README.ar.md ├── README.igb.md ├── README.hb.md ├── README.da.md └── README.bn.md ├── composer.json └── README.md /public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite* 2 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /storage/app/public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !public/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/framework/testing/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/cache/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !data/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 2 3 | paths: 4 | - app 5 | - tests 6 | -------------------------------------------------------------------------------- /bootstrap/providers.php: -------------------------------------------------------------------------------- 1 | 'Next »', 7 | 'previous' => '« Previous', 8 | ]; 9 | -------------------------------------------------------------------------------- /lang/ru/pagination.php: -------------------------------------------------------------------------------- 1 | 'Вперёд »', 7 | 'previous' => '« Назад', 8 | ]; 9 | -------------------------------------------------------------------------------- /docs/translations.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Оther languages 3 | --- 4 | 5 | # Laravel blog README.md in other languages 6 | 7 | - [English](../README.md) 8 | - [Русский](README.ru.md) 9 | -------------------------------------------------------------------------------- /storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | compiled.php 2 | config.php 3 | down 4 | events.scanned.php 5 | maintenance.php 6 | routes.php 7 | routes.scanned.php 8 | schedule-* 9 | services.json 10 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 7 | 'password' => 'The password is incorrect.', 8 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 9 | ]; 10 | -------------------------------------------------------------------------------- /lang/ru/auth.php: -------------------------------------------------------------------------------- 1 | 'Неверное имя пользователя или пароль.', 7 | 'password' => 'Некорректный пароль.', 8 | 'throttle' => 'Слишком много попыток входа. Пожалуйста, попробуйте ещё раз через :seconds секунд.', 9 | ]; 10 | -------------------------------------------------------------------------------- /resources/views/post/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper', ['title' => 'My personal blog']) 2 | 3 | @section('content') 4 |
5 | 6 | @include('post.index.latest_posts') 7 | @include('post.index.liked_posts') 8 | 9 |
10 | @endsection 11 | -------------------------------------------------------------------------------- /public/assets/css/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .font-family-karla { 6 | font-family: karla; 7 | } 8 | 9 | pre { 10 | padding: 1rem; 11 | background-color: #1a202c; 12 | color: white; 13 | border-radius: 0.5rem; 14 | margin-bottom: 1rem; 15 | } 16 | -------------------------------------------------------------------------------- /tests/Unit/ExampleTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | 17 | [docker-compose.yml] 18 | indent_size = 4 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.phpunit.cache 2 | /node_modules 3 | /public/hot 4 | /public/storage 5 | /storage/*.key 6 | /vendor 7 | 8 | .env 9 | .env.backup 10 | .env.production 11 | .phpunit.result.cache 12 | 13 | Homestead.json 14 | Homestead.yaml 15 | auth.json 16 | npm-debug.log 17 | yarn-error.log 18 | 19 | /.fleet 20 | /.idea 21 | /.vscode 22 | 23 | .DS_Store 24 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Post/DeleteController.php: -------------------------------------------------------------------------------- 1 | delete(); 12 | 13 | return redirect()->route('admin.post.index'); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | make('about.index'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Tag/DeleteController.php: -------------------------------------------------------------------------------- 1 | delete(); 13 | 14 | return redirect()->route('admin.tag.index'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Your password has been reset.', 7 | 'sent' => 'We have emailed your password reset link.', 8 | 'throttled' => 'Please wait before retrying.', 9 | 'token' => 'This password reset token is invalid.', 10 | 'user' => 'We can\'t find a user with that email address.', 11 | ]; 12 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Post/BaseController.php: -------------------------------------------------------------------------------- 1 | service = $service; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/User/DeleteController.php: -------------------------------------------------------------------------------- 1 | delete(); 13 | 14 | return redirect()->route('admin.user.index'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/Http/Controllers/ContactsController.php: -------------------------------------------------------------------------------- 1 | make('contact.index'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Tag/CreateController.php: -------------------------------------------------------------------------------- 1 | make('admin.tag.create'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/User/CreateController.php: -------------------------------------------------------------------------------- 1 | make('admin.user.create'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lang/ru/passwords.php: -------------------------------------------------------------------------------- 1 | 'Ваш пароль был сброшен.', 7 | 'sent' => 'Ссылка на сброс пароля была отправлена.', 8 | 'throttled' => 'Пожалуйста, подождите перед повторной попыткой.', 9 | 'token' => 'Ошибочный код сброса пароля.', 10 | 'user' => 'Не удалось найти пользователя с указанным электронным адресом.', 11 | ]; 12 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Category/CreateController.php: -------------------------------------------------------------------------------- 1 | make('admin.category.create'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Category/DeleteController.php: -------------------------------------------------------------------------------- 1 | delete(); 13 | 14 | return redirect()->route('admin.category.index'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Post/ShowController.php: -------------------------------------------------------------------------------- 1 | make('admin.post.show', ['post' => $post]); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/Http/Controllers/Personal/Comment/DeleteController.php: -------------------------------------------------------------------------------- 1 | delete(); 13 | 14 | return redirect()->route('personal.comment.index'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | validated(); 12 | $this->service->store($data); 13 | 14 | return redirect()->route('admin.post.index'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Tag/EditController.php: -------------------------------------------------------------------------------- 1 | make('admin.tag.edit', ['tag' => $tag]); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Tag/ShowController.php: -------------------------------------------------------------------------------- 1 | make('admin.tag.show', ['tag' => $tag]); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Post/IndexController.php: -------------------------------------------------------------------------------- 1 | make('admin.post.index', ['posts' => $posts]); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/User/EditController.php: -------------------------------------------------------------------------------- 1 | make('admin.user.edit', ['user' => $user]); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/User/ShowController.php: -------------------------------------------------------------------------------- 1 | make('admin.user.show', ['user' => $user]); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | get('/'); 16 | 17 | $response->assertStatus(200); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Tag/IndexController.php: -------------------------------------------------------------------------------- 1 | make('admin.tag.index', ['tags' => $tags]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Category/EditController.php: -------------------------------------------------------------------------------- 1 | make('admin.category.edit', ['category' => $category]); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Category/ShowController.php: -------------------------------------------------------------------------------- 1 | make('admin.category.show', ['category' => $category]); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/User/IndexController.php: -------------------------------------------------------------------------------- 1 | make('admin.user.index', ['users' => $users]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Controllers/Personal/Comment/EditController.php: -------------------------------------------------------------------------------- 1 | make('personal.comment.edit', ['comment' => $comment]); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/Http/Controllers/Category/IndexController.php: -------------------------------------------------------------------------------- 1 | make('category.index', ['categories' => $categories]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/User/StoreController.php: -------------------------------------------------------------------------------- 1 | validated(); 14 | StoreUserJob::dispatch($data); 15 | 16 | return redirect()->route('admin.user.index'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Http/Controllers/Post/Like/StoreController.php: -------------------------------------------------------------------------------- 1 | likedPosts()->toggle($post->id); 15 | 16 | return redirect()->back(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Post/UpdateController.php: -------------------------------------------------------------------------------- 1 | validated(); 13 | $post = $this->service->update($data, $post); 14 | 15 | return redirect()->route('admin.post.show', ['post' => $post]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Models/CategoryPost.php: -------------------------------------------------------------------------------- 1 | make('admin.category.index', ['categories' => $categories]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Tag/StoreController.php: -------------------------------------------------------------------------------- 1 | validated(); 14 | /** @phpstan-ignore-next-line */ 15 | Tag::firstOrCreate($data); 16 | 17 | return redirect()->route('admin.tag.index'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/Http/Controllers/Personal/Liked/DeleteController.php: -------------------------------------------------------------------------------- 1 | likedPosts()->detach($post->id); 15 | 16 | return redirect()->route('personal.liked.index'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Http/Controllers/Personal/Comment/UpdateController.php: -------------------------------------------------------------------------------- 1 | validated(); 14 | $comment->update($data); 15 | 16 | return redirect()->route('personal.comment.index'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Post/CreateController.php: -------------------------------------------------------------------------------- 1 | make('admin.post.create', ['categories' => $categories, 'tags' => $tags]); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Http/Controllers/Category/Post/IndexController.php: -------------------------------------------------------------------------------- 1 | posts()->paginate(6); 14 | 15 | return $view_factory->make('category.post.index', ['posts' => $posts, 'category' => $category]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Controllers/Personal/Liked/IndexController.php: -------------------------------------------------------------------------------- 1 | likedPosts; 15 | 16 | return $view_factory->make('personal.liked.index', ['posts' => $posts]); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Post/EditController.php: -------------------------------------------------------------------------------- 1 | make('admin.post.edit', ['post' => $post, 'categories' => $categories, 'tags' => $tags]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Tag/UpdateController.php: -------------------------------------------------------------------------------- 1 | validated(); 15 | $tag->update($data); 16 | 17 | return $view_factory->make('admin.tag.show', ['tag' => $tag]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/Http/Controllers/Personal/Comment/IndexController.php: -------------------------------------------------------------------------------- 1 | comments; 15 | 16 | return $view_factory->make('personal.comment.index', ['comments' => $comments]); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/User/UpdateController.php: -------------------------------------------------------------------------------- 1 | validated(); 15 | $user->update($data); 16 | 17 | return $view_factory->make('admin.user.show', ['user' => $user]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/Http/Middleware/AdminMiddleware.php: -------------------------------------------------------------------------------- 1 | user(); 19 | 20 | if (! $user || ! $user->isAdministrator()) { 21 | abort(404); 22 | } 23 | 24 | return $next($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | validated(); 15 | $category->update($data); 16 | 17 | return $view_factory->make('admin.category.show', ['category' => $category]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Category/StoreController.php: -------------------------------------------------------------------------------- 1 | validated(); 15 | $data['slug'] = Str::slug($data['title']); 16 | /** @phpstan-ignore-next-line */ 17 | Category::firstOrCreate($data); 18 | 19 | return redirect()->route('admin.category.index'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 19 | })->purpose('Display an inspiring quote'); 20 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | withRouting( 9 | web: __DIR__.'/../routes/web.php', 10 | commands: __DIR__.'/../routes/console.php', 11 | health: '/up', 12 | ) 13 | ->withMiddleware(function (Middleware $middleware) { 14 | $middleware->alias([ 15 | 'admin' => App\Http\Middleware\AdminMiddleware::class, 16 | ]); 17 | }) 18 | ->withExceptions(function (Exceptions $exceptions) { 19 | // 20 | })->create(); 21 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Send Requests To Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /docker-compose/nginx/blog.conf: -------------------------------------------------------------------------------- 1 | 2 | server { 3 | listen 80; 4 | index index.php index.html; 5 | error_log /var/log/nginx/error.log; 6 | access_log /var/log/nginx/access.log; 7 | root /var/www/public; 8 | location ~ \.php$ { 9 | try_files $uri =404; 10 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 11 | fastcgi_pass app:9000; 12 | fastcgi_index index.php; 13 | include fastcgi_params; 14 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 15 | fastcgi_param PATH_INFO $fastcgi_path_info; 16 | } 17 | location / { 18 | try_files $uri $uri/ /index.php?$query_string; 19 | gzip_static on; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /database/seeders/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 17 | 18 | User::factory(13)->create(); 19 | 20 | User::factory()->create([ 21 | 'email' => 'test@example.com', 22 | 'name' => 'Admin', 23 | 'role' => 'administrator', 24 | 'password' => bcrypt('password'), 25 | ]); 26 | 27 | // TODO Seed more items 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/Http/Controllers/Personal/Main/IndexController.php: -------------------------------------------------------------------------------- 1 | comments); 15 | /** @phpstan-ignore-next-line */ 16 | $data['countLiked'] = count($user->likedPosts); 17 | 18 | return $view_factory->make('personal.main.index', ['data' => $data]); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Tag/StoreRequest.php: -------------------------------------------------------------------------------- 1 | |\Illuminate\Contracts\Validation\ValidationRule|string> 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'title' => 'required|string', 26 | ]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Tag/UpdateRequest.php: -------------------------------------------------------------------------------- 1 | |\Illuminate\Contracts\Validation\ValidationRule|string> 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'title' => 'required|string', 26 | ]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Http/Requests/Post/Comment/StoreRequest.php: -------------------------------------------------------------------------------- 1 | |\Illuminate\Contracts\Validation\ValidationRule|string> 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'message' => 'required|string', 26 | ]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Category/StoreRequest.php: -------------------------------------------------------------------------------- 1 | |\Illuminate\Contracts\Validation\ValidationRule|string> 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'title' => 'required|string', 26 | ]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Category/UpdateRequest.php: -------------------------------------------------------------------------------- 1 | |\Illuminate\Contracts\Validation\ValidationRule|string> 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'title' => 'required|string', 26 | ]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Http/Requests/Personal/Comment/UpdateRequest.php: -------------------------------------------------------------------------------- 1 | |\Illuminate\Contracts\Validation\ValidationRule|string> 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'message' => 'required|string', 26 | ]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Http/Controllers/Admin/Main/IndexController.php: -------------------------------------------------------------------------------- 1 | make('admin.main.index', ['data' => $data]); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /database/migrations/2024_10_08_000001_create_tags_table.php: -------------------------------------------------------------------------------- 1 | id(); 15 | $table->string('title'); 16 | $table->softDeletes(); 17 | $table->timestamps(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | */ 24 | public function down(): void 25 | { 26 | Schema::dropIfExists('tags'); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/ForgotPasswordController.php: -------------------------------------------------------------------------------- 1 | validated(); 16 | $data['post_id'] = $post->id; 17 | /** @phpstan-ignore-next-line */ 18 | $data['user_id'] = $user->id; 19 | /** @phpstan-ignore-next-line */ 20 | Comment::create($data); 21 | 22 | return redirect()->route('post.show', $post->id); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /database/migrations/2024_10_06_000001_create_categories_table.php: -------------------------------------------------------------------------------- 1 | id(); 15 | $table->string('title'); 16 | $table->string('slug', 2048); 17 | $table->softDeletes(); 18 | $table->timestamps(); 19 | }); 20 | } 21 | 22 | /** 23 | * Reverse the migrations. 24 | */ 25 | public function down(): void 26 | { 27 | Schema::dropIfExists('categories'); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/User/StoreRequest.php: -------------------------------------------------------------------------------- 1 | |\Illuminate\Contracts\Validation\ValidationRule|string> 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'name' => 'required|string', 26 | 'email' => 'required|string|email|unique:users', 27 | 'role' => 'required|string', 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/migrations/2024_10_06_000002_create_category_post_table.php: -------------------------------------------------------------------------------- 1 | id(); 15 | $table->foreignId('category_id')->references('id')->on('categories')->onDelete('cascade'); 16 | $table->foreignId('post_id')->references('id')->on('posts')->onDelete('cascade'); 17 | $table->timestamps(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | */ 24 | public function down(): void 25 | { 26 | Schema::dropIfExists('category_post'); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/ResetPasswordController.php: -------------------------------------------------------------------------------- 1 | |\Illuminate\Contracts\Validation\ValidationRule|string> 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'name' => 'required|string', 26 | 'email' => 'required|string|email|unique:users,email,' . $this->get('user_id'), 27 | 'user_id' => 'required|integer|exists:users,id', 28 | 'role' => 'required|string', 29 | ]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /resources/views/category/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper', ['title' => 'Категории']) 2 | 3 | @section('content') 4 |
5 |
6 |

Категории

7 | 19 |
20 |
21 | 22 | @endsection 23 | -------------------------------------------------------------------------------- /database/factories/PostFactory.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class PostFactory extends Factory 13 | { 14 | /** 15 | * Define the model's default state. 16 | * 17 | * @return array 18 | */ 19 | public function definition(): array 20 | { 21 | return [ 22 | 'title' => $title = fake()->text(100), 23 | 'slug' => Str::slug($title), 24 | 'preview_image' => route('placeholder.generate', ['width' => 640, 'height' => 480, 'seed' => Str::slug($title) . '-preview']), 25 | 'main_image' => route('placeholder.generate', ['width' => 640, 'height' => 480, 'seed' => Str::slug($title) . '-main']), 26 | 'content' => fake()->realText(5000), 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /database/migrations/2024_10_05_000001_create_posts_table.php: -------------------------------------------------------------------------------- 1 | id(); 15 | $table->string('title'); 16 | $table->string('slug', 2048); 17 | $table->longText('content'); 18 | $table->string('preview_image')->nullable(); 19 | $table->string('main_image')->nullable(); 20 | $table->softDeletes(); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | */ 28 | public function down(): void 29 | { 30 | Schema::dropIfExists('posts'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /resources/views/admin/post/show.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-admin', ['title' => $post->title]) 2 | 3 | @section('content') 4 |

Post info

5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
ID{{ $post->id }}
Title{{ $post->title }}
CategoriesTODO Show categories
Created at{{ $post->created_at }}
Updated at{{ $post->updated_at }}
31 |
32 | 33 | @endsection 34 | -------------------------------------------------------------------------------- /database/migrations/2024_10_04_000001_create_cache_table.php: -------------------------------------------------------------------------------- 1 | string('key')->primary(); 15 | $table->mediumText('value'); 16 | $table->integer('expiration'); 17 | }); 18 | 19 | Schema::create('cache_locks', function (Blueprint $table) { 20 | $table->string('key')->primary(); 21 | $table->string('owner'); 22 | $table->integer('expiration'); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | */ 29 | public function down(): void 30 | { 31 | Schema::dropIfExists('cache'); 32 | Schema::dropIfExists('cache_locks'); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /docs/https.md: -------------------------------------------------------------------------------- 1 | # Set up HTTPS 2 | 3 | Оригинальная инструкция: https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal 4 | 5 | ## Install snapd 6 | 7 | ```bash 8 | sudo apt update 9 | sudo apt install snapd 10 | ``` 11 | 12 | ## Ensure that your version of snapd is up to date 13 | 14 | ```bash 15 | sudo snap install core; sudo snap refresh core 16 | ``` 17 | 18 | ## Remove certbot-auto and any Certbot OS packages 19 | 20 | ```bash 21 | sudo apt-get remove certbot 22 | ``` 23 | 24 | ## Install Certbot 25 | 26 | ```bash 27 | sudo snap install --classic certbot 28 | ``` 29 | 30 | ## Prepare the Certbot command 31 | 32 | ```bash 33 | sudo ln -s /snap/bin/certbot /usr/bin/certbot 34 | ``` 35 | 36 | ## Run Certbot 37 | 38 | ```bash 39 | sudo certbot --nginx 40 | ``` 41 | 42 | If you wish to add another SSL-certificate, just run: 43 | 44 | ```bash 45 | sudo certbot certonly --nginx --agree-tos --expand -d laravel-blog.com 46 | ``` 47 | 48 | Where `laravel-blog.com` is the domain that you previously purchased and under which your website will be visible. 49 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.4-fpm 2 | 3 | # Arguments defined in docker-compose.yml 4 | ARG user 5 | ARG uid 6 | 7 | # Install system dependencies 8 | RUN apt-get update && apt-get install -y \ 9 | git \ 10 | curl \ 11 | libicu-dev \ 12 | libpng-dev \ 13 | libonig-dev \ 14 | libxml2-dev \ 15 | libzip-dev \ 16 | zip \ 17 | unzip 18 | 19 | # Clear cache 20 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* 21 | 22 | # Сonfigure PHP extensions 23 | RUN docker-php-ext-configure intl 24 | 25 | # Install PHP extensions 26 | RUN docker-php-ext-install pdo_mysql mbstring exif intl pcntl bcmath gd zip 27 | 28 | # Get latest Composer 29 | COPY --from=composer:latest /usr/bin/composer /usr/bin/composer 30 | 31 | # Create symlink for Composer 32 | RUN ln -s /usr/bin/composer /usr/bin/c 33 | 34 | # Create system user to run Composer and Artisan Commands 35 | RUN useradd -G www-data,root -u $uid -d /home/$user $user 36 | RUN mkdir -p /home/$user/.composer && \ 37 | chown -R $user:$user /home/$user 38 | 39 | # Set working directory 40 | WORKDIR /var/www 41 | 42 | USER $user 43 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Post/StoreRequest.php: -------------------------------------------------------------------------------- 1 | |\Illuminate\Contracts\Validation\ValidationRule|string> 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'title' => 'required|string', 26 | 'content' => 'required|string', 27 | 'category_id' => 'required|integer|exists:categories,id', 28 | 'preview_image' => 'nullable|file', 29 | 'main_image' => 'nullable|file', 30 | 'tag_ids' => 'nullable|array', 31 | 'tag_ids.*' => 'nullable|integer|exists:tags,id', 32 | ]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Post/UpdateRequest.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'title' => 'required|string', 26 | 'content' => 'required|string', 27 | 'category_ids' => 'nullable|array', 28 | 'category_ids.*' => 'nullable|integer|exists:tags,id', 29 | 'preview_image' => 'nullable|file', 30 | 'main_image' => 'nullable|file', 31 | 'tag_ids' => 'nullable|array', 32 | 'tag_ids.*' => 'nullable|integer|exists:tags,id', 33 | ]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Jobs/StoreUserJob.php: -------------------------------------------------------------------------------- 1 | data['password'] = Hash::make($password); 32 | 33 | /** @phpstan-ignore-next-line */ 34 | $user = User::firstOrCreate(['email' => $this->data['email']], $this->data); 35 | Mail::to($this->data['email'])->send(new PasswordMail($password)); 36 | event(new Registered($user)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/migrations/2024_10_08_000002_create_post_tags_table.php: -------------------------------------------------------------------------------- 1 | id(); 15 | $table->unsignedBigInteger('post_id'); 16 | $table->unsignedBigInteger('tag_id'); 17 | $table->timestamps(); 18 | 19 | $table->index('post_id', 'post_tag_post_idx'); 20 | $table->index('tag_id', 'post_tag_tag_idx'); 21 | 22 | $table->foreign('post_id', 'post_tag_post_fk')->on('posts')->references('id'); 23 | $table->foreign('tag_id', 'post_tag_tag_fk')->on('tags')->references('id'); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | */ 30 | public function down(): void 31 | { 32 | Schema::dropIfExists('post_tags'); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), 21 | 'scheme' => 'https', 22 | ], 23 | 24 | 'postmark' => [ 25 | 'token' => env('POSTMARK_TOKEN'), 26 | ], 27 | 28 | 'ses' => [ 29 | 'key' => env('AWS_ACCESS_KEY_ID'), 30 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 31 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 32 | ], 33 | 34 | ]; 35 | -------------------------------------------------------------------------------- /database/migrations/2024_10_07_000001_create_comments_table.php: -------------------------------------------------------------------------------- 1 | id(); 15 | $table->unsignedBigInteger('user_id'); 16 | $table->unsignedBigInteger('post_id'); 17 | $table->text('message'); 18 | $table->timestamps(); 19 | 20 | $table->index('user_id', 'comments_user_idx'); 21 | $table->index('post_id', 'comments_post_idx'); 22 | 23 | $table->foreign('post_id')->references('id')->on('posts'); 24 | $table->foreign('user_id')->references('id')->on('users'); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | */ 31 | public function down(): void 32 | { 33 | Schema::dropIfExists('comments'); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /database/migrations/2024_10_09_000001_create_likes_table.php: -------------------------------------------------------------------------------- 1 | id(); 17 | $table->timestamps(); 18 | $table->unsignedBigInteger('post_id'); 19 | $table->unsignedBigInteger('user_id'); 20 | 21 | $table->index('post_id', 'post_user_likes_post_idx'); 22 | $table->index('user_id', 'post_user_likes_user_idx'); 23 | 24 | $table->foreign('post_id')->references('id')->on('posts'); 25 | $table->foreign('user_id')->references('id')->on('users'); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | */ 32 | public function down(): void 33 | { 34 | Schema::dropIfExists('likes'); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /rector.php: -------------------------------------------------------------------------------- 1 | paths([ 16 | __DIR__ . '/app', 17 | __DIR__ . '/tests', 18 | ]); 19 | 20 | // is your PHP version different from the one you refactor to? [default: your PHP version], uses PHP_VERSION_ID format 21 | $rectorConfig->phpVersion(PhpVersion::PHP_83); 22 | 23 | // Path to PHPStan with extensions, that PHPStan in Rector uses to determine types 24 | $rectorConfig->phpstanConfig(__DIR__ . '/phpstan.neon.dist'); 25 | 26 | // register sets rule 27 | $rectorConfig->sets([ 28 | SetList::CODE_QUALITY, 29 | SetList::PHP_83, 30 | SetList::EARLY_RETURN, 31 | SetList::DEAD_CODE, 32 | LevelSetList::UP_TO_PHP_83, 33 | ]); 34 | }; 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alexander Gomzyakov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/Models/Tag.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/LoginController.php: -------------------------------------------------------------------------------- 1 | middleware('guest')->except('logout'); 38 | $this->middleware('auth')->only('logout'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class UserFactory extends Factory 13 | { 14 | /** 15 | * Define the model's default state. 16 | * 17 | * @return array 18 | */ 19 | public function definition(): array 20 | { 21 | return [ 22 | 'name' => fake()->name(), 23 | 'email' => fake()->unique()->safeEmail(), 24 | 'email_verified_at' => now(), 25 | 'role' => 'reader', 26 | 'password' => Hash::make('password'), 27 | 'remember_token' => Str::random(10), 28 | ]; 29 | } 30 | 31 | /** 32 | * Indicate that the model's email address should be unverified. 33 | */ 34 | public function unverified(): static 35 | { 36 | return $this->state(fn (array $attributes) => [ 37 | 'email_verified_at' => null, 38 | ]); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.env.ci: -------------------------------------------------------------------------------- 1 | APP_NAME=Secretic 2 | APP_ENV=local 3 | APP_KEY=base64:g3cPbmSz3AC3CoGXtbK81jFgYJnobc4iT27AwRs+FQc= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost 6 | 7 | LOG_CHANNEL=stack 8 | LOG_DEPRECATIONS_CHANNEL=null 9 | LOG_LEVEL=debug 10 | 11 | DB_CONNECTION=mysql 12 | DB_HOST=127.0.0.1 13 | DB_PORT=3306 14 | DB_ENGINE=InnoDB 15 | DB_DATABASE=laravel_blog 16 | DB_USERNAME=root 17 | DB_PASSWORD=password 18 | 19 | BROADCAST_DRIVER=log 20 | CACHE_DRIVER=file 21 | FILESYSTEM_DISK=local 22 | QUEUE_CONNECTION=sync 23 | SESSION_DRIVER=file 24 | SESSION_LIFETIME=120 25 | 26 | MEMCACHED_HOST=127.0.0.1 27 | 28 | REDIS_HOST=127.0.0.1 29 | REDIS_PASSWORD=null 30 | REDIS_PORT=6379 31 | 32 | MAIL_MAILER=smtp 33 | MAIL_HOST=mailhog 34 | MAIL_PORT=1025 35 | MAIL_USERNAME=null 36 | MAIL_PASSWORD=null 37 | MAIL_ENCRYPTION=null 38 | MAIL_FROM_ADDRESS="hello@example.com" 39 | MAIL_FROM_NAME="${APP_NAME}" 40 | 41 | AWS_ACCESS_KEY_ID= 42 | AWS_SECRET_ACCESS_KEY= 43 | AWS_DEFAULT_REGION=us-east-1 44 | AWS_BUCKET= 45 | AWS_USE_PATH_STYLE_ENDPOINT=false 46 | 47 | PUSHER_APP_ID= 48 | PUSHER_APP_KEY= 49 | PUSHER_APP_SECRET= 50 | PUSHER_APP_CLUSTER=mt1 51 | 52 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 53 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 54 | 55 | SENTRY_TRACES_SAMPLE_RATE=1.0 56 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | tests/Unit 10 | 11 | 12 | tests/Feature 13 | 14 | 15 | 16 | 17 | app 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /.env.local: -------------------------------------------------------------------------------- 1 | APP_NAME="Laravel Blog" 2 | APP_ENV=local 3 | APP_KEY=base64:g3cPbmSz3AC3CoGXtbK81jFgYJnobc4iT27AwRs+FQc= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost:8000 6 | 7 | LOG_CHANNEL=stack 8 | LOG_DEPRECATIONS_CHANNEL=null 9 | LOG_LEVEL=debug 10 | 11 | DB_CONNECTION=mysql 12 | DB_HOST=db 13 | DB_PORT=3306 14 | DB_ENGINE=InnoDB 15 | DB_DATABASE=laravel_blog 16 | DB_USERNAME=laravel_blog_user 17 | DB_PASSWORD=password 18 | 19 | BROADCAST_DRIVER=log 20 | CACHE_DRIVER=file 21 | FILESYSTEM_DISK=local 22 | QUEUE_CONNECTION=sync 23 | SESSION_DRIVER=file 24 | SESSION_LIFETIME=120 25 | 26 | MEMCACHED_HOST=127.0.0.1 27 | 28 | REDIS_HOST=127.0.0.1 29 | REDIS_PASSWORD=null 30 | REDIS_PORT=6379 31 | 32 | MAIL_MAILER=smtp 33 | MAIL_HOST=mailhog 34 | MAIL_PORT=1025 35 | MAIL_USERNAME=null 36 | MAIL_PASSWORD=null 37 | MAIL_ENCRYPTION=null 38 | MAIL_FROM_ADDRESS="hello@example.com" 39 | MAIL_FROM_NAME="${APP_NAME}" 40 | 41 | AWS_ACCESS_KEY_ID= 42 | AWS_SECRET_ACCESS_KEY= 43 | AWS_DEFAULT_REGION=us-east-1 44 | AWS_BUCKET= 45 | AWS_USE_PATH_STYLE_ENDPOINT=false 46 | 47 | PUSHER_APP_ID= 48 | PUSHER_APP_KEY= 49 | PUSHER_APP_SECRET= 50 | PUSHER_APP_CLUSTER=mt1 51 | 52 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 53 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 54 | 55 | SENTRY_TRACES_SAMPLE_RATE=1.0 56 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/VerificationController.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 38 | $this->middleware('signed')->only('verify'); 39 | $this->middleware('throttle:6,1')->only('verify', 'resend'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Mail/User/PasswordMail.php: -------------------------------------------------------------------------------- 1 | 47 | */ 48 | public function attachments(): array 49 | { 50 | return []; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/Models/PostTag.php: -------------------------------------------------------------------------------- 1 | 'Posts']) 2 | 3 | @section('content') 4 |

Posts

5 | 6 | Add post 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | @foreach($posts as $post) 20 | 21 | 22 | 23 | 24 | 25 | 35 | 36 | @endforeach 37 | 38 |
IDPost Title
{{ $post->id }}{{ $post->title }}InfoEdit 26 |
28 | @csrf 29 | @method('delete') 30 | 33 |
34 |
39 | 40 | 41 | @endsection 42 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | app: 3 | build: 4 | args: 5 | user: sammy 6 | uid: 1000 7 | context: ./ 8 | dockerfile: Dockerfile 9 | image: laravel-blog 10 | container_name: laravel-blog-app 11 | restart: unless-stopped 12 | working_dir: /var/www/ 13 | volumes: 14 | - ./:/var/www 15 | networks: 16 | - app-network 17 | 18 | db: 19 | image: mysql:9.1 20 | container_name: laravel-blog-db 21 | restart: unless-stopped 22 | environment: 23 | MYSQL_DATABASE: ${DB_DATABASE} 24 | MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} 25 | MYSQL_PASSWORD: ${DB_PASSWORD} 26 | MYSQL_USER: ${DB_USERNAME} 27 | SERVICE_TAGS: dev 28 | SERVICE_NAME: mysql 29 | ports: 30 | - "3306:3306" 31 | volumes: 32 | - ./docker-compose/mysql:/docker-entrypoint-initdb.d 33 | networks: 34 | - app-network 35 | 36 | nginx: 37 | image: nginx:1.27-alpine 38 | container_name: laravel-blog-nginx 39 | restart: unless-stopped 40 | ports: 41 | - "8000:80" 42 | volumes: 43 | - ./:/var/www 44 | - ./docker-compose/nginx:/etc/nginx/conf.d 45 | networks: 46 | - app-network 47 | 48 | networks: 49 | app-network: 50 | driver: bridge 51 | -------------------------------------------------------------------------------- /resources/views/layouts/wrapper-admin/navbar.blade.php: -------------------------------------------------------------------------------- 1 | 31 | -------------------------------------------------------------------------------- /app/Models/Category.php: -------------------------------------------------------------------------------- 1 | $posts 20 | * @property-read int|null $posts_count 21 | * 22 | * @method static Builder|Category newModelQuery() 23 | * @method static Builder|Category newQuery() 24 | * @method static Builder|Category onlyTrashed() 25 | * @method static Builder|Category query() 26 | * @method static Builder|Category whereCreatedAt($value) 27 | * @method static Builder|Category whereDeletedAt($value) 28 | * @method static Builder|Category whereId($value) 29 | * @method static Builder|Category whereSlug($value) 30 | * @method static Builder|Category whereTitle($value) 31 | * @method static Builder|Category whereUpdatedAt($value) 32 | * @method static Builder|Category withTrashed() 33 | * @method static Builder|Category withoutTrashed() 34 | */ 35 | class Category extends Model 36 | { 37 | use HasFactory; 38 | 39 | protected $table = 'categories'; 40 | 41 | protected $guarded = false; 42 | 43 | public function posts(): HasMany 44 | { 45 | return $this->hasMany(Post::class); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/Models/Comment.php: -------------------------------------------------------------------------------- 1 | 'datetime', 41 | 'updated_at' => 'datetime', 42 | ]; 43 | 44 | public function post(): BelongsTo 45 | { 46 | return $this->belongsTo(Post::class); 47 | } 48 | 49 | public function user(): BelongsTo 50 | { 51 | return $this->belongsTo(User::class); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /resources/views/layouts/wrapper-personal.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ $title ?? 'Page Title' }} 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | @include('layouts.wrapper._navbar') 21 | 22 | @yield('content') 23 | 24 | @include('layouts.wrapper._footer') 25 | 26 | 29 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /resources/views/layouts/wrapper.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ $title ?? 'Page Title' }} 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | @stack('styles') 18 | 19 | 20 | 21 | 22 | @include('layouts.wrapper._navbar') 23 | 24 |
25 | @yield('content') 26 |
27 | 28 | @include('layouts.wrapper._footer') 29 | 30 | 33 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/Http/Controllers/PlaceholderController.php: -------------------------------------------------------------------------------- 1 | 2000) { 20 | return response('Width must be between 1 and 2000', 400); 21 | } 22 | if ($height < 1 || $height > 2000) { 23 | return response('Height must be between 1 and 2000', 400); 24 | } 25 | 26 | $cx = (int) $request->get('cx', 4); // blurhash components on X axis 27 | $cy = (int) $request->get('cy', 3); // blurhash components on Y axis 28 | 29 | if ($cx < 1 || $cx > 9) { 30 | return response('cx must be between 1 and 9', 400); 31 | } 32 | if ($cy < 1 || $cy > 9) { 33 | return response('cy must be between 1 and 9', 400); 34 | } 35 | 36 | $seed = (string) $request->get('seed', 'default'); 37 | 38 | try { 39 | $generator = new ImagePlaceholder(); 40 | $image_data = $generator->generate($width, $height, $seed, $cx, $cy); 41 | 42 | return response($image_data) 43 | ->header('Content-Type', 'image/png') 44 | ->header('Cache-Control', 'public, max-age=31536000'); 45 | } catch (RuntimeException $e) { 46 | return response($e->getMessage(), 500); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | handleRequest(Request::capture()); 48 | -------------------------------------------------------------------------------- /database/migrations/2024_10_04_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | id(); 15 | $table->string('name'); 16 | $table->string('email')->unique(); 17 | $table->timestamp('email_verified_at')->nullable(); 18 | $table->string('password'); 19 | $table->string('role')->default('reader'); 20 | $table->rememberToken(); 21 | $table->timestamps(); 22 | $table->softDeletes(); 23 | }); 24 | 25 | Schema::create('password_reset_tokens', function (Blueprint $table) { 26 | $table->string('email')->primary(); 27 | $table->string('token'); 28 | $table->timestamp('created_at')->nullable(); 29 | }); 30 | 31 | Schema::create('sessions', function (Blueprint $table) { 32 | $table->string('id')->primary(); 33 | $table->foreignId('user_id')->nullable()->index(); 34 | $table->string('ip_address', 45)->nullable(); 35 | $table->text('user_agent')->nullable(); 36 | $table->longText('payload'); 37 | $table->integer('last_activity')->index(); 38 | }); 39 | } 40 | 41 | /** 42 | * Reverse the migrations. 43 | */ 44 | public function down(): void 45 | { 46 | Schema::dropIfExists('users'); 47 | Schema::dropIfExists('password_reset_tokens'); 48 | Schema::dropIfExists('sessions'); 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /resources/views/about/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper', ['title' => 'About author']) 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
9 | 10 |
11 | 12 |
13 | 14 | 15 |
16 |

About the Author

17 |

Get to know the person behind the posts

18 |
19 | 20 | 21 |

22 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut 23 | labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco 24 | laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in 25 | voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat 26 | non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 27 |

28 |
29 |
30 |
31 |
32 | @endsection -------------------------------------------------------------------------------- /resources/views/personal/comment/edit.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-personal', ['title' => 'My personal blog']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |

8 | Edit comment 9 |

10 |
11 | 12 | 13 |
14 |
15 |
16 | @csrf 17 | @method('patch') 18 | 19 | 20 |
21 | 22 | 24 | @error('message') 25 |
26 | This field is required. 27 |
28 | @enderror 29 |
30 | 31 | 32 |
33 | 36 |
37 |
38 |
39 |
40 |
41 | @endsection -------------------------------------------------------------------------------- /resources/views/admin/tag/create.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-admin', ['title' => 'Tag']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |
8 |
9 |
10 |

Добавление тэга

11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 | @csrf 24 |
25 |
26 | 27 | 29 | @error('title') 30 |
Это поле необходимо заполнить
31 | @enderror 32 |
33 |
34 | 35 |
36 |
37 |
38 |
39 |
40 |
41 | @endsection 42 | -------------------------------------------------------------------------------- /resources/views/admin/category/create.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-admin', ['title' => 'Category']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |
8 |
9 |
10 |

Добавление категории

11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 | @csrf 24 |
25 |
26 | 27 | 29 | @error('title') 30 |
Это поле необходимо заполнить
31 | @enderror 32 |
33 |
34 | 35 |
36 |
37 |
38 |
39 |
40 |
41 | @endsection 42 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make(Illuminate\Contracts\Console\Kernel::class); 34 | 35 | $status = $kernel->handle( 36 | $input = new Symfony\Component\Console\Input\ArgvInput, 37 | new Symfony\Component\Console\Output\ConsoleOutput 38 | ); 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Shutdown The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once Artisan has finished running, we will fire off the shutdown events 46 | | so that any final work may be done by the application before we shut 47 | | down the process. This is the last thing to happen to the request. 48 | | 49 | */ 50 | 51 | $kernel->terminate($input, $status); 52 | 53 | exit($status); 54 | -------------------------------------------------------------------------------- /resources/views/admin/tag/edit.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-admin', ['title' => 'Tag']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |
8 |
9 |
10 |

Редактирование тэга

11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 | @csrf 24 | @method('patch') 25 |
26 |
27 | 28 | Это поле необходимо заполнить
32 | @enderror 33 |
34 |
35 | 36 | 37 |
38 | 39 |
40 | 41 |
42 | @endsection 43 | -------------------------------------------------------------------------------- /resources/views/admin/main/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-admin', ['title' => 'Admin panel']) 2 | 3 | @section('content') 4 | 5 |

Dashboard

6 | 7 |
8 |
9 |
10 |
11 |
{{ $data['countPost'] }}
12 |

Posts

13 | Details 14 |
15 |
16 |
17 |
18 |
19 |
20 |
{{ $data['countUser'] }}
21 |

Users

22 | Details 23 |
24 |
25 |
26 |
27 |
28 |
29 |
{{ $data['countCategory'] }}
30 |

Categories

31 | Details 32 |
33 |
34 |
35 |
36 |
37 |
38 |
{{ $data['countTag'] }}
39 |

Tags

40 | Details 41 |
42 |
43 |
44 |
45 | 46 | @endsection 47 | -------------------------------------------------------------------------------- /resources/views/admin/category/edit.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-admin', ['title' => 'Category']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |
8 |
9 |
10 |

Редактирование категории

11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 | @csrf 24 | @method('patch') 25 |
26 |
27 | 28 | Это поле необходимо заполнить
32 | @enderror 33 |
34 |
35 | 36 | 37 |
38 | 39 |
40 | 41 | 42 | @endsection 43 | -------------------------------------------------------------------------------- /resources/views/layouts/wrapper-admin.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | {{ $title ?? 'Page Title' }} · Blog Admin Panel 11 | 12 | 13 | 15 | 16 | 17 | 18 | @include('layouts.wrapper-admin.custom_css') 19 | 20 | 21 | 22 | 23 | @include('layouts.wrapper-admin.toggle_theme') 24 | @include('layouts.wrapper-admin.svg_symbols') 25 | 26 | @include('layouts.wrapper-admin.navbar') 27 | 28 |
29 |
30 | 31 | @include('layouts.wrapper-admin.sidebar') 32 | 33 |
34 | 35 | @yield('content') 36 | 37 |
38 |
39 |
40 | 43 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /database/migrations/2024_10_04_000002_create_jobs_table.php: -------------------------------------------------------------------------------- 1 | id(); 15 | $table->string('queue')->index(); 16 | $table->longText('payload'); 17 | $table->unsignedTinyInteger('attempts'); 18 | $table->unsignedInteger('reserved_at')->nullable(); 19 | $table->unsignedInteger('available_at'); 20 | $table->unsignedInteger('created_at'); 21 | }); 22 | 23 | Schema::create('job_batches', function (Blueprint $table) { 24 | $table->string('id')->primary(); 25 | $table->string('name'); 26 | $table->integer('total_jobs'); 27 | $table->integer('pending_jobs'); 28 | $table->integer('failed_jobs'); 29 | $table->longText('failed_job_ids'); 30 | $table->mediumText('options')->nullable(); 31 | $table->integer('cancelled_at')->nullable(); 32 | $table->integer('created_at'); 33 | $table->integer('finished_at')->nullable(); 34 | }); 35 | 36 | Schema::create('failed_jobs', function (Blueprint $table) { 37 | $table->id(); 38 | $table->string('uuid')->unique(); 39 | $table->text('connection'); 40 | $table->text('queue'); 41 | $table->longText('payload'); 42 | $table->longText('exception'); 43 | $table->timestamp('failed_at')->useCurrent(); 44 | }); 45 | } 46 | 47 | /** 48 | * Reverse the migrations. 49 | */ 50 | public function down(): void 51 | { 52 | Schema::dropIfExists('jobs'); 53 | Schema::dropIfExists('job_batches'); 54 | Schema::dropIfExists('failed_jobs'); 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /resources/views/auth/passwords/email.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-auth') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Сброс пароля') }}
9 | 10 |
11 | @if (session('status')) 12 | 15 | @endif 16 | 17 |
18 | @csrf 19 | 20 |
21 | 22 | 23 |
24 | 25 | 26 | @error('email') 27 | 28 | {{ $message }} 29 | 30 | @enderror 31 |
32 |
33 | 34 |
35 |
36 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | @endsection 48 | -------------------------------------------------------------------------------- /resources/views/admin/tag/show.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-admin', ['title' => 'Tag']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |
8 |
9 |
10 |

{{ $tag->title }}

11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
ID{{ $tag->id }}
Название{{ $tag->title }}
38 |
39 | 40 |
41 | 42 |
43 |
44 | 45 | 46 |
47 |
48 |
49 | 50 | 51 | 52 | @endsection 53 | -------------------------------------------------------------------------------- /resources/views/admin/category/show.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-admin', ['title' => 'Category']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |
8 |
9 |
10 |

{{ $category->title }}

11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
ID{{ $category->id }}
Название{{ $category->title }}
38 |
39 | 40 |
41 | 42 |
43 |
44 | 45 | 46 |
47 |
48 |
49 | 50 | 51 | 52 | @endsection 53 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/RegisterController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 41 | } 42 | 43 | /** 44 | * Get a validator for an incoming registration request. 45 | * 46 | * @return \Illuminate\Contracts\Validation\Validator 47 | */ 48 | protected function validator(array $data) 49 | { 50 | return Validator::make($data, [ 51 | 'name' => ['required', 'string', 'max:255'], 52 | 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 53 | 'password' => ['required', 'string', 'min:8', 'confirmed'], 54 | ]); 55 | } 56 | 57 | /** 58 | * Create a new user instance after a valid registration. 59 | * 60 | * @return User 61 | */ 62 | protected function create(array $data) 63 | { 64 | /** @phpstan-ignore-next-line */ 65 | return User::create([ 66 | 'name' => $data['name'], 67 | 'email' => $data['email'], 68 | 'password' => Hash::make($data['password']), 69 | ]); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /resources/views/contact/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper', ['title' => 'Contacts']) 2 | 3 | @section('content') 4 |
5 | 6 | 7 |
8 |
9 |
10 |
11 | 12 |
13 |

Contacts

14 |
15 | 16 | 17 |
18 | 19 |

mail@gmail.com 20 |

21 |
22 | 23 | 24 |
25 | 26 |

Telegram

27 |
28 | 29 | 30 |
31 | 32 |

VK

33 |
34 | 35 | 36 |
37 | 38 |

WhatsApp

39 |
40 |
41 |
42 |
43 |
44 |
45 | @endsection -------------------------------------------------------------------------------- /resources/views/post/index/liked_posts.blade.php: -------------------------------------------------------------------------------- 1 | @php 2 | /** @var \App\Models\Post $likedPost */ 3 | @endphp 4 | 5 |
6 | 7 |
8 |
9 |

10 | Liked Posts 11 |

12 |
13 |
14 | 15 | 16 |
17 | @foreach($likedPosts as $likedPost) 18 |
19 |
20 | ... 21 |
22 |
23 | 24 | {{ $likedPost->title }} 25 | 26 |
27 |

{{ $likedPost->shortBody() }}

28 | 30 | Continue reading → 31 | 32 |
33 |
34 |
35 | @endforeach 36 |
37 |
38 | 39 | -------------------------------------------------------------------------------- /resources/views/auth/passwords/confirm.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-auth') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Подтвердите пароль') }}
9 | 10 |
11 | {{ __('Пожалуйста, подтвердите свой пароль, прежде чем продолжить.') }} 12 | 13 |
14 | @csrf 15 | 16 |
17 | 18 | 19 |
20 | 21 | 22 | @error('password') 23 | 24 | {{ $message }} 25 | 26 | @enderror 27 |
28 |
29 | 30 |
31 |
32 | 35 | 36 | @if (Route::has('password.request')) 37 | 38 | {{ __('Забыли пароль?') }} 39 | 40 | @endif 41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | @endsection 50 | -------------------------------------------------------------------------------- /app/Service/PostService.php: -------------------------------------------------------------------------------- 1 | put('/images', $data['preview_image']); 28 | } 29 | if (isset($data['main_image'])) { 30 | $data['main_image'] = Storage::disk('public')->put('/images', $data['main_image']); 31 | } 32 | 33 | // todo No needs to fix this 34 | /** @phpstan-ignore-next-line */ 35 | $post = Post::firstOrCreate($data); 36 | 37 | if (isset($tagIds)) { 38 | $post->tags()->attach($tagIds); 39 | } 40 | DB::commit(); 41 | } catch (Exception) { 42 | DB::rollBack(); 43 | abort(500); 44 | } 45 | } 46 | 47 | public function update($data, $post) 48 | { 49 | try { 50 | DB::beginTransaction(); 51 | if (isset($data['tag_ids'])) { 52 | $tagIds = $data['tag_ids']; 53 | unset($data['tag_ids']); 54 | } 55 | if (isset($data['preview_image'])) { 56 | $data['preview_image'] = Storage::disk('public')->put('/images', $data['preview_image']); 57 | } 58 | if (isset($data['main_image'])) { 59 | $data['main_image'] = Storage::disk('public')->put('/images', $data['main_image']); 60 | } 61 | 62 | $post->update($data); 63 | 64 | if (isset($tagIds)) { 65 | $post->tags()->sync($tagIds); 66 | } 67 | DB::commit(); 68 | } catch (Exception) { 69 | DB::rollBack(); 70 | abort(500); 71 | } 72 | 73 | return $post; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /resources/views/admin/user/show.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-admin', ['title' => 'User']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |
8 |
9 |
10 |

{{ $user->name }}

11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
ID{{ $user->id }}
Имя{{ $user->name }}
Электронная почта{{ $user->email }}
42 |
43 | 44 |
45 | 46 |
47 |
48 | 49 | 50 |
51 |
52 |
53 | 54 | 55 | 56 | @endsection 57 | -------------------------------------------------------------------------------- /resources/views/layouts/wrapper-admin/toggle_theme.blade.php: -------------------------------------------------------------------------------- 1 | 52 | -------------------------------------------------------------------------------- /app/Http/Controllers/PostController.php: -------------------------------------------------------------------------------- 1 | orderBy('liked_users_count', 'desc')->get()->take(3); 20 | 21 | // todo Show recent categories with their latest posts 22 | 23 | return $view_factory->make('post.index', [ 24 | 'posts' => $latest_post, 25 | 'likedPosts' => $liked_posts, 26 | ]); 27 | } 28 | 29 | public function show(Post $post, Request $request, ViewFactory $view_factory) 30 | { 31 | $date = Carbon::parse($post->created_at); 32 | $tags = $post->tags; 33 | 34 | // TODO Add 35 | $relatedPosts = collect(); 36 | 37 | return $view_factory->make('post.show', ['post' => $post, 'relatedPosts' => $relatedPosts, 'date' => $date, 'tags' => $tags]); 38 | } 39 | 40 | public function byCategory(Category $category, ViewFactory $view_factory) 41 | { 42 | $posts = Post::query() 43 | ->join('category_post', 'posts.id', '=', 'category_post.post_id') 44 | ->where('category_post.category_id', '=', $category->id) 45 | ->whereDate('published_at', '<=', Carbon::now()) 46 | ->orderBy('published_at', 'desc') 47 | ->paginate(10); 48 | 49 | return $view_factory->make('post.index', ['posts' => $posts, 'category' => $category]); 50 | } 51 | 52 | public function search(Request $request, ViewFactory $view_factory) 53 | { 54 | $q = $request->get('q'); 55 | 56 | $posts = Post::query() 57 | ->whereDate('published_at', '<=', Carbon::now()) 58 | ->orderBy('published_at', 'desc') 59 | ->where(function ($query) use ($q) { 60 | $query->where('title', 'like', "%{$q}%") 61 | ->orWhere('body', 'like', "%{$q}%"); 62 | }) 63 | ->paginate(10); 64 | 65 | return $view_factory->make('post.search', ['posts' => $posts]); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /resources/views/layouts/wrapper-personal/sidebar.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /translations/README.zh-cn.md: -------------------------------------------------------------------------------- 1 | >[!IMPORTANT] 2 | >This file needs to updated in order to match the [english](/README.md) README file. 3 | 该文件需要更新才能匹配 [英语](/README.md) README 文件。 4 | 5 | ![带有 Filament 管理面板的 Laravel 博客](../docs/social-preview-en.png) 6 | 7 | _Read this in [other languages](./Translations.md)_ 8 | 9 | >This file is automatically translated. If you notice an error, please correct it yourself (by making a PR) or write about it in the [issues](https://github.com/gomzyakov/laravel-blog/issues). 10 | 11 | # Laravel 博客与 Filament 管理面板 12 | 13 | 这是 [Laravel](https://laravel.com) 博客入门套件项目,带有 [Filament](https://filamentphp.com) 管理面板。 14 | 15 | 该存储库的目标是通过一个简单的应用程序展示良好的 [Laravel](https://laravel.com) 开发实践。 16 | 17 | ## 特征 18 | 19 | - 📚 创建和编辑帖子 20 | - 🥑 类别 21 | - 🔥 热门帖子 22 | - 🎉 基于 [Filament](https://filamentphp.com) 构建的管理面板 23 | 24 | ## 请求功能 25 | 26 | 打开一个 [新问题](https://github.com/gomzyakov/laravel-blog/issues/new) 来请求功能(或者如果您发现错误)。 27 | 28 | ## 如何在本地运行博客? 29 | 30 | 克隆项目: 31 | 32 | ```bash 33 | git clone git@github.com:gomzyakov/laravel-blog.git 34 | ``` 35 | 36 | 我相信你已经安装了 Docker。 如果没有,只需在 [Mac](https://docs.docker.com/desktop/install/mac-install/)、[Windows](https://docs.docker.com/desktop/install/windows -install/) 或 [Linux](https://docs.docker.com/desktop/install/linux-install/)。 37 | 38 | 使用以下命令构建`laravel-blog`图像: 39 | 40 | ```bash 41 | docker compose build --no-cache 42 | ``` 43 | 44 | >此命令可能需要几分钟才能完成。 45 | 46 | 构建完成后,您可以使用以下命令在后台模式下运行环境: 47 | 48 | ```bash 49 | docker compose up -d 50 | ``` 51 | 52 | 我们现在将运行`composer install`来安装应用程序依赖项: 53 | 54 | ```bash 55 | docker compose exec app composer install 56 | ``` 57 | 58 | 复制环境设置: 59 | 60 | ```bash 61 | docker compose exec app cp .env.local .env 62 | ``` 63 | 64 | 使用“artisan”Laravel 命令行工具设置加密密钥: 65 | 66 | ```bash 67 | docker compose exec app ./artisan key:generate --ansi 68 | ``` 69 | 70 | 迁移数据库和种子假数据: 71 | 72 | ```bash 73 | docker compose exec app ./artisan migrate:fresh --seed 74 | ``` 75 | 76 | 然后在您喜欢的浏览器中打开 http://127.0.0.1:8000。 祝您使用 Laravel 博客愉快! 77 | 78 | ## 如何进入容器内部? 79 | 80 | 访问Docker容器: 81 | 82 | ```bash 83 | docker exec -ti laravel-blog-app bash 84 | ``` 85 | 86 | ## 执照 87 | 88 | 这是根据 [MIT 许可证](https://github.com/gomzyakov/php-code-style/blob/main/LICENSE) 许可的开源软件。 89 | 90 | 91 | [![GitHub 发布](https://img.shields.io/github/release/gomzyakov/laravel-blog.svg)](https://github.com/gomzyakov/laravel-blog/releases/latest) 92 | [![许可证](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/gomzyakov/laravel-blog/blob/development/LICENSE) 93 | [![codecov](https://codecov.io/gh/gomzyakov/laravel-blog/branch/main/graph/badge.svg?token=4CYTVMVUYV)](https://codecov.io/gh/gomzyakov/ Laravel 博客) 94 | -------------------------------------------------------------------------------- /config/filesystems.php: -------------------------------------------------------------------------------- 1 | env('FILESYSTEM_DISK', 'local'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Filesystem Disks 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Below you may configure as many filesystem disks as necessary, and you 24 | | may even configure multiple disks for the same driver. Examples for 25 | | most supported storage drivers are configured here for reference. 26 | | 27 | | Supported drivers: "local", "ftp", "sftp", "s3" 28 | | 29 | */ 30 | 31 | 'disks' => [ 32 | 33 | 'local' => [ 34 | 'driver' => 'local', 35 | 'root' => storage_path('app'), 36 | 'throw' => false, 37 | ], 38 | 39 | 'public' => [ 40 | 'driver' => 'local', 41 | 'root' => storage_path('app/public'), 42 | 'url' => env('APP_URL') . '/storage', 43 | 'visibility' => 'public', 44 | 'throw' => false, 45 | ], 46 | 47 | 's3' => [ 48 | 'driver' => 's3', 49 | 'key' => env('AWS_ACCESS_KEY_ID'), 50 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 51 | 'region' => env('AWS_DEFAULT_REGION'), 52 | 'bucket' => env('AWS_BUCKET'), 53 | 'url' => env('AWS_URL'), 54 | 'endpoint' => env('AWS_ENDPOINT'), 55 | 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), 56 | 'throw' => false, 57 | ], 58 | 59 | ], 60 | 61 | /* 62 | |-------------------------------------------------------------------------- 63 | | Symbolic Links 64 | |-------------------------------------------------------------------------- 65 | | 66 | | Here you may configure the symbolic links that will be created when the 67 | | `storage:link` Artisan command is executed. The array keys should be 68 | | the locations of the links and the values should be their targets. 69 | | 70 | */ 71 | 72 | 'links' => [ 73 | public_path('storage') => storage_path('app/public'), 74 | ], 75 | 76 | ]; 77 | -------------------------------------------------------------------------------- /resources/views/category/post/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper', ['title' => $category->title]) 2 | 3 | @section('content') 4 | 5 |
6 |
7 |

Категория: {{ $category->title }}

8 | 49 |
50 | 51 |
52 | 53 | @endsection 54 | -------------------------------------------------------------------------------- /translations/README.zh-tw.md: -------------------------------------------------------------------------------- 1 | >[!IMPORTANT] 2 | >This file needs to updated in order to match the [english](/README.md) README file. 3 | 該檔案需要更新才能符合 [英語](/README.md) README 檔案。 4 | 5 | ![帶有 Laravel 部落格](../docs/social-preview-en.png) 6 | 7 | _Read this in [other languages](./Translations.md)_ 8 | 9 | >This file is automatically translated. If you notice an error, please correct it yourself (by making a PR) or write about it in the [issues](https://github.com/gomzyakov/laravel-blog/issues). 10 | 11 | # Laravel 部落格與 Filament 管理面板 12 | 13 | 這是 [Laravel](https://laravel.com) 部落格入門套件項目,附有 [Filament](https://filamentphp.com) 管理面板。 14 | 15 | 這個儲存庫的目標是透過一個簡單的應用程式來展示良好的 [Laravel](https://laravel.com) 開發實踐。 16 | 17 | ## 特徵 18 | 19 | - 📚 建立和編輯帖子 20 | - 🥑 類別 21 | - 🔥 熱門帖子 22 | - 🎉 基於 [Filament](https://filamentphp.com) 建構的管理面板 23 | 24 | ## 請求功能 25 | 26 | 開啟一個 [新問題](https://github.com/gomzyakov/laravel-blog/issues/new) 來要求功能(或如果您發現錯誤)。 27 | 28 | ## 如何在本地經營部落格? 29 | 30 | 克隆項目: 31 | 32 | ```bash 33 | git clone git@github.com:gomzyakov/laravel-blog.git 34 | ``` 35 | 36 | 我相信你已經安裝了 Docker。 如果沒有,只需在 [Mac](https://docs.docker.com/desktop/install/mac-install/)、[Windows](https://docs.docker.com/desktop/install/windows - install/) 或[Linux](https://docs.docker.com/desktop/install/linux-install/)。 37 | 38 | 使用以下命令建立`laravel-blog`映像: 39 | 40 | ```bash 41 | docker compose build --no-cache 42 | ``` 43 | 44 | >此命令可能需要幾分鐘才能完成。 45 | 46 | 建置完成後,您可以使用以下命令在背景模式下執行環境: 47 | 48 | ```bash 49 | docker compose up -d 50 | ``` 51 | 52 | 我們現在將運行`composer install`來安裝應用程式依賴項: 53 | 54 | ```bash 55 | docker compose exec app composer install 56 | ``` 57 | 58 | 複製環境設定: 59 | 60 | ```bash 61 | docker compose exec app cp .env.local .env 62 | ``` 63 | 64 | 使用`artisan`Laravel 命令列工具設定加密金鑰: 65 | 66 | ```bash 67 | docker compose exec app ./artisan key:generate --ansi 68 | ``` 69 | 70 | 遷移資料庫和種子假資料: 71 | 72 | ```bash 73 | docker compose exec app ./artisan migrate:fresh --seed 74 | ``` 75 | 76 | 並新增 Filament 管理員使用者: 77 | 78 | ```bash 79 | docker compose exec app ./artisan make:filament-user 80 | ``` 81 | 82 | 然後在您喜歡的瀏覽器中開啟 http://127.0.0.1:8000。 祝您使用 Laravel 部落格愉快! 83 | 84 | ## 如何進入容器內部? 85 | 86 | 存取Docker容器: 87 | 88 | ```bash 89 | docker exec -ti laravel-blog-app bash 90 | ``` 91 | 92 | ## 執照 93 | 94 | 這是根據 [MIT 許可證](https://github.com/gomzyakov/php-code-style/blob/main/LICENSE) 授權的開源軟體。 95 | 96 | 97 | [![GitHub 發表](https://img.shields.io/github/release/gomzyakov/laravel-blog.svg)](https://github.com/gomzyakov/laravel-blog/releases/latest) 98 | [![許可證](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/gomzyakov/laravel-blog/blob/development/LICENSE) 99 | [![codecov](https://codecov.io/gh/gomzyakov/laravel-blog/branch/main/graph/badge.svg?token=4CYTVMVUYV)](https://codecov.io/gh/gomzyakov/ Laravel 部落格) 100 | -------------------------------------------------------------------------------- /resources/views/personal/liked/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-personal', ['title' => 'My personal blog']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |

8 | Liked posts 9 |

10 |
11 | 12 | 13 |
14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | @foreach($posts as $post) 27 | 28 | 29 | 30 | 49 | 50 | @endforeach 51 | 52 | 53 |
IDPost titleActions
{{ $post->id }}{{ $post->title }} 31 |
32 | 33 | 35 | View 36 | 37 | 38 | 39 |
40 | @csrf 41 | @method('delete') 42 | 46 |
47 |
48 |
54 |
55 | 56 |
57 | 58 |
59 | @endsection -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel/laravel", 3 | "type": "project", 4 | "description": "Blog on Laravel", 5 | "keywords": ["blog", "laravel"], 6 | "license": "MIT", 7 | "require": { 8 | "php": "^8.4", 9 | "ext-intl": "*", 10 | "ext-gd": "*", 11 | "gomzyakov/image-placeholder": "^1.0", 12 | "laravel/framework": "^11.9", 13 | "laravel/tinker": "^2.10.0", 14 | "laravel/ui": "^4.5", 15 | "spatie/laravel-permission": "^6.4" 16 | }, 17 | "require-dev": { 18 | "fakerphp/faker": "^1.23.1", 19 | "friendsofphp/php-cs-fixer": "^3.53", 20 | "gomzyakov/code-style": "^2.1", 21 | "mockery/mockery": "^1.6", 22 | "nunomaduro/collision": "^8.0", 23 | "phpstan/phpstan": "^1.10", 24 | "phpunit/phpunit": "^11.0.1", 25 | "rector/rector": "1.2.10", 26 | "spatie/laravel-ignition": "^2.5" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "App\\": "app/", 31 | "Database\\Factories\\": "database/factories/", 32 | "Database\\Seeders\\": "database/seeders/" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "Tests\\": "tests/" 38 | } 39 | }, 40 | "scripts": { 41 | "phpunit": "@php ./vendor/bin/phpunit ./tests --no-coverage --color=always", 42 | "phpstan": "@php ./vendor/bin/phpstan analyze -c ./phpstan.neon.dist --no-progress --ansi --verbose", 43 | "fix": "@php ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php", 44 | "cs-check": "@php ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --dry-run --diff", 45 | "rector": "@php ./vendor/bin/rector process", 46 | "rector-check": "@php ./vendor/bin/rector process --dry-run", 47 | "test": [ 48 | "@cs-check", 49 | "@phpstan", 50 | "@rector-check", 51 | "@phpunit" 52 | ], 53 | "post-autoload-dump": [ 54 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", 55 | "@php artisan package:discover --ansi" 56 | ], 57 | "post-update-cmd": [ 58 | "@php artisan vendor:publish --tag=laravel-assets --ansi --force" 59 | ], 60 | "post-root-package-install": [ 61 | "@php -r \"file_exists('.env') || copy('.env.local', '.env');\"" 62 | ], 63 | "post-create-project-cmd": [ 64 | "@php ./artisan key:generate --ansi" 65 | ] 66 | }, 67 | "extra": { 68 | "laravel": { 69 | "dont-discover": [ 70 | "barryvdh/laravel-ide-helper" 71 | ] 72 | } 73 | }, 74 | "config": { 75 | "optimize-autoloader": true, 76 | "preferred-install": "dist", 77 | "sort-packages": true, 78 | "allow-plugins": { 79 | "pestphp/pest-plugin": true, 80 | "php-http/discovery": true 81 | } 82 | }, 83 | "minimum-stability": "stable", 84 | "prefer-stable": true 85 | } 86 | -------------------------------------------------------------------------------- /resources/views/personal/comment/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-personal', ['title' => 'My personal blog']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |

8 | Comments 9 |

10 |
11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | @foreach($comments as $comment) 27 | 28 | 29 | 30 | 31 | 50 | 51 | @endforeach 52 | 53 |
IDCommentPost titleActions
{{ $comment->id }}{{ $comment->message }}{{ $comment->post->title }} 32 |
33 | 34 | 36 | Edit 37 | 38 | 39 | 40 |
41 | @csrf 42 | @method('delete') 43 | 47 |
48 |
49 |
54 |
55 | 56 |
57 | 58 |
59 | @endsection -------------------------------------------------------------------------------- /translations/README.ko.md: -------------------------------------------------------------------------------- 1 | >[!IMPORTANT] 2 | >This file needs to updated in order to match the [english](/README.md) README file. 3 | >[영어](/README.md) README 파일과 일치하려면 이 파일을 업데이트해야 합니다. 4 | 5 | ![Filament 관리 패널이 포함된 Laravel 블로그](../docs/social-preview-en.png) 6 | 7 | _Read this in [other languages](./Translations.md)_ 8 | 9 | >This file is automatically translated. If you notice an error, please correct it yourself (by making a PR) or write about it in the [issues](https://github.com/gomzyakov/laravel-blog/issues). 10 | 11 | # 필라멘트 관리 패널이 있는 Laravel 블로그 12 | 13 | 이것은 [Filament](https://ilavelphp.com) 관리자 패널이 포함된 [Laravel](https://laravel.com) 블로그 스타터 키트 프로젝트입니다. 14 | 15 | 이 저장소의 목표는 간단한 애플리케이션으로 좋은 [Laravel](https://laravel.com) 개발 사례를 보여주는 것입니다. 16 | 17 | ## 특징 18 | 19 | - 📚 게시물 작성 및 편집 20 | - 🥑 카테고리 21 | - 🔥 인기 게시물 22 | - 🎉 [Filament](https://pillamentphp.com)를 기반으로 구축된 관리자 패널 23 | 24 | ## 기능 요청 중 25 | 26 | 기능을 요청하려면(또는 버그를 발견한 경우) [새 문제](https://github.com/gomzyakov/laravel-blog/issues/new)를 엽니다. 27 | 28 | ## 블로그를 로컬에서 어떻게 운영하나요? 29 | 30 | 프로젝트를 복제합니다. 31 | 32 | ```bash 33 | git clone git@github.com:gomzyakov/laravel-blog.git 34 | ``` 35 | 36 | 이미 Docker가 설치되어 있다고 생각합니다. 그렇지 않다면 [Mac](https://docs.docker.com/desktop/install/mac-install/), [Windows](https://docs.docker.com/desktop/install/windows)에서 하세요. -install/) 또는 [Linux](https://docs.docker.com/desktop/install/linux-install/). 37 | 38 | 다음 명령을 사용하여 `laravel-blog` 이미지를 빌드합니다. 39 | 40 | ```bash 41 | docker compose build --no-cache 42 | ``` 43 | 44 | >이 명령을 완료하는 데 몇 분 정도 걸릴 수 있습니다. 45 | 46 | 빌드가 완료되면 다음을 사용하여 백그라운드 모드에서 환경을 실행할 수 있습니다. 47 | 48 | ```bash 49 | docker compose up -d 50 | ``` 51 | 52 | 이제 `composer install`을 실행하여 애플리케이션 종속성을 설치하겠습니다. 53 | 54 | ```bash 55 | docker compose exec app composer install 56 | ``` 57 | 58 | 환경 설정을 복사합니다. 59 | 60 | ```bash 61 | docker compose exec app cp .env.local .env 62 | ``` 63 | 64 | `artisan` Laravel 명령줄 도구를 사용하여 암호화 키를 설정하세요. 65 | 66 | ```bash 67 | docker compose exec app ./artisan key:generate --ansi 68 | ``` 69 | 70 | DB 마이그레이션 및 가짜 데이터 시드: 71 | 72 | ```bash 73 | docker compose exec app ./artisan migrate:fresh --seed 74 | ``` 75 | 76 | 그리고 Filament 관리자를 추가하세요: 77 | 78 | ```bash 79 | docker compose exec app ./artisan make:filament-user 80 | ``` 81 | 82 | 그리고 즐겨 사용하는 브라우저에서 http://127.0.0.1:8000을 엽니다. Laravel 블로그를 이용해 주셔서 감사합니다! 83 | 84 | ## 컨테이너 안으로 어떻게 들어가나요? 85 | 86 | Docker 컨테이너에 액세스: 87 | 88 | ```bash 89 | docker exec -ti laravel-blog-app bash 90 | ``` 91 | 92 | ## 라이선스 93 | 94 | 이는 [MIT 라이선스](https://github.com/gomzyakov/php-code-style/blob/main/LICENSE)에 따라 라이선스가 부여된 오픈 소스 소프트웨어입니다. 95 | 96 | 97 | [![GitHub 릴리스](https://img.shields.io/github/release/gomzyakov/laravel-blog.svg)](https://github.com/gomzyakov/laravel-blog/releases/latest) 98 | [![라이선스](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/gomzyakov/laravel-blog/blob/development/LICENSE) 99 | [![codecov](https://codecov.io/gh/gomzyakov/laravel-blog/branch/main/graph/badge.svg?token=4CYTVMVUYV)](https://codecov.io/gh/gomzyakov/ laravel 블로그) 100 | -------------------------------------------------------------------------------- /translations/README.ja.md: -------------------------------------------------------------------------------- 1 | >[!IMPORTANT] 2 | >This file needs to updated in order to match the [english](/README.md) README file. 3 | >[英語](/README.md) README ファイルと一致させるには、このファイルを更新する必要があります。 4 | 5 | ![Filament 管理パネルを備えた Laravel ブログ](../docs/social-preview-en.png) 6 | 7 | _Read this in [other languages](./Translations.md)_ 8 | 9 | >This file is automatically translated. If you notice an error, please correct it yourself (by making a PR) or write about it in the [issues](https://github.com/gomzyakov/laravel-blog/issues). 10 | 11 | # Filament 管理パネルを備えた Laravel ブログ 12 | 13 | これは、[Filament](https://filamentphp.com) 管理パネルを備えた [Laravel](https://laravel.com) ブログ スターター キット プロジェクトです。 14 | 15 | このリポジトリの目標は、単純なアプリケーションを使用した優れた [Laravel](https://laravel.com) 開発実践を紹介することです。 16 | 17 | ## 特徴 18 | 19 | - 📚 投稿の作成と編集 20 | - 🥑 カテゴリ 21 | - 🔥 人気の投稿 22 | - 🎉 [Filament](https://filamentphp.com) 上に構築された管理パネル 23 | 24 | ## 機能のリクエスト 25 | 26 | [新しい問題](https://github.com/gomzyakov/laravel-blog/issues/new) を開いて機能をリクエストします (またはバグを見つけた場合)。 27 | 28 | ## ブログをローカルで実行するにはどうすればよいですか? 29 | 30 | プロジェクトのクローンを作成します。 31 | 32 | ```bash 33 | git clone git@github.com:gomzyakov/laravel-blog.git 34 | ``` 35 | 36 | すでに Docker がインストールされていると思います。 そうでない場合は、[Mac](https://docs.docker.com/desktop/install/mac-install/)、[Windows](https://docs.docker.com/desktop/install/windows)で実行してください。 -install/) または [Linux](https://docs.docker.com/desktop/install/linux-install/)。 37 | 38 | 次のコマンドを使用して「laravel-blog」イメージをビルドします。 39 | 40 | ```bash 41 | docker compose build --no-cache 42 | ``` 43 | 44 | >このコマンドが完了するまでに数分かかる場合があります。 45 | 46 | ビルドが完了したら、次のコマンドを使用して環境をバックグラウンド モードで実行できます。 47 | 48 | ```bash 49 | docker compose up -d 50 | ``` 51 | 52 | ここで `composer install`を実行して、アプリケーションの依存関係をインストールします。 53 | 54 | ```bash 55 | docker compose exec app composer install 56 | ``` 57 | 58 | 環境設定をコピーします。 59 | 60 | ```bash 61 | docker compose exec app cp .env.local .env 62 | ``` 63 | 64 | `artisan` Laravel コマンドライン ツールを使用して暗号化キーを設定します。 65 | 66 | ```bash 67 | docker compose exec app ./artisan key:generate --ansi 68 | ``` 69 | 70 | DB を移行して偽のデータをシードする: 71 | 72 | ```bash 73 | docker compose exec app ./artisan migrate:fresh --seed 74 | ``` 75 | 76 | 77 | そして、Filament 管理者ユーザーを追加します。 78 | 79 | ```bash 80 | docker compose exec app ./artisan make:filament-user 81 | ``` 82 | 83 | そして、お気に入りのブラウザで http://127.0.0.1:8000 を開きます。 Laravel ブログをぜひご利用ください。 84 | 85 | ## コンテナ内に入るにはどうすればよいですか? 86 | 87 | Docker コンテナへのアクセス: 88 | 89 | ```bash 90 | docker exec -ti laravel-blog-app bash 91 | ``` 92 | 93 | ## ライセンス 94 | 95 | これは、[MIT ライセンス](https://github.com/gomzyakov/php-code-style/blob/main/LICENSE) に基づいてライセンス供与されたオープンソース ソフトウェアです。 96 | 97 | 98 | [![GitHub リリース](https://img.shields.io/github/release/gomzyakov/laravel-blog.svg)](https://github.com/gomzyakov/laravel-blog/releases/latest) 99 | [![ライセンス](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/gomzyakov/laravel-blog/blob/development/LICENSE) 100 | [![codecov](https://codecov.io/gh/gomzyakov/laravel-blog/branch/main/graph/badge.svg?token=4CYTVMVUYV)](https://codecov.io/gh/gomzyakov/ laravelブログ) 101 | -------------------------------------------------------------------------------- /public/assets/js/admin/color-modes.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/) 3 | * Copyright 2011-2024 The Bootstrap Authors 4 | * Licensed under the Creative Commons Attribution 3.0 Unported License. 5 | */ 6 | 7 | (() => { 8 | 'use strict' 9 | 10 | const getStoredTheme = () => localStorage.getItem('theme') 11 | const setStoredTheme = theme => localStorage.setItem('theme', theme) 12 | 13 | const getPreferredTheme = () => { 14 | const storedTheme = getStoredTheme() 15 | if (storedTheme) { 16 | return storedTheme 17 | } 18 | 19 | return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' 20 | } 21 | 22 | const setTheme = theme => { 23 | if (theme === 'auto') { 24 | document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')) 25 | } else { 26 | document.documentElement.setAttribute('data-bs-theme', theme) 27 | } 28 | } 29 | 30 | setTheme(getPreferredTheme()) 31 | 32 | const showActiveTheme = (theme, focus = false) => { 33 | const themeSwitcher = document.querySelector('#bd-theme') 34 | 35 | if (!themeSwitcher) { 36 | return 37 | } 38 | 39 | const themeSwitcherText = document.querySelector('#bd-theme-text') 40 | const activeThemeIcon = document.querySelector('.theme-icon-active use') 41 | const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`) 42 | const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href') 43 | 44 | document.querySelectorAll('[data-bs-theme-value]').forEach(element => { 45 | element.classList.remove('active') 46 | element.setAttribute('aria-pressed', 'false') 47 | }) 48 | 49 | btnToActive.classList.add('active') 50 | btnToActive.setAttribute('aria-pressed', 'true') 51 | activeThemeIcon.setAttribute('href', svgOfActiveBtn) 52 | const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})` 53 | themeSwitcher.setAttribute('aria-label', themeSwitcherLabel) 54 | 55 | if (focus) { 56 | themeSwitcher.focus() 57 | } 58 | } 59 | 60 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { 61 | const storedTheme = getStoredTheme() 62 | if (storedTheme !== 'light' && storedTheme !== 'dark') { 63 | setTheme(getPreferredTheme()) 64 | } 65 | }) 66 | 67 | window.addEventListener('DOMContentLoaded', () => { 68 | showActiveTheme(getPreferredTheme()) 69 | 70 | document.querySelectorAll('[data-bs-theme-value]') 71 | .forEach(toggle => { 72 | toggle.addEventListener('click', () => { 73 | const theme = toggle.getAttribute('data-bs-theme-value') 74 | setStoredTheme(theme) 75 | setTheme(theme) 76 | showActiveTheme(theme, true) 77 | }) 78 | }) 79 | }) 80 | })() 81 | -------------------------------------------------------------------------------- /resources/views/layouts/wrapper/_navbar.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 11 |
12 | @auth 13 | 39 | @else 40 | 42 | Log in 43 | 44 | @endauth 45 |
46 |
47 |
48 | 49 | 56 |
-------------------------------------------------------------------------------- /tests/Feature/ProfileXest.php: -------------------------------------------------------------------------------- 1 | create(); 21 | 22 | $response = $this 23 | ->actingAs($user) 24 | ->get('/profile'); 25 | 26 | $response->assertOk(); 27 | } 28 | 29 | public function test_profile_information_can_be_updated(): void 30 | { 31 | /** @var User $user */ 32 | $user = User::factory()->create(); 33 | 34 | $response = $this 35 | ->actingAs($user) 36 | ->patch('/profile', [ 37 | 'name' => 'Test User', 38 | 'email' => 'test@example.com', 39 | ]); 40 | 41 | $response 42 | ->assertSessionHasNoErrors() 43 | ->assertRedirect('/profile'); 44 | 45 | $user->refresh(); 46 | 47 | $this->assertSame('Test User', $user->name); 48 | $this->assertSame('test@example.com', $user->email); 49 | $this->assertNull($user->email_verified_at); 50 | } 51 | 52 | public function test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged(): void 53 | { 54 | /** @var User $user */ 55 | $user = User::factory()->create(); 56 | 57 | $response = $this 58 | ->actingAs($user) 59 | ->patch('/profile', [ 60 | 'name' => 'Test User', 61 | 'email' => $user->email, 62 | ]); 63 | 64 | $response 65 | ->assertSessionHasNoErrors() 66 | ->assertRedirect('/profile'); 67 | 68 | $this->assertNotNull($user->refresh()->email_verified_at); 69 | } 70 | 71 | public function test_user_can_delete_their_account(): void 72 | { 73 | $user = User::factory()->create(); 74 | 75 | $response = $this 76 | ->actingAs($user) 77 | ->delete('/profile', [ 78 | 'password' => 'password', 79 | ]); 80 | 81 | $response 82 | ->assertSessionHasNoErrors() 83 | ->assertRedirect('/'); 84 | 85 | $this->assertGuest(); 86 | $this->assertNull($user->fresh()); 87 | } 88 | 89 | public function test_correct_password_must_be_provided_to_delete_account(): void 90 | { 91 | $user = User::factory()->create(); 92 | 93 | $response = $this 94 | ->actingAs($user) 95 | ->from('/profile') 96 | ->delete('/profile', [ 97 | 'password' => 'wrong-password', 98 | ]); 99 | 100 | $response 101 | ->assertSessionHasErrorsIn('userDeletion', 'password') 102 | ->assertRedirect('/profile'); 103 | 104 | $this->assertNotNull($user->fresh()); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /translations/README.am.md: -------------------------------------------------------------------------------- 1 | >[!IMPORTANT] 2 | >This file needs to updated in order to match the [english](/README.md) README file. 3 | >ይህ ፋይል ከ[እንግሊዝኛ](/README.md) README ፋይል ጋር እንዲዛመድ መዘመን አለበት። 4 | 5 | ![ላራቬል ብሎግ ከፋላመንት አስተዳዳሪ ፓነል ጋር](../docs/social-preview-en.png) 6 | 7 | _Read this in [other languages](./Translations.md)_ 8 | 9 | >This file is automatically translated. If you notice an error, please correct it yourself (by making a PR) or write about it in the [issues](https://github.com/gomzyakov/laravel-blog/issues). 10 | 11 | # የላራቭል ብሎግ ከፋይላመንት አስተዳዳሪ ፓነል ጋር 12 | 13 | ይህ [ላራቬል](https://laravel.com) የብሎግ ጀማሪ ኪት ፕሮጀክት ከ[Filament](https://filamentphp.com) የአስተዳዳሪ ፓነል ጋር ነው። 14 | 15 | የዚህ ማከማቻ ግብ ጥሩ [ላራቬል](https://laravel.com) የልማት ልምዶችን በቀላል መተግበሪያ ማሳየት ነው። 16 | 17 | ## ዋና መለያ ጸባያት 18 | 19 | - 📚 ልጥፎችን መፍጠር እና ማስተካከል 20 | - 🥑 ምድቦች 21 | - 🔥 ታዋቂ ልጥፎች 22 | - 🎉 የአስተዳዳሪ ፓነል በ [Filament] (https://filamentphp.com) ላይ የተገነባ 23 | 24 | ## የመጠየቅ ባህሪዎች 25 | 26 | ባህሪን ለመጠየቅ (ወይም ሳንካ ካገኙ) [አዲስ እትም](https://github.com/gomzyakov/laravel-blog/issues/new) ይክፈቱ። 27 | 28 | ## ብሎግ በአገር ውስጥ እንዴት እንደሚሰራ? 29 | 30 | ፕሮጀክቱን መዝጋት; 31 | 32 | ```bash 33 | git clone git@github.com:gomzyakov/laravel-blog.git 34 | ``` 35 | 36 | አስቀድመህ Docker እንደተጫነህ አምናለሁ። ካልሆነ፣ ልክ በ[Mac](https://docs.docker.com/desktop/install/mac-install/)፣ [Windows](https://docs.docker.com/desktop/install/windows) ላይ ያድርጉት። -install/) ወይም [Linux](https://docs.docker.com/desktop/install/linux-install/)። 37 | 38 | በሚከተለው ትዕዛዝ የ«ላራቬል-ብሎግ» ምስልን ይገንቡ፡ 39 | 40 | ```bash 41 | docker compose build --no-cache 42 | ``` 43 | 44 | > ይህ ትእዛዝ ለማጠናቀቅ ጥቂት ደቂቃዎችን ሊወስድ ይችላል። 45 | 46 | ግንባታው ሲጠናቀቅ አካባቢውን በበስተጀርባ ሁነታ ማስኬድ ይችላሉ፡- 47 | 48 | ```bash 49 | docker compose up -d 50 | ``` 51 | 52 | የመተግበሪያውን ጥገኞች ለመጫን አሁን `composer install`ን እናስሄዳለን፡- 53 | 54 | ```bash 55 | docker compose exec app composer install 56 | ``` 57 | 58 | የአካባቢ ቅንብሮችን ይቅዱ 59 | 60 | ```bash 61 | docker compose exec app cp .env.local .env 62 | ``` 63 | 64 | የምስጠራ ቁልፍን በ `artisan` Laravel የትዕዛዝ መስመር መሣሪያ ያቀናብሩ፡ 65 | 66 | ```bash 67 | docker compose exec app ./artisan key:generate --ansi 68 | ``` 69 | 70 | ዲቢን እና የውሸት ዘርን ያዛውሩ 71 | 72 | ```bash 73 | docker compose exec app ./artisan migrate:fresh --seed 74 | ``` 75 | 76 | እና የFilament አስተዳዳሪ ተጠቃሚን ያክሉ፡- 77 | 78 | ```ባሽ 79 | docker compose exec መተግበሪያ ./artisan make:filament-user 80 | ``` 81 | 82 | እና በሚወዱት አሳሽ ውስጥ http://127.0.0.1:8000 ን ይክፈቱ። የላራቬል ብሎግ በመጠቀም ደስተኛ ነኝ! 83 | 84 | ## ወደ መያዣው ውስጥ እንዴት መግባት ይቻላል? 85 | 86 | ወደ ዶከር መያዣው መድረስ; 87 | 88 | ```bash 89 | docker exec -ti laravel-blog-app bash 90 | ``` 91 | 92 | ## ፈቃድ 93 | 94 | ይህ በ[MIT ፈቃድ](https://github.com/gomzyakov/php-code-style/blob/main/LICENSE) ስር ፈቃድ ያለው ክፍት ምንጭ ሶፍትዌር ነው። 95 | 96 | 97 | [![GitHub ልቀት](https://img.shields.io/github/release/gomzyakov/laravel-blog.svg)](https://github.com/gomzyakov/laravel-blog/releases/latest) 98 | [![license](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/gomzyakov/laravel-blog/blob/development/LICENSE) 99 | [![codecov](https://codecov.io/gh/gomzyakov/laravel-blog/branch/main/graph/badge.svg?token=4CYTVMVUYV)](https://codecov.io/gh/gomzyakov/ ላራቬል-ብሎግ) 100 | -------------------------------------------------------------------------------- /translations/README.ar.md: -------------------------------------------------------------------------------- 1 | >[!IMPORTANT] 2 | >This file needs to updated in order to match the [english](/README.md) README file. 3 | >يحتاج هذا الملف إلى التحديث ليطابق ملف README [إنجليزي](/README.md). 4 | 5 | ![مدونة Laravel مع لوحة إدارة Filament](../docs/social-preview-en.png) 6 | 7 | _Read this in [other languages](./Translations.md)_ 8 | 9 | >This file is automatically translated. If you notice an error, please correct it yourself (by making a PR) or write about it in the [issues](https://github.com/gomzyakov/laravel-blog/issues). 10 | 11 | # مدونة Laravel مع لوحة إدارة Filament 12 | 13 | هذا هو مشروع مجموعة أدوات مدونة [Laravel](https://laravel.com) مع لوحة إدارة [Filament](https://filamentphp.com). 14 | 15 | الهدف من هذا المستودع هو عرض ممارسات تطوير [Laravel](https://laravel.com) الجيدة من خلال تطبيق بسيط. 16 | 17 | ## سمات 18 | 19 | - 📚 إنشاء المشاركات وتحريرها 20 | - 🥑 الفئات 21 | - 🔥 المشاركات الشعبية 22 | - 🎉 لوحة إدارة مبنية على [Filament](https://filamentphp.com) 23 | 24 | ## طلب الميزات 25 | 26 | افتح [إصدارًا جديدًا](https://github.com/gomzyakov/laravel-blog/issues/new) لطلب ميزة (أو إذا وجدت خطأً). 27 | 28 | ## كيفية تشغيل المدونة محليًا؟ 29 | 30 | استنساخ المشروع: 31 | 32 | ```bash 33 | git clone git@github.com:gomzyakov/laravel-blog.git 34 | ``` 35 | 36 | أعتقد أنك قمت بالفعل بتثبيت Docker. إذا لم يكن الأمر كذلك، فما عليك سوى القيام بذلك على [Mac](https://docs.docker.com/desktop/install/mac-install/)، [Windows](https://docs.docker.com/desktop/install/windows -install/) أو [Linux](https://docs.docker.com/desktop/install/linux-install/). 37 | 38 | أنشئ صورة `laravel-blog` باستخدام الأمر التالي: 39 | 40 | ```bash 41 | docker compose build --no-cache 42 | ``` 43 | 44 | >قد يستغرق هذا الأمر بضع دقائق حتى يكتمل. 45 | 46 | عند الانتهاء من الإنشاء، يمكنك تشغيل البيئة في وضع الخلفية باستخدام: 47 | 48 | ```bash 49 | docker compose up -d 50 | ``` 51 | 52 | سنقوم الآن بتشغيل برنامج `composer install` لتثبيت تبعيات التطبيق: 53 | 54 | ```bash 55 | docker compose exec app composer install 56 | ``` 57 | 58 | انسخ إعدادات البيئة: 59 | 60 | ```bash 61 | docker compose exec app cp .env.local .env 62 | ``` 63 | 64 | قم بتعيين مفتاح التشفير باستخدام أداة سطر الأوامر `artisan` Laravel: 65 | 66 | ```bash 67 | docker compose exec app ./artisan key:generate --ansi 68 | ``` 69 | 70 | ترحيل قاعدة البيانات والبيانات المزيفة: 71 | 72 | ```bash 73 | docker compose exec app ./artisan migrate:fresh --seed 74 | ``` 75 | 76 | وافتح http://127.0.0.1:8000 في متصفحك المفضل. سعيد باستخدام مدونة Laravel! 77 | 78 | ## كيفية الدخول إلى الحاوية؟ 79 | 80 | الوصول إلى حاوية Docker: 81 | 82 | ```bash 83 | docker exec -ti laravel-blog-app bash 84 | ``` 85 | 86 | ## رخصة 87 | 88 | هذا برنامج مفتوح المصدر مرخص بموجب [ترخيص MIT](https://github.com/gomzyakov/php-code-style/blob/main/LICENSE). 89 | 90 | 91 | [![إصدار GitHub](https://img.shields.io/github/release/gomzyakov/laravel-blog.svg)](https://github.com/gomzyakov/laravel-blog/releases/latest) 92 | [![الترخيص](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/gomzyakov/laravel-blog/blob/development/LICENSE) 93 | [![codecov](https://codecov.io/gh/gomzyakov/laravel-blog/branch/main/graph/badge.svg?token=4CYTVMVUYV)](https://codecov.io/gh/gomzyakov/ مدونة لارافيل) 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple blog application based on Laravel 2 | 3 | The goal of this repository is to showcase good [Laravel](https://laravel.com) development practices with a simple application. 4 | 5 | _Read this `README.md` in [other languages](./translations/Translations.md)._ 6 | 7 | >[!IMPORTANT] 8 | >This project is under development. Not all functionality is finished and much can still be improved. If you want to help with the development of the project, you can select an [issue](https://github.com/gomzyakov/laravel-blog/issues), do it and open a PR. 9 | 10 | ## Features 11 | 12 | - 📚 Creating and editing posts 13 | - 🥑 Categories 14 | - 🔥 Popular posts 15 | - 🎉 Admin panel 16 | - 🔧 Manage users, posts, categories and tags 17 | - 👥 Roles: reader and administrator 18 | - 🔐 Personal account 19 | - 💬 Comments and likes 20 | - 🖋️ Post`s visual editor 21 | 22 | ## Preview 23 | 24 | ![Laravel blog main page](docs/screenshot-main-page.png) 25 | 26 | ## Requesting features 27 | 28 | Open a new [issue](https://github.com/gomzyakov/laravel-blog/issues) to request a feature (or if you find a bug). 29 | 30 | ## How to run blog locally? 31 | 32 | Clone the project: 33 | 34 | ```bash 35 | git clone git@github.com:gomzyakov/laravel-blog.git 36 | ``` 37 | 38 | I believe you already have Docker installed. If not, just do it on [Mac](https://docs.docker.com/desktop/install/mac-install/), [Windows](https://docs.docker.com/desktop/install/windows-install/) or [Linux](https://docs.docker.com/desktop/install/linux-install/). 39 | 40 | Copy the environment settings: 41 | 42 | ```bash 43 | cp .env.local .env 44 | ``` 45 | 46 | Build the `laravel-blog` image with the following command: 47 | 48 | ```bash 49 | docker compose build --no-cache 50 | ``` 51 | 52 | >This command might take a few minutes to complete. 53 | 54 | When the build is finished, you can run the environment in background mode with: 55 | 56 | ```bash 57 | docker compose up -d 58 | ``` 59 | 60 | We’ll now run `composer install` to install the application dependencies: 61 | 62 | ```bash 63 | docker compose exec app composer install 64 | ``` 65 | 66 | Set encryption key with the `artisan` Laravel command-line tool: 67 | 68 | ```bash 69 | docker compose exec app ./artisan key:generate --ansi 70 | ``` 71 | 72 | Migrate DB & seed fake data: 73 | 74 | ```bash 75 | docker compose exec app ./artisan migrate:fresh --seed 76 | ``` 77 | 78 | And open http://127.0.0.1:8000 in your favorite browser. Happy using Laravel Blog! 79 | 80 | ## How to get inside the container? 81 | 82 | Access to the Docker container: 83 | 84 | ```bash 85 | docker exec -ti laravel-blog-app bash 86 | ``` 87 | 88 | ## License 89 | 90 | This is open-sourced software licensed under the [MIT License](https://github.com/gomzyakov/php-code-style/blob/main/LICENSE). 91 | 92 | 93 | [![GitHub release](https://img.shields.io/github/release/gomzyakov/laravel-blog.svg)](https://github.com/gomzyakov/laravel-blog/releases/latest) 94 | [![license](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/gomzyakov/laravel-blog/blob/development/LICENSE) 95 | [![codecov](https://codecov.io/gh/gomzyakov/laravel-blog/branch/main/graph/badge.svg?token=4CYTVMVUYV)](https://codecov.io/gh/gomzyakov/laravel-blog) 96 | -------------------------------------------------------------------------------- /resources/views/auth/passwords/reset.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-auth') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Сброс пароля') }}
9 | 10 |
11 |
12 | @csrf 13 | 14 | 15 | 16 |
17 | 18 | 19 |
20 | 21 | 22 | @error('email') 23 | 24 | {{ $message }} 25 | 26 | @enderror 27 |
28 |
29 | 30 |
31 | 32 | 33 |
34 | 35 | 36 | @error('password') 37 | 38 | {{ $message }} 39 | 40 | @enderror 41 |
42 |
43 | 44 |
45 | 46 | 47 |
48 | 49 |
50 |
51 | 52 |
53 |
54 | 57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | @endsection 66 | -------------------------------------------------------------------------------- /translations/README.igb.md: -------------------------------------------------------------------------------- 1 | >[!IMPORTANT] 2 | >This file needs to updated in order to match the [english](/README.md) README file. 3 | >Ekwesịrị imelite faịlụ a ka ọ dabara na faịlụ README [bekee](/README.md) 4 | 5 | ![Blọọgụ Laravel nwere panel nchịkwa Filament](../docs/social-preview-en.png) 6 | 7 | _Read this in [other languages](./Translations.md)_ 8 | 9 | >This file is automatically translated. If you notice an error, please correct it yourself (by making a PR) or write about it in the [issues](https://github.com/gomzyakov/laravel-blog/issues). 10 | 11 | # Laravel blọọgụ nwere panel nchịkwa Filament 12 | 13 | Nke a bụ [Laravel](https://laravel.com) blọgụ mmalite kit oru ngo nwere [Filament](https://filamentphp.com) nchịkwa nchịkwa. 14 | 15 | Ebumnuche nke ebe nchekwa a bụ igosi ezi omume mmepe [Laravel](https://laravel.com) site na iji ngwa dị mfe. 16 | 17 | ## Akụkụ 18 | 19 | - 📚 Mepụta na dezie posts 20 | - 🥑 ngalaba 21 | - 🔥 Ederede ndị ama ama 22 | - 🎉 Ogwe nchịkwa wuru na [Filament](https://filamentphp.com) 23 | 24 | ## Arịrịọ atụmatụ 25 | 26 | Mepee [okwu ọhụrụ](https://github.com/gomzyakov/laravel-blog/issues/new) iji rịọ atụmatụ (ma ọ bụ ọ bụrụ na ịchọta ahụhụ). 27 | 28 | ## Kedu ka esi agba blọgụ na mpaghara? 29 | 30 | Mechie oru ngo: 31 | 32 | ```bash 33 | git clone git@github.com:gomzyakov/laravel-blog.git 34 | ``` 35 | 36 | Ekwenyere m na ị tinyela Docker. Ọ bụrụ na ọ bụghị, mee ya na [Mac] (https://docs.docker.com/desktop/install/mac-install/), [Windows](https://docs.docker.com/desktop/install/windows). -install/) ma ọ bụ [Linux] (https://docs.docker.com/desktop/install/linux-install/). 37 | 38 | Jiri iwu a wuo ihe onyonyo `laravel-blog`: 39 | 40 | ```bash 41 | docker compose build --no-cache 42 | ``` 43 | 44 | > Iwu a nwere ike were nkeji ole na ole iji mechaa. 45 | 46 | Mgbe emechara ihe owuwu a, ị nwere ike iji: 47 | 48 | ```bash 49 | docker compose up -d 50 | ``` 51 | 52 | Anyị ga-agba ọsọ `composer install` iji wụnye ndabere ngwa: 53 | 54 | ```bash 55 | docker compose exec app composer install 56 | ``` 57 | 58 | Detuo ntọala gburugburu: 59 | 60 | ```bash 61 | docker compose exec app cp .env.local .env 62 | ``` 63 | 64 | Tọọ igodo nzuzo site na iji ngwa ahịrị iwu `artisan` Laravel: 65 | 66 | ```bash 67 | docker compose exec app ./artisan key:generate --ansi 68 | ``` 69 | 70 | Bugharịa DB & data adịgboroja mkpụrụ: 71 | 72 | ```bash 73 | docker compose exec app ./artisan migrate:fresh --seed 74 | ``` 75 | 76 | Mepee http://127.0.0.1:8000 na ihe nchọgharị kacha amasị gị. Obi ụtọ na-eji Laravel Blog! 77 | 78 | ## Kedu ka esi esi banye n'ime akpa ahụ? 79 | 80 | Ịbanye na akpa Docker: 81 | 82 | ```bash 83 | docker exec -ti laravel-blog-app bash 84 | ``` 85 | 86 | ## Ikikere 87 | 88 | Nke a bụ ngwanrọ mepere emepe nwere ikike n'okpuru [MIT License](https://github.com/gomzyakov/php-code-style/blob/main/LICENSE). 89 | 90 | 91 | [![Ntọhapụ GitHub](https://img.shields.io/github/release/gomzyakov/laravel-blog.svg)](https://github.com/gomzyakov/laravel-blog/releases/latest) 92 | [![akwụkwọ ikike](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/gomzyakov/laravel-blog/blob/development/LICENSE) 93 | [![codecov](https://codecov.io/gh/gomzyakov/laravel-blog/branch/main/graph/badge.svg?token=4CYTVMVUYV)](https://codecov.io/gh/gomzyakov/ laravel-blog) 94 | -------------------------------------------------------------------------------- /translations/README.hb.md: -------------------------------------------------------------------------------- 1 | >[!IMPORTANT] 2 | >This file needs to updated in order to match the [english](/README.md) README file. 3 | >קובץ זה צריך לעדכן כדי להתאים לקובץ README [אנגלית](/README.md). 4 | 5 | ![בלוג Laravel עם פאנל ניהול Filament](../docs/social-preview-en.png) 6 | 7 | _Read this in [other languages](./Translations.md)_ 8 | 9 | >This file is automatically translated. If you notice an error, please correct it yourself (by making a PR) or write about it in the [issues](https://github.com/gomzyakov/laravel-blog/issues). 10 | 11 | # בלוג Laravel עם פאנל ניהול Filament 12 | 13 | זהו פרויקט ערכת ההתחלה של הבלוג [Laravel](https://laravel.com) עם פאנל הניהול של [Filament](https://filamentphp.com). 14 | 15 | המטרה של מאגר זה היא להציג שיטות פיתוח טובות של [Laravel](https://laravel.com) באמצעות אפליקציה פשוטה. 16 | 17 | ## מאפיינים 18 | 19 | - 📚 יצירה ועריכה של פוסטים 20 | - 🥑 קטגוריות 21 | - 🔥 פוסטים פופולריים 22 | - 🎉 פאנל ניהול בנוי על [Filament](https://filamentphp.com) 23 | 24 | ## מבקש תכונות 25 | 26 | פתח [גיליון חדש](https://github.com/gomzyakov/laravel-blog/issues/new) כדי לבקש תכונה (או אם אתה מוצא באג). 27 | 28 | ## איך להפעיל בלוג באופן מקומי? 29 | 30 | שכפול הפרויקט: 31 | 32 | ```bash 33 | git clone git@github.com:gomzyakov/laravel-blog.git 34 | ``` 35 | 36 | אני מאמין שכבר התקנת את Docker. אם לא, פשוט עשה זאת ב-[Mac](https://docs.docker.com/desktop/install/mac-install/), [Windows](https://docs.docker.com/desktop/install/windows -install/) או [Linux](https://docs.docker.com/desktop/install/linux-install/). 37 | 38 | בנה את תמונת `laravel-blog` עם הפקודה הבאה: 39 | 40 | ```bash 41 | docker compose build --no-cache 42 | ``` 43 | 44 | >הפקודה הזו עשויה להימשך מספר דקות. 45 | 46 | לאחר סיום הבנייה, תוכל להפעיל את הסביבה במצב רקע עם: 47 | 48 | ```bash 49 | docker compose up -d 50 | ``` 51 | 52 | כעת נריץ את `composer install` כדי להתקין את התלות באפליקציה: 53 | 54 | ```bash 55 | docker compose exec app composer install 56 | ``` 57 | 58 | העתק את הגדרות הסביבה: 59 | 60 | ```bash 61 | docker compose exec app cp .env.local .env 62 | ``` 63 | 64 | הגדר מפתח הצפנה עם כלי שורת הפקודה 'ארטיזן' Laravel: 65 | 66 | ```bash 67 | docker compose exec app ./artisan key:generate --ansi 68 | ``` 69 | 70 | העבר DB ונתונים מזויפים זרעים: 71 | 72 | ```bash 73 | docker compose exec app ./artisan migrate:fresh --seed 74 | ``` 75 | 76 | והוסף משתמש מנהל Filament: 77 | 78 | ```bash 79 | docker compose exec app ./artisan make:filament-user 80 | ``` 81 | 82 | ופתח את http://127.0.0.1:8000 בדפדפן המועדף עליך. שמח להשתמש בבלוג Laravel! 83 | 84 | ## איך להיכנס למיכל? 85 | 86 | גישה למיכל Docker: 87 | 88 | ```bash 89 | docker exec -ti laravel-blog-app bash 90 | ``` 91 | 92 | ## רישיון 93 | 94 | זוהי תוכנה בקוד פתוח ברישיון [MIT License](https://github.com/gomzyakov/php-code-style/blob/main/LICENSE). 95 | 96 | 97 | [![מהדורת GitHub](https://img.shields.io/github/release/gomzyakov/laravel-blog.svg)](https://github.com/gomzyakov/laravel-blog/releases/latest) 98 | [![רישיון](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/gomzyakov/laravel-blog/blob/development/LICENSE) 99 | [![codecov](https://codecov.io/gh/gomzyakov/laravel-blog/branch/main/graph/badge.svg?token=4CYTVMVUYV)](https://codecov.io/gh/gomzyakov/ laravel-blog) 100 | -------------------------------------------------------------------------------- /resources/views/admin/user/create.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-admin', ['title' => 'User']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |
8 |
9 |
10 |

Добавление пользователя

11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 | @csrf 24 |
25 |
26 | 27 | 29 | @error('name') 30 |
Это поле необходимо заполнить
31 | @enderror 32 |
33 |
34 |
35 |
36 | 37 | 39 | @error('email') 40 |
Это поле необходимо заполнить
41 | @enderror 42 |
43 |
44 |
45 |
46 | 47 | 51 | @error('role') 52 |
Это поле необходимо заполнить
53 | @enderror 54 |
55 |
56 | 57 |
58 |
59 |
60 |
61 |
62 |
63 | @endsection 64 | -------------------------------------------------------------------------------- /resources/views/personal/main/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.wrapper-personal', ['title' => 'My Personal Blog']) 2 | 3 | @section('content') 4 |
5 | 6 |
7 |

Profile

8 |
9 | 10 | 11 |
12 | 13 |
14 |
15 |
16 |
17 |

18 | Liked posts 19 |

20 |
22 | 23 |
24 |
25 |

{{ $data['countLiked'] }}

26 | 28 | Read more 29 | 30 |
31 |
32 |
33 | 34 | 35 |
36 |
37 |
38 |
39 |

40 | Comments 41 |

42 |
44 | 45 |
46 |
47 |

{{ $data['countComments'] }}

48 | 50 | Read more 51 | 52 |
53 |
54 |
55 |
56 |
57 | @endsection 58 | 59 | -------------------------------------------------------------------------------- /translations/README.da.md: -------------------------------------------------------------------------------- 1 | >[!IMPORTANT] 2 | >This file needs to updated in order to match the [english](/README.md) README file. 3 | >Denne fil skal opdateres for at matche [engelsk](/README.md) README-filen. 4 | 5 | ![Laravel blog](../docs/social-preview-en.png) 6 | 7 | _Read this in [other languages](./Translations.md)_ 8 | 9 | >This file is automatically translated. If you notice an error, please correct it yourself (by making a PR) or write about it in the [issues](https://github.com/gomzyakov/laravel-blog/issues). 10 | 11 | # Laravel blog med Filament admin panel 12 | 13 | Dette er [Laravel](https://laravel.com) blog starter kit-projekt med [Filament](https://filamentphp.com) admin panel. 14 | 15 | Målet med dette lager er at fremvise god [Laravel](https://laravel.com) udviklingspraksis med en simpel applikation. 16 | 17 | ## Funktioner 18 | 19 | - 📚 Oprettelse og redigering af indlæg 20 | - 🥑 Kategorier 21 | - 🔥 Populære indlæg 22 | - 🎉 Admin panel bygget på [Filament](https://filamentphp.com) 23 | 24 | ## Anmoder om funktioner 25 | 26 | Åbn en [ny udgave](https://github.com/gomzyakov/laravel-blog/issues/new) for at anmode om en funktion (eller hvis du finder en fejl). 27 | 28 | ## Hvordan kører man en blog lokalt? 29 | 30 | Klon projektet: 31 | 32 | ```bash 33 | git clone git@github.com:gomzyakov/laravel-blog.git 34 | ``` 35 | 36 | Jeg tror, du allerede har Docker installeret. Hvis ikke, skal du bare gøre det på [Mac](https://docs.docker.com/desktop/install/mac-install/), [Windows](https://docs.docker.com/desktop/install/windows -install/) eller [Linux](https://docs.docker.com/desktop/install/linux-install/). 37 | 38 | Byg `laravel-blog`-billedet med følgende kommando: 39 | 40 | ``` bash 41 | docker compose build --no-cache 42 | ``` 43 | 44 | >Denne kommando kan tage et par minutter at fuldføre. 45 | 46 | Når bygningen er færdig, kan du køre miljøet i baggrundstilstand med: 47 | 48 | ``` bash 49 | docker compose up -d 50 | ``` 51 | 52 | Vi kører nu '`composer install` for at installere applikationsafhængighederne: 53 | 54 | ``` bash 55 | docker compose exec app composer install 56 | ``` 57 | 58 | Kopier miljøindstillingerne: 59 | 60 | ``` bash 61 | docker compose exec app cp .env.local .env 62 | ``` 63 | 64 | Indstil krypteringsnøgle med kommandolinjeværktøjet `artisan` Laravel: 65 | 66 | ``` bash 67 | docker compose exec app ./artisan key:generate --ansi 68 | ``` 69 | 70 | Migrer DB og seed falske data: 71 | 72 | ``` bash 73 | docker compose exec app ./artisan migrate:fresh --seed 74 | ``` 75 | 76 | Og åbn http://127.0.0.1:8000 i din yndlingsbrowser. Glad for at bruge Laravel Blog! 77 | 78 | ## Hvordan kommer man ind i containeren? 79 | 80 | Adgang til Docker-containeren: 81 | 82 | ``` bash 83 | docker exec -ti laravel-blog-app bash 84 | ``` 85 | 86 | ## Licens 87 | 88 | Dette er open source software licenseret under [MIT License](https://github.com/gomzyakov/php-code-style/blob/main/LICENSE). 89 | 90 | 91 | [![GitHub release](https://img.shields.io/github/release/gomzyakov/laravel-blog.svg)](https://github.com/gomzyakov/laravel-blog/releases/latest) 92 | [![licens](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/gomzyakov/laravel-blog/blob/development/LICENSE) 93 | [![codecov](https://codecov.io/gh/gomzyakov/laravel-blog/branch/main/graph/badge.svg?token=4CYTVMVUYV)](https://codecov.io/gh/gomzyakov/ laravel-blog) 94 | -------------------------------------------------------------------------------- /translations/README.bn.md: -------------------------------------------------------------------------------- 1 | >[!IMPORTANT] 2 | >This file needs to updated in order to match the [english](/README.md) README file. 3 | >[ইংরেজি](/README.md) README ফাইলের সাথে মেলে এই ফাইলটিকে আপডেট করতে হবে। 4 | 5 | ![ফিলামেন্ট অ্যাডমিন প্যানেল সহ লারাভেল ব্লগ](../docs/social-preview-en.png) 6 | 7 | _Read this in [other languages](./Translations.md)_ 8 | 9 | >This file is automatically translated. If you notice an error, please correct it yourself (by making a PR) or write about it in the [issues](https://github.com/gomzyakov/laravel-blog/issues). 10 | 11 | # ফিলামেন্ট অ্যাডমিন প্যানেল সহ লারাভেল ব্লগ 12 | 13 | এটি হল [Laravel](https://laravel.com) [Filament](https://filamentphp.com) অ্যাডমিন প্যানেলের সাথে ব্লগ স্টার্টার কিট প্রকল্প। 14 | 15 | এই রিপোজিটরির লক্ষ্য হল একটি সহজ অ্যাপ্লিকেশনের মাধ্যমে ভালো [Laravel](https://laravel.com) উন্নয়ন অনুশীলন দেখানো। 16 | 17 | ## বৈশিষ্ট্য 18 | 19 | - 📚 পোস্ট তৈরি করা এবং সম্পাদনা করা 20 | - 🥑 বিভাগ 21 | - 🔥 জনপ্রিয় পোস্ট 22 | - 🎉 [ফিলামেন্ট](https://filamentphp.com) এ তৈরি অ্যাডমিন প্যানেল 23 | 24 | ## বৈশিষ্ট্যগুলি অনুরোধ করা 25 | 26 | একটি বৈশিষ্ট্যের অনুরোধ করতে একটি [নতুন সমস্যা](https://github.com/gomzyakov/laravel-blog/issues/new) খুলুন (অথবা যদি আপনি একটি বাগ খুঁজে পান)। 27 | 28 | ## কিভাবে স্থানীয়ভাবে ব্লগ চালাবেন? 29 | 30 | প্রকল্প ক্লোন করুন: 31 | 32 | ```bash 33 | git clone git@github.com:gomzyakov/laravel-blog.git 34 | ``` 35 | 36 | আমি বিশ্বাস করি আপনি ইতিমধ্যে ডকার ইনস্টল করেছেন। যদি না হয়, শুধু [Mac](https://docs.docker.com/desktop/install/mac-install/), [Windows](https://docs.docker.com/desktop/install/windows) এ এটি করুন -ইনস্টল/) বা [লিনাক্স](https://docs.docker.com/desktop/install/linux-install/)। 37 | 38 | নিম্নলিখিত কমান্ড দিয়ে `laravel-blog` ইমেজ তৈরি করুন: 39 | 40 | ```bash 41 | docker compose build --no-cache 42 | ``` 43 | 44 | > এই কমান্ডটি সম্পূর্ণ হতে কয়েক মিনিট সময় লাগতে পারে। 45 | 46 | বিল্ড শেষ হলে, আপনি এর সাথে পটভূমি মোডে পরিবেশ চালাতে পারেন: 47 | 48 | ```bash 49 | docker compose up -d 50 | ``` 51 | 52 | আমরা এখন অ্যাপ্লিকেশন নির্ভরতা ইনস্টল করতে `composer install` চালাব: 53 | 54 | ```bash 55 | docker compose exec app composer install 56 | ``` 57 | 58 | পরিবেশ সেটিংস অনুলিপি করুন: 59 | 60 | ```bash 61 | docker compose exec app cp .env.local .env 62 | ``` 63 | 64 | `artisan` লারাভেল কমান্ড-লাইন টুল দিয়ে এনক্রিপশন কী সেট করুন: 65 | 66 | ```bash 67 | docker compose exec app ./artisan key:generate --ansi 68 | ``` 69 | 70 | DB এবং বীজ জাল ডেটা মাইগ্রেট করুন: 71 | 72 | ```bash 73 | docker compose exec app ./artisan migrate:fresh --seed 74 | ``` 75 | 76 | এবং আপনার প্রিয় ব্রাউজারে http://127.0.0.1:8000 খুলুন। Laravel ব্লগ ব্যবহার করে খুশি! 77 | 78 | ## কন্টেইনারের ভিতরে কিভাবে প্রবেশ করবেন? 79 | 80 | ডকার কন্টেইনারে অ্যাক্সেস: 81 | 82 | ```bash 83 | docker exec -ti laravel-blog-app bash 84 | ``` 85 | 86 | ## লাইসেন্স 87 | 88 | এটি [MIT লাইসেন্স](https://github.com/gomzyakov/php-code-style/blob/main/LICENSE) এর অধীনে লাইসেন্সকৃত ওপেন-সোর্স সফ্টওয়্যার। 89 | 90 | 91 | [![GitHub প্রকাশ](https://img.shields.io/github/release/gomzyakov/laravel-blog.svg)](https://github.com/gomzyakov/laravel-blog/releases/latest) 92 | [![লাইসেন্স](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/gomzyakov/laravel-blog/blob/development/LICENSE) 93 | [![codecov](https://codecov.io/gh/gomzyakov/laravel-blog/branch/main/graph/badge.svg?token=4CYTVMVUYV)](https://codecov.io/gh/gomzyakov/ লারাভেল-ব্লগ) 94 | --------------------------------------------------------------------------------