diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php index 6b2d6928d..3cb8237ea 100644 --- a/app/Http/Controllers/BookController.php +++ b/app/Http/Controllers/BookController.php @@ -42,8 +42,9 @@ class BookController extends Controller public function index() { $books = $this->bookRepo->getAllPaginated(10); - $recents = $this->signedIn ? $this->bookRepo->getRecentlyViewed(10, 0) : false; - return view('books/index', ['books' => $books, 'recents' => $recents]); + $recents = $this->signedIn ? $this->bookRepo->getRecentlyViewed(4, 0) : false; + $popular = $this->bookRepo->getPopular(4, 0); + return view('books/index', ['books' => $books, 'recents' => $recents, 'popular' => $popular]); } /** diff --git a/app/Repos/BookRepo.php b/app/Repos/BookRepo.php index 9be77defe..110426bbd 100644 --- a/app/Repos/BookRepo.php +++ b/app/Repos/BookRepo.php @@ -77,6 +77,11 @@ class BookRepo return Views::getUserRecentlyViewed($count, $page, $this->book); } + public function getPopular($count = 10, $page = 0) + { + return Views::getPopular($count, $page, $this->book); + } + /** * Get a book by slug * @param $slug diff --git a/app/Services/ViewService.php b/app/Services/ViewService.php index 475500927..5b800d939 100644 --- a/app/Services/ViewService.php +++ b/app/Services/ViewService.php @@ -44,6 +44,29 @@ class ViewService return 1; } + + /** + * Get the entities with the most views. + * @param int $count + * @param int $page + * @param bool|false $filterModel + */ + public function getPopular($count = 10, $page = 0, $filterModel = false) + { + $skipCount = $count * $page; + $query = $this->view->select('id', 'viewable_id', 'viewable_type', \DB::raw('SUM(views) as view_count')) + ->groupBy('viewable_id', 'viewable_type') + ->orderBy('view_count', 'desc'); + + if($filterModel) $query->where('viewable_type', '=', get_class($filterModel)); + + $views = $query->with('viewable')->skip($skipCount)->take($count)->get(); + $viewedEntities = $views->map(function ($item) { + return $item->viewable()->getResults(); + }); + return $viewedEntities; + } + /** * Get all recently viewed entities for the current user. * @param int $count diff --git a/resources/views/books/index.blade.php b/resources/views/books/index.blade.php index 32742d126..f28b7c1dd 100644 --- a/resources/views/books/index.blade.php +++ b/resources/views/books/index.blade.php @@ -34,11 +34,22 @@ @endif
+
+ @if($recents) +
 
+

Recently Viewed

+ @include('partials/entity-list', ['entities' => $recents]) + @endif +
 
- @if($recents) -

Recently Viewed

- @include('partials/entity-list', ['entities' => $recents]) - @endif +
diff --git a/resources/views/partials/entity-list.blade.php b/resources/views/partials/entity-list.blade.php index 058b0b24f..a357a70fa 100644 --- a/resources/views/partials/entity-list.blade.php +++ b/resources/views/partials/entity-list.blade.php @@ -1,6 +1,6 @@ @if(count($entities) > 0) - @foreach($entities as $entity) + @foreach($entities as $index => $entity) @if($entity->isA('page')) @include('pages/list-item', ['page' => $entity]) @elseif($entity->isA('book')) @@ -8,7 +8,11 @@ @elseif($entity->isA('chapter')) @include('chapters/list-item', ['chapter' => $entity, 'hidePages' => true]) @endif -
+ + @if($index !== count($entities) - 1) +
+ @endif + @endforeach @else

diff --git a/tests/ActivityTrackingTest.php b/tests/ActivityTrackingTest.php new file mode 100644 index 000000000..8a237f880 --- /dev/null +++ b/tests/ActivityTrackingTest.php @@ -0,0 +1,38 @@ +take(10); + + $this->asAdmin()->visit('/books') + ->dontSeeInElement('#recents', $books[0]->name) + ->dontSeeInElement('#recents', $books[1]->name) + ->visit($books[0]->getUrl()) + ->visit($books[1]->getUrl()) + ->visit('/books') + ->seeInElement('#recents', $books[0]->name) + ->seeInElement('#recents', $books[1]->name); + } + + public function testPopularBooks() + { + $books = \BookStack\Book::all()->take(10); + + $this->asAdmin()->visit('/books') + ->dontSeeInElement('#popular', $books[0]->name) + ->dontSeeInElement('#popular', $books[1]->name) + ->visit($books[0]->getUrl()) + ->visit($books[1]->getUrl()) + ->visit($books[0]->getUrl()) + ->visit('/books') + ->seeInNthElement('#popular .book', 0, $books[0]->name) + ->seeInNthElement('#popular .book', 1, $books[1]->name); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 3f7d846f7..3a0967c8e 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -48,4 +48,31 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase $settings->put($key, $value); } } + + /** + * Assert that a given string is seen inside an element. + * + * @param bool|string|null $element + * @param integer $position + * @param string $text + * @param bool $negate + * @return $this + */ + protected function seeInNthElement($element, $position, $text, $negate = false) + { + $method = $negate ? 'assertNotRegExp' : 'assertRegExp'; + + $rawPattern = preg_quote($text, '/'); + + $escapedPattern = preg_quote(e($text), '/'); + + $content = $this->crawler->filter($element)->eq($position)->html(); + + $pattern = $rawPattern == $escapedPattern + ? $rawPattern : "({$rawPattern}|{$escapedPattern})"; + + $this->$method("/$pattern/i", $content); + + return $this; + } }