From 4552492bb82e1de8d389a97d117d32f0bc0a9fef Mon Sep 17 00:00:00 2001 From: Kutalo Alexey Date: Wed, 29 Aug 2018 08:27:53 -0300 Subject: [PATCH] Add CRUD operations for site pages --- app/Http/Controllers/PageController.php | 176 ++++++++++++++++++ app/Http/Requests/PageRequest.php | 44 +++++ app/Page.php | 112 +++++++++++ app/Repositories/PageRepository.php | 164 ++++++++++++++++ config/session.php | 2 +- config/system.php | 3 +- .../2018_08_29_164612_create_pages_table.php | 34 ++++ resources/assets/js/layouts/Sidebar.vue | 6 + resources/assets/js/routes.js | 25 +++ .../assets/js/views/category/Category.vue | 3 - resources/assets/js/views/page/Edit.vue | 64 +++++++ resources/assets/js/views/page/Form.vue | 97 ++++++++++ resources/assets/js/views/page/Index.vue | 60 ++++++ resources/assets/js/views/page/List.vue | 60 ++++++ resources/assets/js/views/page/PageLink.vue | 16 ++ .../assets/js/views/page/PageSidebar.vue | 32 ++++ resources/assets/js/views/page/Published.vue | 148 +++++++++++++++ resources/assets/js/views/page/View.vue | 93 +++++++++ resources/assets/js/views/pages/Main.vue | 3 + resources/assets/js/views/post/List.vue | 2 +- resources/assets/js/views/post/View.vue | 2 +- resources/assets/sass/app.scss | 4 + resources/assets/sass/pages.scss | 1 - resources/lang/en/page.php | 25 +++ resources/lang/ru/page.php | 25 +++ routes/api.php | 12 ++ 26 files changed, 1205 insertions(+), 8 deletions(-) create mode 100755 app/Http/Controllers/PageController.php create mode 100755 app/Http/Requests/PageRequest.php create mode 100755 app/Page.php create mode 100755 app/Repositories/PageRepository.php create mode 100755 database/migrations/2018_08_29_164612_create_pages_table.php create mode 100755 resources/assets/js/views/page/Edit.vue create mode 100755 resources/assets/js/views/page/Form.vue create mode 100755 resources/assets/js/views/page/Index.vue create mode 100644 resources/assets/js/views/page/List.vue create mode 100755 resources/assets/js/views/page/PageLink.vue create mode 100755 resources/assets/js/views/page/PageSidebar.vue create mode 100755 resources/assets/js/views/page/Published.vue create mode 100755 resources/assets/js/views/page/View.vue create mode 100755 resources/lang/en/page.php create mode 100755 resources/lang/ru/page.php diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php new file mode 100755 index 0000000..d1c4a4b --- /dev/null +++ b/app/Http/Controllers/PageController.php @@ -0,0 +1,176 @@ +request = $request; + $this->repo = $repo; + $this->activity = $activity; + $this->middleware('permission:access-page')->except(['getPublicPages', 'getPublicPage']); + } + + /** + * Display all public pages + * + * @return JsonResponse + */ + public function getPublicPages() + { + $pages = $this->repo->getPublished(); + + return $this->success(compact('pages')); + } + + /** + * Display a public page + * + * @param string $slug + * + * @return JsonResponse + */ + public function getPublicPage($slug) + { + $page = $this->repo->getBySlugForGuests($slug); + + return $this->success(compact('page')); + } + + /** + * Store page + * + * @param PageRequest $request + * + * @return JsonResponse + * @throws ValidationException + */ + public function store(PageRequest $request) + { + $page = $this->repo->create($this->request->all()); + + $this->activity->record([ + 'module' => $this->module, + 'module_id' => $page->id, + 'activity' => 'published' + ]); + + return $this->success(['page' => trans('page.page_processed', ['action' => trans('page.published')])]); + } + + /** + * Upload image in Summernote editor + * + * @param PageRequest $request + * + * @return JsonResponse + */ + public function uploadImage(PageRequest $request) + { + $upload_path = config('system.upload_path.images'); + $extension = request()->file('file')->getClientOriginalExtension(); + $filename = uniqid(); + request()->file('file')->move($upload_path, $filename . "." . $extension); + $image_url = '/' . $upload_path . '/' . $filename . '.' . $extension; + + return $this->success(compact('image_url')); + } + + /** + * Fetch statistics + * + * @return JsonResponse + */ + public function statistics() + { + $published = $this->repo->getPublished()->count(); + + return $this->success(compact('published')); + } + + /** + * Get all published pages + * + * @return JsonResponse + */ + public function getPublishedList() + { + $pages = $this->repo->getPublishedList($this->request->all()); + + return $this->success(compact('pages')); + } + + /** + * Get page details + * + * @param string $slug + * + * @return JsonResponse + * @throws ValidationException + */ + public function show($slug) + { + $page = $this->repo->getBySlug($slug); + + return $this->success(compact('page')); + } + + /** + * Delete page + * + * @param string $slug + * + * @return JsonResponse + * @throws \Exception + */ + public function destroy($slug) + { + $page = $this->repo->getBySlug($slug); + + $this->activity->record([ + 'module' => 'page', + 'sub_module' => 'page', + 'module_id' => $page->id, + 'activity' => 'deleted' + ]); + + $page->delete(); + + return $this->success(['page' => trans('page.deleted', ['type' => trans('page.page')])]); + } +} diff --git a/app/Http/Requests/PageRequest.php b/app/Http/Requests/PageRequest.php new file mode 100755 index 0000000..e22f6ab --- /dev/null +++ b/app/Http/Requests/PageRequest.php @@ -0,0 +1,44 @@ + 'sometimes|required', + 'body' => 'sometimes|required', + ]; + } + + /** + * Translate fields with user friendly name. + * + * @return array + */ + public function attributes() + { + return [ + 'title' => trans('page.title'), + 'body' => trans('page.body'), + ]; + } +} diff --git a/app/Page.php b/app/Page.php new file mode 100755 index 0000000..5004f33 --- /dev/null +++ b/app/Page.php @@ -0,0 +1,112 @@ +attributes['created_at'])->diffForHumans(); + } + + /** + * Get updated at in a human readable format. + * + * @return string + */ + public function getUpdatedAtAttribute() + { + return Carbon::parse($this->attributes['updated_at'])->diffForHumans(); + } + + /** + * Get body with the stripped HTML tags. + * + * @return string + */ + public function getStrippedBodyAttribute() + { + return strip_tags($this->attributes['body']); + } + + /** + * Sets the title and the readable slug. + * + * @param string $value + */ + public function setTitleAttribute($value) + { + $this->attributes['title'] = $value; + } + + /** + * Scope a query to only include page with the given slug. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param string $slug + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeFilterBySlug($query, $slug = null) + { + if (!$slug) { + return $query; + } + + return $query->where('slug', '=', $slug); + } + + /** + * Scope a query to only include page with the given id. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param int|null $id + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeFilterById($query, $id = null) + { + if (!$id) { + return $query; + } + + return $query->where('id', '=', $id); + } +} diff --git a/app/Repositories/PageRepository.php b/app/Repositories/PageRepository.php new file mode 100755 index 0000000..812bbdd --- /dev/null +++ b/app/Repositories/PageRepository.php @@ -0,0 +1,164 @@ +page = $page; + } + + /** + * Count pages + * + * @return int + */ + public function count() + { + return $this->page->count(); + } + + /** + * Get valid page by slug. + * + * @param string $slug + * + * @return Page + * @throws ValidationException + */ + public function getBySlug($slug) + { + $page = $this->page + ->filterBySlug($slug) + ->first(); + + if (!$page) { + throw ValidationException::withMessages(['message' => trans('general.invalid_link')]); + } + + return $page; + } + + /** + * Get valid page by slug for guests. + * + * @param string $slug + * + * @return Page + */ + public function getBySlugForGuests($slug) + { + $page = $this->page + ->filterBySlug($slug) + ->first(); + + if (!$page) { + return null; + } + + return $page; + } + + /** + * Find page by Id + * + * @param int|null $id + * + * @return Page + * @throws ValidationException + */ + public function findOrFail($id = null) + { + $page = $this->page->find($id); + + if (!$page) { + throw ValidationException::withMessages(['message' => trans('page.could_not_find')]); + } + + return $page; + } + + /** + * Publish page. + * + * @param array $params + * + * @return Page + * @throws ValidationException + */ + public function create($params = []) + { + $id = isset($params['id']) ? $params['id'] : null; + + if ($id) { + $page = $this->page->filterById($id)->first(); + if (!$page) { + throw ValidationException::withMessages(['message' => trans('page.invalid_action')]); + } + } + $page = ($id) ? $this->page->find($id) : $this->page; + $page->fill([ + 'title' => $params['title'], + 'body' => $params['body'], + ]); + + if (!$id) { + $slug = str_slug($params['title']); + if (Page::whereSlug($slug)->exists()) { + throw ValidationException::withMessages(['message' => trans('page.slug_exists')]); + } + $page->fill([ + 'slug' => $slug, + ]); + } + + $page->save(); + + return $page; + } + + /** + * Get published pages. + * + * @return Page[]|Collection + */ + public function getPublished() + { + return $this->page->get(); + } + + /** + * Get published pages. + * + * @param array $params + * + * @return Page[]|Collection + */ + public function getPublishedList($params = []) + { + $page_length = isset($params['page_length']) ? $params['page_length'] : config('config.page_length'); + + $published = $this->page; + + if (!isset($params['page_length'])) { + return $published->get(); + } + + return $published->orderBy('created_at', 'desc')->paginate($page_length); + } +} diff --git a/config/session.php b/config/session.php index 736fb3c..c86c148 100644 --- a/config/session.php +++ b/config/session.php @@ -29,7 +29,7 @@ | */ - 'lifetime' => env('SESSION_LIFETIME', 120), + 'lifetime' => env('SESSION_LIFETIME', 12000), 'expire_on_close' => false, diff --git a/config/system.php b/config/system.php index 6e9233e..a396d4b 100755 --- a/config/system.php +++ b/config/system.php @@ -77,7 +77,8 @@ "change-status-user", "access-post", "enable-login", - "access-category" + "access-category", + "access-page" ], "color_themes" => [ [ diff --git a/database/migrations/2018_08_29_164612_create_pages_table.php b/database/migrations/2018_08_29_164612_create_pages_table.php new file mode 100755 index 0000000..3c3e322 --- /dev/null +++ b/database/migrations/2018_08_29_164612_create_pages_table.php @@ -0,0 +1,34 @@ +increments('id'); + $table->string('title')->nullable(); + $table->string('slug')->nullable(); + $table->longText('body')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('pages'); + } +} diff --git a/resources/assets/js/layouts/Sidebar.vue b/resources/assets/js/layouts/Sidebar.vue index ed7c68a..ccb8992 100755 --- a/resources/assets/js/layouts/Sidebar.vue +++ b/resources/assets/js/layouts/Sidebar.vue @@ -39,6 +39,12 @@ {{ trans('category.categories') }} +
  • + + + {{ trans('page.pages') }} + +
  • diff --git a/resources/assets/js/routes.js b/resources/assets/js/routes.js index b494f93..63d55ef 100755 --- a/resources/assets/js/routes.js +++ b/resources/assets/js/routes.js @@ -212,6 +212,26 @@ let routes = [ path: '/category', component: require('./views/category/Category'), meta: {title: i18n.category.categories + ' | ' + appName} + }, + { + path: '/page', + component: require('./views/page/Index.vue'), + meta: {title: i18n.page.new + ' | ' + appName} + }, + { + path: '/page/new', + component: require('./views/page/Index.vue'), + meta: {title: i18n.page.new + ' | ' + appName} + }, + { + path: '/page/published', + component: require('./views/page/Published.vue'), + meta: {title: i18n.page.published_box + ' | ' + appName} + }, + { + path: '/page/:slug/edit', + component: require('./views/page/Edit'), + meta: {title: i18n.page.edit + ' | ' + appName} } ] }, @@ -234,6 +254,11 @@ let routes = [ path: '/:category/:slug', component: require('./views/post/View.vue'), meta: {title: appName} + }, + { + path: '/:slug', + component: require('./views/page/View.vue'), + meta: {title: appName} } ] }, diff --git a/resources/assets/js/views/category/Category.vue b/resources/assets/js/views/category/Category.vue index 9b5fe92..0313fbb 100755 --- a/resources/assets/js/views/category/Category.vue +++ b/resources/assets/js/views/category/Category.vue @@ -7,9 +7,6 @@
  • - diff --git a/resources/assets/js/views/page/Edit.vue b/resources/assets/js/views/page/Edit.vue new file mode 100755 index 0000000..713b341 --- /dev/null +++ b/resources/assets/js/views/page/Edit.vue @@ -0,0 +1,64 @@ + + + diff --git a/resources/assets/js/views/page/Form.vue b/resources/assets/js/views/page/Form.vue new file mode 100755 index 0000000..8c60f4d --- /dev/null +++ b/resources/assets/js/views/page/Form.vue @@ -0,0 +1,97 @@ + + + diff --git a/resources/assets/js/views/page/Index.vue b/resources/assets/js/views/page/Index.vue new file mode 100755 index 0000000..2a83176 --- /dev/null +++ b/resources/assets/js/views/page/Index.vue @@ -0,0 +1,60 @@ + + + diff --git a/resources/assets/js/views/page/List.vue b/resources/assets/js/views/page/List.vue new file mode 100644 index 0000000..9f0899b --- /dev/null +++ b/resources/assets/js/views/page/List.vue @@ -0,0 +1,60 @@ + + + \ No newline at end of file diff --git a/resources/assets/js/views/page/PageLink.vue b/resources/assets/js/views/page/PageLink.vue new file mode 100755 index 0000000..0e1306a --- /dev/null +++ b/resources/assets/js/views/page/PageLink.vue @@ -0,0 +1,16 @@ + + + diff --git a/resources/assets/js/views/page/PageSidebar.vue b/resources/assets/js/views/page/PageSidebar.vue new file mode 100755 index 0000000..d566ebd --- /dev/null +++ b/resources/assets/js/views/page/PageSidebar.vue @@ -0,0 +1,32 @@ + +2018_07_13_124411_create_posts_table.php + diff --git a/resources/assets/js/views/page/Published.vue b/resources/assets/js/views/page/Published.vue new file mode 100755 index 0000000..03623e3 --- /dev/null +++ b/resources/assets/js/views/page/Published.vue @@ -0,0 +1,148 @@ + + + + diff --git a/resources/assets/js/views/page/View.vue b/resources/assets/js/views/page/View.vue new file mode 100755 index 0000000..3d1ba73 --- /dev/null +++ b/resources/assets/js/views/page/View.vue @@ -0,0 +1,93 @@ + + + diff --git a/resources/assets/js/views/pages/Main.vue b/resources/assets/js/views/pages/Main.vue index 8795834..94a9baa 100755 --- a/resources/assets/js/views/pages/Main.vue +++ b/resources/assets/js/views/pages/Main.vue @@ -55,12 +55,14 @@ +