Added testing to favourite system

- Also removed some old view service references.
- Updated TopFavourites query to be based on favourites table and join
  in the views instead of the other way around, so that favourites still
show even if they have no views.
This commit is contained in:
Dan Brown 2021-05-23 14:34:36 +01:00
parent c2069f37cc
commit ba8ba5c634
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
5 changed files with 72 additions and 23 deletions

View File

@ -588,7 +588,7 @@ class PermissionService
$q = $query->where(function ($query) use ($tableDetails, $action) { $q = $query->where(function ($query) use ($tableDetails, $action) {
$query->whereExists(function ($permissionQuery) use (&$tableDetails, $action) { $query->whereExists(function ($permissionQuery) use (&$tableDetails, $action) {
$permissionQuery->select('id')->from('joint_permissions') $permissionQuery->select(['role_id'])->from('joint_permissions')
->whereRaw('joint_permissions.entity_id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn']) ->whereRaw('joint_permissions.entity_id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
->whereRaw('joint_permissions.entity_type=' . $tableDetails['tableName'] . '.' . $tableDetails['entityTypeColumn']) ->whereRaw('joint_permissions.entity_type=' . $tableDetails['tableName'] . '.' . $tableDetails['entityTypeColumn'])
->where('action', '=', $action) ->where('action', '=', $action)

View File

@ -1,34 +1,33 @@
<?php namespace BookStack\Entities\Queries; <?php namespace BookStack\Entities\Queries;
use BookStack\Actions\View; use BookStack\Actions\Favourite;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Facades\DB;
class TopFavourites extends EntityQuery class TopFavourites extends EntityQuery
{ {
public function run(int $count, int $skip = 0) public function run(int $count, int $skip = 0)
{ {
$user = user(); $user = user();
if ($user === null || $user->isDefault()) { if (is_null($user) || $user->isDefault()) {
return collect(); return collect();
} }
$query = $this->permissionService() $query = $this->permissionService()
->filterRestrictedEntityRelations(View::query(), 'views', 'viewable_id', 'viewable_type', 'view') ->filterRestrictedEntityRelations(Favourite::query(), 'favourites', 'favouritable_id', 'favouritable_type', 'view')
->select('*', 'viewable_id', 'viewable_type', DB::raw('SUM(views) as view_count')) ->select('favourites.*')
->groupBy('viewable_id', 'viewable_type') ->leftJoin('views', function (JoinClause $join) {
->rightJoin('favourites', function (JoinClause $join) { $join->on('favourites.favouritable_id', '=', 'views.viewable_id');
$join->on('views.viewable_id', '=', 'favourites.favouritable_id'); $join->on('favourites.favouritable_type', '=', 'views.viewable_type');
$join->on('views.viewable_type', '=', 'favourites.favouritable_type'); $join->where('views.user_id', '=', user()->id);
$join->where('favourites.user_id', '=', user()->id);
}) })
->orderBy('view_count', 'desc'); ->orderBy('views.views', 'desc')
->where('favourites.user_id', '=', user()->id);
return $query->with('viewable') return $query->with('favouritable')
->skip($skip) ->skip($skip)
->take($count) ->take($count)
->get() ->get()
->pluck('viewable') ->pluck('favouritable')
->filter(); ->filter();
} }
} }

View File

@ -1,6 +1,5 @@
<?php namespace BookStack\Http\Controllers; <?php namespace BookStack\Http\Controllers;
use BookStack\Actions\ViewService;
use BookStack\Entities\Queries\Popular; use BookStack\Entities\Queries\Popular;
use BookStack\Entities\Tools\SearchRunner; use BookStack\Entities\Tools\SearchRunner;
use BookStack\Entities\Tools\ShelfContext; use BookStack\Entities\Tools\ShelfContext;
@ -10,16 +9,13 @@ use Illuminate\Http\Request;
class SearchController extends Controller class SearchController extends Controller
{ {
protected $viewService;
protected $searchRunner; protected $searchRunner;
protected $entityContextManager; protected $entityContextManager;
public function __construct( public function __construct(
ViewService $viewService,
SearchRunner $searchRunner, SearchRunner $searchRunner,
ShelfContext $entityContextManager ShelfContext $entityContextManager
) { ) {
$this->viewService = $viewService;
$this->searchRunner = $searchRunner; $this->searchRunner = $searchRunner;
$this->entityContextManager = $entityContextManager; $this->entityContextManager = $entityContextManager;
} }

View File

@ -3,7 +3,6 @@
namespace BookStack\Providers; namespace BookStack\Providers;
use BookStack\Actions\ActivityService; use BookStack\Actions\ActivityService;
use BookStack\Actions\ViewService;
use BookStack\Auth\Permissions\PermissionService; use BookStack\Auth\Permissions\PermissionService;
use BookStack\Theming\ThemeService; use BookStack\Theming\ThemeService;
use BookStack\Uploads\ImageService; use BookStack\Uploads\ImageService;
@ -32,10 +31,6 @@ class CustomFacadeProvider extends ServiceProvider
return $this->app->make(ActivityService::class); return $this->app->make(ActivityService::class);
}); });
$this->app->singleton('views', function () {
return $this->app->make(ViewService::class);
});
$this->app->singleton('images', function () { $this->app->singleton('images', function () {
return $this->app->make(ImageService::class); return $this->app->make(ImageService::class);
}); });

View File

@ -1,6 +1,9 @@
<?php <?php
use BookStack\Actions\Favourite; use BookStack\Actions\Favourite;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page; use BookStack\Entities\Models\Page;
use Tests\TestCase; use Tests\TestCase;
@ -56,4 +59,60 @@ class FavouriteTest extends TestCase
]); ]);
} }
public function test_book_chapter_shelf_pages_contain_favourite_button()
{
$entities = [
Bookshelf::query()->first(),
Book::query()->first(),
Chapter::query()->first(),
];
$this->actingAs($this->getEditor());
foreach ($entities as $entity) {
$resp = $this->get($entity->getUrl());
$resp->assertElementExists('form[method="POST"][action$="/favourites/add"]');
}
}
public function test_header_contains_link_to_favourites_page_when_logged_in()
{
$this->setSettings(['app-public' => 'true']);
$this->get('/')->assertElementNotContains('header', 'My Favourites');
$this->actingAs($this->getViewer())->get('/')->assertElementContains('header a', 'My Favourites');
}
public function test_favourites_shown_on_homepage()
{
$editor = $this->getEditor();
$resp = $this->actingAs($editor)->get('/');
$resp->assertElementNotExists('#top-favourites');
/** @var Page $page */
$page = Page::query()->first();
$page->favourites()->save((new Favourite)->forceFill(['user_id' => $editor->id]));
$resp = $this->get('/');
$resp->assertElementExists('#top-favourites');
$resp->assertElementContains('#top-favourites', $page->name);
}
public function test_favourites_list_page_shows_favourites_and_has_working_pagination()
{
/** @var Page $page */
$page = Page::query()->first();
$editor = $this->getEditor();
$resp = $this->actingAs($editor)->get('/favourites');
$resp->assertDontSee($page->name);
$page->favourites()->save((new Favourite)->forceFill(['user_id' => $editor->id]));
$resp = $this->get('/favourites');
$resp->assertSee($page->name);
$resp = $this->get('/favourites?page=2');
$resp->assertDontSee($page->name);
}
} }