From 4926a63e69dcc48bb86887723dfe064b216de89b Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Mon, 29 May 2017 14:37:02 +0000 Subject: [PATCH 01/78] Update TODO.md --- TODO.md | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO.md b/TODO.md index 7fba86d..f81c8d7 100644 --- a/TODO.md +++ b/TODO.md @@ -13,6 +13,7 @@ - [ ] Wechat related - [ ] Schedule(backup,stat,) - [ ] I18N +- [ ] Highlight tab ## Frontend From c5eb7c6f84ba8ad9d1e9c9d264c44a8241993a03 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 30 May 2017 07:13:24 +0000 Subject: [PATCH 02/78] Update Post model --- app/Models/Post.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/Models/Post.php b/app/Models/Post.php index f1cee40..9f0154f 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -21,6 +21,11 @@ class Post extends Model 'content' ]; + /** + * @var array + */ + protected $dates = ['published_at']; + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ From 5a70818467c4fc3ed79f6383e7f7026a67c67845 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 30 May 2017 08:48:51 +0000 Subject: [PATCH 03/78] Composer require laracasts/presenter --- composer.json | 1 + composer.lock | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 484fd6f..bf6e429 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,7 @@ "type": "project", "require": { "php": ">=5.6.4", + "laracasts/presenter": "^0.2.1", "laravel/framework": "5.4.*", "laravel/tinker": "~1.0", "rap2hpoutre/laravel-log-viewer": "^0.10.0", diff --git a/composer.lock b/composer.lock index f873be4..d05603b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "d2815162b2528ffa35abb638ecb71119", + "content-hash": "0c09bd0ea5c3a34c2b8c9701d72e9614", "packages": [ { "name": "dnoegel/php-xdg-base-dir", @@ -235,6 +235,52 @@ ], "time": "2015-04-20T18:58:01+00:00" }, + { + "name": "laracasts/presenter", + "version": "0.2.1", + "source": { + "type": "git", + "url": "https://github.com/laracasts/Presenter.git", + "reference": "b284f3137f990efd6e95df49d254f1ccc4541e92" + }, + "dist": { + "type": "zip", + "url": "https://files.phpcomposer.com/files/laracasts/Presenter/b284f3137f990efd6e95df49d254f1ccc4541e92.zip", + "reference": "b284f3137f990efd6e95df49d254f1ccc4541e92", + "shasum": "" + }, + "require": { + "illuminate/support": "~5.0", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Laracasts\\Presenter": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeffrey Way", + "email": "jeffrey@laracasts.com" + } + ], + "description": "Simple view presenters", + "keywords": [ + "laravel", + "presenter", + "view" + ], + "time": "2014-09-13T13:18:07+00:00" + }, { "name": "laravel/framework", "version": "v5.4.21", From 446930fc1becde1377e0779f2de8394c56d849e5 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 30 May 2017 12:28:48 +0000 Subject: [PATCH 04/78] Update repository contracts --- app/Repositories/Contracts/RepositoryInterface.php | 6 ++++++ app/Repositories/Eloquent/Repository.php | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/app/Repositories/Contracts/RepositoryInterface.php b/app/Repositories/Contracts/RepositoryInterface.php index bde70bd..9176001 100644 --- a/app/Repositories/Contracts/RepositoryInterface.php +++ b/app/Repositories/Contracts/RepositoryInterface.php @@ -75,4 +75,10 @@ public function findWhere(array $where, $columns = ['*']); * @return mixed */ public function with($relations); + + /** + * @param array $attributes + * @return mixed + */ + public function firstOrCreate(array $attributes = []); } \ No newline at end of file diff --git a/app/Repositories/Eloquent/Repository.php b/app/Repositories/Eloquent/Repository.php index 61e0aa1..cf24f11 100644 --- a/app/Repositories/Eloquent/Repository.php +++ b/app/Repositories/Eloquent/Repository.php @@ -185,4 +185,13 @@ public function with($relations) $this->model = $this->model->with($relations); return $this; } + + /** + * @param array $attributes + * @return Model + */ + public function firstOrCreate(array $attributes = []) + { + return $this->model->firstOrCreate($attributes); + } } \ No newline at end of file From 420dcd894d8dccf4f626267b02fb2425cc129a95 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 30 May 2017 12:33:25 +0000 Subject: [PATCH 05/78] Fix Post relationship record bug --- .../Controllers/Backend/PostController.php | 4 +- app/Models/Post.php | 9 +++ app/Presenters/PostPresenter.php | 30 ++++++++ app/Repositories/Contracts/PostRepository.php | 7 -- .../Eloquent/PostRepositoryEloquent.php | 73 +++++++++++++------ database/seeds/CategoriesTableSeeder.php | 6 ++ resources/views/admin/posts/_form.blade.php | 13 +--- 7 files changed, 100 insertions(+), 42 deletions(-) create mode 100644 app/Presenters/PostPresenter.php diff --git a/app/Http/Controllers/Backend/PostController.php b/app/Http/Controllers/Backend/PostController.php index 7502d34..86eb060 100644 --- a/app/Http/Controllers/Backend/PostController.php +++ b/app/Http/Controllers/Backend/PostController.php @@ -100,13 +100,11 @@ public function show($id) */ public function edit($id) { - $post = $this->postRepo->find($id); + $post = $this->postRepo->with('tags')->find($id); $categories = $this->cateRepo->all(); $tags = $this->tagRepo->all(); - $selected_tags = $this->postRepo->getTags($post); - return view('admin.posts.edit', compact('post', 'categories', 'tags', 'selected_tags')); } diff --git a/app/Models/Post.php b/app/Models/Post.php index 9f0154f..2bf7ded 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -2,7 +2,9 @@ namespace App\Models; +use App\Presenters\PostPresenter; use Illuminate\Database\Eloquent\Model; +use Laracasts\Presenter\PresentableTrait; /** * Class Post @@ -10,6 +12,13 @@ */ class Post extends Model { + use PresentableTrait; + + /** + * @var string + */ + protected $presenter = PostPresenter::class; + /** * @var array */ diff --git a/app/Presenters/PostPresenter.php b/app/Presenters/PostPresenter.php new file mode 100644 index 0000000..7e5fc12 --- /dev/null +++ b/app/Presenters/PostPresenter.php @@ -0,0 +1,30 @@ +tags->pluck('name')->map(function ($tagName) { + return '"' . $tagName . '"'; + })->implode(','); + } +} \ No newline at end of file diff --git a/app/Repositories/Contracts/PostRepository.php b/app/Repositories/Contracts/PostRepository.php index 738fe90..be08a13 100644 --- a/app/Repositories/Contracts/PostRepository.php +++ b/app/Repositories/Contracts/PostRepository.php @@ -20,11 +20,4 @@ public function createPost(array $attributes); * @return mixed */ public function updatePost(array $attributes, $id); - - /** - * @param $post - * @param bool $toArray - * @return mixed - */ - public function getTags($post, $toArray = true); } diff --git a/app/Repositories/Eloquent/PostRepositoryEloquent.php b/app/Repositories/Eloquent/PostRepositoryEloquent.php index 846b465..a08208b 100644 --- a/app/Repositories/Eloquent/PostRepositoryEloquent.php +++ b/app/Repositories/Eloquent/PostRepositoryEloquent.php @@ -4,7 +4,10 @@ use App\Models\Post; use App\Repositories\Contracts\PostRepository; +use App\Repositories\Contracts\TagRepository; use App\Repositories\Eloquent\Traits\Slugable; +use App\Repositories\Exceptions\RepositoryException; +use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Model; /** @@ -15,6 +18,22 @@ class PostRepositoryEloquent extends Repository implements PostRepository { use Slugable; + /** + * @var TagRepository + */ + protected $tagRepo; + + /** + * PostRepositoryEloquent constructor. + * @param Container $app + * @param TagRepository $tagRepo + */ + public function __construct(Container $app, TagRepository $tagRepo) + { + parent::__construct($app); + $this->tagRepo = $tagRepo; + } + /** * @return string */ @@ -31,7 +50,10 @@ public function createPost(array $attributes) { $attributes = $this->preHandleData($attributes); - return $this->create($attributes); + // TODO use transaction + $this->model = request()->user()->posts()->create($attributes); + + return $this->syncTags(data_get($attributes, 'tag')); } /** @@ -46,36 +68,43 @@ protected function preHandleData(array $attributes) } /** - * @param array $attributes - * @param $id - * @return \Illuminate\Database\Eloquent\Collection|Model + * @param array $tags + * @throws RepositoryException */ - public function updatePost(array $attributes, $id) + protected function syncTags(array $tags) { - $attributes = $this->preHandleData($attributes); + if (!$this->model->exists) { + throw new RepositoryException('Model is not exist'); + } + + if (empty($tags)) { + return; + } - return $this->update($attributes, $id); + $ids = []; + foreach ($tags as $tagName) { + $tag = $this->tagRepo->firstOrCreate([ + 'name' => $tagName, + 'slug' => str_slug($tagName) + ]); + array_push($ids, $tag->id); + } + + return $this->model->tags()->sync($ids); } /** - * @param $post - * @param bool $toArray - * @return mixed + * @param array $attributes + * @param $id + * @return \Illuminate\Database\Eloquent\Collection|Model */ - public function getTags($post, $toArray = true) + public function updatePost(array $attributes, $id) { - if (!$this->model->exists) { - $this->model = $this->find($post); - } elseif ($post instanceof Model) { - $this->model = $post; - } - - $tagIds = $this->model->tags()->get()->pluck('pivot.tag_id'); + $attributes = $this->preHandleData($attributes); - if ($toArray) { - return $tagIds->toArray(); - } + // TODO use transaction + $this->model = $this->update($attributes, $id); - return $tagIds; + return $this->syncTags(data_get($attributes, 'tag')); } } diff --git a/database/seeds/CategoriesTableSeeder.php b/database/seeds/CategoriesTableSeeder.php index 5009c4c..e317643 100644 --- a/database/seeds/CategoriesTableSeeder.php +++ b/database/seeds/CategoriesTableSeeder.php @@ -11,6 +11,12 @@ class CategoriesTableSeeder extends Seeder */ public function run() { + factory(\App\Models\Category::class)->create([ + 'name' => 'uncategorized', + 'description' => 'Default category', + 'slug' => 'uncategorized' + ]); + factory(\App\Models\Category::class, 15)->create(); } } diff --git a/resources/views/admin/posts/_form.blade.php b/resources/views/admin/posts/_form.blade.php index 75a12e7..f8e7083 100644 --- a/resources/views/admin/posts/_form.blade.php +++ b/resources/views/admin/posts/_form.blade.php @@ -19,7 +19,6 @@
@foreach($tags as $tag) - + @endforeach
@@ -56,14 +55,8 @@ var simplemde = new SimpleMDE({element: $("#mdeditor")[0]}); }); - $(".select2").select2(); + $(".category-selected").select2().val([{{ old('category_id', isset($post->category_id) ? $post->category_id : null)}}]).trigger('change'); - @if(old('category_id') || isset($post->id)) - $(".category-selected").select2().val({{ old('category_id', isset($post->category_id) ? $post->category_id : null)}}).trigger('change'); - @endif - - @if(old('tag') || isset($selected_tags)) - $(".tags-selected").select2().val([{{ implode(',', old('tag', isset($selected_tags) ? $selected_tags : null)) }}]).trigger('change'); - @endif + $(".tags-selected").select2({tags:true}).val([{!! $post->present()->selectedTags !!}]).trigger('change'); @endpush From 3576595b6007562cf1364c2ce4a33ca7f3de92a5 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 30 May 2017 13:28:05 +0000 Subject: [PATCH 06/78] Update repository contracts with trash support --- .../Contracts/RepositoryInterface.php | 28 +++++++++++ app/Repositories/Eloquent/Repository.php | 49 +++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/app/Repositories/Contracts/RepositoryInterface.php b/app/Repositories/Contracts/RepositoryInterface.php index 9176001..1c8940d 100644 --- a/app/Repositories/Contracts/RepositoryInterface.php +++ b/app/Repositories/Contracts/RepositoryInterface.php @@ -81,4 +81,32 @@ public function with($relations); * @return mixed */ public function firstOrCreate(array $attributes = []); + + /** + * @param bool $only + * @return mixed + */ + public function trashed($only = false); + + /** + * @return mixed + */ + public function onlyTrashed(); + + /** + * @return mixed + */ + public function withTrashed(); + + /** + * @param $id + * @return mixed + */ + public function restore($id); + + /** + * @param $id + * @return mixed + */ + public function forceDelete($id); } \ No newline at end of file diff --git a/app/Repositories/Eloquent/Repository.php b/app/Repositories/Eloquent/Repository.php index cf24f11..a181db0 100644 --- a/app/Repositories/Eloquent/Repository.php +++ b/app/Repositories/Eloquent/Repository.php @@ -194,4 +194,53 @@ public function firstOrCreate(array $attributes = []) { return $this->model->firstOrCreate($attributes); } + + /** + * @param bool $only + * @return $this + */ + public function trashed($only = false) + { + if ($only) { + $this->model = $this->model->onlyTrashed(); + } else { + $this->model = $this->model->withTrashed(); + } + + return $this; + } + + /** + * @return Repository + */ + public function onlyTrashed() + { + return $this->trashed(true); + } + + /** + * @return Repository + */ + public function withTrashed() + { + return $this->trashed(); + } + + /** + * @param $id + * @return mixed + */ + public function restore($id) + { + return $this->withTrashed()->find($id)->restore(); + } + + /** + * @param $id + * @return bool|null + */ + public function forceDelete($id) + { + return $this->withTrashed()->find($id)->forceDelete(); + } } \ No newline at end of file From 796b4ecebbee5788ca6e49ed3b970e7a87b86b3d Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 30 May 2017 13:28:50 +0000 Subject: [PATCH 07/78] Add trash support of Post --- .../Controllers/Backend/PostController.php | 30 ++++++++++++++++-- app/Models/Post.php | 5 +-- resources/views/admin/posts/index.blade.php | 31 ++++++++++++++----- routes/web.php | 2 ++ 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/Backend/PostController.php b/app/Http/Controllers/Backend/PostController.php index 86eb060..c88af88 100644 --- a/app/Http/Controllers/Backend/PostController.php +++ b/app/Http/Controllers/Backend/PostController.php @@ -43,11 +43,15 @@ public function __construct(PostRepository $postRepo, CategoryRepository $cateRe /** * Display a listing of the resource. - * + * @param Request $request * @return \Illuminate\Http\Response */ - public function index() + public function index(Request $request) { + if ($request->has('trash')) { + $this->postRepo = $this->postRepo->onlyTrashed(); + } + $posts = $this->postRepo->with(['category', 'author'])->paginate(); return view('admin.posts.index', compact('posts')); @@ -134,4 +138,26 @@ public function destroy($id) return redirect()->route('posts.index'); } + + /** + * @param $id + * @return \Illuminate\Http\RedirectResponse + */ + public function restore($id) + { + $this->postRepo->restore($id); + + return redirect()->route('posts.index'); + } + + /** + * @param $id + * @return \Illuminate\Http\RedirectResponse + */ + public function forceDelete($id) + { + $this->postRepo->forceDelete($id); + + return redirect()->back(); + } } diff --git a/app/Models/Post.php b/app/Models/Post.php index 2bf7ded..aa2e7e0 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -4,6 +4,7 @@ use App\Presenters\PostPresenter; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; use Laracasts\Presenter\PresentableTrait; /** @@ -12,7 +13,7 @@ */ class Post extends Model { - use PresentableTrait; + use PresentableTrait, SoftDeletes; /** * @var string @@ -33,7 +34,7 @@ class Post extends Model /** * @var array */ - protected $dates = ['published_at']; + protected $dates = ['published_at', 'deleted_at']; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo diff --git a/resources/views/admin/posts/index.blade.php b/resources/views/admin/posts/index.blade.php index 058c574..83b4d97 100644 --- a/resources/views/admin/posts/index.blade.php +++ b/resources/views/admin/posts/index.blade.php @@ -3,6 +3,12 @@ @section('content') Add New + @if(request()->has('trash')) + All + @else + Trash + @endif +
@@ -28,13 +34,24 @@ {{ $post->category->name }} {{ $post->created_at }} - View - Edit -
- {{ csrf_field() }} - {{ method_field('DELETE') }} - -
+ @if(request()->has('trash')) +
+ {{ csrf_field() }} + +
+
+ {{ csrf_field() }} + +
+ @else + View + Edit +
+ {{ csrf_field() }} + {{ method_field('DELETE') }} + +
+ @endif @endforeach diff --git a/routes/web.php b/routes/web.php index bccbe85..8f6fc00 100644 --- a/routes/web.php +++ b/routes/web.php @@ -27,6 +27,8 @@ Route::resource('users', 'UserController'); Route::resource('categories', 'CategoryController'); Route::resource('tags', 'TagController'); + Route::post('posts/{id}/restore', 'PostController@restore')->name('posts.restore'); + Route::post('posts/{id}/force-delete', 'PostController@forceDelete')->name('posts.force-delete'); Route::resource('posts', 'PostController'); }); From 90e7d442224a44e0425a33ba02b0322b8126cc51 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 30 May 2017 13:55:23 +0000 Subject: [PATCH 08/78] Update TODO.md --- TODO.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TODO.md b/TODO.md index f81c8d7..b64ae0e 100644 --- a/TODO.md +++ b/TODO.md @@ -14,6 +14,10 @@ - [ ] Schedule(backup,stat,) - [ ] I18N - [ ] Highlight tab +- [ ] Links +- [ ] Settings +- [ ] File management +- [ ] Feature image ## Frontend From 35cacf7a290d975e6bbb802cb4a16cfe2ce62695 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Thu, 1 Jun 2017 15:05:37 +0000 Subject: [PATCH 09/78] Update posts views --- resources/views/admin/posts/_form.blade.php | 63 +++++++++++++------- resources/views/admin/posts/create.blade.php | 12 ++-- resources/views/admin/posts/edit.blade.php | 14 ++--- 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/resources/views/admin/posts/_form.blade.php b/resources/views/admin/posts/_form.blade.php index f8e7083..3479e45 100644 --- a/resources/views/admin/posts/_form.blade.php +++ b/resources/views/admin/posts/_form.blade.php @@ -2,45 +2,66 @@
- - + + +
+ +
- - + + +
+ +
- - + + +
+ +
- - + +
+ +
- - + +
+ +
- -
-
+ +@push('box-footer') + +@endpush @push('css') diff --git a/resources/views/admin/posts/create.blade.php b/resources/views/admin/posts/create.blade.php index 2a48f30..235518b 100644 --- a/resources/views/admin/posts/create.blade.php +++ b/resources/views/admin/posts/create.blade.php @@ -5,22 +5,20 @@ @section('content')
-

