diff --git a/app/Classes/Repositories/ArticleRepository.php b/app/Classes/Repositories/ArticleRepository.php
index fe0a2a71..66efb241 100644
--- a/app/Classes/Repositories/ArticleRepository.php
+++ b/app/Classes/Repositories/ArticleRepository.php
@@ -30,7 +30,7 @@ class ArticleRepository extends BaseRepository
*/
public function __construct(Article $model)
{
- $this->model = $model;
+ $this->model = $model->withoutGlobalScopes();
}
/**
diff --git a/app/Classes/Repositories/BaseRepository.php b/app/Classes/Repositories/BaseRepository.php
index e9003df1..6e5e6602 100644
--- a/app/Classes/Repositories/BaseRepository.php
+++ b/app/Classes/Repositories/BaseRepository.php
@@ -37,7 +37,7 @@ public function all()
*/
public function allDescendingOrder()
{
- return $this->model->orderBy('created_at', 'desc')->get();
+ return $this->model->withoutGlobalScopes()->orderBy('created_at', 'desc')->get();
}
/**
diff --git a/app/Model/Article.php b/app/Model/Article.php
index 7a09bc1a..74669044 100644
--- a/app/Model/Article.php
+++ b/app/Model/Article.php
@@ -111,10 +111,32 @@ class Article extends Model implements Linkable
protected $dates = ['created_at', 'updated_at', 'deleted_at', 'publish_date', 'unpublish_date'];
/**
- * Undocumented function.
+ * The "booting" method of the model.
*
* @return void
*/
+ protected static function boot()
+ {
+ parent::boot();
+
+ static::addGlobalScope('published', function (Builder $builder) {
+ return $builder->where([
+ ['publish_date', '<=', Carbon::now()],
+ ['unpublish_date', '>', Carbon::now()],
+ ['status', '=', true],
+ ])->orWhere([
+ ['publish_date', '<=', Carbon::now()],
+ ['unpublish_date', '=', null],
+ ['status', '=', true],
+ ]);
+ });
+ }
+
+ /**
+ * Undocumented function.
+ *
+ * @return string
+ */
public function getRouteKeyName()
{
return 'slug';
@@ -160,17 +182,6 @@ public function setTitleAttribute($value)
$this->attributes['slug'] = str_slug($value);
}
- /**
- * Scope the collection to only published.
- *
- * @param Builder $query
- * @return Builder
- */
- public function scopePublished(Builder $query)
- {
- return $query->where('status', true);
- }
-
/**
* The url that is used to view this model.
* The category will be prefixed if one exists.
diff --git a/app/Model/Page.php b/app/Model/Page.php
index f6b28053..fdcf4e77 100644
--- a/app/Model/Page.php
+++ b/app/Model/Page.php
@@ -43,6 +43,8 @@
* @property Carbon $created_at
* @property Carbon $updated_at
*
+ * @method static Builder sitemap() Query only pages that are for sitemap.
+ *
* @return Page|Collection|Builder
*/
class Page extends Model implements Linkable
@@ -106,7 +108,7 @@ public function getDescriptionForEvent(string $eventName): string
/**
* Undocumented function.
*
- * @return void
+ * @return string
*/
public function getRouteKeyName()
{
@@ -117,22 +119,22 @@ public function getRouteKeyName()
* Return the path to the page, these can sometimes have a prefix
* attached.
*
- * @return void
+ * @return string
*/
public function path()
{
if ($this->prefix) {
- return "{$this->prefix}/{$this->slug}";
+ return url("{$this->prefix}/{$this->slug}");
}
- return "{$this->slug}";
+ return url("{$this->slug}");
}
/**
* Undocumented function.
*
* @param string $string
- * @return void
+ * @return Page
*/
public static function whereIdentifier(string $string)
{
@@ -199,6 +201,17 @@ public function linked()
return $this->morphMany(Link::class, 'to');
}
+ /**
+ * Scope a query to only include sitemap pages.
+ *
+ * @param \Illuminate\Database\Eloquent\Builder $query
+ * @return \Illuminate\Database\Eloquent\Builder
+ */
+ public function scopeSitemap($query)
+ {
+ return $query->where('option', '&', PageOptions::OPTION_SITEMAP);
+ }
+
/**
* The url that is used to view this model.
*
diff --git a/app/Modules/Articles/BackendController.php b/app/Modules/Articles/BackendController.php
index b894085d..4d39867f 100644
--- a/app/Modules/Articles/BackendController.php
+++ b/app/Modules/Articles/BackendController.php
@@ -168,6 +168,8 @@ public function categories_store(Request $request)
* @param int $id
* @param ArticleCategoryRepository $categoryRepository
* @return \Illuminate\Http\RedirectResponse
+ *
+ * @throws \Exception
*/
public function categories_destroy(int $id, ArticleCategoryRepository $categoryRepository)
{
diff --git a/app/Modules/Articles/FrontendController.php b/app/Modules/Articles/FrontendController.php
index 78df4cc4..f2cd8da2 100644
--- a/app/Modules/Articles/FrontendController.php
+++ b/app/Modules/Articles/FrontendController.php
@@ -8,17 +8,14 @@
use App\Model\Categories;
use App\Jobs\IncrementViews;
use Illuminate\Http\Request;
-use App\Classes\SitemapGenerator;
-use App\Classes\Interfaces\Sitemap;
use Illuminate\Support\Facades\View;
use App\Classes\Repositories\PageRepository;
use App\Classes\Library\PageLoader\Frontpage;
-use App\Classes\Repositories\ArticleRepository;
/**
* Class UserController.
*/
-class FrontendController implements Sitemap
+class FrontendController
{
/**
* @var Page
@@ -43,7 +40,7 @@ public function __construct()
*/
public function allArticles(Article $article)
{
- View::share('articles', $article->published()->latest('created_at')->paginate(7));
+ View::share('articles', $article->latest('created_at')->paginate(7));
return Frontpage::build($this->currentPage, 200, 'articles');
}
@@ -54,7 +51,7 @@ public function allArticles(Article $article)
* @param Categories $category The articles category.
* @param Article $article The article model to interact with.
*
- * @return void
+ * @return Frontpage
*/
public function viewArticle($category, Article $article)
{
@@ -70,13 +67,12 @@ public function viewArticle($category, Article $article)
/**
* View all articles in the category.
*
- * @param ArticleRepository $repository
* @param string $string
- * @return void
+ * @return Frontpage
*/
public function categoryArticles(Categories $category)
{
- View::share('articles', $category->articles()->where('status', true)->paginate(7));
+ View::share('articles', $category->articles()->paginate(7));
$this->currentPage->heading = 'Browse Categories';
@@ -84,12 +80,11 @@ public function categoryArticles(Categories $category)
}
/**
- * Search all articles and return results.
+ * Search Articles.
*
- * @param ArticleRepository $repository
* @param Request $request
*
- * @return void
+ * @return Frontpage
*/
public function searchArticles(Request $request)
{
@@ -103,11 +98,10 @@ public function searchArticles(Request $request)
/**
* Get all the articles created by an account.
*
- * @param ArticleRepository $repository
* @param int $id
* @return Frontpage
*/
- public function allCreatorsArticles(ArticleRepository $repository, Account $account)
+ public function allCreatorsArticles(Account $account)
{
$this->currentPage->heading = 'Browse Creators';
@@ -115,24 +109,4 @@ public function allCreatorsArticles(ArticleRepository $repository, Account $acco
return Frontpage::build($this->currentPage, 200, 'articles');
}
-
- /**
- * The sitemap function allows plugins to quickly and effectively
- * show their content for search engines in a modular way.
- *
- * @param SitemapGenerator $sitemap
- * @return SitemapGenerator
- */
- public function sitemap(SitemapGenerator $sitemap)
- {
- /** @var ArticleRepository $repository */
- $repository = app(ArticleRepository::class);
-
- /** @var Article $article */
- foreach ($repository->whereSitemappable() as $article) {
- $sitemap->store(url($article->route()), $article->updated_at, 'weekly', '1.0');
- }
-
- return $sitemap;
- }
}
diff --git a/app/Modules/Configs/Controller.php b/app/Modules/Configs/Controller.php
index c8645f60..92250019 100644
--- a/app/Modules/Configs/Controller.php
+++ b/app/Modules/Configs/Controller.php
@@ -1,12 +1,6 @@
'."\n" ?>
+
+
+ @foreach ($urlset as $set)
+
+ @if (! empty($set['loc']))
+ {{ $set['loc'] }}
+ @endif
+
+ @if (! empty($set['lastmod']))
+ {{ $set['lastmod'] }}
+ @endif
+
+ @if (! empty($set['changefreq']))
+ {{ $set['changefreq'] }}
+ @endif
+
+ @if (! empty($set['priority']))
+ {{ $set['priority'] }}
+ @endif
+
+ @endforeach
+
+
\ No newline at end of file
diff --git a/app/Modules/Sitemap/Routes/frontend.php b/app/Modules/Sitemap/Routes/frontend.php
index 962988fd..e659f1ee 100644
--- a/app/Modules/Sitemap/Routes/frontend.php
+++ b/app/Modules/Sitemap/Routes/frontend.php
@@ -15,7 +15,7 @@
// Get Requests.
// ==================================================================================
- //Route::get('/sitemap.xml')->uses('Controller@all')->name('sitemap');
+ Route::get('/sitemap.xml')->uses('SitemapController@index')->name('sitemap');
// Post Requests.
// ==================================================================================
diff --git a/app/Modules/Sitemap/SitemapConstants.php b/app/Modules/Sitemap/SitemapConstants.php
new file mode 100644
index 00000000..b203d05e
--- /dev/null
+++ b/app/Modules/Sitemap/SitemapConstants.php
@@ -0,0 +1,37 @@
+sitemap = $sitemap;
+ }
+
+ /**
+ * Return a response encoded with xml for sitemap.xml viewing.
+ *
+ * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
+ */
+ public function index()
+ {
+ /** @var Page $page */
+ foreach (Page::sitemap()->get() as $page) {
+ $this->sitemap->add($page->path())->modified($page->updated_at)->withFrequency(Sitemap::FREQUENCY_WEEKLY)->andPriority(Sitemap::PRIORITY_NORMAL);
+ }
+
+ /** @var Article $article */
+ foreach (Article::all() as $article) {
+ $this->sitemap->add($article->path())->modified($article->updated_at)->withFrequency(Sitemap::FREQUENCY_WEEKLY)->andPriority(Sitemap::PRIORITY_NORMAL);
+ }
+
+ return response($this->make('sitemap')->with('urlset', $this->sitemap->collection()), 200, ['Content-type' => 'text/xml']);
+ }
+}
diff --git a/app/Modules/Sitemap/SitemapGenerator.php b/app/Modules/Sitemap/SitemapGenerator.php
new file mode 100644
index 00000000..5d032ae3
--- /dev/null
+++ b/app/Modules/Sitemap/SitemapGenerator.php
@@ -0,0 +1,91 @@
+items = $collection;
+ }
+
+ /**
+ * Add a sitemap item to the collection.
+ * @param string $location
+ * @return SitemapGenerator
+ */
+ public function add(string $location)
+ {
+ $this->items->push(['loc' => $location]);
+
+ return $this;
+ }
+
+ /**
+ * The date of last modification of the file.
+ *
+ * @param Carbon $datetime
+ *
+ * @return SitemapGenerator
+ */
+ public function modified(Carbon $datetime)
+ {
+ $this->items->push(array_merge($this->items->pop(), ['lastmod' => $datetime->format('Y-m-d')]));
+
+ return $this;
+ }
+
+ /**
+ * The frequency of the file to be checked for changes.
+ *
+ * @param string $frequency
+ *
+ * @return SitemapGenerator
+ */
+ public function withFrequency(string $frequency)
+ {
+ $this->items->push(array_merge($this->items->pop(), ['changefreq' => $frequency]));
+
+ return $this;
+ }
+
+ /**
+ * Set the priority of the file to be read or indexed.
+ *
+ * @param int $priority
+ *
+ * @return SitemapGenerator
+ */
+ public function andPriority(float $priority)
+ {
+ $this->items->push(array_merge($this->items->pop(), ['priority' => $priority]));
+
+ return $this;
+ }
+
+ /**
+ * Return all the current sitemap mappings.
+ *
+ * @return Collection
+ */
+ public function collection()
+ {
+ return $this->items;
+ }
+}
diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php
index 9a0847d9..bda114fb 100644
--- a/app/Providers/RouteServiceProvider.php
+++ b/app/Providers/RouteServiceProvider.php
@@ -2,6 +2,8 @@
namespace App\Providers;
+use PDOException;
+use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use App\Modules\ModuleServiceProvider;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
@@ -27,10 +29,14 @@ class RouteServiceProvider extends ServiceProvider
*/
public function map()
{
- ModuleServiceProvider::map();
+ try {
+ ModuleServiceProvider::map();
- Route::middleware('web')->group(base_path('routes/web.php'));
+ Route::middleware('web')->group(base_path('routes/web.php'));
- Route::middleware('web')->group(base_path('routes/vendor.php'));
+ Route::middleware('web')->group(base_path('routes/vendor.php'));
+ } catch (PDOException $e) {
+ Log::warning('Unable to process routes: '.$e->getMessage().', '.$e->getFile());
+ }
}
}
diff --git a/database/migrations/2016_12_21_154441_edit_facebook_plugin_data.php b/database/migrations/2016_12_21_154441_edit_facebook_plugin_data.php
deleted file mode 100644
index 7994751f..00000000
--- a/database/migrations/2016_12_21_154441_edit_facebook_plugin_data.php
+++ /dev/null
@@ -1,26 +0,0 @@
-
- Articles Loaded: {{ resolve('articles')->count() }}
+ Articles Loaded: {{ $articles->count() }}
- @foreach (resolve('articles') as $article)
+ @foreach ($articles as $article)
{{ $article->title }}
diff --git a/tests/Article/ArticlePublishingTest.php b/tests/Article/ArticlePublishingTest.php
new file mode 100644
index 00000000..e91ac1dc
--- /dev/null
+++ b/tests/Article/ArticlePublishingTest.php
@@ -0,0 +1,62 @@
+create(['publish_date' => Carbon::tomorrow()]);
+
+ $this->assertCount(0, Article::all());
+ }
+
+ /**
+ * @test
+ */
+ public function it_should_show_articles_published_today()
+ {
+ factory('App\Model\Article')->create(['publish_date' => Carbon::today()]);
+
+ $this->assertCount(1, Article::all());
+ }
+
+ /**
+ * @test
+ */
+ public function it_should_not_show_articles_with_unpublish_date_less_than_today()
+ {
+ factory('App\Model\Article')->create(['publish_date' => Carbon::yesterday(), 'unpublish_date' => Carbon::today()]);
+
+ $this->assertCount(0, Article::all());
+ }
+
+ /**
+ * @test
+ */
+ public function it_should_show_articles_with_unpublish_date_tommorow()
+ {
+ factory('App\Model\Article')->create(['publish_date' => Carbon::now(), 'unpublish_date' => Carbon::tomorrow()]);
+
+ $this->assertCount(1, Article::all());
+ }
+}
diff --git a/tests/Article/ArticleViewingTest.php b/tests/Article/ArticleResponseTest.php
similarity index 65%
rename from tests/Article/ArticleViewingTest.php
rename to tests/Article/ArticleResponseTest.php
index 13a08cfe..c5c25e8f 100644
--- a/tests/Article/ArticleViewingTest.php
+++ b/tests/Article/ArticleResponseTest.php
@@ -2,13 +2,14 @@
namespace Tests\Article;
+use Carbon\Carbon;
use Tests\TestCase;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
-class ArticleViewingTest extends TestCase
+class ArticleResponseTest extends TestCase
{
/*
* Provide fake content
@@ -53,7 +54,7 @@ public function an_articles_views_are_incremented_after_being_viewed()
/**
* @test
*/
- public function a_single_article_can_be_viewed_on_the_frontpage()
+ public function it_should_show_an_article_that_is_published()
{
$article = factory('App\Model\Article')->create(['views' => 0]);
@@ -62,30 +63,46 @@ public function a_single_article_can_be_viewed_on_the_frontpage()
$response->assertSee($article->title)->assertViewIs('articles')->assertOk();
}
+ /**
+ * @test
+ */
+ public function it_should_not_show_an_article_that_is_not_published()
+ {
+ $this->withExceptionHandling();
+
+ $article = factory('App\Model\Article')->create(['views' => 0, 'publish_date' => Carbon::yesterday(), 'unpublish_date' => Carbon::now()]);
+
+ $response = $this->get($article->path());
+
+ $response->assertStatus(404);
+ }
+
/**
* @test
* t */
- public function a_collection_of_articles_can_be_viewed_on_the_frontpage()
+ public function a_collection_of_articles_can_be_viewed_on_the_frontpage_except_unpublished()
{
$collection = factory('App\Model\Article', 5)->create();
+ $unpublished = factory('App\Model\Article')->create(['unpublish_date' => Carbon::now()]);
$response = $this->get('articles');
- $response->assertSee($collection->random()->title)->assertViewIs('articles')->assertOk();
+ $response->assertSee($collection->random()->title)->assertDontSee($unpublished->title)->assertViewIs('articles')->assertOk();
}
/**
* @test
*/
- public function a_category_can_have_a_collection_of_articles_on_the_frontpage()
+ public function a_category_can_have_a_collection_of_articles_on_the_frontpage_except_unpublished()
{
$category = factory('App\Model\Categories')->create();
+ $unpublished = factory('App\Model\Article')->create(['unpublish_date' => Carbon::now()]);
$collection = factory('App\Model\Article', 5)->create(['category_id' => $category->id]);
$response = $this->get('articles/'.$category->slug);
- $response->assertSee($collection->random()->title)->assertViewIs('articles')->assertOk();
+ $response->assertSee($collection->random()->title)->assertDontSee($unpublished->title)->assertViewIs('articles')->assertOk();
}
/**
@@ -105,14 +122,27 @@ public function articles_can_be_searched_on_the_frontpage()
/**
* @test
*/
- public function view_all_articles_by_creator_on_the_frontpage()
+ public function it_should_not_show_unpublished_articles_on_search()
+ {
+ $unpublished = factory('App\Model\Article')->create(['unpublish_date' => Carbon::now()]);
+
+ $response = $this->get('/articles/search?query='.$unpublished->title);
+
+ $response->assertDontSee($unpublished->title)->assertViewIs('articles')->assertOk();
+ }
+
+ /**
+ * @test
+ */
+ public function view_all_articles_by_creator_on_the_frontpage_except_unpublished()
{
$account = factory('App\Model\Account')->create();
$articles = factory('App\Model\Article', 3)->create(['creator_id' => $account->id]);
+ $unpublished = factory('App\Model\Article')->create(['unpublish_date' => Carbon::now()]);
$response = $this->get('/articles/creator/'.$account->username);
- $response->assertSee($articles->random()->title)->assertViewIs('articles')->assertOk();
+ $response->assertSee($articles->random()->title)->assertDontSee($unpublished->title)->assertViewIs('articles')->assertOk();
}
}
diff --git a/tests/Common/BreadcrumbsTest.php b/tests/Common/BreadcrumbsTest.php
index 4cee8069..a7037fd6 100644
--- a/tests/Common/BreadcrumbsTest.php
+++ b/tests/Common/BreadcrumbsTest.php
@@ -88,7 +88,7 @@ public function testFromCurrentRoute()
$this->call('GET', '/breadcrumb/test');
- $this->assertCount(4, Breadcrumbs::fromCurrentRoute()->crumbs());
+ $this->assertCount(3, Breadcrumbs::fromCurrentRoute()->crumbs());
}
// @todo: Check the array for the correct return string.?
diff --git a/tests/Module/ModuleManagerTest.php b/tests/Module/ModuleManagerTest.php
index 6a9ba981..e18c77e9 100644
--- a/tests/Module/ModuleManagerTest.php
+++ b/tests/Module/ModuleManagerTest.php
@@ -8,6 +8,7 @@
use App\Modules\ModuleManager;
use App\Modules\ModuleRepository;
use Illuminate\Support\Facades\Config;
+use App\Modules\ModuleNotFoundException;
use App\Modules\Pages\Model\PageOptions;
use Illuminate\Foundation\Testing\RefreshDatabase;
diff --git a/tests/Products/ProductInstallationTest.php b/tests/Products/ProductInstallationTest.php
index 8548ac0d..477064e7 100644
--- a/tests/Products/ProductInstallationTest.php
+++ b/tests/Products/ProductInstallationTest.php
@@ -20,12 +20,14 @@ class ProductInstallationTest extends TestCase
*/
public function modules_can_be_toggled()
{
+ $this->signIn();
+
$mocked = Mockery::mock(ModuleManager::class)->shouldReceive('toggle')->andReturn(true)->getMock();
$this->app->instance(ModuleManager::class, $mocked);
$response = $this->get('/admin/products/test/toggle');
- $response->assertRedirect('/admin/products')->assertSee('test');
+ $response->assertRedirect('/admin/products');
}
}
diff --git a/tests/Sitemap/SitemapGeneratorTest.php b/tests/Sitemap/SitemapGeneratorTest.php
new file mode 100644
index 00000000..082706bc
--- /dev/null
+++ b/tests/Sitemap/SitemapGeneratorTest.php
@@ -0,0 +1,89 @@
+generator = new SitemapGenerator(new Collection);
+ }
+
+ /**
+ * @test
+ */
+ public function it_should_add_urls()
+ {
+ $this->generator->add($this->faker->url);
+
+ $this->assertCount(1, $this->generator->collection());
+ }
+
+ /**
+ * @test
+ */
+ public function it_should_add_multiple_urls()
+ {
+ $this->generator->add($this->faker->url);
+ $this->generator->add($this->faker->url);
+
+ $this->assertCount(2, $this->generator->collection());
+ }
+
+ /**
+ * @test
+ */
+ public function it_can_have_a_last_modified_date()
+ {
+ $this->generator->add($this->faker->url)->modified(Carbon::create(2018, 7, 7));
+
+ $this->assertTrue(array_has($this->generator->collection(), '0.loc'));
+ }
+
+ /**
+ * @test
+ */
+ public function it_can_have_a_change_frequency()
+ {
+ $this->generator->add($this->faker->url)->withFrequency(Sitemap::FREQUENCY_DAILY);
+
+ $this->assertTrue(array_has($this->generator->collection(), '0.changefreq'));
+ }
+
+ /**
+ * @test
+ */
+ public function it_can_have_a_priority()
+ {
+ $this->generator->add($this->faker->url)->andPriority(Sitemap::PRIORITY_HIGHEST);
+
+ $this->assertTrue(array_has($this->generator->collection(), '0.priority'));
+ }
+}
diff --git a/tests/Sitemap/SitemapResponseTest.php b/tests/Sitemap/SitemapResponseTest.php
new file mode 100644
index 00000000..4fe08fc9
--- /dev/null
+++ b/tests/Sitemap/SitemapResponseTest.php
@@ -0,0 +1,57 @@
+get('/sitemap.xml')->assertHeader('Content-type', 'text/xml; charset=UTF-8')->assertOk();
+ }
+
+ /**
+ * @test
+ */
+ public function it_shows_pages_on_sitemap()
+ {
+ $page = factory('App\Model\Page')->create(['option' => PageOptions::OPTION_SITEMAP]);
+
+ $response = $this->get('/sitemap.xml');
+
+ $response->assertSee(''.$page->path().'');
+ $response->assertSee(''.$page->updated_at->format('Y-m-d').'');
+
+ $this->assertCount(2, $response->getOriginalContent()->getData()['urlset']);
+ }
+
+ /**
+ * @test
+ */
+ public function it_shows_articles_on_sitemap_except_unpublished()
+ {
+ $collection = factory('App\Model\Article', 2)->create(['status' => true]);
+ $unpublished = factory('App\Model\Article')->create(['unpublish_date' => Carbon::now()]);
+
+ $response = $this->get('/sitemap.xml');
+
+ $this->assertCount(3, $response->getOriginalContent()->getData()['urlset']);
+
+ $response->assertSee($collection->random()->path())->assertDontSee($unpublished->path());
+ }
+}