diff --git a/.styleci.yml b/.styleci.yml index 837286d..6400542 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,4 +1,4 @@ -# Styleci for WebDevEtc. +# Styleci for binshops. preset: laravel diff --git a/LICENSE.txt b/LICENSE.txt index 00f04a7..bac0ded 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Hessam. +Copyright (c) 2020 Binshops. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 0f4ff7c..009eaf6 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,122 @@ -
+
-
-
- Add post -
- -
-
-
- All posts -
- -
-
-
- Add category -
- +## Recent Changes +- **9.1.x** Multi language support +- 8.0.x Compatibility with Laravel 8.x + ## What/who this package is for: - For websites running Laravel - - Who wants to have a site blog, and have an easy to use interface to write blog posts/assign categories/manage existing posts + - Anyone, who wants to have a site blog. This laravel blog gives an easy to use interface to write blog posts/assign categories/manage existing posts - Where only admin users can edit/manage the blog (this is not suitable for every user on your site to be able to manage posts) - - For anyone who likes to add a wordpress-like CMS to her/his web app + - For anyone who likes to add a wordpress-like laravel blog to laravel website ## How to customise the blog views/templates -After doing the correct `vendor:publish`, all of the default template files will be found in /resources/views/vendor/blogetc/ and are easy to edit to match your needs. +After doing the correct `vendor:publish`, all of the default template files will be found in /resources/views/vendor/binshopsblog/ and are easy to edit to match your needs. ### Customizing admin views If you need to customize the admin view, just copy the files from -`vendor/webdevetc/blogetc/src/Views/blogetc_admin` +`vendor/binshopsblog/src/Views/binshopsblog_admin` to -`resources/views/vendor/blogetc_admin` +`resources/views/vendor/binshopsblog_admin` Then you can modify them just like any other view file. ## Routes -It will auto set all required routes (both public facing, and admin backend). There are some config options (such as changing the /blog/ url to something else), which can be done in the blogetc.php file. +It will auto set all required routes (both public facing, and admin backend). There are some config options (such as changing the /blog/ url to something else), which can be done in the binshopsblog.php file. ## Config options -All config options have comments which describe what they do. Please just refer to the `blogetc.php` file in your /config/ dir. +All config options have comments which describe what they do. Please just refer to the `binshopsblog.php` file in your /config/ dir. ### Custom User Model You can change the default user model through the config file. @@ -108,9 +165,31 @@ Add these (and an Event Listener) to your `EventServiceProvider.php` file to mak ## Built in CAPTCHA / anti spam -There is a built in captcha (anti spam comment) system built in, which will be easy for you to replace with your own implementation. +There is a built-in captcha (anti-spam comment) system built in, which will be easy for you to replace with your own implementation. + +There is a basic anti-spam captcha function built-in. + +See the config/binshops.php captcha section. There is a built in system (basic!) that will prevent most automated spam attempts. +Writing your own captcha system: + +I wrote the captcha system simple on purpose, so you can add your own captcha options. It should be easy to add any other captcha system to this. - Please see [this Captcha docs](https://hessam.binshops.com/laravel-blog-package#captcha) for more details. +If you want to write your own implementation then create your own class that implements \BinshopsBlog\Interfaces\CaptchaInterface, then update the config/binshopsblog.php file (change the captcha_type option). + +There are three methods you need to implement: +public function captcha_field_name() : string + +Return a string such as "captcha". It is used for the form validation and . +public function view() : string + +What view file should the binshops::partials.add_comment_form view include? You can set this to whatever you need, and then create your own view file. The default included basic captcha class will return "binshops::captcha.basic". +public function rules() : array + +Return an array for the rules (which are just the standard Laravel validation rules. This is where you can check if the captcha was successful or not. +Optional: +public function runCaptchaBeforeShowingPosts() : null + +This isn't part of the interface, it isn't required. By default it does nothing. But you can put some code in this method and it'll be run in the BinshopsReaderController::viewSinglePost method. ## Image upload errors @@ -123,41 +202,13 @@ Try adding this to config/app.php: - You might need to set a higher memory limit, or upload smaller image files. This will depend on your server. I've used it to upload huge (10mb+) jpg images without problem, once the server was set up correctly to handle larger file uploads. ## Version History -- **8.0.x** Compatibility with Laravel 8 -- 7.3.2 Some bug fixes +- **9.3.x** Stable version of package +- 9.0.x Multi-language support beta release +- 8.0.x Compatibility with Laravel 8 - 7.3.0 New Admin UI -- 7.2.2 - - bug fix: do not show search bar when it's disabled - - feature: configure to show full text post or preview -- 7.2.1 - adds logout button at admin panel -- 7.2.0 - - adds sub-category functionality to blog - - adds reading progress bar feature (if you upgrade, re-publish config file and view files) -- 7.1.8 - ability to remove images from posts (this feature does not work for old posts) -- 7.1.7 - updates CKEditor -- 7.1.5 - minor fix for recent posts -- 7.1.4 - updates fulltext search package which solves the search issue -- 7.1.2 - shows categories on blog home page - minor fix (if you upgrade try to re-publish view files) -- 7.1.1 - minor fix and some admin panel text changes -- 7.1.0 - Adds support for custom user model (if you upgrade, try to publish new config) -- 7.0.2 - Bug fix for listing posts and search page -- 7.0.1 - made compatible with Laravel 6.x & 7.x -- 3.1 - minor fixes -- 3.0.3 - fixed RSS feed cache issue -- 3.0.2 - fixed default medium image size (changed to 600x400) - 3.0.1 - replaced all short tags () with full opening ones (create('laravel_fulltext', function (Blueprint $table) { + $table->increments('id'); + $table->integer('indexable_id'); + $table->string('indexable_type'); + $table->text('indexed_title'); + $table->text('indexed_content'); + + $table->unique(['indexable_type', 'indexable_id']); + + $table->timestamps(); + }); + + DB::connection(config('laravel-fulltext.db_connection'))->statement('ALTER TABLE laravel_fulltext ADD FULLTEXT fulltext_title(indexed_title)'); + DB::connection(config('laravel-fulltext.db_connection'))->statement('ALTER TABLE laravel_fulltext ADD FULLTEXT fulltext_title_content(indexed_title, indexed_content)'); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::connection(config('laravel-fulltext.db_connection'))->drop('laravel_fulltext'); + } +} diff --git a/migrations/2018_05_28_224023_create_blog_etc_posts_table.php b/migrations/2018_05_28_224023_create_blog_etc_posts_table.php deleted file mode 100755 index 683a076..0000000 --- a/migrations/2018_05_28_224023_create_blog_etc_posts_table.php +++ /dev/null @@ -1,92 +0,0 @@ -increments('id'); - $table->unsignedInteger("user_id")->index()->nullable(); - $table->string("slug")->unique(); - - $table->string("title")->nullable()->default("New blog post"); - $table->string("subtitle")->nullable()->default(""); - $table->text("meta_desc")->nullable(); - $table->mediumText("post_body")->nullable(); - - $table->string("use_view_file")->nullable()->comment("should refer to a blade file in /views/"); - - $table->dateTime("posted_at")->index()->nullable()->comment("Public posted at time, if this is in future then it wont appear yet"); - $table->boolean("is_published")->default(true); - - $table->string('image_large')->nullable(); - $table->string('image_medium')->nullable(); - $table->string('image_thumbnail')->nullable(); - - $table->timestamps(); - }); - - Schema::create('blog_etc_categories', function (Blueprint $table) { - $table->increments('id'); - - $table->string("category_name")->nullable(); - $table->string("slug")->unique(); - $table->mediumText("category_description")->nullable(); - - $table->unsignedInteger("created_by")->nullable()->index()->comment("user id"); - - $table->timestamps(); - }); - - Schema::create('blog_etc_post_categories', function (Blueprint $table) { - $table->increments('id'); - - $table->unsignedInteger("blog_etc_post_id")->index(); - $table->foreign('blog_etc_post_id')->references('id')->on('blog_etc_posts')->onDelete("cascade"); - - $table->unsignedInteger("blog_etc_category_id")->index(); - $table->foreign('blog_etc_category_id')->references('id')->on('blog_etc_categories')->onDelete("cascade"); - }); - - - Schema::create('blog_etc_comments', function (Blueprint $table) { - $table->increments('id'); - - $table->unsignedInteger("blog_etc_post_id")->index(); - $table->foreign('blog_etc_post_id')->references('id')->on('blog_etc_posts')->onDelete("cascade"); - $table->unsignedInteger("user_id")->nullable()->index()->comment("if user was logged in"); - - $table->string("ip")->nullable()->comment("if enabled in the config file"); - $table->string("author_name")->nullable()->comment("if not logged in"); - - $table->text("comment")->comment("the comment body"); - - $table->boolean("approved")->default(true); - - $table->timestamps(); - }); - - - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('blog_etc_post_categories'); - Schema::dropIfExists('blog_etc_categories'); - Schema::dropIfExists('blog_etc_posts'); - } -} diff --git a/migrations/2018_09_16_224023_add_author_and_url_blog_etc_posts_table.php b/migrations/2018_09_16_224023_add_author_and_url_blog_etc_posts_table.php deleted file mode 100644 index 67cec73..0000000 --- a/migrations/2018_09_16_224023_add_author_and_url_blog_etc_posts_table.php +++ /dev/null @@ -1,37 +0,0 @@ -string("author_email")->nullable(); - $table->string("author_website")->nullable(); - }); - - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - - Schema::table('blog_etc_comments', function (Blueprint $table) { - $table->dropColumn("author_email"); - $table->dropColumn("author_website"); - }); - } -} - diff --git a/migrations/2020_10_16_004241_create_binshops_languages_table.php b/migrations/2020_10_16_004241_create_binshops_languages_table.php new file mode 100644 index 0000000..cbf41a9 --- /dev/null +++ b/migrations/2020_10_16_004241_create_binshops_languages_table.php @@ -0,0 +1,39 @@ +increments('id'); + + $table->string("name")->unique(); + $table->string("locale")->unique(); + $table->string("iso_code")->unique(); + $table->string("date_format"); + $table->boolean("active")->default(true); + $table->boolean("rtl")->default(false); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('binshops_languages'); + } +} diff --git a/migrations/2020_05_27_104123_add_parameters_blog_etc_categories_table.php b/migrations/2020_10_16_005400_create_binshops_categories_table.php similarity index 52% rename from migrations/2020_05_27_104123_add_parameters_blog_etc_categories_table.php rename to migrations/2020_10_16_005400_create_binshops_categories_table.php index 1fc8255..1e1c566 100644 --- a/migrations/2020_05_27_104123_add_parameters_blog_etc_categories_table.php +++ b/migrations/2020_10_16_005400_create_binshops_categories_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class AddParametersBlogEtcCategoriesTable extends Migration +class CreateBinshopsCategoriesTable extends Migration { /** * Run the migrations. @@ -13,12 +13,20 @@ class AddParametersBlogEtcCategoriesTable extends Migration */ public function up() { - Schema::table('blog_etc_categories', function (Blueprint $table) { - $table->integer('parent_id')->nullable()->default(0); + Schema::create('binshops_categories', function (Blueprint $table) { + $table->increments('id'); + + $table->unsignedInteger("created_by")->nullable()->index()->comment("user id"); + + //columns related to multi-level categories + $table->integer('parent_id')->nullable(); $table->integer('lft')->nullable(); $table->integer('rgt')->nullable(); $table->integer('depth')->nullable(); + + $table->timestamps(); }); + } /** @@ -28,8 +36,6 @@ public function up() */ public function down() { - Schema::table('blog_etc_categories', function (Blueprint $table) { - // - }); + Schema::dropIfExists('binshops_categories'); } } diff --git a/migrations/2020_10_16_005425_create_binshops_category_translations_table.php b/migrations/2020_10_16_005425_create_binshops_category_translations_table.php new file mode 100644 index 0000000..713197b --- /dev/null +++ b/migrations/2020_10_16_005425_create_binshops_category_translations_table.php @@ -0,0 +1,41 @@ +increments('id'); + + $table->unsignedInteger('category_id')->nullable(); + + $table->string("category_name")->nullable(); + $table->string("slug")->unique(); + $table->mediumText("category_description")->nullable(); + + $table->unsignedInteger("lang_id")->index(); + $table->foreign('lang_id')->references('id')->on('binshops_languages'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('binshops_category_translations'); + } +} diff --git a/migrations/2020_10_16_010039_create_binshops_posts_table.php b/migrations/2020_10_16_010039_create_binshops_posts_table.php new file mode 100644 index 0000000..398b44e --- /dev/null +++ b/migrations/2020_10_16_010039_create_binshops_posts_table.php @@ -0,0 +1,46 @@ +increments('id'); + $table->unsignedInteger("user_id")->index()->nullable(); + + $table->dateTime("posted_at")->index()->nullable()->comment("Public posted at time, if this is in future then it wont appear yet"); + $table->boolean("is_published")->default(true); + + $table->timestamps(); + }); + + Schema::create('binshops_post_categories', function (Blueprint $table) { + $table->increments('id'); + + $table->unsignedInteger("post_id")->index(); + $table->foreign('post_id')->references('id')->on('binshops_posts')->onDelete("cascade"); + + $table->unsignedInteger("category_id")->index(); + $table->foreign('category_id')->references('id')->on('binshops_categories')->onDelete("cascade"); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('binshops_posts'); + } +} diff --git a/migrations/2020_10_16_010049_create_binshops_post_translations_table.php b/migrations/2020_10_16_010049_create_binshops_post_translations_table.php new file mode 100644 index 0000000..3c52d9f --- /dev/null +++ b/migrations/2020_10_16_010049_create_binshops_post_translations_table.php @@ -0,0 +1,51 @@ +increments('id'); + + $table->unsignedInteger('post_id')->nullable(); + + $table->string("slug"); + $table->string("title")->nullable()->default("New blog post"); + $table->string("subtitle")->nullable()->default(""); + $table->text("meta_desc")->nullable(); + $table->string("seo_title")->nullable(); + $table->mediumText("post_body")->nullable(); + $table->text("short_description")->nullable(); + + $table->string("use_view_file")->nullable()->comment("should refer to a blade file in /views/"); + + $table->string('image_large')->nullable(); + $table->string('image_medium')->nullable(); + $table->string('image_thumbnail')->nullable(); + + $table->unsignedInteger("lang_id")->index(); + $table->foreign('lang_id')->references('id')->on('binshops_languages'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('binshops_post_translations'); + } +} diff --git a/migrations/2020_10_16_121230_create_binshops_comments_table.php b/migrations/2020_10_16_121230_create_binshops_comments_table.php new file mode 100644 index 0000000..91091d8 --- /dev/null +++ b/migrations/2020_10_16_121230_create_binshops_comments_table.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->unsignedInteger("post_id")->index(); + $table->unsignedInteger("user_id")->nullable()->index()->comment("if user was logged in"); + + $table->string("ip")->nullable()->comment("if enabled in the config file"); + $table->string("author_name")->nullable()->comment("if not logged in"); + + $table->text("comment")->comment("the comment body"); + + $table->boolean("approved")->default(true); + + $table->string("author_email")->nullable(); + $table->string("author_website")->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('binshops_comments'); + } +} diff --git a/migrations/2018_09_27_122627_create_blog_etc_uploaded_photos_table.php b/migrations/2020_10_16_121728_create_binshops_uploaded_photos_table.php similarity index 61% rename from migrations/2018_09_27_122627_create_blog_etc_uploaded_photos_table.php rename to migrations/2020_10_16_121728_create_binshops_uploaded_photos_table.php index 5098b13..9485997 100644 --- a/migrations/2018_09_27_122627_create_blog_etc_uploaded_photos_table.php +++ b/migrations/2020_10_16_121728_create_binshops_uploaded_photos_table.php @@ -1,10 +1,10 @@ increments('id'); $table->text("uploaded_images")->nullable(); $table->string("image_title")->nullable(); @@ -21,9 +21,6 @@ public function up() $table->unsignedInteger("uploader_id")->nullable()->index(); $table->timestamps(); }); - Schema::table("blog_etc_posts",function(Blueprint $table) { - $table->string("seo_title")->nullable(); - }); } /** @@ -33,10 +30,6 @@ public function up() */ public function down() { - Schema::dropIfExists('blog_etc_uploaded_photos'); - - Schema::table("blog_etc_posts",function(Blueprint $table) { - $table->dropColumn("seo_title"); - }); + Schema::dropIfExists('binshops_uploaded_photos'); } } diff --git a/migrations/2018_09_26_085711_add_short_desc_textrea_to_blog_etc.php b/migrations/2020_10_22_132005_create_binshops_configurations_table.php similarity index 53% rename from migrations/2018_09_26_085711_add_short_desc_textrea_to_blog_etc.php rename to migrations/2020_10_22_132005_create_binshops_configurations_table.php index e24feed..b62c443 100644 --- a/migrations/2018_09_26_085711_add_short_desc_textrea_to_blog_etc.php +++ b/migrations/2020_10_22_132005_create_binshops_configurations_table.php @@ -1,10 +1,10 @@ text("short_description")->nullable(); + Schema::create('binshops_configurations', function (Blueprint $table) { + $table->string("key")->primary(); + $table->string("value"); + $table->timestamps(); }); - } /** @@ -26,9 +27,6 @@ public function up() */ public function down() { - - Schema::table('blog_etc_posts', function (Blueprint $table) { - $table->dropColumn("short_description"); - }); + Schema::dropIfExists('binshops_configurations'); } } diff --git a/src/Baum/Extensions/Eloquent/Collection.php b/src/Baum/Extensions/Eloquent/Collection.php index 41884af..5fb8a4a 100644 --- a/src/Baum/Extensions/Eloquent/Collection.php +++ b/src/Baum/Extensions/Eloquent/Collection.php @@ -1,5 +1,5 @@ getDictionary(); - // Enforce sorting by $orderColumn setting in WebDevEtc\BlogEtc\Baum\Node instance + // Enforce sorting by $orderColumn setting in BinshopsBlog\Baum\Node instance uasort($dict, function($a, $b){ return ($a->getOrder() >= $b->getOrder()) ? 1 : -1; }); diff --git a/src/Baum/Extensions/Eloquent/Model.php b/src/Baum/Extensions/Eloquent/Model.php index 66fb0c5..2a2cb2b 100644 --- a/src/Baum/Extensions/Eloquent/Model.php +++ b/src/Baum/Extensions/Eloquent/Model.php @@ -1,10 +1,10 @@ guardAgainstImpossibleMove(); @@ -176,14 +176,14 @@ public function updateStructure() { /** * Resolves suplied node. Basically returns the node unchanged if - * supplied parameter is an instance of \WebDevEtc\BlogEtc\Baum\Node. Otherwise it will try + * supplied parameter is an instance of \BinshopsBlog\Baum\Node. Otherwise it will try * to find the node in the database. * - * @param \WebDevEtc\BlogEtc\Baum\node|int - * @return \WebDevEtc\BlogEtc\Baum\Node + * @param \BinshopsBlog\Baum\node|int + * @return \BinshopsBlog\Baum\Node */ protected function resolveNode($node) { - if ( $node instanceof \WebDevEtc\BlogEtc\Baum\Node ) return $node->reload(); + if ( $node instanceof \BinshopsBlog\Baum\Node ) return $node->reload(); return $this->node->newNestedSetQuery()->find($node); } diff --git a/src/Baum/MoveNotPossibleException.php b/src/Baum/MoveNotPossibleException.php index a05c4b2..8056c90 100644 --- a/src/Baum/MoveNotPossibleException.php +++ b/src/Baum/MoveNotPossibleException.php @@ -1,4 +1,4 @@ moveToLeftOf($this->getLeftSibling()); @@ -896,7 +896,7 @@ public function moveLeft() { /** * Find the right sibling and move to the right of it. * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function moveRight() { return $this->moveToRightOf($this->getRightSibling()); @@ -905,7 +905,7 @@ public function moveRight() { /** * Move to the node to the left of ... * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function moveToLeftOf($node) { return $this->moveTo($node, 'left'); @@ -914,7 +914,7 @@ public function moveToLeftOf($node) { /** * Move to the node to the right of ... * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function moveToRightOf($node) { return $this->moveTo($node, 'right'); @@ -923,7 +923,7 @@ public function moveToRightOf($node) { /** * Alias for moveToRightOf * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function makeNextSiblingOf($node) { return $this->moveToRightOf($node); @@ -932,7 +932,7 @@ public function makeNextSiblingOf($node) { /** * Alias for moveToRightOf * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function makeSiblingOf($node) { return $this->moveToRightOf($node); @@ -941,7 +941,7 @@ public function makeSiblingOf($node) { /** * Alias for moveToLeftOf * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function makePreviousSiblingOf($node) { return $this->moveToLeftOf($node); @@ -950,7 +950,7 @@ public function makePreviousSiblingOf($node) { /** * Make the node a child of ... * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function makeChildOf($node) { return $this->moveTo($node, 'child'); @@ -959,7 +959,7 @@ public function makeChildOf($node) { /** * Make the node the first child of ... * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function makeFirstChildOf($node) { if ( $node->children()->count() == 0 ) @@ -971,7 +971,7 @@ public function makeFirstChildOf($node) { /** * Make the node the last child of ... * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function makeLastChildOf($node) { return $this->makeChildOf($node); @@ -980,7 +980,7 @@ public function makeLastChildOf($node) { /** * Make current node a root node. * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function makeRoot() { return $this->moveTo($this, 'root'); @@ -989,7 +989,7 @@ public function makeRoot() { /** * Equals? * - * @param \WebDevEtc\BlogEtc\Baum\Node + * @param \BinshopsBlog\Baum\Node * @return boolean */ public function equals($node) { @@ -999,7 +999,7 @@ public function equals($node) { /** * Checkes if the given node is in the same scope as the current one. * - * @param \WebDevEtc\BlogEtc\Baum\Node + * @param \BinshopsBlog\Baum\Node * @return boolean */ public function inSameScope($other) { @@ -1014,7 +1014,7 @@ public function inSameScope($other) { * Checks wether the given node is a descendant of itself. Basically, whether * its in the subtree defined by the left and right indices. * - * @param \WebDevEtc\BlogEtc\Baum\Node + * @param \BinshopsBlog\Baum\Node * @return boolean */ public function insideSubtree($node) { @@ -1071,7 +1071,7 @@ public function moveToNewParent() { /** * Sets the depth attribute * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function setDepth() { $self = $this; @@ -1091,7 +1091,7 @@ public function setDepth() { /** * Sets the depth attribute for the current node and all of its descendants. * - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ public function setDepthWithSubtree() { $self = $this; @@ -1232,9 +1232,9 @@ public function makeTree($nodeList) { * Main move method. Here we handle all node movements with the corresponding * lft/rgt index updates. * - * @param WebDevEtc\BlogEtc\Baum\Node|int $target + * @param BinshopsBlog\Baum\Node|int $target * @param string $position - * @return \WebDevEtc\BlogEtc\Baum\Node + * @return \BinshopsBlog\Baum\Node */ protected function moveTo($target, $position) { return Move::to($this, $target, $position); @@ -1259,7 +1259,7 @@ protected function computeLevel() { /** * Return an array with the last node we could reach and its nesting level * - * @param WebDevEtc\BlogEtc\Baum\Node $node + * @param BinshopsBlog\Baum\Node $node * @param integer $nesting * @return array */ diff --git a/src/Baum/SetBuilder.php b/src/Baum/SetBuilder.php index e3b57bb..0374ddc 100644 --- a/src/Baum/SetBuilder.php +++ b/src/Baum/SetBuilder.php @@ -1,15 +1,15 @@ publishes([ + __DIR__ . '/../migrations/' . $file => database_path('migrations/' . $file) + ]); + + } + + $this->publishes([ + __DIR__ . '/Views/binshopsblog' => base_path('resources/views/vendor/binshopsblog'), + __DIR__ . '/Config/binshopsblog.php' => config_path('binshopsblog.php'), + __DIR__ . '/css/binshopsblog_admin_css.css' => public_path('binshopsblog_admin_css.css'), + __DIR__ . '/css/binshops-blog.css' => public_path('binshops-blog.css'), + __DIR__ . '/css/admin-setup.css' => public_path('admin-setup.css'), + __DIR__ . '/js/binshops-blog.js' => public_path('binshops-blog.js'), + ]); + + + } + + /** + * Register services. + * + * @return void + */ + public function register() + { + $this->app->bind( + SearchInterface::class, + Search::class + ); + + // for the admin backend views ( view("binshopsblog_admin::BLADEFILE") ) + $this->loadViewsFrom(__DIR__ . "/Views/binshopsblog_admin", 'binshopsblog_admin'); + + // for public facing views (view("binshopsblog::BLADEFILE")): + // if you do the vendor:publish, these will be copied to /resources/views/vendor/binshopsblog anyway + $this->loadViewsFrom(__DIR__ . "/Views/binshopsblog", 'binshopsblog'); + } + +} diff --git a/src/BlogEtcServiceProvider.php b/src/BlogEtcServiceProvider.php deleted file mode 100755 index a8ed524..0000000 --- a/src/BlogEtcServiceProvider.php +++ /dev/null @@ -1,70 +0,0 @@ -publishes([ - __DIR__ . '/../migrations/' . $file => database_path('migrations/' . $file) - ]); - - } - - $this->publishes([ - __DIR__ . '/Views/blogetc' => base_path('resources/views/vendor/blogetc'), - __DIR__ . '/Config/blogetc.php' => config_path('blogetc.php'), - __DIR__ . '/css/blogetc_admin_css.css' => public_path('blogetc_admin_css.css'), - __DIR__ . '/css/hessam-blog.css' => public_path('hessam-blog.css'), - __DIR__ . '/js/hessam-blog.js' => public_path('hessam-blog.js'), - ]); - - - } - - /** - * Register services. - * - * @return void - */ - public function register() - { - - // for the admin backend views ( view("blogetc_admin::BLADEFILE") ) - $this->loadViewsFrom(__DIR__ . "/Views/blogetc_admin", 'blogetc_admin'); - - // for public facing views (view("blogetc::BLADEFILE")): - // if you do the vendor:publish, these will be copied to /resources/views/vendor/blogetc anyway - $this->loadViewsFrom(__DIR__ . "/Views/blogetc", 'blogetc'); - } - -} diff --git a/src/Captcha/Basic.php b/src/Captcha/Basic.php index c98c380..f65694e 100644 --- a/src/Captcha/Basic.php +++ b/src/Captcha/Basic.php @@ -1,15 +1,15 @@ -\App\User::class, + //Change it to \App\User::class for previous laravel versions + 'user_model'=>\App\Models\User::class, // reading progress bar is the bar which shows on top of your post when you are scrolling down the page. You can disable this feature if you want 'reading_progress_bar' => true, - 'include_default_routes' => true, // set to false to not include routes.php for BlogEtcReaderController and admin related routes. Default: true. If you disable this, you will have to manually copy over the data from routes.php and add it to your web.php. + 'include_default_routes' => true, // set to false to not include routes.php for BinshopsReaderController and admin related routes. Default: true. If you disable this, you will have to manually copy over the data from routes.php and add it to your web.php. 'blog_prefix' => "blog", // used in routes.php. If you want to your http://yoursite.com/latest-news (or anything else), then enter that here. Default: blog 'admin_prefix' => "blog_admin", // similar to above, but used for the admin panel for the blog. Default: blog_admin @@ -26,7 +25,7 @@ 'memory_limit' => '2048M', // This is used when uploading images : - // @ini_set('memory_limit', config("blogetc.memory_limit")); + // @ini_set('memory_limit', config("binshopsblog.memory_limit")); // See PHP.net for detailso // Set to false to not set any value. @@ -89,7 +88,7 @@ ], // you can add more fields here, but make sure that you create the relevant database columns too! - // They must be in the same format as the default ones - image_xxxxx (and this db column must exist on the blog_etc_posts table) + // They must be in the same format as the default ones - image_xxxxx (and this db column must exist on the binshops_posts table) /* 'image_custom_example_size' => [ // << MAKE A DB COLUM WITH THIS NAME. @@ -103,7 +102,7 @@ ], */ // Create the custom db table by doing - // php artisan make:migration --table=blog_etc_posts AddCustomBlogImageSize + // php artisan make:migration --table=binshops_posts AddCustomBlogImageSize // then adding in the up() method: // $table->string("image_custom_example_size")->nullable(); // and in the down() method: @@ -115,23 +114,11 @@ 'captcha' => [ 'captcha_enabled' => true, // true = we should use a captcha, false = turn it off. If comments are disabled this makes no difference. - 'captcha_type' => \WebDevEtc\BlogEtc\Captcha\Basic::class, // this should be a class that implements the \WebDevEtc\BlogEtc\Interfaces\CaptchaInterface interface + 'captcha_type' => \BinshopsBlog\Captcha\Basic::class, // this should be a class that implements the \BinshopsBlog\Interfaces\CaptchaInterface interface 'basic_question' => "What is the opposite of white?", // a simple captcha question to always ask (if captcha_type is set to 'basic' 'basic_answers' => "black,dark", // comma separated list of possible answers. Don't worry about case. ], - ////////// RSS FEED - - 'rssfeed' => [ - - 'should_shorten_text' => true, // boolean. Default: true. Should we shorten the text in rss feed? - 'text_limit' => 100, // max length of description text in the rss feed - 'posts_to_show_in_rss_feed' => 10, // how many posts should we show in the rss feed - 'cache_in_minutes' => 60, // how long (in minutes) to cache the RSS blog feed for. - 'description' => "Our blog post RSS feed", //description for the RSS feed - 'language' => "en", // see https://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes - ], - ////////// comments: 'comments' => [ @@ -141,7 +128,7 @@ // options: // 'built_in' (default, uses own database for comments), // 'disqus' (uses https://disqus.com/, please enter further config options below), - // 'custom' (will load blogetc::partials.custom_comments, which you can copy to your vendor view dir to customise + // 'custom' (will load binshopsblog::partials.custom_comments, which you can copy to your vendor view dir to customise // 'disabled' (turn comments off) 'type_of_comments_to_show' => 'built_in', // default: built_in @@ -177,6 +164,13 @@ 'search' => [ 'search_enabled' => true, //you can easily turn off search functionality + + 'limit-results'=> 50, + 'enable_wildcards' => true, + 'weight' => [ + 'title' => 1.5, + 'content' => 1, + ], ], //Shows full text of post in listing pages like search result page or category page. Now it shows a preview diff --git a/src/Controllers/BinshopsAdminController.php b/src/Controllers/BinshopsAdminController.php new file mode 100755 index 0000000..34c3ef1 --- /dev/null +++ b/src/Controllers/BinshopsAdminController.php @@ -0,0 +1,503 @@ +middleware(UserCanManageBlogPosts::class); + $this->middleware(LoadLanguage::class); + $this->middleware(PackageSetup::class); + + if (!is_array(config("binshopsblog"))) { + throw new \RuntimeException('The config/binshopsblog.php does not exist. Publish the vendor files for the BinshopsBlog package by running the php artisan publish:vendor command'); + } + } + + /** + * View all posts + * + * @return mixed + */ + public function index(Request $request) + { + $language_id = $request->get('language_id'); + $posts = BinshopsPostTranslation::orderBy("post_id", "desc")->where('lang_id', $language_id) + ->paginate(10); + + return view("binshopsblog_admin::index", [ + 'post_translations'=>$posts, + 'language_id' => $language_id + ]); + } + + /** + * Show form for creating new post + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function create_post(Request $request) + { + $language_id = $request->get('language_id'); + $language_list = BinshopsLanguage::where('active',true)->get(); + $ts = BinshopsCategoryTranslation::where("lang_id",$language_id)->limit(1000)->get(); + + $new_post = new BinshopsPost(); + $new_post->is_published = true; + + return view("binshopsblog_admin::posts.add_post", [ + 'cat_ts' => $ts, + 'language_list' => $language_list, + 'selected_lang' => $language_id, + 'post' => $new_post, + 'post_translation' => new \BinshopsBlog\Models\BinshopsPostTranslation(), + 'post_id' => -1 + ]); + } + + /** + * Save a new post - this method is called whenever add post button is clicked + * + * @param CreateBinshopsBlogPostRequest $request + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + * @throws \Exception + */ + public function store_post(CreateBinshopsBlogPostRequest $request) + { + $new_blog_post = null; + $translation = BinshopsPostTranslation::where( + [ + ['post_id','=',$request['post_id']], + ['lang_id', '=', $request['lang_id']] + ] + )->first(); + + if (!$translation){ + $translation = new BinshopsPostTranslation(); + } + + if ($request['post_id'] == -1 || $request['post_id'] == null){ + //cretes new post + $new_blog_post = new BinshopsPost(); + $translation = new BinshopsPostTranslation(); + + $new_blog_post->posted_at = Carbon::now(); + }else{ + //edits post + $new_blog_post = BinshopsPost::findOrFail($request['post_id']); + } + + $post_exists = $this->check_if_same_post_exists($request['slug'] , $request['lang_id'], $request['post_id']); + if ($post_exists){ + Helpers::flash_message("Post already exists - try to change the slug for this language"); + }else { + $new_blog_post->is_published = $request['is_published']; + $new_blog_post->user_id = \Auth::user()->id; + $new_blog_post->save(); + + $translation->title = $request['title']; + $translation->subtitle = $request['subtitle']; + $translation->short_description = $request['short_description']; + $translation->post_body = $request['post_body']; + $translation->seo_title = $request['seo_title']; + $translation->meta_desc = $request['meta_desc']; + $translation->slug = $request['slug']; + $translation->use_view_file = $request['use_view_file']; + + $translation->lang_id = $request['lang_id']; + $translation->post_id = $new_blog_post->id; + + $this->processUploadedImages($request, $translation); + $translation->save(); + + $new_blog_post->categories()->sync($request->categories()); + Helpers::flash_message("Added post"); + event(new BlogPostAdded($new_blog_post)); + } + + return redirect( route('binshopsblog.admin.index') ); + } + + /** + * This method is called whenever a language is selected + */ + public function store_post_toggle(CreateBinshopsPostToggleRequest $request){ + $new_blog_post = null; + $translation = BinshopsPostTranslation::where( + [ + ['post_id','=',$request['post_id']], + ['lang_id', '=', $request['lang_id']] + ] + )->first(); + + if (!$translation){ + $translation = new BinshopsPostTranslation(); + } + + if ($request['post_id'] == -1 || $request['post_id'] == null){ + //cretes new post + $new_blog_post = new BinshopsPost(); + $new_blog_post->is_published = true; + $new_blog_post->posted_at = Carbon::now(); + }else{ + //edits post + $new_blog_post = BinshopsPost::findOrFail($request['post_id']); + } + + if ($request['slug']){ + $post_exists = $this->check_if_same_post_exists($request['slug'] , $request['lang_id'], $new_blog_post->id); + if ($post_exists){ + Helpers::flash_message("Post already exists - try to change the slug for this language"); + }else{ + $new_blog_post->is_published = $request['is_published']; + $new_blog_post->user_id = \Auth::user()->id; + $new_blog_post->save(); + + $translation->title = $request['title']; + $translation->subtitle = $request['subtitle']; + $translation->short_description = $request['short_description']; + $translation->post_body = $request['post_body']; + $translation->seo_title = $request['seo_title']; + $translation->meta_desc = $request['meta_desc']; + $translation->slug = $request['slug']; + $translation->use_view_file = $request['use_view_file']; + + $translation->lang_id = $request['lang_id']; + $translation->post_id = $new_blog_post->id; + + $this->processUploadedImages($request, $translation); + $translation->save(); + + $new_blog_post->categories()->sync($request->categories()); + + event(new BlogPostAdded($new_blog_post)); + } + } + + //todo: generate event + + $language_id = $request->get('language_id'); + $language_list = BinshopsLanguage::where('active',true)->get(); + $ts = BinshopsCategoryTranslation::where("lang_id",$language_id)->limit(1000)->get(); + + $translation = BinshopsPostTranslation::where( + [ + ['post_id','=',$request['post_id']], + ['lang_id', '=', $request['selected_lang']] + ] + )->first(); + if (!$translation){ + $translation = new BinshopsPostTranslation(); + } + + return view("binshopsblog_admin::posts.add_post", [ + 'cat_ts' => $ts, + 'language_list' => $language_list, + 'selected_lang' => $request['selected_lang'], + 'post_translation' => $translation, + 'post' => $new_blog_post, + 'post_id' => $new_blog_post->id + ]); + } + + /** + * Show form to edit post + * + * @param $blogPostId + * @return mixed + */ + public function edit_post( $blogPostId , Request $request) + { + $language_id = $request->get('language_id'); + + $post_translation = BinshopsPostTranslation::where( + [ + ['lang_id', '=', $language_id], + ['post_id', '=', $blogPostId] + ] + )->first(); + + $post = BinshopsPost::findOrFail($blogPostId); + $language_list = BinshopsLanguage::where('active',true)->get(); + $ts = BinshopsCategoryTranslation::where("lang_id",$language_id)->limit(1000)->get(); + + return view("binshopsblog_admin::posts.edit_post", [ + 'cat_ts' => $ts, + 'language_list' => $language_list, + 'selected_lang' => $language_id, + 'selected_locale' => BinshopsLanguage::where('id', $language_id)->first()->locale, + 'post' => $post, + 'post_translation' => $post_translation + ]); + } + + /** + * Show form to edit post + * + * @param $blogPostId + * @return mixed + */ + public function edit_post_toggle( $blogPostId , Request $request) + { + $post_translation = BinshopsPostTranslation::where( + [ + ['lang_id', '=', $request['selected_lang']], + ['post_id', '=', $blogPostId] + ] + )->first(); + if (!$post_translation){ + $post_translation = new BinshopsPostTranslation(); + } + + $post = BinshopsPost::findOrFail($blogPostId); + $language_list = BinshopsLanguage::where('active',true)->get(); + $ts = BinshopsCategoryTranslation::where("lang_id", $request['selected_lang'])->limit(1000)->get(); + + return view("binshopsblog_admin::posts.edit_post", [ + 'cat_ts' => $ts, + 'language_list' => $language_list, + 'selected_lang' => $request['selected_lang'], + 'selected_locale' => BinshopsLanguage::where('id', $request['selected_lang'])->first()->locale, + 'post' => $post, + 'post_translation' => $post_translation + ]); + } + + /** + * Save changes to a post + * + * @param UpdateBinshopsBlogPostRequest $request + * @param $blogPostId + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + * @throws \Exception + */ + public function update_post(UpdateBinshopsBlogPostRequest $request, $blogPostId) + { + $new_blog_post = BinshopsPost::findOrFail($blogPostId); + $translation = BinshopsPostTranslation::where( + [ + ['post_id','=', $new_blog_post->id], + ['lang_id', '=', $request['lang_id']] + ] + )->first(); + + if (!$translation){ + $translation = new BinshopsPostTranslation(); + $new_blog_post->posted_at = Carbon::now(); + } + + $post_exists = $this->check_if_same_post_exists($request['slug'] , $request['lang_id'], $blogPostId); + if ($post_exists){ + Helpers::flash_message("Post already exists - try to change the slug for this language"); + }else { + $new_blog_post->is_published = $request['is_published']; + $new_blog_post->user_id = \Auth::user()->id; + $new_blog_post->save(); + + $translation->title = $request['title']; + $translation->subtitle = $request['subtitle']; + $translation->short_description = $request['short_description']; + $translation->post_body = $request['post_body']; + $translation->seo_title = $request['seo_title']; + $translation->meta_desc = $request['meta_desc']; + $translation->slug = $request['slug']; + $translation->use_view_file = $request['use_view_file']; + + $translation->lang_id = $request['lang_id']; + $translation->post_id = $new_blog_post->id; + + $this->processUploadedImages($request, $translation); + $translation->save(); + + $new_blog_post->categories()->sync($request->categories()); + Helpers::flash_message("Post Updated"); + event(new BlogPostAdded($new_blog_post)); + } + + return redirect( route('binshopsblog.admin.index') ); + } + + public function remove_photo($postSlug, $lang_id) + { + $post = BinshopsPostTranslation::where([ + ["slug", '=', $postSlug], + ['lang_id', '=', $lang_id] + ])->firstOrFail(); + + $path = public_path('/' . config("binshopsblog.blog_upload_dir")); + if (!$this->checked_blog_image_dir_is_writable) { + if (!is_writable($path)) { + throw new \RuntimeException("Image destination path is not writable ($path)"); + } + } + + $destinationPath = $this->image_destination_path(); + + if (file_exists($destinationPath.'/'.$post->image_large)) { + unlink($destinationPath.'/'.$post->image_large); + } + + if (file_exists($destinationPath.'/'.$post->image_medium)) { + unlink($destinationPath.'/'.$post->image_medium); + } + + if (file_exists($destinationPath.'/'.$post->image_thumbnail)) { + unlink($destinationPath.'/'.$post->image_thumbnail); + } + + $post->image_large = null; + $post->image_medium = null; + $post->image_thumbnail = null; + $post->save(); + + Helpers::flash_message("Photo removed"); + + return redirect($post->edit_url()); + } + + /** + * Delete a post + * + * @param DeleteBinshopsBlogPostRequest $request + * @param $blogPostId + * @return mixed + */ + public function destroy_post(DeleteBinshopsBlogPostRequest $request, $blogPostId) + { + $post = BinshopsPost::findOrFail($blogPostId); + //archive deleted post + + $post->delete(); + event(new BlogPostWillBeDeleted($post)); + + // todo - delete the featured images? + // At the moment it just issues a warning saying the images are still on the server. + + Helpers::flash_message("Post successfully deleted!"); + + return redirect( route('binshopsblog.admin.index') ); + } + + /** + * Process any uploaded images (for featured image) + * + * @param BaseRequestInterface $request + * @param $new_blog_post + * @throws \Exception + * @todo - next full release, tidy this up! + */ + protected function processUploadedImages(BaseRequestInterface $request, BinshopsPostTranslation $new_blog_post) + { + if (!config("binshopsblog.image_upload_enabled")) { + // image upload was disabled + return; + } + + $this->increaseMemoryLimit(); + + // to save in db later + $uploaded_image_details = []; + + + foreach ((array)config('binshopsblog.image_sizes') as $size => $image_size_details) { + + if ($image_size_details['enabled'] && $photo = $request->get_image_file($size)) { + // this image size is enabled, and + // we have an uploaded image that we can use + + $uploaded_image = $this->UploadAndResize($new_blog_post, $new_blog_post->slug, $image_size_details, $photo); + + $new_blog_post->$size = $uploaded_image['filename']; + $uploaded_image_details[$size] = $uploaded_image; + } + } + + // store the image upload. + // todo: link this to the binshopsblog_post row. + if (count(array_filter($uploaded_image_details))>0) { + BinshopsUploadedPhoto::create([ + 'source' => "BlogFeaturedImage", + 'uploaded_images' => $uploaded_image_details, + ]); + } + } + + //translations for the same psots are ignored + protected function check_if_same_post_exists($slug, $lang_id, $post_id){ + $slg = BinshopsPostTranslation::where( + [ + ['slug','=', $slug], + ['lang_id', '=', $lang_id], + ['post_id', '<>', $post_id] + ] + )->first(); + if ($slg){ + return true; + }else{ + return false; + } + } + + /** + * Show the search results for $_GET['s'] + * + * @param Request $request + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + * @throws \Exception + */ + public function searchBlog(Request $request) + { + if (!config("binshopsblog.search.search_enabled")) { + throw new \Exception("Search is disabled"); + } + $query = $request->get("s"); + $search = new Search(); + $search_results = $search->run($query); + + \View::share("title", "Search results for " . e($query)); + + $rootList = BinshopsCategory::roots()->get(); + BinshopsCategory::loadSiblingsWithList($rootList); + + $language_id = $request->get('language_id'); + + return view("binshopsblog_admin::index", [ + 'search' => true, + 'post_translations'=>$search_results, + 'language_id' => $language_id + ]); + } +} diff --git a/src/Controllers/BinshopsAdminSetupController.php b/src/Controllers/BinshopsAdminSetupController.php new file mode 100644 index 0000000..8612907 --- /dev/null +++ b/src/Controllers/BinshopsAdminSetupController.php @@ -0,0 +1,59 @@ +middleware(UserCanManageBlogPosts::class); + + if (!is_array(config("binshopsblog"))) { + throw new \RuntimeException('The config/binshopsblog.php does not exist. Publish the vendor files for the BinshopsBlog package by running the php artisan publish:vendor command'); + } + } + + /** + * View all posts + * + * @return mixed + */ + public function setup(Request $request) + { + return view("binshopsblog_admin::setup.setup"); + } + + public function setup_submit(Request $request){ + if ($request['locale'] == null){ + return redirect( route('binshopsblog.admin.setup_submit') ); + } + $language = new BinshopsLanguage(); + $language->active = $request['active']; + $language->iso_code = $request['iso_code']; + $language->locale = $request['locale']; + $language->name = $request['name']; + $language->date_format = $request['date_format']; + + $language->save(); + if (!BinshopsConfiguration::get('INITIAL_SETUP')){ + BinshopsConfiguration::set('INITIAL_SETUP', true); + BinshopsConfiguration::set('DEFAULT_LANGUAGE_LOCALE', $request['locale']); + } + + return redirect( route('binshopsblog.admin.index') ); + } +} diff --git a/src/Controllers/BinshopsCategoryAdminController.php b/src/Controllers/BinshopsCategoryAdminController.php new file mode 100755 index 0000000..6fb33c0 --- /dev/null +++ b/src/Controllers/BinshopsCategoryAdminController.php @@ -0,0 +1,210 @@ +middleware(UserCanManageBlogPosts::class); + $this->middleware(LoadLanguage::class); + + } + + /** + * Show list of categories + * + * @return mixed + */ + public function index(Request $request){ + $language_id = $request->get('language_id'); + $categories = BinshopsCategoryTranslation::orderBy("category_id")->where('lang_id', $language_id)->paginate(25); + return view("binshopsblog_admin::categories.index",[ + 'categories' => $categories, + 'language_id' => $language_id + ]); + } + + /** + * Show the form for creating new category + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function create_category(Request $request){ + $language_id = $request->get('language_id'); + $language_list = BinshopsLanguage::where('active',true)->get(); + + $cat_list = BinshopsCategory::whereHas('categoryTranslations', function ($query) use ($language_id) { + return $query->where('lang_id', '=', $language_id); + })->get(); + + $rootList = BinshopsCategory::roots()->get(); + BinshopsCategory::loadSiblingsWithList($rootList); + + + return view("binshopsblog_admin::categories.add_category",[ + 'category' => new \BinshopsBlog\Models\BinshopsCategory(), + 'category_translation' => new \BinshopsBlog\Models\BinshopsCategoryTranslation(), + 'category_tree' => $cat_list, + 'cat_roots' => $rootList, + 'language_id' => $language_id, + 'language_list' => $language_list + ]); + } + + /** + * Store a new category + * + * @param StoreBinshopsBlogCategoryRequest $request + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + * + * This controller is totally REST controller + */ + public function store_category(Request $request){ + $language_id = $request->get('language_id'); + $language_list = $request['data']; + + if ($request['parent_id']== 0){ + $request['parent_id'] = null; + } + $new_category = BinshopsCategory::create([ + 'parent_id' => $request['parent_id'] + ]); + + foreach ($language_list as $key => $value) { + if ($value['lang_id'] != -1 && $value['category_name'] !== null){ + //check for slug availability + $obj = BinshopsCategoryTranslation::where('slug',$value['slug'])->first(); + if ($obj){ + BinshopsCategory::destroy($new_category->id); + return response()->json([ + 'code' => 403, + 'message' => "slug is already taken", + 'data' => $value['lang_id'] + ]); + } + $new_category_translation = $new_category->categoryTranslations()->create([ + 'category_name' => $value['category_name'], + 'slug' => $value['slug'], + 'category_description' => $value['category_description'], + 'lang_id' => $value['lang_id'], + 'category_id' => $new_category->id + ]); + } + } + + event(new CategoryAdded($new_category, $new_category_translation)); + Helpers::flash_message("Saved new category"); + return response()->json([ + 'code' => 200, + 'message' => "category successfully aaded" + ]); + } + + /** + * Show the edit form for category + * @param $categoryId + * @return mixed + */ + public function edit_category($categoryId, Request $request){ + $language_id = $request->get('language_id'); + $language_list = BinshopsLanguage::where('active',true)->get(); + + $category = BinshopsCategory::findOrFail($categoryId); + $cat_trans = BinshopsCategoryTranslation::where( + [ + ['lang_id', '=', $language_id], + ['category_id', '=', $categoryId] + ] + )->first(); + + return view("binshopsblog_admin::categories.edit_category",[ + 'category' => $category, + 'category_translation' => $cat_trans, + 'categories_list' => BinshopsCategoryTranslation::orderBy("category_id")->where('lang_id', $language_id)->get(), + 'language_id' => $language_id, + 'language_list' => $language_list + ]); + } + + /** + * Save submitted changes + * + * @param UpdateBinshopsBlogCategoryRequest $request + * @param $categoryId + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function update_category(UpdateBinshopsBlogCategoryRequest $request, $categoryId){ + /** @var BinshopsCategory $category */ + $category = BinshopsCategory::findOrFail($categoryId); + $language_id = $request->get('language_id'); + $translation = BinshopsCategoryTranslation::where( + [ + ['lang_id', '=', $language_id], + ['category_id', '=', $categoryId] + ] + )->first(); + $category->fill($request->all()); + $translation->fill($request->all()); + + // if the parent_id is passed in as 0 it will create an error + if ($category->parent_id <= 0) { + $category->parent_id = null; + } + + $category->save(); + $translation->save(); + + Helpers::flash_message("Saved category changes"); + event(new CategoryEdited($category)); + return redirect($translation->edit_url()); + } + + /** + * Delete the category + * + * @param DeleteBinshopsBlogCategoryRequest $request + * @param $categoryId + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function destroy_category(DeleteBinshopsBlogCategoryRequest $request, $categoryId){ + + /* Please keep this in, so code inspectiwons don't say $request was unused. Of course it might now get marked as left/right parts are equal */ + $request=$request; + + $category = BinshopsCategory::findOrFail($categoryId); + $children = $category->children()->get(); + if (sizeof($children) > 0) { + Helpers::flash_message("This category could not be deleted it has some sub-categories. First try to change parent category of subs."); + return redirect(route('binshopsblog.admin.categories.index')); + } + + event(new CategoryWillBeDeleted($category)); + $category->delete(); + + Helpers::flash_message("Category successfully deleted!"); + return redirect( route('binshopsblog.admin.categories.index') ); + } + +} diff --git a/src/Controllers/BinshopsCommentWriterController.php b/src/Controllers/BinshopsCommentWriterController.php new file mode 100755 index 0000000..5cf3fad --- /dev/null +++ b/src/Controllers/BinshopsCommentWriterController.php @@ -0,0 +1,100 @@ +middleware(UserCanManageBlogPosts::class); + $this->middleware(LoadLanguage::class); + + } + + /** + * Let a guest (or logged in user) submit a new comment for a blog post + * + * @param AddNewCommentRequest $request + * @param $blog_post_slug + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + * @throws \Exception + */ + public function addNewComment(AddNewCommentRequest $request, $locale, $blog_post_slug) + { + + if (config("binshopsblog.comments.type_of_comments_to_show", "built_in") !== 'built_in') { + throw new \RuntimeException("Built in comments are disabled"); + } + + $post_translation = BinshopsPostTranslation::where("slug", $blog_post_slug) + ->with('post') + ->firstOrFail(); + $blog_post = $post_translation->post; + + /** @var CaptchaAbstract $captcha */ + $captcha = $this->getCaptchaObject(); + if ($captcha) { + $captcha->runCaptchaBeforeAddingComment($request, $blog_post); + } + + $new_comment = $this->createNewComment($request, $blog_post); + + return view("binshopsblog::saved_comment", [ + 'captcha' => $captcha, + 'blog_post' => $post_translation, + 'new_comment' => $new_comment + ]); + + } + + /** + * @param AddNewCommentRequest $request + * @param $blog_post + * @return BinshopsComment + */ + protected function createNewComment(AddNewCommentRequest $request, $blog_post) + { + $new_comment = new BinshopsComment($request->all()); + + if (config("binshopsblog.comments.save_ip_address")) { + $new_comment->ip = $request->ip(); + } + if (config("binshopsblog.comments.ask_for_author_website")) { + $new_comment->author_website = $request->get('author_website'); + } + if (config("binshopsblog.comments.ask_for_author_email")) { + $new_comment->author_email = $request->get('author_email'); + } + if (config("binshopsblog.comments.save_user_id_if_logged_in", true) && Auth::check()) { + $new_comment->user_id = Auth::user()->id; + } + + $new_comment->approved = config("binshopsblog.comments.auto_approve_comments", true) ? true : false; + + $blog_post->comments()->save($new_comment); + + event(new CommentAdded($blog_post, $new_comment)); + + return $new_comment; + } + +} diff --git a/src/Controllers/BlogEtcCommentsAdminController.php b/src/Controllers/BinshopsCommentsAdminController.php similarity index 61% rename from src/Controllers/BlogEtcCommentsAdminController.php rename to src/Controllers/BinshopsCommentsAdminController.php index 3557aed..6574900 100755 --- a/src/Controllers/BlogEtcCommentsAdminController.php +++ b/src/Controllers/BinshopsCommentsAdminController.php @@ -1,27 +1,30 @@ middleware(UserCanManageBlogPosts::class); + $this->middleware(LoadLanguage::class); + } /** @@ -32,7 +35,7 @@ public function __construct() */ public function index(Request $request) { - $comments = BlogEtcComment::withoutGlobalScopes()->orderBy("created_at", "desc") + $comments = BinshopsComment::withoutGlobalScopes()->orderBy("created_at", "desc") ->with("post"); if ($request->get("waiting_for_approval")) { @@ -40,7 +43,7 @@ public function index(Request $request) } $comments = $comments->paginate(100); - return view("blogetc_admin::comments.index") + return view("binshopsblog_admin::comments.index") ->withComments($comments ); } @@ -54,7 +57,7 @@ public function index(Request $request) */ public function approve($blogCommentId) { - $comment = BlogEtcComment::withoutGlobalScopes()->findOrFail($blogCommentId); + $comment = BinshopsComment::withoutGlobalScopes()->findOrFail($blogCommentId); $comment->approved = true; $comment->save(); @@ -73,7 +76,7 @@ public function approve($blogCommentId) */ public function destroy($blogCommentId) { - $comment = BlogEtcComment::withoutGlobalScopes()->findOrFail($blogCommentId); + $comment = BinshopsComment::withoutGlobalScopes()->findOrFail($blogCommentId); event(new CommentWillBeDeleted($comment)); $comment->delete(); diff --git a/src/Controllers/BlogEtcImageUploadController.php b/src/Controllers/BinshopsImageUploadController.php similarity index 59% rename from src/Controllers/BlogEtcImageUploadController.php rename to src/Controllers/BinshopsImageUploadController.php index de80e75..eaa4b2d 100755 --- a/src/Controllers/BlogEtcImageUploadController.php +++ b/src/Controllers/BinshopsImageUploadController.php @@ -1,38 +1,40 @@ middleware(UserCanManageBlogPosts::class); + $this->middleware(LoadLanguage::class); - if (!is_array(config("blogetc"))) { - throw new \RuntimeException('The config/blogetc.php does not exist. Publish the vendor files for the BlogEtc package by running the php artisan publish:vendor command'); + if (!is_array(config("binshopsblog"))) { + throw new \RuntimeException('The config/binshopsblog.php does not exist. Publish the vendor files for the BinshopsBlog package by running the php artisan publish:vendor command'); } - if (!config("blogetc.image_upload_enabled")) { - throw new \RuntimeException("The blogetc.php config option has not enabled image uploading"); + if (!config("binshopsblog.image_upload_enabled")) { + throw new \RuntimeException("The binshopsblog.php config option has not enabled image uploading"); } @@ -46,7 +48,7 @@ public function __construct() public function index() { - return view("blogetc_admin::imageupload.index", ['uploaded_photos' => BlogEtcUploadedPhoto::orderBy("id", "desc")->paginate(10)]); + return view("binshopsblog_admin::imageupload.index", ['uploaded_photos' => BinshopsUploadedPhoto::orderBy("id", "desc")->paginate(10)]); } /** @@ -56,7 +58,7 @@ public function index() */ public function create() { - return view("blogetc_admin::imageupload.create", []); + return view("binshopsblog_admin::imageupload.create", []); } /** @@ -70,7 +72,7 @@ public function store(UploadImageRequest $request) { $processed_images = $this->processUploadedImages($request); - return view("blogetc_admin::imageupload.uploaded", ['images' => $processed_images]); + return view("binshopsblog_admin::imageupload.uploaded", ['images' => $processed_images]); } /** @@ -80,7 +82,7 @@ public function store(UploadImageRequest $request) * * @return array returns an array of details about each file resized. * @throws \Exception - * @todo - This class was added after the other main features, so this duplicates some code from the main blog post admin controller (BlogEtcAdminController). For next full release this should be tided up. + * @todo - This class was added after the other main features, so this duplicates some code from the main blog post admin controller (BinshopsAdminController). For next full release this should be tided up. */ protected function processUploadedImages(UploadImageRequest $request) { @@ -93,13 +95,13 @@ protected function processUploadedImages(UploadImageRequest $request) $sizes_to_upload = $request->get("sizes_to_upload"); // now upload a full size - this is a special case, not in the config file. We only store full size images in this class, not as part of the featured blog image uploads. - if (isset($sizes_to_upload['blogetc_full_size']) && $sizes_to_upload['blogetc_full_size'] === 'true') { + if (isset($sizes_to_upload['binshopsblog_full_size']) && $sizes_to_upload['binshopsblog_full_size'] === 'true') { - $uploaded_image_details['blogetc_full_size'] = $this->UploadAndResize(null, $request->get("image_title"), 'fullsize', $photo); + $uploaded_image_details['binshopsblog_full_size'] = $this->UploadAndResize(null, $request->get("image_title"), 'fullsize', $photo); } - foreach ((array)config('blogetc.image_sizes') as $size => $image_size_details) { + foreach ((array)config('binshopsblog.image_sizes') as $size => $image_size_details) { if (!isset($sizes_to_upload[$size]) || !$sizes_to_upload[$size] || !$image_size_details['enabled']) { continue; @@ -112,7 +114,7 @@ protected function processUploadedImages(UploadImageRequest $request) // store the image upload. - BlogEtcUploadedPhoto::create([ + BinshopsUploadedPhoto::create([ 'image_title' => $request->get("image_title"), 'source' => "ImageUpload", 'uploader_id' => optional(\Auth::user())->id, diff --git a/src/Controllers/BinshopsLanguageAdminController.php b/src/Controllers/BinshopsLanguageAdminController.php new file mode 100644 index 0000000..6f6addc --- /dev/null +++ b/src/Controllers/BinshopsLanguageAdminController.php @@ -0,0 +1,91 @@ +middleware(UserCanManageBlogPosts::class); + $this->middleware(LoadLanguage::class); + + } + + public function index(){ + $language_list = BinshopsLanguage::all(); + return view("binshopsblog_admin::languages.index",[ + 'language_list' => $language_list + ]); + } + + public function create_language(){ + return view("binshopsblog_admin::languages.add_language"); + } + + public function store_language(Request $request){ + if ($request['locale'] == null){ + Helpers::flash_message("Select a language!"); + return view("binshopsblog_admin::languages.add_language"); + } + $language = new BinshopsLanguage(); + $language->active = $request['active']; + $language->iso_code = $request['iso_code']; + $language->locale = $request['locale']; + $language->name = $request['name']; + $language->date_format = $request['date_format']; + $language->rtl = $request['rtl']; + + $language->save(); + + Helpers::flash_message("Language: " . $language->name . " has been added."); + return redirect( route('binshopsblog.admin.languages.index') ); + } + + public function destroy_language(Request $request, $languageId){ + $lang = BinshopsLanguage::where('locale', BinshopsConfiguration::get('DEFAULT_LANGUAGE_LOCALE'))->first(); + if ($languageId == $lang->id){ + Helpers::flash_message("The default language can not be deleted!"); + return redirect( route('binshopsblog.admin.languages.index') ); + } + + try { + $language = BinshopsLanguage::findOrFail($languageId); + //todo +// event(new CategoryWillBeDeleted($category)); + $language->delete(); + Helpers::flash_message("The language is successfully deleted!"); + return redirect( route('binshopsblog.admin.languages.index') ); + } catch (\Illuminate\Database\QueryException $e) { + Helpers::flash_message("You can not delete this language, because it's used in posts or categoies."); + return redirect( route('binshopsblog.admin.languages.index') ); + } + } + + public function toggle_language(Request $request, $languageId){ + $language = BinshopsLanguage::findOrFail($languageId); + if ($language->active == 1){ + $language->active = 0; + }else if ($language->active == 0){ + $language->active = 1; + } + + $language->save(); + //todo + //event + + Helpers::flash_message("Language: " . $language->name . " has been disabled."); + return redirect( route('binshopsblog.admin.languages.index') ); + } +} diff --git a/src/Controllers/BinshopsReaderController.php b/src/Controllers/BinshopsReaderController.php new file mode 100755 index 0000000..3386ca2 --- /dev/null +++ b/src/Controllers/BinshopsReaderController.php @@ -0,0 +1,176 @@ +middleware(DetectLanguage::class); + } + + /** + * Show blog posts + * If category_slug is set, then only show from that category + * + * @param null $category_slug + * @return mixed + */ + public function index($locale = null, Request $request, $category_slug = null) + { + // the published_at + is_published are handled by BinshopsBlogPublishedScope, and don't take effect if the logged in user can manageb log posts + + //todo + $title = 'Blog Page'; // default title... + + $categoryChain = null; + $posts = array(); + if ($category_slug) { + $category = BinshopsCategoryTranslation::where("slug", $category_slug)->with('category')->firstOrFail()->category; + $categoryChain = $category->getAncestorsAndSelf(); + $posts = $category->posts()->where("binshops_post_categories.category_id", $category->id)->with([ 'postTranslations' => function($query) use ($request){ + $query->where("lang_id" , '=' , $request->get("lang_id")); + } + ])->get(); + + $posts = BinshopsPostTranslation::join('binshops_posts', 'binshops_post_translations.post_id', '=', 'binshops_posts.id') + ->where('lang_id', $request->get("lang_id")) + ->where("is_published" , '=' , true) + ->where('posted_at', '<', Carbon::now()->format('Y-m-d H:i:s')) + ->orderBy("posted_at", "desc") + ->whereIn('binshops_posts.id', $posts->pluck('id')) + ->paginate(config("binshopsblog.per_page", 10)); + + // at the moment we handle this special case (viewing a category) by hard coding in the following two lines. + // You can easily override this in the view files. + \View::share('binshopsblog_category', $category); // so the view can say "You are viewing $CATEGORYNAME category posts" + $title = 'Posts in ' . $category->category_name . " category"; // hardcode title here... + } else { + $posts = BinshopsPostTranslation::join('binshops_posts', 'binshops_post_translations.post_id', '=', 'binshops_posts.id') + ->where('lang_id', $request->get("lang_id")) + ->where("is_published" , '=' , true) + ->where('posted_at', '<', Carbon::now()->format('Y-m-d H:i:s')) + ->orderBy("posted_at", "desc") + ->paginate(config("binshopsblog.per_page", 10)); + } + + //load category hierarchy + $rootList = BinshopsCategory::roots()->get(); + BinshopsCategory::loadSiblingsWithList($rootList); + + return view("binshopsblog::index", [ + 'lang_list' => BinshopsLanguage::all('locale','name'), + 'locale' => $request->get("locale"), + 'lang_id' => $request->get('lang_id'), + 'category_chain' => $categoryChain, + 'categories' => $rootList, + 'posts' => $posts, + 'title' => $title, + 'routeWithoutLocale' => $request->get("routeWithoutLocale") + ]); + } + + /** + * Show the search results for $_GET['s'] + * + * @param Request $request + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + * @throws \Exception + */ + public function search(Request $request) + { + if (!config("binshopsblog.search.search_enabled")) { + throw new \Exception("Search is disabled"); + } + $query = $request->get("s"); + $search = new Search(); + $search_results = $search->run($query); + + \View::share("title", "Search results for " . e($query)); + + $rootList = BinshopsCategory::roots()->get(); + BinshopsCategory::loadSiblingsWithList($rootList); + + return view("binshopsblog::search", [ + 'lang_id' => $request->get('lang_id'), + 'locale' => $request->get("locale"), + 'categories' => $rootList, + 'query' => $query, + 'search_results' => $search_results, + 'routeWithoutLocale' => $request->get("routeWithoutLocale") + ] + ); + } + + /** + * View all posts in $category_slug category + * + * @param Request $request + * @param $category_slug + * @return mixed + */ + public function view_category(Request $request) + { + $hierarchy = $request->route('subcategories'); + + $categories = explode('/', $hierarchy); + return $this->index($request->get('locale'), $request, end($categories)); + } + + /** + * View a single post and (if enabled) it's comments + * + * @param Request $request + * @param $blogPostSlug + * @return mixed + */ + public function viewSinglePost(Request $request) + { + $blogPostSlug = $request->route('blogPostSlug'); + + // the published_at + is_published are handled by BinshopsBlogPublishedScope, and don't take effect if the logged in user can manage log posts + $blog_post = BinshopsPostTranslation::where([ + ["slug", "=", $blogPostSlug], + ['lang_id', "=" , $request->get("lang_id")] + ])->firstOrFail(); + + if ($captcha = $this->getCaptchaObject()) { + $captcha->runCaptchaBeforeShowingPosts($request, $blog_post); + } + + $categories = $blog_post->post->categories()->with([ 'categoryTranslations' => function($query) use ($request){ + $query->where("lang_id" , '=' , $request->get("lang_id")); + } + ])->get(); + return view("binshopsblog::single_post", [ + 'post' => $blog_post, + // the default scope only selects approved comments, ordered by id + 'comments' => $blog_post->post->comments() + ->with("user") + ->get(), + 'captcha' => $captcha, + 'categories' => $categories, + 'locale' => $request->get("locale"), + 'routeWithoutLocale' => $request->get("routeWithoutLocale") + ]); + } +} diff --git a/src/Controllers/BlogEtcAdminController.php b/src/Controllers/BlogEtcAdminController.php deleted file mode 100755 index 9f93a30..0000000 --- a/src/Controllers/BlogEtcAdminController.php +++ /dev/null @@ -1,230 +0,0 @@ -middleware(UserCanManageBlogPosts::class); - - if (!is_array(config("blogetc"))) { - throw new \RuntimeException('The config/blogetc.php does not exist. Publish the vendor files for the BlogEtc package by running the php artisan publish:vendor command'); - } - } - - - /** - * View all posts - * - * @return mixed - */ - public function index() - { - $posts = BlogEtcPost::orderBy("posted_at", "desc") - ->paginate(10); - - return view("blogetc_admin::index", ['posts'=>$posts]); - } - - /** - * Show form for creating new post - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - */ - public function create_post() - { - return view("blogetc_admin::posts.add_post"); - } - - /** - * Save a new post - * - * @param CreateBlogEtcPostRequest $request - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - * @throws \Exception - */ - public function store_post(CreateBlogEtcPostRequest $request) - { - $new_blog_post = new BlogEtcPost($request->all()); - - $this->processUploadedImages($request, $new_blog_post); - - if (!$new_blog_post->posted_at) { - $new_blog_post->posted_at = Carbon::now(); - } - - $new_blog_post->user_id = \Auth::user()->id; - $new_blog_post->save(); - - $new_blog_post->categories()->sync($request->categories()); - - Helpers::flash_message("Added post"); - event(new BlogPostAdded($new_blog_post)); - return redirect($new_blog_post->edit_url()); - } - - /** - * Show form to edit post - * - * @param $blogPostId - * @return mixed - */ - public function edit_post( $blogPostId) - { - $post = BlogEtcPost::findOrFail($blogPostId); - return view("blogetc_admin::posts.edit_post")->withPost($post); - } - - /** - * Save changes to a post - * - * @param UpdateBlogEtcPostRequest $request - * @param $blogPostId - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - * @throws \Exception - */ - public function update_post(UpdateBlogEtcPostRequest $request, $blogPostId) - { - /** @var BlogEtcPost $post */ - $post = BlogEtcPost::findOrFail($blogPostId); - $post->fill($request->all()); - - $this->processUploadedImages($request, $post); - - $post->save(); - $post->categories()->sync($request->categories()); - - Helpers::flash_message("Updated post"); - event(new BlogPostEdited($post)); - - return redirect($post->edit_url()); - - } - - public function remove_photo($postSlug) - { - $post = BlogEtcPost::where("slug", $postSlug)->firstOrFail(); - - $path = public_path('/' . config("blogetc.blog_upload_dir")); - if (!$this->checked_blog_image_dir_is_writable) { - if (!is_writable($path)) { - throw new \RuntimeException("Image destination path is not writable ($path)"); - } - } - - $destinationPath = $this->image_destination_path(); - - if (file_exists($destinationPath.'/'.$post->image_large)) { - unlink($destinationPath.'/'.$post->image_large); - } - - if (file_exists($destinationPath.'/'.$post->image_medium)) { - unlink($destinationPath.'/'.$post->image_medium); - } - - if (file_exists($destinationPath.'/'.$post->image_thumbnail)) { - unlink($destinationPath.'/'.$post->image_thumbnail); - } - - $post->image_large = null; - $post->image_medium = null; - $post->image_thumbnail = null; - $post->save(); - - Helpers::flash_message("Photo removed"); - - return redirect($post->edit_url()); - } - - /** - * Delete a post - * - * @param DeleteBlogEtcPostRequest $request - * @param $blogPostId - * @return mixed - */ - public function destroy_post(DeleteBlogEtcPostRequest $request, $blogPostId) - { - - $post = BlogEtcPost::findOrFail($blogPostId); - event(new BlogPostWillBeDeleted($post)); - - $post->delete(); - - // todo - delete the featured images? - // At the moment it just issues a warning saying the images are still on the server. - - return view("blogetc_admin::posts.deleted_post") - ->withDeletedPost($post); - - } - - /** - * Process any uploaded images (for featured image) - * - * @param BaseRequestInterface $request - * @param $new_blog_post - * @throws \Exception - * @todo - next full release, tidy this up! - */ - protected function processUploadedImages(BaseRequestInterface $request, BlogEtcPost $new_blog_post) - { - if (!config("blogetc.image_upload_enabled")) { - // image upload was disabled - return; - } - - $this->increaseMemoryLimit(); - - // to save in db later - $uploaded_image_details = []; - - - foreach ((array)config('blogetc.image_sizes') as $size => $image_size_details) { - - if ($image_size_details['enabled'] && $photo = $request->get_image_file($size)) { - // this image size is enabled, and - // we have an uploaded image that we can use - - $uploaded_image = $this->UploadAndResize($new_blog_post, $new_blog_post->slug, $image_size_details, $photo); - - $new_blog_post->$size = $uploaded_image['filename']; - $uploaded_image_details[$size] = $uploaded_image; - } - } - - // store the image upload. - // todo: link this to the blogetc_post row. - if (count(array_filter($uploaded_image_details))>0) { - BlogEtcUploadedPhoto::create([ - 'source' => "BlogFeaturedImage", - 'uploaded_images' => $uploaded_image_details, - ]); - } - } -} diff --git a/src/Controllers/BlogEtcCategoryAdminController.php b/src/Controllers/BlogEtcCategoryAdminController.php deleted file mode 100755 index 827222c..0000000 --- a/src/Controllers/BlogEtcCategoryAdminController.php +++ /dev/null @@ -1,122 +0,0 @@ -middleware(UserCanManageBlogPosts::class); - } - - /** - * Show list of categories - * - * @return mixed - */ - public function index(){ - - $categories = BlogEtcCategory::orderBy("category_name")->paginate(25); - return view("blogetc_admin::categories.index")->withCategories($categories); - } - - /** - * Show the form for creating new category - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - */ - public function create_category(){ - - return view("blogetc_admin::categories.add_category",[ - 'category' => new \WebDevEtc\BlogEtc\Models\BlogEtcCategory(), - 'categories_list' => BlogEtcCategory::orderBy("category_name")->get() - ]); - - } - - /** - * Store a new category - * - * @param StoreBlogEtcCategoryRequest $request - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - public function store_category(StoreBlogEtcCategoryRequest $request){ - if ($request['parent_id']== 0){ - $request['parent_id'] = null; - } - $new_category = BlogEtcCategory::create($request->all()); - - Helpers::flash_message("Saved new category"); - - event(new CategoryAdded($new_category)); - return redirect( route('blogetc.admin.categories.index') ); - } - - /** - * Show the edit form for category - * @param $categoryId - * @return mixed - */ - public function edit_category($categoryId){ - $category = BlogEtcCategory::findOrFail($categoryId); - return view("blogetc_admin::categories.edit_category",[ - 'categories_list' => BlogEtcCategory::orderBy("category_name")->get() - ])->withCategory($category); - } - - /** - * Save submitted changes - * - * @param UpdateBlogEtcCategoryRequest $request - * @param $categoryId - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - public function update_category(UpdateBlogEtcCategoryRequest $request, $categoryId){ - /** @var BlogEtcCategory $category */ - $category = BlogEtcCategory::findOrFail($categoryId); - $category->fill($request->all()); - $category->save(); - - Helpers::flash_message("Saved category changes"); - event(new CategoryEdited($category)); - return redirect($category->edit_url()); - } - - /** - * Delete the category - * - * @param DeleteBlogEtcCategoryRequest $request - * @param $categoryId - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - */ - public function destroy_category(DeleteBlogEtcCategoryRequest $request, $categoryId){ - - /* Please keep this in, so code inspections don't say $request was unused. Of course it might now get marked as left/right parts are equal */ - $request=$request; - - $category = BlogEtcCategory::findOrFail($categoryId); - event(new CategoryWillBeDeleted($category)); - $category->delete(); - - return view ("blogetc_admin::categories.deleted_category"); - - } - -} diff --git a/src/Controllers/BlogEtcCommentWriterController.php b/src/Controllers/BlogEtcCommentWriterController.php deleted file mode 100755 index d033439..0000000 --- a/src/Controllers/BlogEtcCommentWriterController.php +++ /dev/null @@ -1,88 +0,0 @@ -firstOrFail(); - - /** @var CaptchaAbstract $captcha */ - $captcha = $this->getCaptchaObject(); - if ($captcha) { - $captcha->runCaptchaBeforeAddingComment($request, $blog_post); - } - - $new_comment = $this->createNewComment($request, $blog_post); - - return view("blogetc::saved_comment", [ - 'captcha' => $captcha, - 'blog_post' => $blog_post, - 'new_comment' => $new_comment - ]); - - } - - /** - * @param AddNewCommentRequest $request - * @param $blog_post - * @return BlogEtcComment - */ - protected function createNewComment(AddNewCommentRequest $request, $blog_post) - { - $new_comment = new BlogEtcComment($request->all()); - - if (config("blogetc.comments.save_ip_address")) { - $new_comment->ip = $request->ip(); - } - if (config("blogetc.comments.ask_for_author_website")) { - $new_comment->author_website = $request->get('author_website'); - } - if (config("blogetc.comments.ask_for_author_website")) { - $new_comment->author_email = $request->get('author_email'); - } - if (config("blogetc.comments.save_user_id_if_logged_in", true) && Auth::check()) { - $new_comment->user_id = Auth::user()->id; - } - - $new_comment->approved = config("blogetc.comments.auto_approve_comments", true) ? true : false; - - $blog_post->comments()->save($new_comment); - - event(new CommentAdded($blog_post, $new_comment)); - - return $new_comment; - } - -} diff --git a/src/Controllers/BlogEtcReaderController.php b/src/Controllers/BlogEtcReaderController.php deleted file mode 100755 index 242a437..0000000 --- a/src/Controllers/BlogEtcReaderController.php +++ /dev/null @@ -1,135 +0,0 @@ -firstOrFail(); - $categoryChain = $category->getAncestorsAndSelf(); - $posts = $category->posts()->where("blog_etc_post_categories.blog_etc_category_id", $category->id); - - // at the moment we handle this special case (viewing a category) by hard coding in the following two lines. - // You can easily override this in the view files. - \View::share('blogetc_category', $category); // so the view can say "You are viewing $CATEGORYNAME category posts" - $title = 'Posts in ' . $category->category_name . " category"; // hardcode title here... - } else { - $posts = BlogEtcPost::query(); - } - - $posts = $posts->where('is_published', '=', 1)->where('posted_at', '<', Carbon::now()->format('Y-m-d H:i:s'))->orderBy("posted_at", "desc")->paginate(config("blogetc.per_page", 10)); - - //load categories in 3 levels - $rootList = BlogEtcCategory::where('parent_id' ,'=' , null)->get(); - for($i = 0 ; sizeof($rootList) > $i ; $i++){ - $rootList[$i]->loadSiblings(); - for ($j = 0 ; sizeof($rootList[$i]->siblings) > $j; $j++){ - $rootList[$i]->siblings[$j]->loadSiblings(); - } - } - - return view("blogetc::index", [ - 'category_chain' => $categoryChain, - 'categories' => $rootList, - 'posts' => $posts, - 'title' => $title, - ]); - } - - /** - * Show the search results for $_GET['s'] - * - * @param Request $request - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - * @throws \Exception - */ - public function search(Request $request) - { - if (!config("blogetc.search.search_enabled")) { - throw new \Exception("Search is disabled"); - } - $query = $request->get("s"); - $search = new Search(); - $search_results = $search->run($query); - - \View::share("title", "Search results for " . e($query)); - - $categories = BlogEtcCategory::all(); - - return view("blogetc::search", [ - 'categories' => $categories, - 'query' => $query, - 'search_results' => $search_results] - ); - - } - - /** - * View all posts in $category_slug category - * - * @param Request $request - * @param $category_slug - * @return mixed - */ - public function view_category($hierarchy) - { - $categories = explode('/', $hierarchy); - return $this->index(end($categories)); - } - - /** - * View a single post and (if enabled) it's comments - * - * @param Request $request - * @param $blogPostSlug - * @return mixed - */ - public function viewSinglePost(Request $request, $blogPostSlug) - { - // the published_at + is_published are handled by BlogEtcPublishedScope, and don't take effect if the logged in user can manage log posts - $blog_post = BlogEtcPost::where("slug", $blogPostSlug) - ->firstOrFail(); - - if ($captcha = $this->getCaptchaObject()) { - $captcha->runCaptchaBeforeShowingPosts($request, $blog_post); - } - - return view("blogetc::single_post", [ - 'post' => $blog_post, - // the default scope only selects approved comments, ordered by id - 'comments' => $blog_post->comments() - ->with("user") - ->get(), - 'captcha' => $captcha, - ]); - } - -} diff --git a/src/Controllers/BlogEtcRssFeedController.php b/src/Controllers/BlogEtcRssFeedController.php deleted file mode 100755 index 2b0ada9..0000000 --- a/src/Controllers/BlogEtcRssFeedController.php +++ /dev/null @@ -1,88 +0,0 @@ -title = config("app.name") . ' Blog'; - $feed->description = config("blogetc.rssfeed.description", "Our blog RSS feed"); - $feed->link = route('blogetc.index'); - $feed->setDateFormat('carbon'); - $feed->pubdate = isset($posts[0]) ? $posts[0]->posted_at : Carbon::now()->subYear(10); - $feed->lang = config("blogetc.rssfeed.language", "en"); - $feed->setShortening(config("blogetc.rssfeed.should_shorten_text", true)); // true or false - $feed->setTextLimit(config("blogetc.rssfeed.text_limit", 100)); - } - - - /** - * @param $feed - */ - protected function makeFreshFeed(Feed $feed) - { - $posts = BlogEtcPost::orderBy("posted_at", "desc") - ->limit(config("blogetc.rssfeed.posts_to_show_in_rss_feed", 10)) - ->with("author") - ->get(); - - $this->setupFeed($feed, $posts); - - /** @var BlogEtcPost $post */ - foreach ($posts as $post) { - $feed->add($post->title, - $post->author_string(), - $post->url(), - $post->posted_at, - $post->short_description, - $post->generate_introduction() - ); - } - } - - /** - * RSS Feed - * This is a long (but quite simple) method to show an RSS feed - * It makes use of Laravelium\Feed\Feed. - * - * @param FeedRequest $request - * @param Feed $feed - * @return mixed - */ - public function feed(FeedRequest $request, Feed $feed) - { - - // if a logged in user views the RSS feed it will get cached, and if they are an admin user then it'll show all posts (even if it is not set as published) - $user_or_guest = \Auth::check() ? \Auth::user()->id : 'guest'; - - $feed->setCache( - config("blogetc.rssfeed.cache_in_minutes", 60), - "blogetc-" . $request->getFeedType() . $user_or_guest - ); - - if (!$feed->isCached()) { - $this->makeFreshFeed($feed); - } - - return $feed->render($request->getFeedType()); - } - - -} diff --git a/src/Events/BlogPostAdded.php b/src/Events/BlogPostAdded.php index d0bfb21..4aef3b5 100644 --- a/src/Events/BlogPostAdded.php +++ b/src/Events/BlogPostAdded.php @@ -1,30 +1,30 @@ blogEtcPost=$blogEtcPost; + $this->binshopsBlogPost=$binshopsBlogPost; } } diff --git a/src/Events/BlogPostEdited.php b/src/Events/BlogPostEdited.php index 3bade22..94d4b13 100644 --- a/src/Events/BlogPostEdited.php +++ b/src/Events/BlogPostEdited.php @@ -1,30 +1,30 @@ blogEtcPost=$blogEtcPost; + $this->binshopsBlogPost=$binshopsBlogPost; } } diff --git a/src/Events/BlogPostWillBeDeleted.php b/src/Events/BlogPostWillBeDeleted.php index 3e1f332..07c473e 100644 --- a/src/Events/BlogPostWillBeDeleted.php +++ b/src/Events/BlogPostWillBeDeleted.php @@ -1,30 +1,30 @@ blogEtcPost=$blogEtcPost; + $this->binshopsBlogPost=$binshopsBlogPost; } } diff --git a/src/Events/CategoryAdded.php b/src/Events/CategoryAdded.php index 825339e..a090f31 100644 --- a/src/Events/CategoryAdded.php +++ b/src/Events/CategoryAdded.php @@ -1,30 +1,33 @@ blogEtcCategory=$blogEtcCategory; + $this->binshopsCategory=$binshopsCategory; + $this->binshopsCategoryTranslation = $binshopsCategoryTranslation; } } diff --git a/src/Events/CategoryEdited.php b/src/Events/CategoryEdited.php index 9fe3ef6..f8cbf19 100644 --- a/src/Events/CategoryEdited.php +++ b/src/Events/CategoryEdited.php @@ -1,30 +1,30 @@ blogEtcCategory=$blogEtcCategory; + $this->binshopsBlogCategory=$binshopsBlogCategory; } } diff --git a/src/Events/CategoryWillBeDeleted.php b/src/Events/CategoryWillBeDeleted.php index 980d233..f831fa7 100644 --- a/src/Events/CategoryWillBeDeleted.php +++ b/src/Events/CategoryWillBeDeleted.php @@ -1,30 +1,30 @@ blogEtcCategory=$blogEtcCategory; + $this->binshopsBlogCategory=$binshopsBlogCategory; } } diff --git a/src/Events/CommentAdded.php b/src/Events/CommentAdded.php index dcb383c..e0332f3 100644 --- a/src/Events/CommentAdded.php +++ b/src/Events/CommentAdded.php @@ -1,34 +1,34 @@ blogEtcPost=$blogEtcPost; + $this->binshopsBlogPost=$binshopsBlogPost; $this->newComment=$newComment; } diff --git a/src/Events/CommentApproved.php b/src/Events/CommentApproved.php index 43c9351..8c4555e 100644 --- a/src/Events/CommentApproved.php +++ b/src/Events/CommentApproved.php @@ -1,28 +1,28 @@ comment=$comment; // you can get the blog post via $comment->post diff --git a/src/Events/CommentWillBeDeleted.php b/src/Events/CommentWillBeDeleted.php index 7947eb5..25ba513 100644 --- a/src/Events/CommentWillBeDeleted.php +++ b/src/Events/CommentWillBeDeleted.php @@ -1,28 +1,28 @@ comment=$comment; } diff --git a/src/Events/UploadedImage.php b/src/Events/UploadedImage.php index 1feb61d..cb3ac03 100644 --- a/src/Events/UploadedImage.php +++ b/src/Events/UploadedImage.php @@ -1,22 +1,23 @@ image_filename = $image_filename; - $this->blogEtcPost=$blogEtcPost; + $this->binshopsBlogPost=$binshopsBlogPost; $this->image=$image; $this->source=$source; } diff --git a/src/FulltextSearch/src/Commands/Index.php b/src/FulltextSearch/src/Commands/Index.php new file mode 100644 index 0000000..def85d8 --- /dev/null +++ b/src/FulltextSearch/src/Commands/Index.php @@ -0,0 +1,29 @@ +indexAllByClass($this->argument('model_class')); + } +} diff --git a/src/FulltextSearch/src/Commands/IndexOne.php b/src/FulltextSearch/src/Commands/IndexOne.php new file mode 100644 index 0000000..564bbe6 --- /dev/null +++ b/src/FulltextSearch/src/Commands/IndexOne.php @@ -0,0 +1,29 @@ +indexOneByClass($this->argument('model_class'), $this->argument('id')); + } +} diff --git a/src/FulltextSearch/src/Commands/UnindexOne.php b/src/FulltextSearch/src/Commands/UnindexOne.php new file mode 100644 index 0000000..a8b69fe --- /dev/null +++ b/src/FulltextSearch/src/Commands/UnindexOne.php @@ -0,0 +1,29 @@ +unIndexOneByClass($this->argument('model_class'), $this->argument('id')); + } +} diff --git a/src/FulltextSearch/src/Indexable.php b/src/FulltextSearch/src/Indexable.php new file mode 100644 index 0000000..438a451 --- /dev/null +++ b/src/FulltextSearch/src/Indexable.php @@ -0,0 +1,95 @@ +getIndexDataFromColumns($this->indexContentColumns); + } + + public function getIndexTitle() + { + return $this->getIndexDataFromColumns($this->indexTitleColumns); + } + + public function indexedRecord() + { + return $this->morphOne(IndexedRecord::class, 'indexable'); + } + + public function indexRecord() + { + if (null === $this->indexedRecord) { + $this->indexedRecord = new IndexedRecord(); + $this->indexedRecord->indexable()->associate($this); + } + $this->indexedRecord->updateIndex(); + } + + public function unIndexRecord() + { + if (null !== $this->indexedRecord) { + $this->indexedRecord->delete(); + } + } + + protected function getIndexDataFromColumns($columns) + { + $indexData = []; + foreach ($columns as $column) { + if ($this->indexDataIsRelation($column)) { + $indexData[] = $this->getIndexValueFromRelation($column); + } else { + $indexData[] = trim($this->{$column}); + } + } + + return implode(' ', array_filter($indexData)); + } + + /** + * @param $column + * + * @return bool + */ + protected function indexDataIsRelation($column) + { + return (int) strpos($column, '.') > 0; + } + + /** + * @param $column + * + * @return string + */ + protected function getIndexValueFromRelation($column) + { + list($relation, $column) = explode('.', $column); + if (is_null($this->{$relation})) { + return ''; + } + + $relationship = $this->{$relation}(); + if ($relationship instanceof BelongsTo || $relationship instanceof HasOne) { + return $this->{$relation}->{$column}; + } + + return $this->{$relation}->pluck($column)->implode(', '); + } +} diff --git a/src/FulltextSearch/src/IndexedRecord.php b/src/FulltextSearch/src/IndexedRecord.php new file mode 100644 index 0000000..4c572ab --- /dev/null +++ b/src/FulltextSearch/src/IndexedRecord.php @@ -0,0 +1,29 @@ +connection = config('binshopsblog.search.db_connection'); + + parent::__construct($attributes); + } + + public function indexable() + { + return $this->morphTo(); + } + + public function updateIndex() + { + $this->setAttribute('indexed_title', $this->indexable->getIndexTitle()); + $this->setAttribute('indexed_content', $this->indexable->getIndexContent()); + $this->save(); + } +} diff --git a/src/FulltextSearch/src/Indexer.php b/src/FulltextSearch/src/Indexer.php new file mode 100644 index 0000000..394c493 --- /dev/null +++ b/src/FulltextSearch/src/Indexer.php @@ -0,0 +1,42 @@ +indexRecord(); + } + + public function unIndexOneByClass($class, $id) + { + $record = IndexedRecord::where('indexable_id', $id)->where('indexable_type', $class); + if ($record->exists) { + $record->delete(); + } + } + + public function indexOneByClass($class, $id) + { + $model = call_user_func([$class, 'find'], $id); + if (in_array(Indexable::class, class_uses($model), true)) { + $this->indexModel($model); + } + } + + public function indexAllByClass($class) + { + $model = new $class(); + $self = $this; + if (in_array(Indexable::class, class_uses($model), true)) { + $model->chunk(100, function ($chunk) use ($self) { + foreach ($chunk as $modelRecord) { + $self->indexModel($modelRecord); + } + }); + } + } +} diff --git a/src/FulltextSearch/src/ModelObserver.php b/src/FulltextSearch/src/ModelObserver.php new file mode 100644 index 0000000..8cc3d88 --- /dev/null +++ b/src/FulltextSearch/src/ModelObserver.php @@ -0,0 +1,95 @@ +indexRecord(); + } + + /** + * Handle the updated event for the model. + * + * @param \Illuminate\Database\Eloquent\Model $model + */ + public function updated($model) + { + $this->created($model); + } + + /** + * Handle the deleted event for the model. + * + * @param \Illuminate\Database\Eloquent\Model $model + */ + public function deleted($model) + { + if (static::syncingDisabledFor($model)) { + return; + } + + $model->unIndexRecord(); + } + + /** + * Handle the restored event for the model. + * + * @param \Illuminate\Database\Eloquent\Model $model + */ + public function restored($model) + { + $this->created($model); + } +} diff --git a/src/FulltextSearch/src/Search.php b/src/FulltextSearch/src/Search.php new file mode 100644 index 0000000..01a95d0 --- /dev/null +++ b/src/FulltextSearch/src/Search.php @@ -0,0 +1,72 @@ +searchQuery($search); + + return $query->get(); + } + + /** + * @param $search + * @param $class + * + * @return \Illuminate\Database\Eloquent\Collection|\BinshopsBlog\Laravel\Fulltext\IndexedRecord[] + */ + public function runForClass($search, $class) + { + $query = $this->searchQuery($search); + $query->where('indexable_type', $class); + + return $query->get(); + } + + /** + * @param string $search + * + * This search query is designed for post queries - todo: + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function searchQuery($search) + { + $termsBool = ''; + $termsMatch = ''; + + if ($search) { + $terms = TermBuilder::terms($search); + + $termsBool = '+'.$terms->implode(' +'); + $termsMatch = ''.$terms->implode(' '); + } + + $titleWeight = str_replace(',', '.', (float) config('binshopsblog.search.weight.title', 1.5)); + $contentWeight = str_replace(',', '.', (float) config('binshopsblog.search.weight.content', 1.0)); + + $query = IndexedRecord::query() + ->whereRaw('MATCH (indexed_title, indexed_content) AGAINST (? IN BOOLEAN MODE)', [$termsBool]) + ->orderByRaw( + '('.$titleWeight.' * (MATCH (indexed_title) AGAINST (?)) + + '.$contentWeight.' * (MATCH (indexed_title, indexed_content) AGAINST (?)) + ) DESC', + [$termsMatch, $termsMatch]) + ->limit(config('binshopsblog.search.limit-results')); + + $query->with(['indexable' => function ($query) { + $query->with(['post' => function($query){ + $query->where('is_published', '=', true); + }]); + }]); + + return $query; + } +} diff --git a/src/FulltextSearch/src/SearchInterface.php b/src/FulltextSearch/src/SearchInterface.php new file mode 100644 index 0000000..22e0ae2 --- /dev/null +++ b/src/FulltextSearch/src/SearchInterface.php @@ -0,0 +1,12 @@ + <, ( ), ~, *, ", @distance) from the search query + // else we will break the MySQL query. + $search = trim(preg_replace('/[+\-><\(\)~*\"@]+/', ' ', $search)); + + $terms = collect(preg_split('/[\s,]+/', $search)); + + if ($wildcards === true) { + $terms->transform(function ($term) { + return $term.'*'; + }); + } + + return $terms; + } +} diff --git a/src/Helpers.php b/src/Helpers.php index 3fd7c47..6ff1435 100755 --- a/src/Helpers.php +++ b/src/Helpers.php @@ -1,18 +1,18 @@ - * to auto insert the links to rss feed - * @return string - */ - public static function rss_html_tag() - { - - - return ' - - '; - - - } - /** * This method is depreciated. Just use the config() directly. * @return array * @deprecated */ public static function image_sizes(){ - return config("blogetc.image_sizes"); + return config("binshopsblog.image_sizes"); } } diff --git a/src/Interfaces/BaseRequestInterface.php b/src/Interfaces/BaseRequestInterface.php index 6ddd97d..c45580a 100755 --- a/src/Interfaces/BaseRequestInterface.php +++ b/src/Interfaces/BaseRequestInterface.php @@ -1,4 +1,4 @@ -route('locale'); + $routeWithoutLocale = false; + + if (!$request->route('locale')){ + $routeWithoutLocale = true; + $locale = BinshopsConfiguration::get('DEFAULT_LANGUAGE_LOCALE'); + } + + $lang = BinshopsLanguage::where('locale', $locale) + ->where('active', true) + ->first(); + + if (!$lang){ + return abort(404); + } + + $request->attributes->add([ + 'lang_id' => $lang->id, + 'locale' => $lang->locale, + 'routeWithoutLocale' => $routeWithoutLocale + ]); + + return $next($request); + } +} diff --git a/src/Middleware/LoadLanguage.php b/src/Middleware/LoadLanguage.php new file mode 100644 index 0000000..08c7479 --- /dev/null +++ b/src/Middleware/LoadLanguage.php @@ -0,0 +1,25 @@ +first(); + + $request->attributes->add([ + 'locale' => $lang->locale, + 'language_id' => $lang->id + ]); + + return $next($request); + } +} diff --git a/src/Middleware/PackageSetup.php b/src/Middleware/PackageSetup.php new file mode 100644 index 0000000..fe71282 --- /dev/null +++ b/src/Middleware/PackageSetup.php @@ -0,0 +1,20 @@ +canManageBlogEtcPosts() == false + * Show 401 error if \Auth::user()->canManageBinshopsBlogPosts() == false * @param $request * @param Closure $next * @return mixed @@ -21,8 +21,9 @@ public function handle($request, Closure $next) { if (!\Auth::check()) { abort(401,"User not authorised to manage blog posts: You are not logged in"); + return redirect('/login'); } - if (!\Auth::user()->canManageBlogEtcPosts()) { + if (!\Auth::user()->canManageBinshopsBlogPosts()) { abort(401,"User not authorised to manage blog posts: Your account is not authorised to edit blog posts"); } return $next($request); diff --git a/src/Models/BinshopsCategory.php b/src/Models/BinshopsCategory.php new file mode 100755 index 0000000..e7d400a --- /dev/null +++ b/src/Models/BinshopsCategory.php @@ -0,0 +1,79 @@ +categoryTranslations()->delete(); + }); + } + + /** + * The associated category translations + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function categoryTranslations() + { + return $this->hasMany(BinshopsCategoryTranslation::class,"category_id"); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + */ + public function posts() + { + return $this->belongsToMany(BinshopsPost::class, 'binshops_post_categories','category_id', 'post_id'); + } + + public function loadSiblings(){ + $this->siblings = $this->children()->get(); + } + + public static function loadSiblingsWithList($node_list){ + for($i = 0 ; sizeof($node_list) > $i ; $i++){ + $node_list[$i]->loadSiblings(); + if (sizeof($node_list[$i]->siblings) > 0){ + self::loadSiblingsWithList($node_list[$i]->siblings); + } + } + } + +// public function parent() +// { +// return $this->belongsTo('BinshopsBlog\Models\BinshopsCategory', 'parent_id'); +// } +// +// public function children() +// { +// return $this->hasMany('BinshopsBlog\Models\BinshopsCategory', 'parent_id'); +// } +// +// // recursive, loads all descendants +// private function childrenRecursive() +// { +// return $this->children()->with('children')->get(); +// } +// +// public function loadChildren(){ +// $this->childrenCat = $this->childrenRecursive(); +// } + +// public function scopeApproved($query) +// { +// dd("A"); +// return $query->where("approved", true); +// } +} diff --git a/src/Models/BinshopsCategoryTranslation.php b/src/Models/BinshopsCategoryTranslation.php new file mode 100644 index 0000000..f4450d5 --- /dev/null +++ b/src/Models/BinshopsCategoryTranslation.php @@ -0,0 +1,58 @@ +belongsTo(BinshopsCategory::class, 'category_id'); + } + + /** + * The associated Language + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function language() + { + return $this->hasOne(BinshopsLanguage::class,"lang_id"); + } + + /** + * Returns the public facing URL of showing blog posts in this category + * @return string + */ + public function url($locale, $routeWithoutLocale = false) + { + $theChainString = ""; + $cat = $this->category()->get(); + $chain = $cat[0]->getAncestorsAndSelf(); + foreach ($chain as $category){ + $theChainString .= "/" . $category->categoryTranslations()->where('lang_id' , $this->lang_id)->first()->slug; + } + + return $routeWithoutLocale ? route("binshopsblog.view_category",["", $theChainString]) : route("binshopsblog.view_category",[$locale, $theChainString]); + } + + /** + * Returns the URL for an admin user to edit this category + * @return string + */ + public function edit_url() + { + return route("binshopsblog.admin.categories.edit_category", $this->category_id); + } +} diff --git a/src/Models/BlogEtcComment.php b/src/Models/BinshopsComment.php similarity index 70% rename from src/Models/BlogEtcComment.php rename to src/Models/BinshopsComment.php index 680bb1c..b621d0e 100755 --- a/src/Models/BlogEtcComment.php +++ b/src/Models/BinshopsComment.php @@ -1,12 +1,12 @@ 'boolean', @@ -28,7 +28,7 @@ protected static function boot() { parent::boot(); - /* If user is logged in and \Auth::user()->canManageBlogEtcPosts() == true, show any/all posts. + /* If user is logged in and \Auth::user()->canManageBinshopsBlogPosts() == true, show any/all posts. otherwise (which will be for most users) it should only show published posts that have a posted_at time <= Carbon::now(). This sets it up: */ static::addGlobalScope(new BlogCommentApprovedAndDefaultOrderScope()); @@ -37,12 +37,12 @@ protected static function boot() /** - * The associated BlogEtcPost + * The associated BinshopsPost * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function post() { - return $this->belongsTo(BlogEtcPost::class,"blog_etc_post_id"); + return $this->belongsTo(BinshopsPost::class,"post_id"); } /** @@ -51,7 +51,7 @@ public function post() */ public function user() { - return $this->belongsTo(config("blogetc.user_model"), 'user_id'); + return $this->belongsTo(config("binshopsblog.user_model"), 'user_id'); } /** @@ -62,7 +62,7 @@ public function user() public function author() { if ($this->user_id) { - $field = config("blogetc.comments.user_field_for_author_name","name"); + $field = config("binshopsblog.comments.user_field_for_author_name","name"); return optional($this->user)->$field; } diff --git a/src/Models/BinshopsConfiguration.php b/src/Models/BinshopsConfiguration.php new file mode 100644 index 0000000..59a583e --- /dev/null +++ b/src/Models/BinshopsConfiguration.php @@ -0,0 +1,37 @@ +first(); + if ($obj){ + return $obj->value; + } + else{ + return null; + } + } + + public static function set($key, $value){ + $config = new BinshopsConfiguration(); + $config->key = $key; + $config->value = $value; + $config->save(); + } +} diff --git a/src/Models/BinshopsLanguage.php b/src/Models/BinshopsLanguage.php new file mode 100644 index 0000000..1ba7a87 --- /dev/null +++ b/src/Models/BinshopsLanguage.php @@ -0,0 +1,37 @@ +belongsTo(BinshopsPost::class, 'post_id'); + } + + /** + * The associated author (if category_id) is set + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function category() + { + return $this->belongsTo(BinshopsCategory::class, 'category_id'); + } + +} \ No newline at end of file diff --git a/src/Models/BinshopsPost.php b/src/Models/BinshopsPost.php new file mode 100755 index 0000000..ebebb77 --- /dev/null +++ b/src/Models/BinshopsPost.php @@ -0,0 +1,107 @@ + 'boolean', + 'posted_at' => 'date' + ]; + + /** + * @var array + */ + public $dates = [ + 'posted_at' + ]; + + /** + * @var array + */ + public $fillable = [ + 'is_published', + 'posted_at', + ]; + + /** + * The associated post translations + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function postTranslations() + { + return $this->hasMany(BinshopsPostTranslation::class,"post_id"); + } + + /** + * The "booting" method of the model. + * + * @return void + */ + protected static function boot() + { + parent::boot(); + + /* If user is logged in and \Auth::user()->canManageBinshopsBlogPosts() == true, show any/all posts. + otherwise (which will be for most users) it should only show published posts that have a posted_at + time <= Carbon::now(). This sets it up: */ + static::addGlobalScope(new BinshopsBlogPublishedScope()); + + static::deleting(function($post) { // before delete() method call this + $post->postTranslations()->delete(); + }); + } + + /** + * The associated author (if user_id) is set + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function author() + { + return $this->belongsTo(config("binshopsblog.user_model"), 'user_id'); + } + + /** + * Return author string (either from the User (via ->user_id), or the submitted author_name value + * @return string + */ + public function author_string() + { + if ($this->author) { + return optional($this->author)->name; + } else { + return 'Unknown Author'; + } + } + + /** + * The associated categories for this blog post + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + */ + public function categories() + { + return $this->belongsToMany(BinshopsCategory::class, 'binshops_post_categories','post_id','category_id'); + } + + /** + * Comments for this post + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function comments() + { + return $this->hasMany(BinshopsComment::class, 'post_id'); + } + +} diff --git a/src/Models/BlogEtcPost.php b/src/Models/BinshopsPostTranslation.php old mode 100755 new mode 100644 similarity index 60% rename from src/Models/BlogEtcPost.php rename to src/Models/BinshopsPostTranslation.php index 12d97f5..856de2f --- a/src/Models/BlogEtcPost.php +++ b/src/Models/BinshopsPostTranslation.php @@ -1,45 +1,21 @@ 'boolean', - ]; - - /** - * @var array - */ - public $dates = [ - 'posted_at' - ]; - - /** - * @var array - */ public $fillable = [ - 'title', 'subtitle', 'short_description', @@ -48,17 +24,31 @@ class BlogEtcPost extends Model implements SearchResultInterface 'meta_desc', 'slug', 'use_view_file', - - 'is_published', - 'posted_at', ]; + /** + * Get the user that owns the phone. + */ + public function post() + { + return $this->belongsTo(BinshopsPost::class, 'post_id'); + } + + /** + * The associated Language + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function language() + { + return $this->hasOne(BinshopsLanguage::class,"lang_id"); + } + /** * Return the sluggable configuration array for this model. * * @return array */ - public function sluggable() + public function sluggable(): array { return [ 'slug' => [ @@ -77,82 +67,6 @@ public function search_result_page_title() return $this->title; } - /** - * The "booting" method of the model. - * - * @return void - */ - protected static function boot() - { - parent::boot(); - - /* If user is logged in and \Auth::user()->canManageBlogEtcPosts() == true, show any/all posts. - otherwise (which will be for most users) it should only show published posts that have a posted_at - time <= Carbon::now(). This sets it up: */ - static::addGlobalScope(new BlogEtcPublishedScope()); - } - - /** - * The associated author (if user_id) is set - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function author() - { - return $this->belongsTo(config("blogetc.user_model"), 'user_id'); - } - - /** - * Return author string (either from the User (via ->user_id), or the submitted author_name value - * @return string - */ - public function author_string() - { - if ($this->author) { - return optional($this->author)->name; - } else { - return 'Unknown Author'; - } - } - - /** - * The associated categories for this blog post - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany - */ - public function categories() - { - return $this->belongsToMany(BlogEtcCategory::class, 'blog_etc_post_categories'); - } - - /** - * Comments for this post - * - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function comments() - { - return $this->hasMany(BlogEtcComment::class); - } - - /** - * Returns the public facing URL to view this blog post - * - * @return string - */ - public function url() - { - return route("blogetc.single", $this->slug); - } - - /** - * Return the URL for editing the post (used for admin users) - * @return string - */ - public function edit_url() - { - return route("blogetc.admin.edit_post", $this->id); - } - /** * If $this->user_view_file is not empty, then it'll return the dot syntax location of the blade file it should look for * @return string @@ -190,7 +104,7 @@ public function image_url($size = 'medium') { $this->check_valid_image_size($size); $filename = $this->{"image_" . $size}; - return asset(config("blogetc.blog_upload_dir", "blog_images") . "/" . $filename); + return asset(config("binshopsblog.blog_upload_dir", "blog_images") . "/" . $filename); } /** @@ -211,7 +125,7 @@ public function image_tag($size = 'medium', $auto_link = true, $img_class = null $url = e($this->image_url($size)); $alt = e($this->title); $img = "You are logged in as a blog admin user.
-
Go To Blog Admin Panel
@@ -27,8 +27,8 @@ class='btn border btn-outline-primary btn-sm '>
{{$blogetc_category->category_description}}
+ @if($binshopsblog_category->category_description) +{{$binshopsblog_category->category_description}}
@endif @endif @@ -48,7 +48,7 @@ class='btn border btn-outline-primary btn-sm '>
Add a comment
-