- 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.
$q = $query->where(function ($query) 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_type=' . $tableDetails['tableName'] . '.' . $tableDetails['entityTypeColumn'])
->where('action', '=', $action)
<?php namespace BookStack\Entities\Queries;
-use BookStack\Actions\View;
+use BookStack\Actions\Favourite;
use Illuminate\Database\Query\JoinClause;
-use Illuminate\Support\Facades\DB;
class TopFavourites extends EntityQuery
{
public function run(int $count, int $skip = 0)
{
$user = user();
- if ($user === null || $user->isDefault()) {
+ if (is_null($user) || $user->isDefault()) {
return collect();
}
$query = $this->permissionService()
- ->filterRestrictedEntityRelations(View::query(), 'views', 'viewable_id', 'viewable_type', 'view')
- ->select('*', 'viewable_id', 'viewable_type', DB::raw('SUM(views) as view_count'))
- ->groupBy('viewable_id', 'viewable_type')
- ->rightJoin('favourites', function (JoinClause $join) {
- $join->on('views.viewable_id', '=', 'favourites.favouritable_id');
- $join->on('views.viewable_type', '=', 'favourites.favouritable_type');
- $join->where('favourites.user_id', '=', user()->id);
+ ->filterRestrictedEntityRelations(Favourite::query(), 'favourites', 'favouritable_id', 'favouritable_type', 'view')
+ ->select('favourites.*')
+ ->leftJoin('views', function (JoinClause $join) {
+ $join->on('favourites.favouritable_id', '=', 'views.viewable_id');
+ $join->on('favourites.favouritable_type', '=', 'views.viewable_type');
+ $join->where('views.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)
->take($count)
->get()
- ->pluck('viewable')
+ ->pluck('favouritable')
->filter();
}
}
<?php namespace BookStack\Http\Controllers;
-use BookStack\Actions\ViewService;
use BookStack\Entities\Queries\Popular;
use BookStack\Entities\Tools\SearchRunner;
use BookStack\Entities\Tools\ShelfContext;
class SearchController extends Controller
{
- protected $viewService;
protected $searchRunner;
protected $entityContextManager;
public function __construct(
- ViewService $viewService,
SearchRunner $searchRunner,
ShelfContext $entityContextManager
) {
- $this->viewService = $viewService;
$this->searchRunner = $searchRunner;
$this->entityContextManager = $entityContextManager;
}
namespace BookStack\Providers;
use BookStack\Actions\ActivityService;
-use BookStack\Actions\ViewService;
use BookStack\Auth\Permissions\PermissionService;
use BookStack\Theming\ThemeService;
use BookStack\Uploads\ImageService;
return $this->app->make(ActivityService::class);
});
- $this->app->singleton('views', function () {
- return $this->app->make(ViewService::class);
- });
-
$this->app->singleton('images', function () {
return $this->app->make(ImageService::class);
});
<?php
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 Tests\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);
+ }
+
}
\ No newline at end of file