mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Notifications: Updated watch control to show parent status
This commit is contained in:
parent
ecab2c8e42
commit
c47b3f805a
@ -3,7 +3,7 @@
|
||||
namespace BookStack\Activity\Controllers;
|
||||
|
||||
use BookStack\Activity\Models\Watch;
|
||||
use BookStack\Activity\Tools\UserWatchOptions;
|
||||
use BookStack\Activity\Tools\UserEntityWatchOptions;
|
||||
use BookStack\App\Model;
|
||||
use BookStack\Entities\Models\Entity;
|
||||
use BookStack\Http\Controller;
|
||||
@ -20,8 +20,8 @@ class WatchController extends Controller
|
||||
]);
|
||||
|
||||
$watchable = $this->getValidatedModelFromRequest($request);
|
||||
$watchOptions = new UserWatchOptions(user());
|
||||
$watchOptions->updateEntityWatchLevel($watchable, $requestData['level']);
|
||||
$watchOptions = new UserEntityWatchOptions(user(), $watchable);
|
||||
$watchOptions->updateWatchLevel($requestData['level']);
|
||||
|
||||
$this->showSuccessNotification(trans('activities.watch_update_level_notification'));
|
||||
|
||||
|
124
app/Activity/Tools/UserEntityWatchOptions.php
Normal file
124
app/Activity/Tools/UserEntityWatchOptions.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Activity\Tools;
|
||||
|
||||
use BookStack\Activity\Models\Watch;
|
||||
use BookStack\Activity\WatchLevels;
|
||||
use BookStack\Entities\Models\BookChild;
|
||||
use BookStack\Entities\Models\Entity;
|
||||
use BookStack\Entities\Models\Page;
|
||||
use BookStack\Users\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class UserEntityWatchOptions
|
||||
{
|
||||
protected ?array $watchMap = null;
|
||||
|
||||
public function __construct(
|
||||
protected User $user,
|
||||
protected Entity $entity,
|
||||
) {
|
||||
}
|
||||
|
||||
public function canWatch(): bool
|
||||
{
|
||||
return $this->user->can('receive-notifications') && !$this->user->isDefault();
|
||||
}
|
||||
|
||||
public function getWatchLevel(): string
|
||||
{
|
||||
return WatchLevels::levelValueToName($this->getWatchLevelValue());
|
||||
}
|
||||
|
||||
public function isWatching(): bool
|
||||
{
|
||||
return $this->getWatchLevelValue() !== WatchLevels::DEFAULT;
|
||||
}
|
||||
|
||||
public function getWatchedParent(): ?WatchedParentDetails
|
||||
{
|
||||
$watchMap = $this->getWatchMap();
|
||||
unset($watchMap[$this->entity->getMorphClass()]);
|
||||
|
||||
if (isset($watchMap['chapter'])) {
|
||||
return new WatchedParentDetails('chapter', $watchMap['chapter']);
|
||||
}
|
||||
|
||||
if (isset($watchMap['book'])) {
|
||||
return new WatchedParentDetails('book', $watchMap['book']);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function updateWatchLevel(string $level): void
|
||||
{
|
||||
$levelValue = WatchLevels::levelNameToValue($level);
|
||||
if ($levelValue < 0) {
|
||||
$this->remove();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->updateLevel($levelValue);
|
||||
}
|
||||
|
||||
public function getWatchMap(): array
|
||||
{
|
||||
if (!is_null($this->watchMap)) {
|
||||
return $this->watchMap;
|
||||
}
|
||||
|
||||
$entities = [$this->entity];
|
||||
if ($this->entity instanceof BookChild) {
|
||||
$entities[] = $this->entity->book;
|
||||
}
|
||||
if ($this->entity instanceof Page && $this->entity->chapter) {
|
||||
$entities[] = $this->entity->chapter;
|
||||
}
|
||||
|
||||
$query = Watch::query()->where(function (Builder $subQuery) use ($entities) {
|
||||
foreach ($entities as $entity) {
|
||||
$subQuery->orWhere(function (Builder $whereQuery) use ($entity) {
|
||||
$whereQuery->where('watchable_type', '=', $entity->getMorphClass())
|
||||
->where('watchable_id', '=', $entity->id);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$this->watchMap = $query->get(['watchable_type', 'level'])
|
||||
->pluck('level', 'watchable_type')
|
||||
->toArray();
|
||||
|
||||
return $this->watchMap;
|
||||
}
|
||||
|
||||
protected function getWatchLevelValue()
|
||||
{
|
||||
return $this->getWatchMap()[$this->entity->getMorphClass()] ?? WatchLevels::DEFAULT;
|
||||
}
|
||||
|
||||
protected function updateLevel(int $levelValue): void
|
||||
{
|
||||
Watch::query()->updateOrCreate([
|
||||
'watchable_id' => $this->entity->id,
|
||||
'watchable_type' => $this->entity->getMorphClass(),
|
||||
'user_id' => $this->user->id,
|
||||
], [
|
||||
'level' => $levelValue,
|
||||
]);
|
||||
$this->watchMap = null;
|
||||
}
|
||||
|
||||
protected function remove(): void
|
||||
{
|
||||
$this->entityQuery()->delete();
|
||||
$this->watchMap = null;
|
||||
}
|
||||
|
||||
protected function entityQuery(): Builder
|
||||
{
|
||||
return Watch::query()->where('watchable_id', '=', $this->entity->id)
|
||||
->where('watchable_type', '=', $this->entity->getMorphClass())
|
||||
->where('user_id', '=', $this->user->id);
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Activity\Tools;
|
||||
|
||||
use BookStack\Activity\Models\Watch;
|
||||
use BookStack\Activity\WatchLevels;
|
||||
use BookStack\Entities\Models\Entity;
|
||||
use BookStack\Users\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class UserWatchOptions
|
||||
{
|
||||
public function __construct(
|
||||
protected User $user,
|
||||
) {
|
||||
}
|
||||
|
||||
public function canWatch(): bool
|
||||
{
|
||||
return $this->user->can('receive-notifications') && !$this->user->isDefault();
|
||||
}
|
||||
|
||||
public function getEntityWatchLevel(Entity $entity): string
|
||||
{
|
||||
$levelValue = $this->entityQuery($entity)->first(['level'])->level ?? -1;
|
||||
return WatchLevels::levelValueToName($levelValue);
|
||||
}
|
||||
|
||||
public function isWatching(Entity $entity): bool
|
||||
{
|
||||
return $this->entityQuery($entity)->exists();
|
||||
}
|
||||
|
||||
public function updateEntityWatchLevel(Entity $entity, string $level): void
|
||||
{
|
||||
$levelValue = WatchLevels::levelNameToValue($level);
|
||||
if ($levelValue < 0) {
|
||||
$this->removeForEntity($entity);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->updateForEntity($entity, $levelValue);
|
||||
}
|
||||
|
||||
protected function updateForEntity(Entity $entity, int $levelValue): void
|
||||
{
|
||||
Watch::query()->updateOrCreate([
|
||||
'watchable_id' => $entity->id,
|
||||
'watchable_type' => $entity->getMorphClass(),
|
||||
'user_id' => $this->user->id,
|
||||
], [
|
||||
'level' => $levelValue,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function removeForEntity(Entity $entity): void
|
||||
{
|
||||
$this->entityQuery($entity)->delete();
|
||||
}
|
||||
|
||||
protected function entityQuery(Entity $entity): Builder
|
||||
{
|
||||
return Watch::query()->where('watchable_id', '=', $entity->id)
|
||||
->where('watchable_type', '=', $entity->getMorphClass())
|
||||
->where('user_id', '=', $this->user->id);
|
||||
}
|
||||
}
|
19
app/Activity/Tools/WatchedParentDetails.php
Normal file
19
app/Activity/Tools/WatchedParentDetails.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Activity\Tools;
|
||||
|
||||
use BookStack\Activity\WatchLevels;
|
||||
|
||||
class WatchedParentDetails
|
||||
{
|
||||
public function __construct(
|
||||
public string $type,
|
||||
public int $level,
|
||||
) {
|
||||
}
|
||||
|
||||
public function ignoring(): bool
|
||||
{
|
||||
return $this->level === WatchLevels::IGNORE;
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ namespace BookStack\Entities\Controllers;
|
||||
use BookStack\Activity\ActivityQueries;
|
||||
use BookStack\Activity\ActivityType;
|
||||
use BookStack\Activity\Models\View;
|
||||
use BookStack\Activity\Tools\UserWatchOptions;
|
||||
use BookStack\Activity\Tools\UserEntityWatchOptions;
|
||||
use BookStack\Entities\Models\Bookshelf;
|
||||
use BookStack\Entities\Repos\BookRepo;
|
||||
use BookStack\Entities\Tools\BookContents;
|
||||
@ -139,7 +139,7 @@ class BookController extends Controller
|
||||
'current' => $book,
|
||||
'bookChildren' => $bookChildren,
|
||||
'bookParentShelves' => $bookParentShelves,
|
||||
'watchOptions' => new UserWatchOptions(user()),
|
||||
'watchOptions' => new UserEntityWatchOptions(user(), $book),
|
||||
'activity' => $activities->entityActivity($book, 20, 1),
|
||||
'referenceCount' => $this->referenceFetcher->getPageReferenceCountToEntity($book),
|
||||
]);
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace BookStack\Entities\Controllers;
|
||||
|
||||
use BookStack\Activity\Models\View;
|
||||
use BookStack\Activity\Tools\UserWatchOptions;
|
||||
use BookStack\Activity\Tools\UserEntityWatchOptions;
|
||||
use BookStack\Entities\Models\Book;
|
||||
use BookStack\Entities\Repos\ChapterRepo;
|
||||
use BookStack\Entities\Tools\BookContents;
|
||||
@ -82,7 +82,7 @@ class ChapterController extends Controller
|
||||
'chapter' => $chapter,
|
||||
'current' => $chapter,
|
||||
'sidebarTree' => $sidebarTree,
|
||||
'watchOptions' => new UserWatchOptions(user()),
|
||||
'watchOptions' => new UserEntityWatchOptions(user(), $chapter),
|
||||
'pages' => $pages,
|
||||
'next' => $nextPreviousLocator->getNext(),
|
||||
'previous' => $nextPreviousLocator->getPrevious(),
|
||||
|
@ -4,7 +4,7 @@ namespace BookStack\Entities\Controllers;
|
||||
|
||||
use BookStack\Activity\Models\View;
|
||||
use BookStack\Activity\Tools\CommentTree;
|
||||
use BookStack\Activity\Tools\UserWatchOptions;
|
||||
use BookStack\Activity\Tools\UserEntityWatchOptions;
|
||||
use BookStack\Entities\Models\Page;
|
||||
use BookStack\Entities\Repos\PageRepo;
|
||||
use BookStack\Entities\Tools\BookContents;
|
||||
@ -152,7 +152,7 @@ class PageController extends Controller
|
||||
'sidebarTree' => $sidebarTree,
|
||||
'commentTree' => $commentTree,
|
||||
'pageNav' => $pageNav,
|
||||
'watchOptions' => new UserWatchOptions(user()),
|
||||
'watchOptions' => new UserEntityWatchOptions(user(), $page),
|
||||
'next' => $nextPreviousLocator->getNext(),
|
||||
'previous' => $nextPreviousLocator->getPrevious(),
|
||||
'referenceCount' => $this->referenceFetcher->getPageReferenceCountToEntity($page),
|
||||
|
@ -421,4 +421,8 @@ return [
|
||||
'watch_detail_new' => 'Watching for new pages',
|
||||
'watch_detail_updates' => 'Watching new pages and updates',
|
||||
'watch_detail_comments' => 'Watching new pages, updates & comments',
|
||||
'watch_detail_parent_book' => 'Watching via parent book',
|
||||
'watch_detail_parent_book_ignore' => 'Ignoring via parent book',
|
||||
'watch_detail_parent_chapter' => 'Watching via parent chapter',
|
||||
'watch_detail_parent_chapter_ignore' => 'Ignoring via parent chapter',
|
||||
];
|
||||
|
@ -139,7 +139,7 @@
|
||||
|
||||
<hr class="primary-background">
|
||||
|
||||
@if($watchOptions->canWatch() && !$watchOptions->isWatching($book))
|
||||
@if($watchOptions->canWatch() && !$watchOptions->isWatching())
|
||||
@include('entities.watch-action', ['entity' => $book])
|
||||
@endif
|
||||
@if(signedInUser())
|
||||
|
@ -157,7 +157,7 @@
|
||||
|
||||
<hr class="primary-background"/>
|
||||
|
||||
@if($watchOptions->canWatch() && !$watchOptions->isWatching($chapter))
|
||||
@if($watchOptions->canWatch() && !$watchOptions->isWatching())
|
||||
@include('entities.watch-action', ['entity' => $chapter])
|
||||
@endif
|
||||
@if(signedInUser())
|
||||
|
@ -69,17 +69,21 @@
|
||||
</a>
|
||||
@endif
|
||||
|
||||
@if($watchOptions?->canWatch() && $watchOptions->isWatching($entity))
|
||||
@php
|
||||
$watchLevel = $watchOptions->getEntityWatchLevel($entity);
|
||||
@endphp
|
||||
<div component="dropdown"
|
||||
class="dropdown-container block my-xxs">
|
||||
<a refs="dropdown@toggle" href="#" class="entity-meta-item my-none">
|
||||
@icon(($watchLevel === 'ignore' ? 'watch-ignore' : 'watch'))
|
||||
<span>{{ trans('entities.watch_detail_' . $watchLevel) }}</span>
|
||||
</a>
|
||||
@include('entities.watch-controls', ['entity' => $entity, 'watchLevel' => $watchLevel])
|
||||
</div>
|
||||
@if($watchOptions?->canWatch())
|
||||
@if($watchOptions->isWatching())
|
||||
@include('entities.watch-controls', [
|
||||
'entity' => $entity,
|
||||
'watchLevel' => $watchOptions->getWatchLevel(),
|
||||
'label' => trans('entities.watch_detail_' . $watchOptions->getWatchLevel()),
|
||||
'ignoring' => $watchOptions->getWatchLevel() === 'ignore',
|
||||
])
|
||||
@elseif($watchedParent = $watchOptions->getWatchedParent())
|
||||
@include('entities.watch-controls', [
|
||||
'entity' => $entity,
|
||||
'watchLevel' => $watchOptions->getWatchLevel(),
|
||||
'label' => trans('entities.watch_detail_parent_' . $watchedParent->type . ($watchedParent->ignoring() ? '_ignore' : '')),
|
||||
'ignoring' => $watchedParent->ignoring(),
|
||||
])
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
@ -1,35 +1,42 @@
|
||||
<form action="{{ url('/watching/update') }}" method="POST">
|
||||
{{ method_field('PUT') }}
|
||||
{{ csrf_field() }}
|
||||
<input type="hidden" name="type" value="{{ get_class($entity) }}">
|
||||
<input type="hidden" name="id" value="{{ $entity->id }}">
|
||||
<div component="dropdown"
|
||||
class="dropdown-container block my-xxs">
|
||||
<a refs="dropdown@toggle" href="#" class="entity-meta-item my-none">
|
||||
@icon(($ignoring ? 'watch-ignore' : 'watch'))
|
||||
<span>{{ $label }}</span>
|
||||
</a>
|
||||
<form action="{{ url('/watching/update') }}" method="POST">
|
||||
{{ method_field('PUT') }}
|
||||
{{ csrf_field() }}
|
||||
<input type="hidden" name="type" value="{{ get_class($entity) }}">
|
||||
<input type="hidden" name="id" value="{{ $entity->id }}">
|
||||
|
||||
<ul refs="dropdown@menu" class="dropdown-menu xl-limited anchor-left pb-none">
|
||||
@foreach(\BookStack\Activity\WatchLevels::all() as $option => $value)
|
||||
<li>
|
||||
<button name="level" value="{{ $option }}" class="icon-item">
|
||||
@if($watchLevel === $option)
|
||||
<span class="text-pos pt-m"
|
||||
title="{{ trans('common.status_active') }}">@icon('check-circle')</span>
|
||||
@else
|
||||
<span title="{{ trans('common.status_inactive') }}"></span>
|
||||
@endif
|
||||
<div class="break-text">
|
||||
<div class="mb-xxs"><strong>{{ trans('entities.watch_title_' . $option) }}</strong></div>
|
||||
<div class="text-muted text-small">
|
||||
{{ trans('entities.watch_desc_' . $option) }}
|
||||
<ul refs="dropdown@menu" class="dropdown-menu xl-limited anchor-left pb-none">
|
||||
@foreach(\BookStack\Activity\WatchLevels::all() as $option => $value)
|
||||
<li>
|
||||
<button name="level" value="{{ $option }}" class="icon-item">
|
||||
@if($watchLevel === $option)
|
||||
<span class="text-pos pt-m"
|
||||
title="{{ trans('common.status_active') }}">@icon('check-circle')</span>
|
||||
@else
|
||||
<span title="{{ trans('common.status_inactive') }}"></span>
|
||||
@endif
|
||||
<div class="break-text">
|
||||
<div class="mb-xxs"><strong>{{ trans('entities.watch_title_' . $option) }}</strong></div>
|
||||
<div class="text-muted text-small">
|
||||
{{ trans('entities.watch_desc_' . $option) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<hr class="my-none">
|
||||
</li>
|
||||
@endforeach
|
||||
<li>
|
||||
<hr class="my-none">
|
||||
<a href="{{ url('/preferences/notifications') }}"
|
||||
target="_blank"
|
||||
class="text-item text-muted text-small break-text">{{ trans('entities.watch_change_default') }}</a>
|
||||
</li>
|
||||
@endforeach
|
||||
<li>
|
||||
<a href="{{ url('/preferences/notifications') }}"
|
||||
target="_blank"
|
||||
class="text-item text-muted text-small break-text">{{ trans('entities.watch_change_default') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
@ -185,7 +185,7 @@
|
||||
|
||||
<hr class="primary-background"/>
|
||||
|
||||
@if($watchOptions->canWatch() && !$watchOptions->isWatching($page))
|
||||
@if($watchOptions->canWatch() && !$watchOptions->isWatching())
|
||||
@include('entities.watch-action', ['entity' => $page])
|
||||
@endif
|
||||
@if(signedInUser())
|
||||
|
Loading…
Reference in New Issue
Block a user