Post Info

+
- - - - @include('admin.posts._form') - - + @include('admin.posts._form')
+ @stack('box-footer') + +
diff --git a/resources/views/admin/posts/edit.blade.php b/resources/views/admin/posts/edit.blade.php index 9e2ed9a..c35517e 100644 --- a/resources/views/admin/posts/edit.blade.php +++ b/resources/views/admin/posts/edit.blade.php @@ -3,23 +3,21 @@ @section('content')
-

Post Info

+
- - - {{ method_field('PATCH') }} - - @include('admin.posts._form') - - + {{ method_field('PATCH') }} + @include('admin.posts._form')
+ @stack('box-footer') + +
From 220b809d3ddbacf748e8fd8c3311ed6d2ef3d544 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Thu, 1 Jun 2017 15:07:42 +0000 Subject: [PATCH 10/78] Update posts add column is_draft --- database/migrations/2017_05_29_154816_create_posts_table.php | 1 + 1 file changed, 1 insertion(+) diff --git a/database/migrations/2017_05_29_154816_create_posts_table.php b/database/migrations/2017_05_29_154816_create_posts_table.php index aff088a..b2dda07 100644 --- a/database/migrations/2017_05_29_154816_create_posts_table.php +++ b/database/migrations/2017_05_29_154816_create_posts_table.php @@ -25,6 +25,7 @@ public function up() $table->longText('content'); $table->integer('view_count')->unsigned()->default(0); $table->timestamp('published_at')->nullable(); + $table->boolean('is_draft')->default(false); $table->timestamps(); $table->softDeletes(); }); From eb607bcc81802fdf88c094e038e5099176ed48ad Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Fri, 2 Jun 2017 14:03:21 +0000 Subject: [PATCH 11/78] Add npm packages bootstrap-datetimepicker --- package.json | 5 +++-- webpack.mix.js | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index c310530..f4e7370 100644 --- a/package.json +++ b/package.json @@ -14,12 +14,13 @@ "axios": "^0.15.3", "bootstrap-sass": "^3.3.7", "cross-env": "^3.2.3", + "eonasdan-bootstrap-datetimepicker": "^4.17.47", "font-awesome": "^4.7.0", "ionicons": "^3.0.0", "jquery": "^3.1.1", "laravel-mix": "0.*", "lodash": "^4.17.4", - "vue": "^2.1.10", - "simplemde": "^1.11.2" + "simplemde": "^1.11.2", + "vue": "^2.1.10" } } diff --git a/webpack.mix.js b/webpack.mix.js index a77ef66..1255425 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -16,7 +16,10 @@ mix.js('resources/assets/js/app.js', 'public/js') .less('resources/assets/less/adminlte.less', 'public/css') .copyDirectory('node_modules/admin-lte/plugins/', 'public/plugins/') .copy('node_modules/simplemde/dist/simplemde.min.css', 'public/css') - .copy('node_modules/simplemde/dist/simplemde.min.js', 'public/js'); + .copy('node_modules/simplemde/dist/simplemde.min.js', 'public/js') + .copy('node_modules/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css', 'public/css') + .copy('node_modules/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js', 'public/js') + .copy('node_modules/moment/min/moment.min.js', 'public/js'); if (!mix.config.inProduction) { mix.sourceMaps(); From 5f3950d638a72ad200ee7f7ea3f220e1657a08ff Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Fri, 2 Jun 2017 15:00:21 +0000 Subject: [PATCH 12/78] Add published_at&draft elements in view --- resources/views/admin/posts/_form.blade.php | 43 +++++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/resources/views/admin/posts/_form.blade.php b/resources/views/admin/posts/_form.blade.php index 3479e45..6b194fe 100644 --- a/resources/views/admin/posts/_form.blade.php +++ b/resources/views/admin/posts/_form.blade.php @@ -55,6 +55,23 @@
+
+ + +
+ +
+
+ +
+
Draft
+ +
+ is_draft))checked="checked"@endif> + +
+
+ @push('box-footer') From 1017a5602de01c9fb3815b5b18b2f92c48b20c66 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Fri, 2 Jun 2017 15:17:58 +0000 Subject: [PATCH 14/78] Update post request validation rules --- app/Http/Requests/StoreUpdatePostRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Requests/StoreUpdatePostRequest.php b/app/Http/Requests/StoreUpdatePostRequest.php index 631be05..e567f89 100644 --- a/app/Http/Requests/StoreUpdatePostRequest.php +++ b/app/Http/Requests/StoreUpdatePostRequest.php @@ -24,7 +24,7 @@ public function authorize() public function rules() { $rules = [ - 'title' => 'required|max:25', + 'title' => 'required', 'description' => 'max:100', 'category_id' => 'required', 'slug' => 'unique:posts', From 74c646647f9115cbfc09fe0b86456eb749171f89 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Fri, 2 Jun 2017 15:20:20 +0000 Subject: [PATCH 15/78] Update PostRepositoryEloquent --- .../Eloquent/PostRepositoryEloquent.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/app/Repositories/Eloquent/PostRepositoryEloquent.php b/app/Repositories/Eloquent/PostRepositoryEloquent.php index a08208b..95bf07f 100644 --- a/app/Repositories/Eloquent/PostRepositoryEloquent.php +++ b/app/Repositories/Eloquent/PostRepositoryEloquent.php @@ -7,6 +7,7 @@ use App\Repositories\Contracts\TagRepository; use App\Repositories\Eloquent\Traits\Slugable; use App\Repositories\Exceptions\RepositoryException; +use Carbon\Carbon; use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Model; @@ -64,9 +65,44 @@ protected function preHandleData(array $attributes) { $attributes = $this->autoSlug($attributes, 'title'); + $publishedAt = $this->getPublishedAt(array_get($attributes, 'published_at')); + + $isDraft = $this->getIsDraft(array_get($attributes, 'is_draft')); + + $attributes = array_merge($attributes, [ + 'published_at' => $publishedAt, + 'is_draft' => $isDraft, + ]); + return $attributes; } + /** + * @param $value + * @return Carbon + */ + protected function getPublishedAt($value) + { + if (empty($value)) { + return Carbon::now(); + } + + return Carbon::createFromTimestamp(strtotime($value)); + } + + /** + * @param $value + * @return int + */ + protected function getIsDraft($value) + { + if (empty($value)) { + return 0; + } + + return 1; + } + /** * @param array $tags * @throws RepositoryException From 20c77d75e01242fa619542ac6433d788f1c8d472 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Fri, 2 Jun 2017 15:35:02 +0000 Subject: [PATCH 16/78] Update PostPresenter with publishedTime --- app/Models/Post.php | 4 +++- app/Presenters/PostPresenter.php | 16 ++++++++++++++++ resources/views/admin/posts/_form.blade.php | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/Models/Post.php b/app/Models/Post.php index aa2e7e0..30696a1 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -28,7 +28,9 @@ class Post extends Model 'title', 'slug', 'description', - 'content' + 'content', + 'published_at', + 'is_draft' ]; /** diff --git a/app/Presenters/PostPresenter.php b/app/Presenters/PostPresenter.php index 7e5fc12..0875fea 100644 --- a/app/Presenters/PostPresenter.php +++ b/app/Presenters/PostPresenter.php @@ -27,4 +27,20 @@ public function selectedTags() return '"' . $tagName . '"'; })->implode(','); } + + /** + * @return false|mixed|null|string + */ + public function publishedTime() + { + if ($old = old('published_at')) { + return $old; + } + + if ($this->published_at) { + return date('m/d/Y g:i A', $this->published_at->timestamp); + } + + return null; + } } \ No newline at end of file diff --git a/resources/views/admin/posts/_form.blade.php b/resources/views/admin/posts/_form.blade.php index d3bb831..243f940 100644 --- a/resources/views/admin/posts/_form.blade.php +++ b/resources/views/admin/posts/_form.blade.php @@ -59,7 +59,7 @@
- +
From 32ee4c9ac22aa7344537cb28b9134f05343dbc2c Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Fri, 2 Jun 2017 15:39:39 +0000 Subject: [PATCH 17/78] Fix post view with missing name fields --- resources/views/admin/posts/_form.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/admin/posts/_form.blade.php b/resources/views/admin/posts/_form.blade.php index 243f940..3c43668 100644 --- a/resources/views/admin/posts/_form.blade.php +++ b/resources/views/admin/posts/_form.blade.php @@ -13,7 +13,7 @@
- +
@@ -21,7 +21,7 @@
- +
From a9f3f103ee84738cc19e011b0926def587c431d4 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sat, 3 Jun 2017 07:55:00 +0000 Subject: [PATCH 18/78] Fix post editor full screen bug --- resources/views/admin/posts/_form.blade.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/resources/views/admin/posts/_form.blade.php b/resources/views/admin/posts/_form.blade.php index 3c43668..ffbb54a 100644 --- a/resources/views/admin/posts/_form.blade.php +++ b/resources/views/admin/posts/_form.blade.php @@ -85,6 +85,13 @@ + @endpush @push('js') From 7e3e17c8e33bde4938b9e246f094239ff3cb2f8a Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sat, 3 Jun 2017 13:22:33 +0000 Subject: [PATCH 19/78] Add active tab helpers --- app/helpers.php | 13 ++++++++ .../views/admin/partials/sidebar.blade.php | 30 +++++++++---------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/app/helpers.php b/app/helpers.php index 0f43222..bf46472 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -22,3 +22,16 @@ function markdownContent(Faker\Generator $faker) return $content; } } + +if (!function_exists('setActiveClass')) { + /** + * @param $route + * @param string $class + * @param string $adminPrefix + * @return string + */ + function setActiveClass($route, $class = 'active', $adminPrefix = 'dashboard') + { + return Request::is($adminPrefix . '/' . $route . '*') ? $class : ''; + } +} diff --git a/resources/views/admin/partials/sidebar.blade.php b/resources/views/admin/partials/sidebar.blade.php index 1df08bc..8a90c8d 100644 --- a/resources/views/admin/partials/sidebar.blade.php +++ b/resources/views/admin/partials/sidebar.blade.php @@ -32,22 +32,22 @@ From bcbf7288a70233cedcd7ade59aa9064cff9ded9b Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sat, 3 Jun 2017 13:57:09 +0000 Subject: [PATCH 20/78] Using dismissible alert component in alerts partial --- .../admin/components/dismissible.blade.php | 11 ++++++++ resources/views/admin/layouts/admin.blade.php | 2 +- .../views/admin/partials/alerts.blade.php | 25 +++++++++++++++++++ .../views/admin/partials/error.blade.php | 11 -------- 4 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 resources/views/admin/components/dismissible.blade.php create mode 100644 resources/views/admin/partials/alerts.blade.php delete mode 100644 resources/views/admin/partials/error.blade.php diff --git a/resources/views/admin/components/dismissible.blade.php b/resources/views/admin/components/dismissible.blade.php new file mode 100644 index 0000000..32086c8 --- /dev/null +++ b/resources/views/admin/components/dismissible.blade.php @@ -0,0 +1,11 @@ +
+ +

+ + @if(isset($title)) + {{ ucfirst($title) }} + @endif +

+ + {{ $slot }} +
\ No newline at end of file diff --git a/resources/views/admin/layouts/admin.blade.php b/resources/views/admin/layouts/admin.blade.php index 1a59fe5..935fba8 100644 --- a/resources/views/admin/layouts/admin.blade.php +++ b/resources/views/admin/layouts/admin.blade.php @@ -43,7 +43,7 @@
- @include('admin.partials.error') + @include('admin.partials.alerts') @yield('content') diff --git a/resources/views/admin/partials/alerts.blade.php b/resources/views/admin/partials/alerts.blade.php new file mode 100644 index 0000000..d30e328 --- /dev/null +++ b/resources/views/admin/partials/alerts.blade.php @@ -0,0 +1,25 @@ +@if(Session::has('success')) + @component('admin.components.dismissible', ['title' => 'success']) + @slot('type') + success + @endslot + {{ Session::get('success') }} + @endcomponent +@endif + +@if(Session::has('errors')) + @component('admin.components.dismissible', ['title' => 'error']) + @slot('type') + danger + @endslot + @if(count($errors) > 1) +
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+ @else + {{ $errors->first() }} + @endif + @endcomponent +@endif \ No newline at end of file diff --git a/resources/views/admin/partials/error.blade.php b/resources/views/admin/partials/error.blade.php deleted file mode 100644 index e11f1b7..0000000 --- a/resources/views/admin/partials/error.blade.php +++ /dev/null @@ -1,11 +0,0 @@ -@if(count($errors) > 0) -
- -

Alert!

-
    - @foreach ($errors->all() as $error) -
  • {{ $error }}
  • - @endforeach -
