mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-01-03 23:42:28 +03:00
Watching: Prevent issues when watchable or user is deleted
- Adds filtering to the watched items list in notification preferences so that deleted (recycle bin) items are removed via query. - Adds relations and logic to properly remove watches upon user and entity delete events, to old watches in database do not linger. - Adds testing to cover the above. Did not add migration for existing data, since patch will be close to introduction, and lingering DB entries don't open a security concern, just some potential confusion in specific potential scenarios. Probably not work extra migration risk, although could add in future if concerns/issues are found. Related to #4499
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
namespace BookStack\Permissions;
|
||||
|
||||
use BookStack\App\Model;
|
||||
use BookStack\Entities\EntityProvider;
|
||||
use BookStack\Entities\Models\Entity;
|
||||
use BookStack\Entities\Models\Page;
|
||||
use BookStack\Permissions\Models\EntityPermission;
|
||||
@@ -11,6 +12,7 @@ use BookStack\Users\Models\HasOwner;
|
||||
use BookStack\Users\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class PermissionApplicator
|
||||
@@ -147,6 +149,42 @@ class PermissionApplicator
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out items that have related entity relations where
|
||||
* the entity is marked as deleted.
|
||||
*/
|
||||
public function filterDeletedFromEntityRelationQuery(Builder $query, string $tableName, string $entityIdColumn, string $entityTypeColumn): Builder
|
||||
{
|
||||
$tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn, 'entityTypeColumn' => $entityTypeColumn];
|
||||
$entityProvider = new EntityProvider();
|
||||
|
||||
$joinQuery = function ($query) use ($entityProvider) {
|
||||
$first = true;
|
||||
/** @var Builder $query */
|
||||
foreach ($entityProvider->all() as $entity) {
|
||||
$entityQuery = function ($query) use ($entity) {
|
||||
/** @var Builder $query */
|
||||
$query->select(['id', 'deleted_at'])
|
||||
->selectRaw("'{$entity->getMorphClass()}' as type")
|
||||
->from($entity->getTable())
|
||||
->whereNotNull('deleted_at');
|
||||
};
|
||||
|
||||
if ($first) {
|
||||
$entityQuery($query);
|
||||
$first = false;
|
||||
} else {
|
||||
$query->union($entityQuery);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return $query->leftJoinSub($joinQuery, 'deletions', function (JoinClause $join) use ($tableDetails) {
|
||||
$join->on($tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'], '=', 'deletions.id')
|
||||
->on($tableDetails['tableName'] . '.' . $tableDetails['entityTypeColumn'], '=', 'deletions.type');
|
||||
})->whereNull('deletions.deleted_at');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add conditions to a query for a model that's a relation of a page, so only the model results
|
||||
* on visible pages are returned by the query.
|
||||
|
||||
Reference in New Issue
Block a user