-
-@endif \ No newline at end of file From 3b14bd57ec62834825106e5319e9cdea2b465e98 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sat, 3 Jun 2017 14:09:43 +0000 Subject: [PATCH 21/78] Add flash session in route redirection --- app/Http/Controllers/Backend/CategoryController.php | 6 +++--- app/Http/Controllers/Backend/PermissionController.php | 6 +++--- app/Http/Controllers/Backend/PostController.php | 10 +++++----- app/Http/Controllers/Backend/RoleController.php | 6 +++--- app/Http/Controllers/Backend/TagController.php | 6 +++--- app/Http/Controllers/Backend/UserController.php | 6 +++--- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/app/Http/Controllers/Backend/CategoryController.php b/app/Http/Controllers/Backend/CategoryController.php index fb6a440..ad5cda8 100644 --- a/app/Http/Controllers/Backend/CategoryController.php +++ b/app/Http/Controllers/Backend/CategoryController.php @@ -52,7 +52,7 @@ public function store(StoreUpdateCategoryRequest $request) { $category = $this->cateRepo->createCategory($request->all()); - return redirect()->route('categories.index'); + return redirect()->route('categories.index')->withSuccess('Create category successfully!'); } /** @@ -92,7 +92,7 @@ public function update(StoreUpdateCategoryRequest $request, $id) { $category = $this->cateRepo->updateCategory($request->all(), $id); - return redirect()->route('categories.index'); + return redirect()->route('categories.index')->withSuccess('Update category successfully!'); } /** @@ -105,6 +105,6 @@ public function destroy($id) { $this->cateRepo->delete($id); - return redirect()->route('categories.index'); + return redirect()->route('categories.index')->withSuccess('Delete category successfully!'); } } diff --git a/app/Http/Controllers/Backend/PermissionController.php b/app/Http/Controllers/Backend/PermissionController.php index 28c1ed5..4284ce1 100644 --- a/app/Http/Controllers/Backend/PermissionController.php +++ b/app/Http/Controllers/Backend/PermissionController.php @@ -52,7 +52,7 @@ public function store(StoreUpdatePermissionRequest $request) { $perm = $this->permRepo->create($request->all()); - return redirect()->route('permissions.index'); + return redirect()->route('permissions.index')->withSuccess('Create permission successfully!'); } /** @@ -92,7 +92,7 @@ public function update(StoreUpdatePermissionRequest $request, $id) { $perm = $this->permRepo->update($request->all(), $id); - return redirect()->route('permissions.index'); + return redirect()->route('permissions.index')->withSuccess('Update permission successfully!'); } /** @@ -105,6 +105,6 @@ public function destroy($id) { $this->permRepo->delete($id); - return redirect()->route('permissions.index'); + return redirect()->route('permissions.index')->withSuccess('Delete permission successfully!'); } } diff --git a/app/Http/Controllers/Backend/PostController.php b/app/Http/Controllers/Backend/PostController.php index c88af88..fbd73b8 100644 --- a/app/Http/Controllers/Backend/PostController.php +++ b/app/Http/Controllers/Backend/PostController.php @@ -80,7 +80,7 @@ public function store(StoreUpdatePostRequest $request) { $this->postRepo->createPost($request->all()); - return redirect()->route('posts.index'); + return redirect()->route('posts.index')->withSuccess('Create post successfully!'); } /** @@ -123,7 +123,7 @@ public function update(StoreUpdatePostRequest $request, $id) { $this->postRepo->updatePost($request->all(), $id); - return redirect()->route('posts.index'); + return redirect()->route('posts.index')->withSuccess('Update post successfully!'); } /** @@ -136,7 +136,7 @@ public function destroy($id) { $this->postRepo->delete($id); - return redirect()->route('posts.index'); + return redirect()->route('posts.index')->withSuccess('Move post to trash successfully!'); } /** @@ -147,7 +147,7 @@ public function restore($id) { $this->postRepo->restore($id); - return redirect()->route('posts.index'); + return redirect()->route('posts.index')->withSuccess('Restore post successfully!'); } /** @@ -158,6 +158,6 @@ public function forceDelete($id) { $this->postRepo->forceDelete($id); - return redirect()->back(); + return redirect()->back()->withSuccess('Force delete post successfully!'); } } diff --git a/app/Http/Controllers/Backend/RoleController.php b/app/Http/Controllers/Backend/RoleController.php index 775a239..12bcb69 100644 --- a/app/Http/Controllers/Backend/RoleController.php +++ b/app/Http/Controllers/Backend/RoleController.php @@ -65,7 +65,7 @@ public function store(StoreUpdateRoleRequest $request) { $role = $this->roleRepo->createRole($request->all()); - return redirect()->route('roles.index'); + return redirect()->route('roles.index')->withSuccess('Create role successfully!'); } /** @@ -109,7 +109,7 @@ public function update(StoreUpdateRoleRequest $request, $id) { $role = $this->roleRepo->updateRole($request->all(), $id); - return redirect()->route('roles.index'); + return redirect()->route('roles.index')->withSuccess('Update role successfully!'); } /** @@ -122,6 +122,6 @@ public function destroy($id) { $this->roleRepo->delete($id); - return redirect()->route('roles.index'); + return redirect()->route('roles.index')->withSuccess('Delete role successfully!'); } } diff --git a/app/Http/Controllers/Backend/TagController.php b/app/Http/Controllers/Backend/TagController.php index 147a8af..78e1ed7 100644 --- a/app/Http/Controllers/Backend/TagController.php +++ b/app/Http/Controllers/Backend/TagController.php @@ -52,7 +52,7 @@ public function store(StoreUpdateTagRequest $request) { $this->tagRepo->createTag($request->all()); - return redirect()->route('tags.index'); + return redirect()->route('tags.index')->withSuccess('Create tag successfully!'); } /** @@ -92,7 +92,7 @@ public function update(StoreUpdateTagRequest $request, $id) { $this->tagRepo->updateTag($request->all(), $id); - return redirect()->route('tags.index'); + return redirect()->route('tags.index')->withSuccess('Update tag successfully!'); } /** @@ -105,6 +105,6 @@ public function destroy($id) { $this->tagRepo->delete($id); - return redirect()->route('tags.index'); + return redirect()->route('tags.index')->withSuccess('Delete tag successfully!'); } } diff --git a/app/Http/Controllers/Backend/UserController.php b/app/Http/Controllers/Backend/UserController.php index a802759..5af7c06 100644 --- a/app/Http/Controllers/Backend/UserController.php +++ b/app/Http/Controllers/Backend/UserController.php @@ -65,7 +65,7 @@ public function store(StoreUpdateUserRequest $request) { $this->userRepo->createUser($request->all()); - return redirect()->route('users.index'); + return redirect()->route('users.index')->withSuccess('Create user successfully!'); } /** @@ -109,7 +109,7 @@ public function update(StoreUpdateUserRequest $request, $id) { $this->userRepo->updateUser($request->all(), $id); - return redirect()->route('users.index'); + return redirect()->route('users.index')->withSuccess('Update user successfully!'); } /** @@ -122,6 +122,6 @@ public function destroy($id) { $this->userRepo->delete($id); - return redirect()->route('users.index'); + return redirect()->route('users.index')->withSuccess('Delete user successfully!'); } } From a52c342258574c2f1b2d1e262fa04715011edbe0 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sat, 3 Jun 2017 14:24:35 +0000 Subject: [PATCH 22/78] Update backend route name with prefix --- .../Controllers/Backend/CategoryController.php | 6 +++--- .../Controllers/Backend/PermissionController.php | 6 +++--- app/Http/Controllers/Backend/PostController.php | 8 ++++---- app/Http/Controllers/Backend/RoleController.php | 6 +++--- app/Http/Controllers/Backend/TagController.php | 6 +++--- app/Http/Controllers/Backend/UserController.php | 6 +++--- .../views/admin/categories/create.blade.php | 2 +- resources/views/admin/categories/edit.blade.php | 2 +- resources/views/admin/categories/index.blade.php | 8 ++++---- resources/views/admin/partials/sidebar.blade.php | 12 ++++++------ .../views/admin/permissions/create.blade.php | 2 +- resources/views/admin/permissions/edit.blade.php | 2 +- .../views/admin/permissions/index.blade.php | 8 ++++---- resources/views/admin/posts/create.blade.php | 2 +- resources/views/admin/posts/edit.blade.php | 2 +- resources/views/admin/posts/index.blade.php | 16 ++++++++-------- resources/views/admin/roles/create.blade.php | 2 +- resources/views/admin/roles/edit.blade.php | 2 +- resources/views/admin/roles/index.blade.php | 8 ++++---- resources/views/admin/tags/create.blade.php | 2 +- resources/views/admin/tags/edit.blade.php | 2 +- resources/views/admin/tags/index.blade.php | 8 ++++---- resources/views/admin/users/create.blade.php | 2 +- resources/views/admin/users/edit.blade.php | 2 +- resources/views/admin/users/index.blade.php | 8 ++++---- routes/web.php | 2 +- 26 files changed, 66 insertions(+), 66 deletions(-) diff --git a/app/Http/Controllers/Backend/CategoryController.php b/app/Http/Controllers/Backend/CategoryController.php index ad5cda8..865998f 100644 --- a/app/Http/Controllers/Backend/CategoryController.php +++ b/app/Http/Controllers/Backend/CategoryController.php @@ -52,7 +52,7 @@ public function store(StoreUpdateCategoryRequest $request) { $category = $this->cateRepo->createCategory($request->all()); - return redirect()->route('categories.index')->withSuccess('Create category successfully!'); + return redirect()->route('admin.categories.index')->withSuccess('Create category successfully!'); } /** @@ -92,7 +92,7 @@ public function update(StoreUpdateCategoryRequest $request, $id) { $category = $this->cateRepo->updateCategory($request->all(), $id); - return redirect()->route('categories.index')->withSuccess('Update category successfully!'); + return redirect()->route('admin.categories.index')->withSuccess('Update category successfully!'); } /** @@ -105,6 +105,6 @@ public function destroy($id) { $this->cateRepo->delete($id); - return redirect()->route('categories.index')->withSuccess('Delete category successfully!'); + return redirect()->route('admin.categories.index')->withSuccess('Delete category successfully!'); } } diff --git a/app/Http/Controllers/Backend/PermissionController.php b/app/Http/Controllers/Backend/PermissionController.php index 4284ce1..a88e6a1 100644 --- a/app/Http/Controllers/Backend/PermissionController.php +++ b/app/Http/Controllers/Backend/PermissionController.php @@ -52,7 +52,7 @@ public function store(StoreUpdatePermissionRequest $request) { $perm = $this->permRepo->create($request->all()); - return redirect()->route('permissions.index')->withSuccess('Create permission successfully!'); + return redirect()->route('admin.permissions.index')->withSuccess('Create permission successfully!'); } /** @@ -92,7 +92,7 @@ public function update(StoreUpdatePermissionRequest $request, $id) { $perm = $this->permRepo->update($request->all(), $id); - return redirect()->route('permissions.index')->withSuccess('Update permission successfully!'); + return redirect()->route('admin.permissions.index')->withSuccess('Update permission successfully!'); } /** @@ -105,6 +105,6 @@ public function destroy($id) { $this->permRepo->delete($id); - return redirect()->route('permissions.index')->withSuccess('Delete permission successfully!'); + return redirect()->route('admin.permissions.index')->withSuccess('Delete permission successfully!'); } } diff --git a/app/Http/Controllers/Backend/PostController.php b/app/Http/Controllers/Backend/PostController.php index fbd73b8..bcd75fe 100644 --- a/app/Http/Controllers/Backend/PostController.php +++ b/app/Http/Controllers/Backend/PostController.php @@ -80,7 +80,7 @@ public function store(StoreUpdatePostRequest $request) { $this->postRepo->createPost($request->all()); - return redirect()->route('posts.index')->withSuccess('Create post successfully!'); + return redirect()->route('admin.posts.index')->withSuccess('Create post successfully!'); } /** @@ -123,7 +123,7 @@ public function update(StoreUpdatePostRequest $request, $id) { $this->postRepo->updatePost($request->all(), $id); - return redirect()->route('posts.index')->withSuccess('Update post successfully!'); + return redirect()->route('admin.posts.index')->withSuccess('Update post successfully!'); } /** @@ -136,7 +136,7 @@ public function destroy($id) { $this->postRepo->delete($id); - return redirect()->route('posts.index')->withSuccess('Move post to trash successfully!'); + return redirect()->route('admin.posts.index')->withSuccess('Move post to trash successfully!'); } /** @@ -147,7 +147,7 @@ public function restore($id) { $this->postRepo->restore($id); - return redirect()->route('posts.index')->withSuccess('Restore post successfully!'); + return redirect()->route('admin.posts.index')->withSuccess('Restore post successfully!'); } /** diff --git a/app/Http/Controllers/Backend/RoleController.php b/app/Http/Controllers/Backend/RoleController.php index 12bcb69..9e657fd 100644 --- a/app/Http/Controllers/Backend/RoleController.php +++ b/app/Http/Controllers/Backend/RoleController.php @@ -65,7 +65,7 @@ public function store(StoreUpdateRoleRequest $request) { $role = $this->roleRepo->createRole($request->all()); - return redirect()->route('roles.index')->withSuccess('Create role successfully!'); + return redirect()->route('admin.roles.index')->withSuccess('Create role successfully!'); } /** @@ -109,7 +109,7 @@ public function update(StoreUpdateRoleRequest $request, $id) { $role = $this->roleRepo->updateRole($request->all(), $id); - return redirect()->route('roles.index')->withSuccess('Update role successfully!'); + return redirect()->route('admin.roles.index')->withSuccess('Update role successfully!'); } /** @@ -122,6 +122,6 @@ public function destroy($id) { $this->roleRepo->delete($id); - return redirect()->route('roles.index')->withSuccess('Delete role successfully!'); + return redirect()->route('admin.roles.index')->withSuccess('Delete role successfully!'); } } diff --git a/app/Http/Controllers/Backend/TagController.php b/app/Http/Controllers/Backend/TagController.php index 78e1ed7..45d7794 100644 --- a/app/Http/Controllers/Backend/TagController.php +++ b/app/Http/Controllers/Backend/TagController.php @@ -52,7 +52,7 @@ public function store(StoreUpdateTagRequest $request) { $this->tagRepo->createTag($request->all()); - return redirect()->route('tags.index')->withSuccess('Create tag successfully!'); + return redirect()->route('admin.tags.index')->withSuccess('Create tag successfully!'); } /** @@ -92,7 +92,7 @@ public function update(StoreUpdateTagRequest $request, $id) { $this->tagRepo->updateTag($request->all(), $id); - return redirect()->route('tags.index')->withSuccess('Update tag successfully!'); + return redirect()->route('admin.tags.index')->withSuccess('Update tag successfully!'); } /** @@ -105,6 +105,6 @@ public function destroy($id) { $this->tagRepo->delete($id); - return redirect()->route('tags.index')->withSuccess('Delete tag successfully!'); + return redirect()->route('admin.tags.index')->withSuccess('Delete tag successfully!'); } } diff --git a/app/Http/Controllers/Backend/UserController.php b/app/Http/Controllers/Backend/UserController.php index 5af7c06..ccd8cda 100644 --- a/app/Http/Controllers/Backend/UserController.php +++ b/app/Http/Controllers/Backend/UserController.php @@ -65,7 +65,7 @@ public function store(StoreUpdateUserRequest $request) { $this->userRepo->createUser($request->all()); - return redirect()->route('users.index')->withSuccess('Create user successfully!'); + return redirect()->route('admin.users.index')->withSuccess('Create user successfully!'); } /** @@ -109,7 +109,7 @@ public function update(StoreUpdateUserRequest $request, $id) { $this->userRepo->updateUser($request->all(), $id); - return redirect()->route('users.index')->withSuccess('Update user successfully!'); + return redirect()->route('admin.users.index')->withSuccess('Update user successfully!'); } /** @@ -122,6 +122,6 @@ public function destroy($id) { $this->userRepo->delete($id); - return redirect()->route('users.index')->withSuccess('Delete user successfully!'); + return redirect()->route('admin.users.index')->withSuccess('Delete user successfully!'); } } diff --git a/resources/views/admin/categories/create.blade.php b/resources/views/admin/categories/create.blade.php index 143bfc6..2ab1951 100644 --- a/resources/views/admin/categories/create.blade.php +++ b/resources/views/admin/categories/create.blade.php @@ -14,7 +14,7 @@
-
+ @include('admin.categories._form') diff --git a/resources/views/admin/categories/edit.blade.php b/resources/views/admin/categories/edit.blade.php index b44f733..c068724 100644 --- a/resources/views/admin/categories/edit.blade.php +++ b/resources/views/admin/categories/edit.blade.php @@ -12,7 +12,7 @@
- + {{ method_field('PATCH') }} @include('admin.categories._form') diff --git a/resources/views/admin/categories/index.blade.php b/resources/views/admin/categories/index.blade.php index 05bbd15..9512888 100644 --- a/resources/views/admin/categories/index.blade.php +++ b/resources/views/admin/categories/index.blade.php @@ -1,7 +1,7 @@ @extends('admin.layouts.admin') @section('content') - Add New + Add New
@@ -26,9 +26,9 @@ {{ $category->slug }} {{ $category->parent_id }} - View - Edit - + View + Edit + {{ csrf_field() }} {{ method_field('DELETE') }} diff --git a/resources/views/admin/partials/sidebar.blade.php b/resources/views/admin/partials/sidebar.blade.php index 8a90c8d..3eee2ee 100644 --- a/resources/views/admin/partials/sidebar.blade.php +++ b/resources/views/admin/partials/sidebar.blade.php @@ -40,14 +40,14 @@ -
  • Users
  • -
  • Categories
  • -
  • Tags
  • -
  • Posts
  • +
  • Users
  • +
  • Categories
  • +
  • Tags
  • +
  • Posts
  • diff --git a/resources/views/admin/permissions/create.blade.php b/resources/views/admin/permissions/create.blade.php index fac0495..4e637b9 100644 --- a/resources/views/admin/permissions/create.blade.php +++ b/resources/views/admin/permissions/create.blade.php @@ -14,7 +14,7 @@
    - + @include('admin.permissions._form') diff --git a/resources/views/admin/permissions/edit.blade.php b/resources/views/admin/permissions/edit.blade.php index 9da5a0e..9835203 100644 --- a/resources/views/admin/permissions/edit.blade.php +++ b/resources/views/admin/permissions/edit.blade.php @@ -12,7 +12,7 @@
    - + {{ method_field('PATCH') }} @include('admin.permissions._form') diff --git a/resources/views/admin/permissions/index.blade.php b/resources/views/admin/permissions/index.blade.php index ce5f46c..f8e8d56 100644 --- a/resources/views/admin/permissions/index.blade.php +++ b/resources/views/admin/permissions/index.blade.php @@ -1,7 +1,7 @@ @extends('admin.layouts.admin') @section('content') - Add New + Add New
    @@ -24,9 +24,9 @@ {{ $permission->display_name }} {{ str_limit($permission->description, 20) }} - View - Edit - + View + Edit + {{ csrf_field() }} {{ method_field('DELETE') }} diff --git a/resources/views/admin/posts/create.blade.php b/resources/views/admin/posts/create.blade.php index 235518b..19dfc78 100644 --- a/resources/views/admin/posts/create.blade.php +++ b/resources/views/admin/posts/create.blade.php @@ -11,7 +11,7 @@

    Post Info

    - +
    @include('admin.posts._form')
    diff --git a/resources/views/admin/posts/edit.blade.php b/resources/views/admin/posts/edit.blade.php index c35517e..d0cd6ff 100644 --- a/resources/views/admin/posts/edit.blade.php +++ b/resources/views/admin/posts/edit.blade.php @@ -9,7 +9,7 @@

    Post Info

    - +
    {{ method_field('PATCH') }} @include('admin.posts._form') diff --git a/resources/views/admin/posts/index.blade.php b/resources/views/admin/posts/index.blade.php index 83b4d97..a89a842 100644 --- a/resources/views/admin/posts/index.blade.php +++ b/resources/views/admin/posts/index.blade.php @@ -1,12 +1,12 @@ @extends('admin.layouts.admin') @section('content') - Add New + Add New @if(request()->has('trash')) - All + All @else - Trash + Trash @endif
    @@ -35,18 +35,18 @@ {{ $post->created_at }} @if(request()->has('trash')) - + {{ csrf_field() }} -
    + {{ csrf_field() }}
    @else - View - Edit -
    + View + Edit + {{ csrf_field() }} {{ method_field('DELETE') }} diff --git a/resources/views/admin/roles/create.blade.php b/resources/views/admin/roles/create.blade.php index 227ac2c..da44023 100644 --- a/resources/views/admin/roles/create.blade.php +++ b/resources/views/admin/roles/create.blade.php @@ -14,7 +14,7 @@
    - + @include('admin.roles._form') diff --git a/resources/views/admin/roles/edit.blade.php b/resources/views/admin/roles/edit.blade.php index 7258e92..73eea5a 100644 --- a/resources/views/admin/roles/edit.blade.php +++ b/resources/views/admin/roles/edit.blade.php @@ -12,7 +12,7 @@
    - + {{ method_field('PATCH') }} @include('admin.roles._form') diff --git a/resources/views/admin/roles/index.blade.php b/resources/views/admin/roles/index.blade.php index 3d841f8..63b1d49 100644 --- a/resources/views/admin/roles/index.blade.php +++ b/resources/views/admin/roles/index.blade.php @@ -1,7 +1,7 @@ @extends('admin.layouts.admin') @section('content') - Add New + Add New
    @@ -27,9 +27,9 @@ {{ $role->display_name }} {{ str_limit($role->description, 20) }} - View - Edit - + View + Edit + {{ csrf_field() }} {{ method_field('DELETE') }} diff --git a/resources/views/admin/tags/create.blade.php b/resources/views/admin/tags/create.blade.php index a4b0925..da86850 100644 --- a/resources/views/admin/tags/create.blade.php +++ b/resources/views/admin/tags/create.blade.php @@ -14,7 +14,7 @@
    - + @include('admin.tags._form') diff --git a/resources/views/admin/tags/edit.blade.php b/resources/views/admin/tags/edit.blade.php index 026e338..c92afd0 100644 --- a/resources/views/admin/tags/edit.blade.php +++ b/resources/views/admin/tags/edit.blade.php @@ -12,7 +12,7 @@
    - + {{ method_field('PATCH') }} @include('admin.tags._form') diff --git a/resources/views/admin/tags/index.blade.php b/resources/views/admin/tags/index.blade.php index d3d6aba..01b7cfd 100644 --- a/resources/views/admin/tags/index.blade.php +++ b/resources/views/admin/tags/index.blade.php @@ -1,7 +1,7 @@ @extends('admin.layouts.admin') @section('content') - Add New + Add New
    @@ -24,9 +24,9 @@ {{ $tag->description }} {{ $tag->slug }} - View - Edit - + View + Edit + {{ csrf_field() }} {{ method_field('DELETE') }} diff --git a/resources/views/admin/users/create.blade.php b/resources/views/admin/users/create.blade.php index 72a40d5..6fc4478 100644 --- a/resources/views/admin/users/create.blade.php +++ b/resources/views/admin/users/create.blade.php @@ -14,7 +14,7 @@
    - + @include('admin.users._form') diff --git a/resources/views/admin/users/edit.blade.php b/resources/views/admin/users/edit.blade.php index ba40538..d4b9912 100644 --- a/resources/views/admin/users/edit.blade.php +++ b/resources/views/admin/users/edit.blade.php @@ -12,7 +12,7 @@
    - + {{ method_field('PATCH') }} @include('admin.users._form') diff --git a/resources/views/admin/users/index.blade.php b/resources/views/admin/users/index.blade.php index f98b420..eb5b90b 100644 --- a/resources/views/admin/users/index.blade.php +++ b/resources/views/admin/users/index.blade.php @@ -1,7 +1,7 @@ @extends('admin.layouts.admin') @section('content') - Add New + Add New
    @@ -26,9 +26,9 @@ {{ $user->created_at }} {{ $user->updated_at }} - View - Edit - + View + Edit + {{ csrf_field() }} {{ method_field('DELETE') }} diff --git a/routes/web.php b/routes/web.php index 8f6fc00..c237b5a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -19,7 +19,7 @@ Auth::routes(); -Route::group(['namespace' => 'Backend', 'middleware' => 'auth', 'prefix' => 'dashboard'], function () { +Route::group(['namespace' => 'Backend', 'middleware' => 'auth', 'prefix' => 'dashboard', 'as' => 'admin.'], function () { Route::get('/', 'DashboardController@index')->name('dashboard.index'); Route::resource('roles', 'RoleController'); From 72305ee8a9b92fb7657f6fecbafed742b91dfa2b Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sat, 3 Jun 2017 14:43:44 +0000 Subject: [PATCH 23/78] Fix auto-genrated slug could be repeated bug --- app/Repositories/Eloquent/Traits/Slugable.php | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/app/Repositories/Eloquent/Traits/Slugable.php b/app/Repositories/Eloquent/Traits/Slugable.php index d652459..65b32c1 100644 --- a/app/Repositories/Eloquent/Traits/Slugable.php +++ b/app/Repositories/Eloquent/Traits/Slugable.php @@ -2,6 +2,8 @@ namespace App\Repositories\Eloquent\Traits; +use Carbon\Carbon; + /** * Trait Slugable * @package App\Repositories\Eloquent\Traits @@ -20,9 +22,34 @@ public function autoSlug($attributes, $keyName = 'name', $keySlug = 'slug') { if (array_get($attributes, $keySlug) == null) { $name = array_get($attributes, $keyName); - array_set($attributes, $keySlug, str_slug($name)); + + $slug = str_slug($name); + if ($this->slugExists($slug, $keySlug)) { + $slug = $this->unique($name); + } + + array_set($attributes, $keySlug, $slug); } return $attributes; } + + /** + * @param $slug + * @param string $column + * @return mixed + */ + protected function slugExists($slug, $column = 'slug') + { + return $this->model->where($column, $slug)->exists(); + } + + /** + * @param $value + * @return string + */ + protected function unique($value) + { + return str_slug($value) . '-' . Carbon::now()->toDateTimeString(); + } } \ No newline at end of file From d0ae2e38ad768b7702edd3c8d54082b745d4c1c4 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sat, 3 Jun 2017 15:06:22 +0000 Subject: [PATCH 24/78] Update TODO.md --- TODO.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index b64ae0e..d309a6c 100644 --- a/TODO.md +++ b/TODO.md @@ -18,6 +18,7 @@ - [ ] Settings - [ ] File management - [ ] Feature image +- [ ] Flash session ## Frontend @@ -30,4 +31,5 @@ - [ ] Refactor views with VueJs - [ ] API - [ ] Package -- [ ] Unit test \ No newline at end of file +- [ ] Unit test +- [ ] Pjax From ff29634ed9cf0d1335086f6613beb180bd421882 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sun, 4 Jun 2017 02:48:25 +0000 Subject: [PATCH 25/78] Composer require jellybool/translug and set configs --- .env.example | 3 + composer.json | 1 + composer.lock | 278 +++++++++++++++++++++++++++++++++++++++++++- config/app.php | 4 +- config/services.php | 5 + 5 files changed, 289 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 668c06f..81a975a 100644 --- a/.env.example +++ b/.env.example @@ -31,3 +31,6 @@ MAIL_ENCRYPTION=null PUSHER_APP_ID= PUSHER_APP_KEY= PUSHER_APP_SECRET= + +YOUDAO_APP_KEY= +YOUDAO_APP_SECRET= diff --git a/composer.json b/composer.json index bf6e429..08add9c 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,7 @@ "type": "project", "require": { "php": ">=5.6.4", + "jellybool/translug": "^2.0", "laracasts/presenter": "^0.2.1", "laravel/framework": "5.4.*", "laravel/tinker": "~1.0", diff --git a/composer.lock b/composer.lock index d05603b..f21ede7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "0c09bd0ea5c3a34c2b8c9701d72e9614", + "content-hash": "f03fcb895ad3aa86ba5ce33b47db38ba", "packages": [ { "name": "dnoegel/php-xdg-base-dir", @@ -148,6 +148,184 @@ ], "time": "2017-03-29T16:04:15+00:00" }, + { + "name": "guzzlehttp/guzzle", + "version": "6.2.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006" + }, + "dist": { + "type": "zip", + "url": "https://files.phpcomposer.com/files/guzzle/guzzle/8d6c6cc55186db87b7dc5009827429ba4e9dc006.zip", + "reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.0", + "psr/log": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2017-02-28T22:50:30+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://files.phpcomposer.com/files/guzzle/promises/a59da6cf61d80060647ff4d3eb2c03a2bc694646.zip", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + }, + "dist": { + "type": "zip", + "url": "https://files.phpcomposer.com/files/guzzle/psr7/f5b8a8512e2b58b0071a7280e39f14f72e05d87c.zip", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2017-03-20T17:10:46+00:00" + }, { "name": "jakub-onderka/php-console-color", "version": "0.1", @@ -235,6 +413,54 @@ ], "time": "2015-04-20T18:58:01+00:00" }, + { + "name": "jellybool/translug", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/JellyBool/translug.git", + "reference": "351bf143e2c60fdc8acbb0c4fe6ddc1811d6d746" + }, + "dist": { + "type": "zip", + "url": "https://files.phpcomposer.com/files/JellyBool/translug/351bf143e2c60fdc8acbb0c4fe6ddc1811d6d746.zip", + "reference": "351bf143e2c60fdc8acbb0c4fe6ddc1811d6d746", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "~5.3|~6.0", + "php": ">=5.5.9" + }, + "require-dev": { + "illuminate/support": "^5.2", + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "JellyBool\\Translug\\": "src/" + }, + "files": [ + "src/helpers/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "JellyBool", + "email": "jellybool@outlook.com" + } + ], + "description": "Translate Chinese And Then Make It Sluggable", + "keywords": [ + "slug", + "translate" + ], + "time": "2017-05-26T15:45:17+00:00" + }, { "name": "laracasts/presenter", "version": "0.2.1", @@ -825,6 +1051,56 @@ ], "time": "2017-03-13T16:27:32+00:00" }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://files.phpcomposer.com/files/php-fig/http-message/f6561bf28d520154e4b0ec72be95418abe6d9363.zip", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, { "name": "psr/log", "version": "1.0.2", diff --git a/config/app.php b/config/app.php index dfa9597..4eb8f52 100644 --- a/config/app.php +++ b/config/app.php @@ -179,7 +179,8 @@ Rap2hpoutre\LaravelLogViewer\LaravelLogViewerServiceProvider::class, Zizaco\Entrust\EntrustServiceProvider::class, - Thomaswelton\LaravelGravatar\LaravelGravatarServiceProvider::class + Thomaswelton\LaravelGravatar\LaravelGravatarServiceProvider::class, + JellyBool\Translug\TranslugServiceProvider::class, ], @@ -233,6 +234,7 @@ 'Debugbar' => Barryvdh\Debugbar\Facade::class, 'Entrust' => Zizaco\Entrust\EntrustFacade::class, 'Gravatar' => Thomaswelton\LaravelGravatar\Facades\Gravatar::class, + 'Translug' => \JellyBool\Translug\TranslugFacade::class, ], ]; diff --git a/config/services.php b/config/services.php index 4b5f049..f5cf3e0 100644 --- a/config/services.php +++ b/config/services.php @@ -35,4 +35,9 @@ 'secret' => env('STRIPE_SECRET'), ], + 'youdao' => [ + 'appKey' => env('YOUDAO_APP_KEY'), + 'appSecret' => env('YOUDAO_APP_SECRET'), + ], + ]; From 9c38de700b3fe1640c21abc203e6d40839f728a6 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sun, 4 Jun 2017 05:00:00 +0000 Subject: [PATCH 26/78] Fix dashboard redirect route name --- app/Http/Controllers/Auth/Traits/AuthRedirect.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Auth/Traits/AuthRedirect.php b/app/Http/Controllers/Auth/Traits/AuthRedirect.php index 8831272..9868cb0 100644 --- a/app/Http/Controllers/Auth/Traits/AuthRedirect.php +++ b/app/Http/Controllers/Auth/Traits/AuthRedirect.php @@ -11,6 +11,6 @@ trait AuthRedirect */ protected function redirectTo() { - return route('dashboard.index'); + return route('admin.dashboard.index'); } } \ No newline at end of file From 8c053d77199e24799c6a5d6585013f6d0464017a Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sun, 4 Jun 2017 05:16:58 +0000 Subject: [PATCH 27/78] Update post's draft status with constant --- app/Models/Post.php | 19 +++++++++++++++++++ .../Eloquent/PostRepositoryEloquent.php | 4 ++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/app/Models/Post.php b/app/Models/Post.php index 30696a1..0227507 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -15,6 +15,16 @@ class Post extends Model { use PresentableTrait, SoftDeletes; + /** + * Is draft status + */ + const IS_DRAFT = 1; + + /** + * Is not draft status + */ + const IS_NOT_DRAFT = 0; + /** * @var string */ @@ -61,4 +71,13 @@ public function tags() { return $this->morphToMany(Tag::class, 'taggable'); } + + /** + * @param $name + * @return mixed + */ + public function getConst($name) + { + return constant("self::{$name}"); + } } diff --git a/app/Repositories/Eloquent/PostRepositoryEloquent.php b/app/Repositories/Eloquent/PostRepositoryEloquent.php index 95bf07f..f4a9675 100644 --- a/app/Repositories/Eloquent/PostRepositoryEloquent.php +++ b/app/Repositories/Eloquent/PostRepositoryEloquent.php @@ -97,10 +97,10 @@ protected function getPublishedAt($value) protected function getIsDraft($value) { if (empty($value)) { - return 0; + return $this->model->getConst('IS_NOT_DRAFT'); } - return 1; + return $this->model->getConst('IS_DRAFT'); } /** From 2f00dfb7471bc6abd4ccbb70c9e9fea46ca12518 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sun, 4 Jun 2017 05:36:00 +0000 Subject: [PATCH 28/78] Add str_slug compitable with Chinese --- app/Repositories/Eloquent/Traits/Slugable.php | 15 ++++++-- app/helpers.php | 36 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/app/Repositories/Eloquent/Traits/Slugable.php b/app/Repositories/Eloquent/Traits/Slugable.php index 65b32c1..a0ddb0e 100644 --- a/app/Repositories/Eloquent/Traits/Slugable.php +++ b/app/Repositories/Eloquent/Traits/Slugable.php @@ -23,7 +23,10 @@ public function autoSlug($attributes, $keyName = 'name', $keySlug = 'slug') if (array_get($attributes, $keySlug) == null) { $name = array_get($attributes, $keyName); - $slug = str_slug($name); + $slug = str_slug_with_cn($name); + // TODO known bug + // If update post with deleting original auto-generated slug, slug will generate again + // and may 'duplicate' in DB. One solution is exclude current record(based on id) while doing update if ($this->slugExists($slug, $keySlug)) { $slug = $this->unique($name); } @@ -50,6 +53,14 @@ protected function slugExists($slug, $column = 'slug') */ protected function unique($value) { - return str_slug($value) . '-' . Carbon::now()->toDateTimeString(); + return str_slug_with_cn($value) . '-' . $this->uniqueChar(); + } + + /** + * @return string + */ + protected function uniqueChar() + { + return Carbon::now()->timestamp; } } \ No newline at end of file diff --git a/app/helpers.php b/app/helpers.php index bf46472..ad8fc8f 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -35,3 +35,39 @@ function setActiveClass($route, $class = 'active', $adminPrefix = 'dashboard') return Request::is($adminPrefix . '/' . $route . '*') ? $class : ''; } } + +if (!function_exists('hasChinese')) { + /** + * @param $text + * @return bool + */ + function hasChinese($text) + { + if (preg_match("/\p{Han}+/u", $text)) { + return true; + } + + return false; + } +} + +if (!function_exists('str_slug_with_cn')) { + + /** + * @param $text + * @param bool $forceTrans + * @return \Illuminate\Foundation\Application|\JellyBool\Translug\Translation|mixed|string|translug + */ + function str_slug_with_cn($text, $forceTrans = false) + { + if (empty(trim($text))) { + return ''; + } + + if ($forceTrans || hasChinese($text)) { + return translug($text); + } + + return str_slug($text); + } +} From 7542b7628d8de1b42a243b30fc97040c984aa40a Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sun, 4 Jun 2017 05:44:48 +0000 Subject: [PATCH 29/78] Fix bug while create&update post without selected tags --- app/Repositories/Eloquent/PostRepositoryEloquent.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/Repositories/Eloquent/PostRepositoryEloquent.php b/app/Repositories/Eloquent/PostRepositoryEloquent.php index f4a9675..a3e9514 100644 --- a/app/Repositories/Eloquent/PostRepositoryEloquent.php +++ b/app/Repositories/Eloquent/PostRepositoryEloquent.php @@ -54,7 +54,7 @@ public function createPost(array $attributes) // TODO use transaction $this->model = request()->user()->posts()->create($attributes); - return $this->syncTags(data_get($attributes, 'tag')); + return $this->syncTags(data_get($attributes, 'tag', [])); } /** @@ -113,11 +113,12 @@ protected function syncTags(array $tags) throw new RepositoryException('Model is not exist'); } + $ids = []; + if (empty($tags)) { - return; + return $this->model->tags()->sync($ids); } - $ids = []; foreach ($tags as $tagName) { $tag = $this->tagRepo->firstOrCreate([ 'name' => $tagName, @@ -141,6 +142,6 @@ public function updatePost(array $attributes, $id) // TODO use transaction $this->model = $this->update($attributes, $id); - return $this->syncTags(data_get($attributes, 'tag')); + return $this->syncTags(data_get($attributes, 'tag', [])); } } From f301d083e582453009fd6db702750f57e40e01f6 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sun, 4 Jun 2017 06:12:38 +0000 Subject: [PATCH 30/78] Fix dismissible alert icon --- resources/views/admin/components/dismissible.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/admin/components/dismissible.blade.php b/resources/views/admin/components/dismissible.blade.php index 32086c8..e950981 100644 --- a/resources/views/admin/components/dismissible.blade.php +++ b/resources/views/admin/components/dismissible.blade.php @@ -1,7 +1,7 @@

    - + @if(isset($title)) {{ ucfirst($title) }} @endif From 15caf5d71851eab22d50ac4edfa4267686c765f4 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sun, 4 Jun 2017 07:35:34 +0000 Subject: [PATCH 31/78] Update Repository concrete with adding method scopeBoot --- app/Repositories/Eloquent/Repository.php | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/app/Repositories/Eloquent/Repository.php b/app/Repositories/Eloquent/Repository.php index a181db0..0eca98b 100644 --- a/app/Repositories/Eloquent/Repository.php +++ b/app/Repositories/Eloquent/Repository.php @@ -54,12 +54,22 @@ public function makeModel() */ abstract public function model(); + /** + * The fake "booting" method of the model in calling scopes. + */ + public function scopeBoot() + { + + } + /** * @param array $columns * @return \Illuminate\Database\Eloquent\Collection|static[] */ public function all($columns = ['*']) { + $this->scopeBoot(); + if ($this->model instanceof Builder) { $results = $this->model->get(); } else { @@ -76,6 +86,8 @@ public function all($columns = ['*']) */ public function paginate($perPage = 10, $columns = ['*']) { + $this->scopeBoot(); + return $this->model->paginate($perPage, $columns); } @@ -95,6 +107,8 @@ public function create(array $attributes) */ public function update(array $attributes, $id) { + $this->scopeBoot(); + $model = $this->model->findOrFail($id); $model->fill($attributes); $model->save(); @@ -108,6 +122,8 @@ public function update(array $attributes, $id) */ public function delete($id) { + $this->scopeBoot(); + return $this->model->destroy($id); } @@ -118,6 +134,8 @@ public function delete($id) */ public function find($id, $columns = ['*']) { + $this->scopeBoot(); + return $this->model->findOrFail($id, $columns); } @@ -129,6 +147,8 @@ public function find($id, $columns = ['*']) */ public function findBy($field, $value, $columns = ['*']) { + $this->scopeBoot(); + return $this->model->where($field, '=', $value)->first($columns); } @@ -140,6 +160,8 @@ public function findBy($field, $value, $columns = ['*']) */ public function findAllBy($field, $value, $columns = ['*']) { + $this->scopeBoot(); + return $this->model->where($field, '=', $value)->get($columns); } @@ -150,6 +172,8 @@ public function findAllBy($field, $value, $columns = ['*']) */ public function findWhere(array $where, $columns = ['*']) { + $this->scopeBoot(); + $this->applyConditions($where); return $this->model->get($columns); @@ -192,6 +216,8 @@ public function with($relations) */ public function firstOrCreate(array $attributes = []) { + $this->scopeBoot(); + return $this->model->firstOrCreate($attributes); } @@ -201,6 +227,8 @@ public function firstOrCreate(array $attributes = []) */ public function trashed($only = false) { + $this->scopeBoot(); + if ($only) { $this->model = $this->model->onlyTrashed(); } else { @@ -232,6 +260,8 @@ public function withTrashed() */ public function restore($id) { + $this->scopeBoot(); + return $this->withTrashed()->find($id)->restore(); } @@ -241,6 +271,8 @@ public function restore($id) */ public function forceDelete($id) { + $this->scopeBoot(); + return $this->withTrashed()->find($id)->forceDelete(); } } \ No newline at end of file From 3350b4e975b69cbd91f94b580730133d434b5132 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sun, 4 Jun 2017 07:38:31 +0000 Subject: [PATCH 32/78] Add PublishedScope to filter draft and future posts --- app/Models/Post.php | 12 ++++++++++ app/Models/User.php | 10 ++++++++ .../Eloquent/PostRepositoryEloquent.php | 12 ++++++++++ app/Scopes/PublishedScope.php | 24 +++++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 app/Scopes/PublishedScope.php diff --git a/app/Models/Post.php b/app/Models/Post.php index 0227507..988bb8e 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Presenters\PostPresenter; +use App\Scopes\PublishedScope; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Laracasts\Presenter\PresentableTrait; @@ -48,6 +49,17 @@ class Post extends Model */ protected $dates = ['published_at', 'deleted_at']; + /** + * The "booting" method of the model. + * + * @return void + */ + protected static function boot() + { + parent::boot(); + static::addGlobalScope(new PublishedScope); + } + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ diff --git a/app/Models/User.php b/app/Models/User.php index 81200d6..ac7cbdc 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -35,4 +35,14 @@ public function posts() { return $this->hasMany(Post::class); } + + /** + * TODO condition should be compared with role + * + * @return bool + */ + public function isAdmin() + { + return $this->id == 1; + } } diff --git a/app/Repositories/Eloquent/PostRepositoryEloquent.php b/app/Repositories/Eloquent/PostRepositoryEloquent.php index a3e9514..72b7a49 100644 --- a/app/Repositories/Eloquent/PostRepositoryEloquent.php +++ b/app/Repositories/Eloquent/PostRepositoryEloquent.php @@ -7,6 +7,7 @@ use App\Repositories\Contracts\TagRepository; use App\Repositories\Eloquent\Traits\Slugable; use App\Repositories\Exceptions\RepositoryException; +use App\Scopes\PublishedScope; use Carbon\Carbon; use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Model; @@ -35,6 +36,17 @@ public function __construct(Container $app, TagRepository $tagRepo) $this->tagRepo = $tagRepo; } + public function scopeBoot() + { + parent::scopeBoot(); + + // TODO to be optimized + // Session middleware is called after ServiceProvider binding, so can't set method boot in constructor + if (auth()->user()->isAdmin()) { + return $this->model = $this->model->withoutGlobalScope(PublishedScope::class); + } + } + /** * @return string */ diff --git a/app/Scopes/PublishedScope.php b/app/Scopes/PublishedScope.php new file mode 100644 index 0000000..0d801c2 --- /dev/null +++ b/app/Scopes/PublishedScope.php @@ -0,0 +1,24 @@ +where('published_at', '<=', Carbon::now()) + ->where('is_draft', '=', Post::IS_NOT_DRAFT); + } +} \ No newline at end of file From cffd2169a6d159d85f7ae1166e6db8159d27db35 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sun, 4 Jun 2017 14:04:37 +0000 Subject: [PATCH 33/78] Update password is not required in user-update action --- app/Http/Requests/StoreUpdateUserRequest.php | 23 ++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/app/Http/Requests/StoreUpdateUserRequest.php b/app/Http/Requests/StoreUpdateUserRequest.php index 712c058..d909556 100644 --- a/app/Http/Requests/StoreUpdateUserRequest.php +++ b/app/Http/Requests/StoreUpdateUserRequest.php @@ -26,16 +26,15 @@ public function rules() $rules = [ 'name' => 'required|max:255', 'email' => 'required|email|max:255|unique:users', - 'password' => 'required|min:6|confirmed', + 'password' => 'required|between:6,20|confirmed', ]; switch ($this->method()) { case "PUT": case "PATCH": - // TODO password is not required while in update event $rules = array_merge($rules, [ - 'password' => 'sometimes|min:6|confirmed', - // 'password_confirmation' => 'required_with:password|min:6', + 'password' => 'sometimes|required|between:6,20|confirmed', + 'password_confirmation' => 'sometimes|required|same:password', 'email' => 'required|email|max:255|unique:users,email,' . $this->route('user') ]); break; @@ -45,4 +44,20 @@ public function rules() return $rules; } + + /** + * Prepare the data for validation. + * + * @return void + */ + protected function prepareForValidation() + { + $pwd = ['password', 'password_confirmation']; + + collect($pwd)->each(function ($item) { + if (!$this->has($item)) { + $this->replace($this->except($item)); + } + }); + } } From 5658b84e756c5b16fef06dd06284ef097e51d256 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sun, 4 Jun 2017 14:16:04 +0000 Subject: [PATCH 34/78] Update enhance validation rules --- app/Http/Requests/StoreUpdatePostRequest.php | 2 +- app/Http/Requests/StoreUpdateRoleRequest.php | 3 ++- app/Http/Requests/StoreUpdateUserRequest.php | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Http/Requests/StoreUpdatePostRequest.php b/app/Http/Requests/StoreUpdatePostRequest.php index e567f89..b088c24 100644 --- a/app/Http/Requests/StoreUpdatePostRequest.php +++ b/app/Http/Requests/StoreUpdatePostRequest.php @@ -26,7 +26,7 @@ public function rules() $rules = [ 'title' => 'required', 'description' => 'max:100', - 'category_id' => 'required', + 'category_id' => 'required|exists:categories,id', 'slug' => 'unique:posts', 'content' => 'required' ]; diff --git a/app/Http/Requests/StoreUpdateRoleRequest.php b/app/Http/Requests/StoreUpdateRoleRequest.php index f95b41c..5a0fc6d 100644 --- a/app/Http/Requests/StoreUpdateRoleRequest.php +++ b/app/Http/Requests/StoreUpdateRoleRequest.php @@ -26,7 +26,8 @@ public function rules() $rules = [ 'name' => 'required|unique:roles|max:20', 'display_name' => 'max:50', - 'description' => 'string' + 'description' => 'string', + 'permission.*' => 'exists:permissions,id' ]; switch ($this->method()) { diff --git a/app/Http/Requests/StoreUpdateUserRequest.php b/app/Http/Requests/StoreUpdateUserRequest.php index d909556..3282872 100644 --- a/app/Http/Requests/StoreUpdateUserRequest.php +++ b/app/Http/Requests/StoreUpdateUserRequest.php @@ -27,6 +27,7 @@ public function rules() 'name' => 'required|max:255', 'email' => 'required|email|max:255|unique:users', 'password' => 'required|between:6,20|confirmed', + 'role.*' => 'exists:roles,id' ]; switch ($this->method()) { From da5e001f0068bc3dae61492668bec883db106d1d Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Sun, 4 Jun 2017 14:21:44 +0000 Subject: [PATCH 35/78] Add possible solution of repeated auto-generated slug --- app/Repositories/Eloquent/Traits/Slugable.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Repositories/Eloquent/Traits/Slugable.php b/app/Repositories/Eloquent/Traits/Slugable.php index a0ddb0e..4af5764 100644 --- a/app/Repositories/Eloquent/Traits/Slugable.php +++ b/app/Repositories/Eloquent/Traits/Slugable.php @@ -27,6 +27,10 @@ public function autoSlug($attributes, $keyName = 'name', $keySlug = 'slug') // TODO known bug // If update post with deleting original auto-generated slug, slug will generate again // and may 'duplicate' in DB. One solution is exclude current record(based on id) while doing update + // Solution 1: Add method 'prepareForValidation' in FormRequest, example below, + // $this->merge([ + // 'slug' => str_slug($this->input('title')) + // ]); if ($this->slugExists($slug, $keySlug)) { $slug = $this->unique($name); } From 1ee68d64081c0373ef999dce9dc89fc3f94b151a Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Mon, 5 Jun 2017 14:18:12 +0000 Subject: [PATCH 36/78] Rename admin.balde.php to app.blade.php --- resources/views/admin/categories/create.blade.php | 2 +- resources/views/admin/categories/edit.blade.php | 2 +- resources/views/admin/categories/index.blade.php | 2 +- resources/views/admin/home.blade.php | 2 +- .../views/admin/layouts/{admin.blade.php => app.blade.php} | 0 resources/views/admin/permissions/create.blade.php | 2 +- resources/views/admin/permissions/edit.blade.php | 2 +- resources/views/admin/permissions/index.blade.php | 2 +- resources/views/admin/posts/create.blade.php | 2 +- resources/views/admin/posts/edit.blade.php | 2 +- resources/views/admin/posts/index.blade.php | 2 +- resources/views/admin/roles/create.blade.php | 2 +- resources/views/admin/roles/edit.blade.php | 2 +- resources/views/admin/roles/index.blade.php | 2 +- resources/views/admin/tags/create.blade.php | 2 +- resources/views/admin/tags/edit.blade.php | 2 +- resources/views/admin/tags/index.blade.php | 2 +- resources/views/admin/users/create.blade.php | 2 +- resources/views/admin/users/edit.blade.php | 2 +- resources/views/admin/users/index.blade.php | 2 +- 20 files changed, 19 insertions(+), 19 deletions(-) rename resources/views/admin/layouts/{admin.blade.php => app.blade.php} (100%) diff --git a/resources/views/admin/categories/create.blade.php b/resources/views/admin/categories/create.blade.php index 2ab1951..d301f5e 100644 --- a/resources/views/admin/categories/create.blade.php +++ b/resources/views/admin/categories/create.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @inject('category', 'App\Models\Category') diff --git a/resources/views/admin/categories/edit.blade.php b/resources/views/admin/categories/edit.blade.php index c068724..d431c08 100644 --- a/resources/views/admin/categories/edit.blade.php +++ b/resources/views/admin/categories/edit.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content')
    diff --git a/resources/views/admin/categories/index.blade.php b/resources/views/admin/categories/index.blade.php index 9512888..aa3429c 100644 --- a/resources/views/admin/categories/index.blade.php +++ b/resources/views/admin/categories/index.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content') Add New diff --git a/resources/views/admin/home.blade.php b/resources/views/admin/home.blade.php index 41b5d12..3e2f312 100644 --- a/resources/views/admin/home.blade.php +++ b/resources/views/admin/home.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content') diff --git a/resources/views/admin/layouts/admin.blade.php b/resources/views/admin/layouts/app.blade.php similarity index 100% rename from resources/views/admin/layouts/admin.blade.php rename to resources/views/admin/layouts/app.blade.php diff --git a/resources/views/admin/permissions/create.blade.php b/resources/views/admin/permissions/create.blade.php index 4e637b9..e2dc7d7 100644 --- a/resources/views/admin/permissions/create.blade.php +++ b/resources/views/admin/permissions/create.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @inject('permission', 'App\Models\Permission') diff --git a/resources/views/admin/permissions/edit.blade.php b/resources/views/admin/permissions/edit.blade.php index 9835203..50b74b3 100644 --- a/resources/views/admin/permissions/edit.blade.php +++ b/resources/views/admin/permissions/edit.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content')
    diff --git a/resources/views/admin/permissions/index.blade.php b/resources/views/admin/permissions/index.blade.php index f8e8d56..6f54970 100644 --- a/resources/views/admin/permissions/index.blade.php +++ b/resources/views/admin/permissions/index.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content') Add New diff --git a/resources/views/admin/posts/create.blade.php b/resources/views/admin/posts/create.blade.php index 19dfc78..26f5e9f 100644 --- a/resources/views/admin/posts/create.blade.php +++ b/resources/views/admin/posts/create.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @inject('post', 'App\Models\Post') diff --git a/resources/views/admin/posts/edit.blade.php b/resources/views/admin/posts/edit.blade.php index d0cd6ff..d79e499 100644 --- a/resources/views/admin/posts/edit.blade.php +++ b/resources/views/admin/posts/edit.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content')
    diff --git a/resources/views/admin/posts/index.blade.php b/resources/views/admin/posts/index.blade.php index a89a842..5d24e30 100644 --- a/resources/views/admin/posts/index.blade.php +++ b/resources/views/admin/posts/index.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content') Add New diff --git a/resources/views/admin/roles/create.blade.php b/resources/views/admin/roles/create.blade.php index da44023..4c9e7da 100644 --- a/resources/views/admin/roles/create.blade.php +++ b/resources/views/admin/roles/create.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @inject('role', 'App\Models\Role') diff --git a/resources/views/admin/roles/edit.blade.php b/resources/views/admin/roles/edit.blade.php index 73eea5a..1068256 100644 --- a/resources/views/admin/roles/edit.blade.php +++ b/resources/views/admin/roles/edit.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content')
    diff --git a/resources/views/admin/roles/index.blade.php b/resources/views/admin/roles/index.blade.php index 63b1d49..981b06f 100644 --- a/resources/views/admin/roles/index.blade.php +++ b/resources/views/admin/roles/index.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content') Add New diff --git a/resources/views/admin/tags/create.blade.php b/resources/views/admin/tags/create.blade.php index da86850..3ea736f 100644 --- a/resources/views/admin/tags/create.blade.php +++ b/resources/views/admin/tags/create.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @inject('tag', 'App\Models\Tag') diff --git a/resources/views/admin/tags/edit.blade.php b/resources/views/admin/tags/edit.blade.php index c92afd0..7e50722 100644 --- a/resources/views/admin/tags/edit.blade.php +++ b/resources/views/admin/tags/edit.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content')
    diff --git a/resources/views/admin/tags/index.blade.php b/resources/views/admin/tags/index.blade.php index 01b7cfd..9da0868 100644 --- a/resources/views/admin/tags/index.blade.php +++ b/resources/views/admin/tags/index.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content') Add New diff --git a/resources/views/admin/users/create.blade.php b/resources/views/admin/users/create.blade.php index 6fc4478..979f539 100644 --- a/resources/views/admin/users/create.blade.php +++ b/resources/views/admin/users/create.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @inject('user', 'App\Models\User') diff --git a/resources/views/admin/users/edit.blade.php b/resources/views/admin/users/edit.blade.php index d4b9912..0531577 100644 --- a/resources/views/admin/users/edit.blade.php +++ b/resources/views/admin/users/edit.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content')
    diff --git a/resources/views/admin/users/index.blade.php b/resources/views/admin/users/index.blade.php index eb5b90b..73bb08f 100644 --- a/resources/views/admin/users/index.blade.php +++ b/resources/views/admin/users/index.blade.php @@ -1,4 +1,4 @@ -@extends('admin.layouts.admin') +@extends('admin.layouts.app') @section('content') Add New From e1d41172a83ab3fd4238647ae05f04af9949148c Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Mon, 5 Jun 2017 14:24:38 +0000 Subject: [PATCH 37/78] Change text html_header_title to title --- resources/views/admin/partials/html-header.blade.php | 2 +- resources/views/auth/login.blade.php | 2 +- resources/views/auth/passwords/email.blade.php | 2 +- resources/views/auth/passwords/reset.blade.php | 2 +- resources/views/auth/register.blade.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/views/admin/partials/html-header.blade.php b/resources/views/admin/partials/html-header.blade.php index df3e914..f757f88 100644 --- a/resources/views/admin/partials/html-header.blade.php +++ b/resources/views/admin/partials/html-header.blade.php @@ -1,7 +1,7 @@ - @yield('html_header_title', 'Dashboard') - {{ config('app.name', 'Laravel') }} + @yield('title', 'Dashboard') - {{ config('app.name', 'Laravel') }} diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index fe7c09a..9cf8dc4 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -1,6 +1,6 @@ @extends('layouts.auth') -@section('html_header_title') +@section('title') Log in @endsection diff --git a/resources/views/auth/passwords/email.blade.php b/resources/views/auth/passwords/email.blade.php index 23df9e6..482ebea 100644 --- a/resources/views/auth/passwords/email.blade.php +++ b/resources/views/auth/passwords/email.blade.php @@ -1,6 +1,6 @@ @extends('layouts.auth') -@section('html_header_title') +@section('title') Reset @endsection diff --git a/resources/views/auth/passwords/reset.blade.php b/resources/views/auth/passwords/reset.blade.php index a2aa94b..d141fa8 100644 --- a/resources/views/auth/passwords/reset.blade.php +++ b/resources/views/auth/passwords/reset.blade.php @@ -1,6 +1,6 @@ @extends('layouts.auth') -@section('html_header_title') +@section('title') Password Reset @endsection diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php index b4e19af..bfc58e4 100644 --- a/resources/views/auth/register.blade.php +++ b/resources/views/auth/register.blade.php @@ -1,6 +1,6 @@ @extends('layouts.auth') -@section('html_header_title') +@section('title') Register @endsection From e763a6244c6a68810c9f83ffdc57d4b01f549609 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Mon, 5 Jun 2017 14:27:24 +0000 Subject: [PATCH 38/78] Rename html-header.blade.php to head.blade.php --- resources/views/admin/layouts/app.blade.php | 2 +- .../admin/partials/{html-header.blade.php => head.blade.php} | 0 resources/views/layouts/auth.blade.php | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename resources/views/admin/partials/{html-header.blade.php => head.blade.php} (100%) diff --git a/resources/views/admin/layouts/app.blade.php b/resources/views/admin/layouts/app.blade.php index 935fba8..3f08fdc 100644 --- a/resources/views/admin/layouts/app.blade.php +++ b/resources/views/admin/layouts/app.blade.php @@ -5,7 +5,7 @@ --> -@include('admin.partials.html-header') +@include('admin.partials.head') -

    \ No newline at end of file diff --git a/resources/views/partials/navbar.blade.php b/resources/views/partials/navbar.blade.php new file mode 100644 index 0000000..46623b8 --- /dev/null +++ b/resources/views/partials/navbar.blade.php @@ -0,0 +1,24 @@ + + +@push('js') + +@endpush \ No newline at end of file From f05e72db507416496b705145833038b24833cb95 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Mon, 12 Jun 2017 12:44:53 +0000 Subject: [PATCH 48/78] Add laravel-pagination blade by using publish command --- .../vendor/pagination/bootstrap-4.blade.php | 36 +++++++++++++++++++ .../views/vendor/pagination/default.blade.php | 36 +++++++++++++++++++ .../pagination/simple-bootstrap-4.blade.php | 17 +++++++++ .../pagination/simple-default.blade.php | 17 +++++++++ 4 files changed, 106 insertions(+) create mode 100644 resources/views/vendor/pagination/bootstrap-4.blade.php create mode 100644 resources/views/vendor/pagination/default.blade.php create mode 100644 resources/views/vendor/pagination/simple-bootstrap-4.blade.php create mode 100644 resources/views/vendor/pagination/simple-default.blade.php diff --git a/resources/views/vendor/pagination/bootstrap-4.blade.php b/resources/views/vendor/pagination/bootstrap-4.blade.php new file mode 100644 index 0000000..3f98455 --- /dev/null +++ b/resources/views/vendor/pagination/bootstrap-4.blade.php @@ -0,0 +1,36 @@ +@if ($paginator->hasPages()) +
      + {{-- Previous Page Link --}} + @if ($paginator->onFirstPage()) +
    • «
    • + @else +
    • + @endif + + {{-- Pagination Elements --}} + @foreach ($elements as $element) + {{-- "Three Dots" Separator --}} + @if (is_string($element)) +
    • {{ $element }}
    • + @endif + + {{-- Array Of Links --}} + @if (is_array($element)) + @foreach ($element as $page => $url) + @if ($page == $paginator->currentPage()) +
    • {{ $page }}
    • + @else +
    • {{ $page }}
    • + @endif + @endforeach + @endif + @endforeach + + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
    • + @else +
    • »
    • + @endif +
    +@endif diff --git a/resources/views/vendor/pagination/default.blade.php b/resources/views/vendor/pagination/default.blade.php new file mode 100644 index 0000000..4e795ff --- /dev/null +++ b/resources/views/vendor/pagination/default.blade.php @@ -0,0 +1,36 @@ +@if ($paginator->hasPages()) +
      + {{-- Previous Page Link --}} + @if ($paginator->onFirstPage()) +
    • «
    • + @else +
    • + @endif + + {{-- Pagination Elements --}} + @foreach ($elements as $element) + {{-- "Three Dots" Separator --}} + @if (is_string($element)) +
    • {{ $element }}
    • + @endif + + {{-- Array Of Links --}} + @if (is_array($element)) + @foreach ($element as $page => $url) + @if ($page == $paginator->currentPage()) +
    • {{ $page }}
    • + @else +
    • {{ $page }}
    • + @endif + @endforeach + @endif + @endforeach + + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
    • + @else +
    • »
    • + @endif +
    +@endif diff --git a/resources/views/vendor/pagination/simple-bootstrap-4.blade.php b/resources/views/vendor/pagination/simple-bootstrap-4.blade.php new file mode 100644 index 0000000..a9a18d3 --- /dev/null +++ b/resources/views/vendor/pagination/simple-bootstrap-4.blade.php @@ -0,0 +1,17 @@ +@if ($paginator->hasPages()) +
      + {{-- Previous Page Link --}} + @if ($paginator->onFirstPage()) +
    • @lang('pagination.previous')
    • + @else +
    • + @endif + + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
    • + @else +
    • @lang('pagination.next')
    • + @endif +
    +@endif diff --git a/resources/views/vendor/pagination/simple-default.blade.php b/resources/views/vendor/pagination/simple-default.blade.php new file mode 100644 index 0000000..1801609 --- /dev/null +++ b/resources/views/vendor/pagination/simple-default.blade.php @@ -0,0 +1,17 @@ +@if ($paginator->hasPages()) +
      + {{-- Previous Page Link --}} + @if ($paginator->onFirstPage()) +
    • @lang('pagination.previous')
    • + @else +
    • + @endif + + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
    • + @else +
    • @lang('pagination.next')
    • + @endif +
    +@endif From a671c59b1b2da13cf5a55d781ec35fd3bde858e1 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Mon, 12 Jun 2017 13:01:11 +0000 Subject: [PATCH 49/78] Add materialize pagination blade --- .../vendor/pagination/materialize.blade.php | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 resources/views/vendor/pagination/materialize.blade.php diff --git a/resources/views/vendor/pagination/materialize.blade.php b/resources/views/vendor/pagination/materialize.blade.php new file mode 100644 index 0000000..94fa4c5 --- /dev/null +++ b/resources/views/vendor/pagination/materialize.blade.php @@ -0,0 +1,37 @@ +{{-- Usage: $paginator->links('view.name') --}} +@if ($paginator->hasPages()) +
      + {{-- Previous Page Link --}} + @if ($paginator->onFirstPage()) +
    • chevron_left
    • + @else +
    • + @endif + + {{-- Pagination Elements --}} + @foreach ($elements as $element) + {{-- "Three Dots" Separator --}} + @if (is_string($element)) +
    • {{ $element }}
    • + @endif + + {{-- Array Of Links --}} + @if (is_array($element)) + @foreach ($element as $page => $url) + @if ($page == $paginator->currentPage()) +
    • {{ $page }}
    • + @else +
    • {{ $page }}
    • + @endif + @endforeach + @endif + @endforeach + + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
    • + @else +
    • chevron_right
    • + @endif +
    +@endif From d84879a676ce0af2b5ddb8ce332159cec70b4c05 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Mon, 12 Jun 2017 15:23:00 +0000 Subject: [PATCH 50/78] Add static header example --- resources/views/layouts/app.blade.php | 2 + resources/views/partials/header.blade.php | 12 ++++++ resources/views/partials/navbar.blade.php | 47 +++++++++++++++-------- 3 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 resources/views/partials/header.blade.php diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 5b232bd..332d0e3 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -47,6 +47,8 @@ {{--
    --}}
    @include('partials.navbar') + + @include('partials.header')
    diff --git a/resources/views/partials/header.blade.php b/resources/views/partials/header.blade.php new file mode 100644 index 0000000..4c192b8 --- /dev/null +++ b/resources/views/partials/header.blade.php @@ -0,0 +1,12 @@ +
    +
    +
    +
    + +
    +
    +
    Miles Peng
    +
    +
    +
    +
    \ No newline at end of file diff --git a/resources/views/partials/navbar.blade.php b/resources/views/partials/navbar.blade.php index 46623b8..0f2fd6f 100644 --- a/resources/views/partials/navbar.blade.php +++ b/resources/views/partials/navbar.blade.php @@ -1,24 +1,39 @@ - + + @push('js') @endpush \ No newline at end of file From f4409f31310604de62c4648aa069a27226a2f65d Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 13 Jun 2017 11:37:35 +0800 Subject: [PATCH 51/78] Update Repository Contract&Concrete with adding withCount method --- app/Repositories/Contracts/RepositoryInterface.php | 8 ++++++++ app/Repositories/Eloquent/Repository.php | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/app/Repositories/Contracts/RepositoryInterface.php b/app/Repositories/Contracts/RepositoryInterface.php index 1c8940d..a9f0c47 100644 --- a/app/Repositories/Contracts/RepositoryInterface.php +++ b/app/Repositories/Contracts/RepositoryInterface.php @@ -76,6 +76,14 @@ public function findWhere(array $where, $columns = ['*']); */ public function with($relations); + /** + * Add subselect queries to count the relations. + * + * @param mixed $relations + * @return $this + */ + public function withCount($relations); + /** * @param array $attributes * @return mixed diff --git a/app/Repositories/Eloquent/Repository.php b/app/Repositories/Eloquent/Repository.php index b6969c9..d83998e 100644 --- a/app/Repositories/Eloquent/Repository.php +++ b/app/Repositories/Eloquent/Repository.php @@ -273,4 +273,15 @@ public function forceDelete($id) return $this->withTrashed()->find($id)->forceDelete(); } + + /** + * @param mixed $relations + * @return $this + */ + public function withCount($relations) + { + $this->model = $this->model->withCount($relations); + + return $this; + } } \ No newline at end of file From 48a2714f3ca48e24f8f0c35d49927788fb9d03d2 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 13 Jun 2017 14:43:58 +0800 Subject: [PATCH 52/78] Update RepositoryEloquent with missing params --- app/Repositories/Eloquent/Repository.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Repositories/Eloquent/Repository.php b/app/Repositories/Eloquent/Repository.php index d83998e..d5115c6 100644 --- a/app/Repositories/Eloquent/Repository.php +++ b/app/Repositories/Eloquent/Repository.php @@ -71,9 +71,9 @@ public function all($columns = ['*']) $this->scopeBoot(); if ($this->model instanceof Builder) { - $results = $this->model->get(); + $results = $this->model->get($columns); } else { - $results = $this->model->all(); + $results = $this->model->all($columns); } return $results; From f9ad7eec5c98a3f8b01f566cf55ed5d3fd6f1bb1 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 13 Jun 2017 14:44:31 +0800 Subject: [PATCH 53/78] Add isAdmin() global function --- app/Repositories/Eloquent/PostRepositoryEloquent.php | 2 +- app/helpers.php | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/Repositories/Eloquent/PostRepositoryEloquent.php b/app/Repositories/Eloquent/PostRepositoryEloquent.php index 280d825..5e9d310 100644 --- a/app/Repositories/Eloquent/PostRepositoryEloquent.php +++ b/app/Repositories/Eloquent/PostRepositoryEloquent.php @@ -42,7 +42,7 @@ public function scopeBoot() // TODO to be optimized // Session middleware is called after ServiceProvider binding, so can't set method boot in constructor - if (auth()->check() && auth()->user()->isAdmin()) { + if (isAdmin()) { return $this->model = $this->model->withoutGlobalScope(PublishedScope::class); } } diff --git a/app/helpers.php b/app/helpers.php index ad8fc8f..c339a1d 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -71,3 +71,15 @@ function str_slug_with_cn($text, $forceTrans = false) return str_slug($text); } } + +if (!function_exists('isAdmin')) { + /** + * Determine if current user is login and is admin. + * + * @return bool + */ + function isAdmin() + { + return auth()->check() && auth()->user()->isAdmin(); + } +} From 3fa816bcf21ac31ede6f94757034790819d09557 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 13 Jun 2017 14:47:54 +0800 Subject: [PATCH 54/78] Add allWithPostCount contract&concrete in CateRepository --- .../Contracts/CategoryRepository.php | 6 ++++++ .../Eloquent/CategoryRepositoryEloquent.php | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/app/Repositories/Contracts/CategoryRepository.php b/app/Repositories/Contracts/CategoryRepository.php index 9654769..f97a91f 100644 --- a/app/Repositories/Contracts/CategoryRepository.php +++ b/app/Repositories/Contracts/CategoryRepository.php @@ -20,4 +20,10 @@ public function createCategory(array $attributes); * @return mixed */ public function updateCategory(array $attributes, $id); + + /** + * @param array $columns + * @return mixed + */ + public function allWithPostCount($columns = ['*']); } diff --git a/app/Repositories/Eloquent/CategoryRepositoryEloquent.php b/app/Repositories/Eloquent/CategoryRepositoryEloquent.php index eb9969a..c34eed2 100644 --- a/app/Repositories/Eloquent/CategoryRepositoryEloquent.php +++ b/app/Repositories/Eloquent/CategoryRepositoryEloquent.php @@ -5,6 +5,7 @@ use App\Models\Category; use App\Repositories\Contracts\CategoryRepository; use App\Repositories\Eloquent\Traits\Slugable; +use App\Scopes\PublishedScope; /** * Class CategoryRepositoryEloquent @@ -55,4 +56,23 @@ public function updateCategory(array $attributes, $id) return $this->update($attributes, $id); } + + /** + * @param array $columns + * @return mixed + */ + public function allWithPostCount($columns = ['*']) + { + return $this->withCount([ + 'posts' => function ($query) { + if (isAdmin()) { + $query->withoutGlobalScope(PublishedScope::class); + } + } + ]) + ->all($columns) + ->reject(function ($category) { + return $category->posts_count == 0; + }); + } } From 4c6cc0b19f90432e90080e121140e79599c1afe0 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 13 Jun 2017 14:50:38 +0800 Subject: [PATCH 55/78] Add CategoriesComposer and related views, service provider --- app/Http/ViewComposers/CategoriesComposer.php | 37 +++++++++++++++++++ app/Providers/ComposerServiceProvider.php | 34 +++++++++++++++++ config/app.php | 1 + resources/views/widgets/category.blade.php | 6 +++ 4 files changed, 78 insertions(+) create mode 100644 app/Http/ViewComposers/CategoriesComposer.php create mode 100644 app/Providers/ComposerServiceProvider.php create mode 100644 resources/views/widgets/category.blade.php diff --git a/app/Http/ViewComposers/CategoriesComposer.php b/app/Http/ViewComposers/CategoriesComposer.php new file mode 100644 index 0000000..015a4f0 --- /dev/null +++ b/app/Http/ViewComposers/CategoriesComposer.php @@ -0,0 +1,37 @@ +cateRepo = $cateRepo; + } + + /** + * @param View $view + */ + public function compose(View $view) + { + $categories = $this->cateRepo->allWithPostCount(); + + $view->with('categories', $categories); + } +} \ No newline at end of file diff --git a/app/Providers/ComposerServiceProvider.php b/app/Providers/ComposerServiceProvider.php new file mode 100644 index 0000000..125e648 --- /dev/null +++ b/app/Providers/ComposerServiceProvider.php @@ -0,0 +1,34 @@ + +
    Categories
    + @foreach($categories as $category) + {{ $category->posts_count }}{{ $category->name }} + @endforeach +
    \ No newline at end of file From e6030e1653a66ea414e05031d03eca72f2764b5f Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 13 Jun 2017 15:34:59 +0800 Subject: [PATCH 56/78] Add TagsComposer and related views, service provider --- app/Http/ViewComposers/TagsComposer.php | 38 +++++++++++++++++++ app/Providers/ComposerServiceProvider.php | 2 + app/Repositories/Contracts/TagRepository.php | 6 +++ .../Eloquent/CategoryRepositoryEloquent.php | 2 +- .../Eloquent/TagRepositoryEloquent.php | 20 ++++++++++ resources/views/widgets/tag.blade.php | 24 ++++++++++++ 6 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 app/Http/ViewComposers/TagsComposer.php create mode 100644 resources/views/widgets/tag.blade.php diff --git a/app/Http/ViewComposers/TagsComposer.php b/app/Http/ViewComposers/TagsComposer.php new file mode 100644 index 0000000..7b04b32 --- /dev/null +++ b/app/Http/ViewComposers/TagsComposer.php @@ -0,0 +1,38 @@ +tagRepo = $tagRepo; + } + + /** + * @param View $view + */ + public function compose(View $view) + { + $tags = $this->tagRepo->allWithPostCount(); + + $view->with('tags', $tags); + } +} \ No newline at end of file diff --git a/app/Providers/ComposerServiceProvider.php b/app/Providers/ComposerServiceProvider.php index 125e648..7dde51b 100644 --- a/app/Providers/ComposerServiceProvider.php +++ b/app/Providers/ComposerServiceProvider.php @@ -3,6 +3,7 @@ namespace App\Providers; use App\Http\ViewComposers\CategoriesComposer; +use App\Http\ViewComposers\TagsComposer; use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; @@ -20,6 +21,7 @@ class ComposerServiceProvider extends ServiceProvider public function boot() { View::composer('widgets.category', CategoriesComposer::class); + View::composer('widgets.tag', TagsComposer::class); } /** diff --git a/app/Repositories/Contracts/TagRepository.php b/app/Repositories/Contracts/TagRepository.php index dc60440..18a6e45 100644 --- a/app/Repositories/Contracts/TagRepository.php +++ b/app/Repositories/Contracts/TagRepository.php @@ -20,4 +20,10 @@ public function createTag(array $attributes); * @return mixed */ public function updateTag(array $attributes, $id); + + /** + * @param array $columns + * @return mixed + */ + public function allWithPostCount($columns = ['*']); } diff --git a/app/Repositories/Eloquent/CategoryRepositoryEloquent.php b/app/Repositories/Eloquent/CategoryRepositoryEloquent.php index c34eed2..53cb540 100644 --- a/app/Repositories/Eloquent/CategoryRepositoryEloquent.php +++ b/app/Repositories/Eloquent/CategoryRepositoryEloquent.php @@ -70,7 +70,7 @@ public function allWithPostCount($columns = ['*']) } } ]) - ->all($columns) + ->all() ->reject(function ($category) { return $category->posts_count == 0; }); diff --git a/app/Repositories/Eloquent/TagRepositoryEloquent.php b/app/Repositories/Eloquent/TagRepositoryEloquent.php index 3392b14..2cea2a8 100644 --- a/app/Repositories/Eloquent/TagRepositoryEloquent.php +++ b/app/Repositories/Eloquent/TagRepositoryEloquent.php @@ -5,6 +5,7 @@ use App\Models\Tag; use App\Repositories\Contracts\TagRepository; use App\Repositories\Eloquent\Traits\Slugable; +use App\Scopes\PublishedScope; /** * Class TagRepositoryEloquent @@ -55,4 +56,23 @@ public function updateTag(array $attributes, $id) return $this->update($attributes, $id); } + + /** + * @param array $columns + * @return mixed + */ + public function allWithPostCount($columns = ['*']) + { + return $this->withCount([ + 'posts' => function ($query) { + if (isAdmin()) { + $query->withoutGlobalScope(PublishedScope::class); + } + } + ]) + ->all() + ->reject(function ($tag) { + return $tag->posts_count == 0; + }); + } } diff --git a/resources/views/widgets/tag.blade.php b/resources/views/widgets/tag.blade.php new file mode 100644 index 0000000..7dd797a --- /dev/null +++ b/resources/views/widgets/tag.blade.php @@ -0,0 +1,24 @@ +{{-- TODO move to app.css --}} + + +
    +
    Tags
    +
    + @foreach($tags as $tag) + + {{ $tag->name }} + {{ $tag->posts_count }} + + @endforeach +
    +
    \ No newline at end of file From d7aae692ef9cdb1c297997f75214bd9c4f425611 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Tue, 13 Jun 2017 16:43:37 +0800 Subject: [PATCH 57/78] Add FAB to scroll up to top --- resources/views/layouts/app.blade.php | 2 ++ resources/views/partials/fab.blade.php | 39 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 resources/views/partials/fab.blade.php diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 332d0e3..8f6f2a6 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -58,6 +58,8 @@ @include('partials.footer') + + @include('partials.fab') {{--
    --}} diff --git a/resources/views/partials/fab.blade.php b/resources/views/partials/fab.blade.php new file mode 100644 index 0000000..238b893 --- /dev/null +++ b/resources/views/partials/fab.blade.php @@ -0,0 +1,39 @@ +
    + + expand_less + + {{----}} +
    + +@push('js') + +@endpush \ No newline at end of file From 2620f5d3cf302ebb2a8353579d06a82e6cd88cc4 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Wed, 14 Jun 2017 11:17:46 +0800 Subject: [PATCH 58/78] Add excerpt column to posts and related logic --- app/Http/Requests/StoreUpdatePostRequest.php | 3 ++- app/Models/Post.php | 3 ++- .../Eloquent/PostRepositoryEloquent.php | 2 ++ database/factories/ModelFactory.php | 1 + .../2017_05_29_154816_create_posts_table.php | 1 + resources/views/admin/posts/_form.blade.php | 19 +++++++++++++++---- 6 files changed, 23 insertions(+), 6 deletions(-) diff --git a/app/Http/Requests/StoreUpdatePostRequest.php b/app/Http/Requests/StoreUpdatePostRequest.php index b088c24..cc9b681 100644 --- a/app/Http/Requests/StoreUpdatePostRequest.php +++ b/app/Http/Requests/StoreUpdatePostRequest.php @@ -28,7 +28,8 @@ public function rules() 'description' => 'max:100', 'category_id' => 'required|exists:categories,id', 'slug' => 'unique:posts', - 'content' => 'required' + 'content' => 'required', + 'excerpt' => 'required' ]; switch ($this->method()) { diff --git a/app/Models/Post.php b/app/Models/Post.php index 988bb8e..1c2af04 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -41,7 +41,8 @@ class Post extends Model 'description', 'content', 'published_at', - 'is_draft' + 'is_draft', + 'excerpt' ]; /** diff --git a/app/Repositories/Eloquent/PostRepositoryEloquent.php b/app/Repositories/Eloquent/PostRepositoryEloquent.php index 72b7a49..e55bb6c 100644 --- a/app/Repositories/Eloquent/PostRepositoryEloquent.php +++ b/app/Repositories/Eloquent/PostRepositoryEloquent.php @@ -86,6 +86,8 @@ protected function preHandleData(array $attributes) 'is_draft' => $isDraft, ]); + // TODO excerpt should be html purifier + return $attributes; } diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index 4d2a17c..195469a 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -74,6 +74,7 @@ 'category_id' => \App\Models\Category::pluck('id')->random(), 'description' => $faker->sentence(10), 'slug' => str_slug($title), + 'excerpt' => $faker->sentences(3, true), 'content' => markdownContent($faker) ]; }); \ No newline at end of file diff --git a/database/migrations/2017_05_29_154816_create_posts_table.php b/database/migrations/2017_05_29_154816_create_posts_table.php index b2dda07..342faab 100644 --- a/database/migrations/2017_05_29_154816_create_posts_table.php +++ b/database/migrations/2017_05_29_154816_create_posts_table.php @@ -21,6 +21,7 @@ public function up() $table->foreign('category_id')->references('id')->on('categories'); $table->string('title'); $table->string('description')->nullable(); + $table->text('excerpt'); $table->string('slug')->unique(); $table->longText('content'); $table->integer('view_count')->unsigned()->default(0); diff --git a/resources/views/admin/posts/_form.blade.php b/resources/views/admin/posts/_form.blade.php index ffbb54a..138b104 100644 --- a/resources/views/admin/posts/_form.blade.php +++ b/resources/views/admin/posts/_form.blade.php @@ -28,7 +28,7 @@
    - @foreach($categories as $category) @endforeach @@ -39,7 +39,7 @@
    - @foreach($tags as $tag) @endforeach @@ -48,7 +48,14 @@
    - + +
    + +
    +
    + +
    +
    @@ -68,7 +75,7 @@
    is_draft))checked="checked"@endif> - +
    @@ -91,6 +98,10 @@ .editor-preview-side { z-index: 2000 } + + textarea[name=excerpt] { + width: 100%; + } @endpush From 989ea712e930a4e43cc97c3f069ced84588e447f Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Wed, 14 Jun 2017 11:37:58 +0800 Subject: [PATCH 59/78] Update model factory of Post --- database/factories/ModelFactory.php | 6 +++++- .../migrations/2017_05_29_154816_create_posts_table.php | 2 +- database/seeds/PostsTableSeeder.php | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index 195469a..7851355 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -75,6 +75,10 @@ 'description' => $faker->sentence(10), 'slug' => str_slug($title), 'excerpt' => $faker->sentences(3, true), - 'content' => markdownContent($faker) + 'content' => markdownContent($faker), + 'view_count' => mt_rand(0, 10000), + 'is_draft' => $faker->boolean, + 'published_at' => $faker->dateTimeThisYear('2018-12-31 23:59:59'), + 'deleted_at' => $faker->optional(0.3)->dateTime(), ]; }); \ No newline at end of file diff --git a/database/migrations/2017_05_29_154816_create_posts_table.php b/database/migrations/2017_05_29_154816_create_posts_table.php index 342faab..1df290a 100644 --- a/database/migrations/2017_05_29_154816_create_posts_table.php +++ b/database/migrations/2017_05_29_154816_create_posts_table.php @@ -25,7 +25,7 @@ public function up() $table->string('slug')->unique(); $table->longText('content'); $table->integer('view_count')->unsigned()->default(0); - $table->timestamp('published_at')->nullable(); + $table->timestamp('published_at'); $table->boolean('is_draft')->default(false); $table->timestamps(); $table->softDeletes(); diff --git a/database/seeds/PostsTableSeeder.php b/database/seeds/PostsTableSeeder.php index 5cbfb97..99569dc 100644 --- a/database/seeds/PostsTableSeeder.php +++ b/database/seeds/PostsTableSeeder.php @@ -11,9 +11,9 @@ class PostsTableSeeder extends Seeder */ public function run() { - factory(\App\Models\Post::class, 15)->create()->each(function (\App\Models\Post $post) { + factory(\App\Models\Post::class, 30)->create()->each(function (\App\Models\Post $post) { $tagCount = \App\Models\Tag::count(); - $post->tags()->sync(\App\Models\Tag::inRandomOrder()->take(mt_rand(1, $tagCount))->get()); + $post->tags()->sync(\App\Models\Tag::inRandomOrder()->take(mt_rand(1, 4))->get()); // $post->tags()->attach(App\Models\Tag::all()->random(rand(1, App\Models\Tag::count()))); }); } From 74f773a36abb8f0ef557dc2d0fae28ea3fcd2881 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Wed, 14 Jun 2017 11:58:52 +0800 Subject: [PATCH 60/78] Add feature_img column to posts and related logic --- app/Http/Requests/StoreUpdatePostRequest.php | 15 ++++++++++++++- app/Models/Post.php | 3 ++- .../Eloquent/PostRepositoryEloquent.php | 2 ++ database/factories/ModelFactory.php | 1 + .../2017_05_29_154816_create_posts_table.php | 1 + resources/views/admin/posts/_form.blade.php | 7 +++++++ 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/app/Http/Requests/StoreUpdatePostRequest.php b/app/Http/Requests/StoreUpdatePostRequest.php index cc9b681..ec94d0b 100644 --- a/app/Http/Requests/StoreUpdatePostRequest.php +++ b/app/Http/Requests/StoreUpdatePostRequest.php @@ -29,7 +29,8 @@ public function rules() 'category_id' => 'required|exists:categories,id', 'slug' => 'unique:posts', 'content' => 'required', - 'excerpt' => 'required' + 'excerpt' => 'required', + 'feature_img' => 'sometimes|required|url' ]; switch ($this->method()) { @@ -45,4 +46,16 @@ public function rules() return $rules; } + + /** + * Prepare the data for validation. + * + * @return void + */ + protected function prepareForValidation() + { + if (!$this->has('feature_img')) { + $this->replace($this->except('feature_img')); + } + } } diff --git a/app/Models/Post.php b/app/Models/Post.php index 1c2af04..d93f097 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -42,7 +42,8 @@ class Post extends Model 'content', 'published_at', 'is_draft', - 'excerpt' + 'excerpt', + 'feature_img' ]; /** diff --git a/app/Repositories/Eloquent/PostRepositoryEloquent.php b/app/Repositories/Eloquent/PostRepositoryEloquent.php index e55bb6c..83beb31 100644 --- a/app/Repositories/Eloquent/PostRepositoryEloquent.php +++ b/app/Repositories/Eloquent/PostRepositoryEloquent.php @@ -88,6 +88,8 @@ protected function preHandleData(array $attributes) // TODO excerpt should be html purifier + // TODO condition while no feature_img + return $attributes; } diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index 7851355..391cf97 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -75,6 +75,7 @@ 'description' => $faker->sentence(10), 'slug' => str_slug($title), 'excerpt' => $faker->sentences(3, true), + 'feature_img' => $faker->imageUrl(), 'content' => markdownContent($faker), 'view_count' => mt_rand(0, 10000), 'is_draft' => $faker->boolean, diff --git a/database/migrations/2017_05_29_154816_create_posts_table.php b/database/migrations/2017_05_29_154816_create_posts_table.php index 1df290a..ae1d6ce 100644 --- a/database/migrations/2017_05_29_154816_create_posts_table.php +++ b/database/migrations/2017_05_29_154816_create_posts_table.php @@ -23,6 +23,7 @@ public function up() $table->string('description')->nullable(); $table->text('excerpt'); $table->string('slug')->unique(); + $table->string('feature_img')->nullable(); $table->longText('content'); $table->integer('view_count')->unsigned()->default(0); $table->timestamp('published_at'); diff --git a/resources/views/admin/posts/_form.blade.php b/resources/views/admin/posts/_form.blade.php index 138b104..f6d38b5 100644 --- a/resources/views/admin/posts/_form.blade.php +++ b/resources/views/admin/posts/_form.blade.php @@ -47,6 +47,13 @@
    +
    + +
    + +
    +
    +
    From b6c0605fa4f178d4f03e81fa6dcdf605cd343a2a Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Wed, 14 Jun 2017 14:38:10 +0800 Subject: [PATCH 61/78] Add base frontend structure. Check commit detail Massive changed of frontend, including controller and views(major) * Add PostController * Add posts frontend route * Add widgets search, category, tag, post-card * Add main views of posts --- .../Controllers/Frontend/PostController.php | 51 +++++++++++++++++++ resources/views/layouts/app.blade.php | 49 ++++++++++++++++++ resources/views/partials/sidebar.blade.php | 15 ++++++ resources/views/posts/_list.blade.php | 1 + resources/views/posts/_show.blade.php | 3 ++ resources/views/posts/index.blade.php | 15 ++++++ resources/views/widgets/category.blade.php | 5 +- resources/views/widgets/post-card.blade.php | 42 +++++++++++++++ resources/views/widgets/search.blade.php | 19 +++++++ resources/views/widgets/tag.blade.php | 13 ----- routes/web.php | 2 +- 11 files changed, 200 insertions(+), 15 deletions(-) create mode 100644 app/Http/Controllers/Frontend/PostController.php create mode 100644 resources/views/partials/sidebar.blade.php create mode 100644 resources/views/posts/_list.blade.php create mode 100644 resources/views/posts/_show.blade.php create mode 100644 resources/views/posts/index.blade.php create mode 100644 resources/views/widgets/post-card.blade.php create mode 100644 resources/views/widgets/search.blade.php diff --git a/app/Http/Controllers/Frontend/PostController.php b/app/Http/Controllers/Frontend/PostController.php new file mode 100644 index 0000000..8a56cdb --- /dev/null +++ b/app/Http/Controllers/Frontend/PostController.php @@ -0,0 +1,51 @@ +postRepo = $postRepo; + } + + /** + * Display a listing of the resource. + * + * @return \Illuminate\Http\Response + */ + public function index() + { + // TODO paginate page should be dynamic set in config, e.g. config('app.post.perPage', 5) + $posts = $this->postRepo + ->with(['category', 'tags', 'author']) + ->paginate(5); + + return view('posts.index', compact('posts')); + } + + /** + * Display the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function show($id) + { + $post = $this->postRepo + ->with(['category', 'tags', 'author']) + ->find($id); + + return view('posts.show', compact('post')); + } +} diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 8f6f2a6..81d0d76 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -28,6 +28,55 @@ main { flex: 1 0 auto; } + + .post-card .card-content { + padding-bottom: 0 + } + + .post-card .post-meta { + margin-top: 0; + } + + .post-card .post-meta ul li { + display: inline-block; + margin-right: 16px + } + + .post-card .post-meta ul li i { + vertical-align: middle; + margin-right: 10px + } + + .post-card .excerpt { + /*font-size: 1.22rem;*/ + } + + .post-card .post-tag { + padding: 12px 24px; + } + + .post-card .post-tag i { + vertical-align: middle; + margin-right: 10px + } + + .search-form .row { + margin-bottom: 0; + } + + .search-form .input-field { + width: 100%; + } + + .tag-list { + padding: 10px; + } + .badge-tag { + padding: 3px 7px; + font-size: 12px; + vertical-align: middle; + margin-left: 5px; + } {{-- TODO stack is not work before push, if not using extend view --}} diff --git a/resources/views/partials/sidebar.blade.php b/resources/views/partials/sidebar.blade.php new file mode 100644 index 0000000..ce2625a --- /dev/null +++ b/resources/views/partials/sidebar.blade.php @@ -0,0 +1,15 @@ +
    + @include('widgets.search') +
    + +
    + +
    + @include('widgets.category') +
    + +
    + +
    + @include('widgets.tag') +
    \ No newline at end of file diff --git a/resources/views/posts/_list.blade.php b/resources/views/posts/_list.blade.php new file mode 100644 index 0000000..da3eb9b --- /dev/null +++ b/resources/views/posts/_list.blade.php @@ -0,0 +1 @@ +@each('posts._show', $posts, 'post') \ No newline at end of file diff --git a/resources/views/posts/_show.blade.php b/resources/views/posts/_show.blade.php new file mode 100644 index 0000000..8500106 --- /dev/null +++ b/resources/views/posts/_show.blade.php @@ -0,0 +1,3 @@ +
    + @include('widgets.post-card') +
    \ No newline at end of file diff --git a/resources/views/posts/index.blade.php b/resources/views/posts/index.blade.php new file mode 100644 index 0000000..ef41662 --- /dev/null +++ b/resources/views/posts/index.blade.php @@ -0,0 +1,15 @@ +@extends('layouts.app') + +@section('content') +
    +
    + @include('posts._list') +
    +
    + @include('partials.sidebar') +
    +
    + {{ $posts->links('pagination::materialize') }} +
    +
    +@endsection \ No newline at end of file diff --git a/resources/views/widgets/category.blade.php b/resources/views/widgets/category.blade.php index 68880d7..b5f1279 100644 --- a/resources/views/widgets/category.blade.php +++ b/resources/views/widgets/category.blade.php @@ -1,6 +1,9 @@ \ No newline at end of file diff --git a/resources/views/widgets/post-card.blade.php b/resources/views/widgets/post-card.blade.php new file mode 100644 index 0000000..7414d94 --- /dev/null +++ b/resources/views/widgets/post-card.blade.php @@ -0,0 +1,42 @@ +
    + +
    +
    + {{ $post->title }} +
    + + +
    + +
    {{ $post->excerpt }}
    + +
    +
    + +
    \ No newline at end of file diff --git a/resources/views/widgets/search.blade.php b/resources/views/widgets/search.blade.php new file mode 100644 index 0000000..f2769a2 --- /dev/null +++ b/resources/views/widgets/search.blade.php @@ -0,0 +1,19 @@ +
    + +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    + +
    +
    diff --git a/resources/views/widgets/tag.blade.php b/resources/views/widgets/tag.blade.php index 7dd797a..06fdd9e 100644 --- a/resources/views/widgets/tag.blade.php +++ b/resources/views/widgets/tag.blade.php @@ -1,16 +1,3 @@ -{{-- TODO move to app.css --}} - -
    Tags
    diff --git a/routes/web.php b/routes/web.php index c237b5a..6b83104 100644 --- a/routes/web.php +++ b/routes/web.php @@ -33,5 +33,5 @@ }); Route::group(['namespace' => 'Frontend'], function () { - + Route::resource('posts', 'PostController', ['only' => ['index', 'show']]); }); From c1e0e46696cc5731afb623f47432d6b324a44fa2 Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Wed, 14 Jun 2017 15:02:15 +0800 Subject: [PATCH 62/78] Add static avatar.jpg to header --- .gitignore | 1 - public/images/.gitignore | 1 + public/images/avatar.jpg | Bin 0 -> 77411 bytes resources/views/partials/header.blade.php | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 public/images/.gitignore create mode 100644 public/images/avatar.jpg diff --git a/.gitignore b/.gitignore index 837bcb8..898ce67 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,3 @@ _ide_helper.php /public/img /public/plugins /public/mix-manifest.json -/public/images diff --git a/public/images/.gitignore b/public/images/.gitignore new file mode 100644 index 0000000..22d0d82 --- /dev/null +++ b/public/images/.gitignore @@ -0,0 +1 @@ +vendor diff --git a/public/images/avatar.jpg b/public/images/avatar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7a23f338265c8b5231067c40d4e1a4dbfc34a252 GIT binary patch literal 77411 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
    un)wsNa?6$vtly`o~L+66R9H(0D}BV?2b7 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∈A-G7&D%!$0XT47qivfe5FCi3=Qd( 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 literal 0 HcmV?d00001 diff --git a/resources/views/partials/header.blade.php b/resources/views/partials/header.blade.php index 4c192b8..17af752 100644 --- a/resources/views/partials/header.blade.php +++ b/resources/views/partials/header.blade.php @@ -2,7 +2,7 @@
    - +
    Miles Peng
    From 529267024ba27a80bd37091f3103084b9b07a64e Mon Sep 17 00:00:00 2001 From: Miles Pong Date: Wed, 14 Jun 2017 15:09:30 +0800 Subject: [PATCH 63/78] Update fab button color and duration --- resources/views/partials/fab.blade.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/views/partials/fab.blade.php b/resources/views/partials/fab.blade.php index 238b893..22c833b 100644 --- a/resources/views/partials/fab.blade.php +++ b/resources/views/partials/fab.blade.php @@ -1,5 +1,5 @@
    - + expand_less {{--
      --}} @@ -12,6 +12,7 @@ @push('js') -@endpush \ No newline at end of file +
    \ No newline at end of file diff --git a/resources/views/partials/footer.blade.php b/resources/views/partials/footer.blade.php index 0a7fe8a..b5b7b8e 100644 --- a/resources/views/partials/footer.blade.php +++ b/resources/views/partials/footer.blade.php @@ -2,15 +2,15 @@
    -
    Footer content
    -

    This is the end of the page. Good day.

    +
    About project
    +

    Indigo is a blog built with Laravel 5.x and with AdminLTE, Materialize CSS support.

    External links
    diff --git a/resources/views/partials/navbar.blade.php b/resources/views/partials/navbar.blade.php index 0f2fd6f..d2f4e76 100644 --- a/resources/views/partials/navbar.blade.php +++ b/resources/views/partials/navbar.blade.php @@ -1,28 +1,54 @@ + + + @push('js')