mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-11-23 11:22:33 +01:00
Started change for entities to have concept of owners
This commit is contained in:
parent
c71f00b2ec
commit
b493becadf
@ -1,6 +1,8 @@
|
||||
<?php namespace BookStack\Actions;
|
||||
|
||||
use BookStack\Ownable;
|
||||
use BookStack\Model;
|
||||
use BookStack\Traits\HasCreatorAndUpdater;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
/**
|
||||
* @property string text
|
||||
@ -8,25 +10,25 @@ use BookStack\Ownable;
|
||||
* @property int|null parent_id
|
||||
* @property int local_id
|
||||
*/
|
||||
class Comment extends Ownable
|
||||
class Comment extends Model
|
||||
{
|
||||
use HasCreatorAndUpdater;
|
||||
|
||||
protected $fillable = ['text', 'parent_id'];
|
||||
protected $appends = ['created', 'updated'];
|
||||
|
||||
/**
|
||||
* Get the entity that this comment belongs to
|
||||
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
|
||||
*/
|
||||
public function entity()
|
||||
public function entity(): MorphTo
|
||||
{
|
||||
return $this->morphTo('entity');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a comment has been updated since creation.
|
||||
* @return bool
|
||||
*/
|
||||
public function isUpdated()
|
||||
public function isUpdated(): bool
|
||||
{
|
||||
return $this->updated_at->timestamp > $this->created_at->timestamp;
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ use BookStack\Auth\Role;
|
||||
use BookStack\Entities\Models\Book;
|
||||
use BookStack\Entities\Models\Entity;
|
||||
use BookStack\Entities\EntityProvider;
|
||||
use BookStack\Ownable;
|
||||
use BookStack\Model;
|
||||
use BookStack\Traits\HasCreatorAndUpdater;
|
||||
use BookStack\Traits\HasOwner;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
@ -168,7 +170,7 @@ class PermissionService
|
||||
});
|
||||
|
||||
// Chunk through all bookshelves
|
||||
$this->entityProvider->bookshelf->newQuery()->withTrashed()->select(['id', 'restricted', 'created_by'])
|
||||
$this->entityProvider->bookshelf->newQuery()->withTrashed()->select(['id', 'restricted', 'owned_by'])
|
||||
->chunk(50, function ($shelves) use ($roles) {
|
||||
$this->buildJointPermissionsForShelves($shelves, $roles);
|
||||
});
|
||||
@ -181,10 +183,10 @@ class PermissionService
|
||||
protected function bookFetchQuery()
|
||||
{
|
||||
return $this->entityProvider->book->withTrashed()->newQuery()
|
||||
->select(['id', 'restricted', 'created_by'])->with(['chapters' => function ($query) {
|
||||
$query->withTrashed()->select(['id', 'restricted', 'created_by', 'book_id']);
|
||||
->select(['id', 'restricted', 'owned_by'])->with(['chapters' => function ($query) {
|
||||
$query->withTrashed()->select(['id', 'restricted', 'owned_by', 'book_id']);
|
||||
}, 'pages' => function ($query) {
|
||||
$query->withTrashed()->select(['id', 'restricted', 'created_by', 'book_id', 'chapter_id']);
|
||||
$query->withTrashed()->select(['id', 'restricted', 'owned_by', 'book_id', 'chapter_id']);
|
||||
}]);
|
||||
}
|
||||
|
||||
@ -286,7 +288,7 @@ class PermissionService
|
||||
});
|
||||
|
||||
// Chunk through all bookshelves
|
||||
$this->entityProvider->bookshelf->newQuery()->select(['id', 'restricted', 'created_by'])
|
||||
$this->entityProvider->bookshelf->newQuery()->select(['id', 'restricted', 'owned_by'])
|
||||
->chunk(50, function ($shelves) use ($roles) {
|
||||
$this->buildJointPermissionsForShelves($shelves, $roles);
|
||||
});
|
||||
@ -508,28 +510,24 @@ class PermissionService
|
||||
'action' => $action,
|
||||
'has_permission' => $permissionAll,
|
||||
'has_permission_own' => $permissionOwn,
|
||||
'created_by' => $entity->getRawAttribute('created_by')
|
||||
'owned_by' => $entity->getRawAttribute('owned_by')
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an entity has a restriction set upon it.
|
||||
* @param Ownable $ownable
|
||||
* @param $permission
|
||||
* @return bool
|
||||
* @param HasCreatorAndUpdater|HasOwner $ownable
|
||||
*/
|
||||
public function checkOwnableUserAccess(Ownable $ownable, $permission)
|
||||
public function checkOwnableUserAccess(Model $ownable, string $permission): bool
|
||||
{
|
||||
$explodedPermission = explode('-', $permission);
|
||||
|
||||
$baseQuery = $ownable->where('id', '=', $ownable->id);
|
||||
$baseQuery = $ownable->newQuery()->where('id', '=', $ownable->id);
|
||||
$action = end($explodedPermission);
|
||||
$this->currentAction = $action;
|
||||
|
||||
$nonJointPermissions = ['restrictions', 'image', 'attachment', 'comment'];
|
||||
|
||||
// Handle non entity specific jointPermissions
|
||||
if (in_array($explodedPermission[0], $nonJointPermissions)) {
|
||||
if (!($ownable instanceof Entity)) {
|
||||
$allPermission = $this->currentUser() && $this->currentUser()->can($permission . '-all');
|
||||
$ownPermission = $this->currentUser() && $this->currentUser()->can($permission . '-own');
|
||||
$this->currentAction = 'view';
|
||||
@ -566,7 +564,7 @@ class PermissionService
|
||||
$query->where('has_permission', '=', 1)
|
||||
->orWhere(function ($query2) use ($userId) {
|
||||
$query2->where('has_permission_own', '=', 1)
|
||||
->where('created_by', '=', $userId);
|
||||
->where('owned_by', '=', $userId);
|
||||
});
|
||||
});
|
||||
|
||||
@ -615,7 +613,7 @@ class PermissionService
|
||||
$query->where('has_permission', '=', true)
|
||||
->orWhere(function ($query) {
|
||||
$query->where('has_permission_own', '=', true)
|
||||
->where('created_by', '=', $this->currentUser()->id);
|
||||
->where('owned_by', '=', $this->currentUser()->id);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -639,7 +637,7 @@ class PermissionService
|
||||
$query->where('has_permission', '=', true)
|
||||
->orWhere(function (Builder $query) {
|
||||
$query->where('has_permission_own', '=', true)
|
||||
->where('created_by', '=', $this->currentUser()->id);
|
||||
->where('owned_by', '=', $this->currentUser()->id);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -656,7 +654,7 @@ class PermissionService
|
||||
$query->where('draft', '=', false)
|
||||
->orWhere(function (Builder $query) {
|
||||
$query->where('draft', '=', true)
|
||||
->where('created_by', '=', $this->currentUser()->id);
|
||||
->where('owned_by', '=', $this->currentUser()->id);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -676,7 +674,7 @@ class PermissionService
|
||||
$query->where('draft', '=', false)
|
||||
->orWhere(function ($query) {
|
||||
$query->where('draft', '=', true)
|
||||
->where('created_by', '=', $this->currentUser()->id);
|
||||
->where('owned_by', '=', $this->currentUser()->id);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -710,7 +708,7 @@ class PermissionService
|
||||
->where(function ($query) {
|
||||
$query->where('has_permission', '=', true)->orWhere(function ($query) {
|
||||
$query->where('has_permission_own', '=', true)
|
||||
->where('created_by', '=', $this->currentUser()->id);
|
||||
->where('owned_by', '=', $this->currentUser()->id);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -746,7 +744,7 @@ class PermissionService
|
||||
->where(function ($query) {
|
||||
$query->where('has_permission', '=', true)->orWhere(function ($query) {
|
||||
$query->where('has_permission_own', '=', true)
|
||||
->where('created_by', '=', $this->currentUser()->id);
|
||||
->where('owned_by', '=', $this->currentUser()->id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -9,7 +9,9 @@ use BookStack\Auth\Permissions\JointPermission;
|
||||
use BookStack\Entities\Tools\SearchIndex;
|
||||
use BookStack\Entities\Tools\SlugGenerator;
|
||||
use BookStack\Facades\Permissions;
|
||||
use BookStack\Ownable;
|
||||
use BookStack\Model;
|
||||
use BookStack\Traits\HasCreatorAndUpdater;
|
||||
use BookStack\Traits\HasOwner;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
@ -35,9 +37,11 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @method static Builder withLastView()
|
||||
* @method static Builder withViewCount()
|
||||
*/
|
||||
abstract class Entity extends Ownable
|
||||
abstract class Entity extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
use HasCreatorAndUpdater;
|
||||
use HasOwner;
|
||||
|
||||
/**
|
||||
* @var string - Name of property where the main text content is found
|
||||
|
@ -4,7 +4,8 @@ namespace BookStack\Http\Controllers;
|
||||
|
||||
use BookStack\Facades\Activity;
|
||||
use BookStack\Interfaces\Loggable;
|
||||
use BookStack\Ownable;
|
||||
use BookStack\HasCreatorAndUpdater;
|
||||
use BookStack\Model;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Http\Exceptions\HttpResponseException;
|
||||
@ -72,7 +73,7 @@ abstract class Controller extends BaseController
|
||||
/**
|
||||
* Check the current user's permissions against an ownable item otherwise throw an exception.
|
||||
*/
|
||||
protected function checkOwnablePermission(string $permission, Ownable $ownable): void
|
||||
protected function checkOwnablePermission(string $permission, Model $ownable): void
|
||||
{
|
||||
if (!userCan($permission, $ownable)) {
|
||||
$this->showPermissionError();
|
||||
|
@ -1,27 +1,26 @@
|
||||
<?php namespace BookStack;
|
||||
<?php namespace BookStack\Traits;
|
||||
|
||||
use BookStack\Auth\User;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* @property int created_by
|
||||
* @property int updated_by
|
||||
*/
|
||||
abstract class Ownable extends Model
|
||||
trait HasCreatorAndUpdater
|
||||
{
|
||||
/**
|
||||
* Relation for the user that created this entity.
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function createdBy()
|
||||
public function createdBy(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'created_by');
|
||||
}
|
||||
|
||||
/**
|
||||
* Relation for the user that updated this entity.
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function updatedBy()
|
||||
public function updatedBy(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'updated_by');
|
||||
}
|
19
app/Traits/HasOwner.php
Normal file
19
app/Traits/HasOwner.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php namespace BookStack\Traits;
|
||||
|
||||
use BookStack\Auth\User;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* @property int owned_by
|
||||
*/
|
||||
trait HasOwner
|
||||
{
|
||||
/**
|
||||
* Relation for the user that owns this entity.
|
||||
*/
|
||||
public function ownedBy(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'owned_by');
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
<?php namespace BookStack\Uploads;
|
||||
|
||||
use BookStack\Entities\Models\Page;
|
||||
use BookStack\Ownable;
|
||||
use BookStack\Model;
|
||||
use BookStack\Traits\HasCreatorAndUpdater;
|
||||
|
||||
/**
|
||||
* @property int id
|
||||
@ -10,8 +11,10 @@ use BookStack\Ownable;
|
||||
* @property string extension
|
||||
* @property bool external
|
||||
*/
|
||||
class Attachment extends Ownable
|
||||
class Attachment extends Model
|
||||
{
|
||||
use HasCreatorAndUpdater;
|
||||
|
||||
protected $fillable = ['name', 'order'];
|
||||
|
||||
/**
|
||||
|
@ -1,11 +1,13 @@
|
||||
<?php namespace BookStack\Uploads;
|
||||
|
||||
use BookStack\Entities\Models\Page;
|
||||
use BookStack\Ownable;
|
||||
use BookStack\Model;
|
||||
use BookStack\Traits\HasCreatorAndUpdater;
|
||||
use Images;
|
||||
|
||||
class Image extends Ownable
|
||||
class Image extends Model
|
||||
{
|
||||
use HasCreatorAndUpdater;
|
||||
|
||||
protected $fillable = ['name'];
|
||||
protected $hidden = [];
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use BookStack\Auth\Permissions\PermissionService;
|
||||
use BookStack\Auth\User;
|
||||
use BookStack\Ownable;
|
||||
use BookStack\Model;
|
||||
use BookStack\Settings\SettingService;
|
||||
|
||||
/**
|
||||
@ -56,7 +56,7 @@ function hasAppAccess(): bool
|
||||
* Check if the current user has a permission. If an ownable element
|
||||
* is passed in the jointPermissions are checked against that particular item.
|
||||
*/
|
||||
function userCan(string $permission, Ownable $ownable = null): bool
|
||||
function userCan(string $permission, Model $ownable = null): bool
|
||||
{
|
||||
if ($ownable === null) {
|
||||
return user() && user()->can($permission);
|
||||
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AddOwnedByFieldToEntities extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$tables = ['pages', 'books', 'chapters', 'bookshelves'];
|
||||
foreach ($tables as $table) {
|
||||
Schema::table($table, function (Blueprint $table) {
|
||||
$table->integer('owned_by')->unsigned()->index();
|
||||
});
|
||||
|
||||
DB::table($table)->update(['owned_by' => DB::raw('`created_by`')]);
|
||||
}
|
||||
|
||||
Schema::table('joint_permissions', function (Blueprint $table) {
|
||||
$table->renameColumn('created_by', 'owned_by');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
$tables = ['pages', 'books', 'chapters', 'bookshelves'];
|
||||
foreach ($tables as $table) {
|
||||
Schema::table($table, function (Blueprint $table) {
|
||||
$table->dropColumn('owned_by');
|
||||
});
|
||||
}
|
||||
|
||||
Schema::table('joint_permissions', function (Blueprint $table) {
|
||||
$table->renameColumn('owned_by', 'created_by');
|
||||
});
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ return [
|
||||
'meta_created_name' => 'Created :timeLength by :user',
|
||||
'meta_updated' => 'Updated :timeLength',
|
||||
'meta_updated_name' => 'Updated :timeLength by :user',
|
||||
'meta_owned_name' => 'Owned by :user',
|
||||
'entity_select' => 'Entity Select',
|
||||
'images' => 'Images',
|
||||
'my_recent_drafts' => 'My Recent Drafts',
|
||||
|
@ -1,34 +1,50 @@
|
||||
<div class="entity-meta">
|
||||
@if($entity->isA('revision'))
|
||||
@icon('history'){{ trans('entities.pages_revision') }}
|
||||
{{ trans('entities.pages_revisions_number') }}{{ $entity->revision_number == 0 ? '' : $entity->revision_number }}
|
||||
<br>
|
||||
<div>
|
||||
@icon('history'){{ trans('entities.pages_revision') }}
|
||||
{{ trans('entities.pages_revisions_number') }}{{ $entity->revision_number == 0 ? '' : $entity->revision_number }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($entity->isA('page'))
|
||||
@if (userCan('page-update', $entity)) <a href="{{ $entity->getUrl('/revisions') }}"> @endif
|
||||
@icon('history'){{ trans('entities.meta_revision', ['revisionCount' => $entity->revision_count]) }} <br>
|
||||
<div>
|
||||
@if (userCan('page-update', $entity)) <a href="{{ $entity->getUrl('/revisions') }}"> @endif
|
||||
@icon('history'){{ trans('entities.meta_revision', ['revisionCount' => $entity->revision_count]) }}
|
||||
@if (userCan('page-update', $entity))</a>@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($entity->ownedBy && $entity->ownedBy->id !== $entity->createdBy->id)
|
||||
<div>
|
||||
@icon('user'){!! trans('entities.meta_owned_name', [
|
||||
'user' => "<a href='{$entity->ownedBy->getProfileUrl()}'>".e($entity->ownedBy->name). "</a>"
|
||||
]) !!}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($entity->createdBy)
|
||||
@icon('star'){!! trans('entities.meta_created_name', [
|
||||
<div>
|
||||
@icon('star'){!! trans('entities.meta_created_name', [
|
||||
'timeLength' => '<span title="'.$entity->created_at->toDayDateTimeString().'">'.$entity->created_at->diffForHumans() . '</span>',
|
||||
'user' => "<a href='{$entity->createdBy->getProfileUrl()}'>".htmlentities($entity->createdBy->name). "</a>"
|
||||
'user' => "<a href='{$entity->createdBy->getProfileUrl()}'>".e($entity->createdBy->name). "</a>"
|
||||
]) !!}
|
||||
</div>
|
||||
@else
|
||||
@icon('star')<span title="{{$entity->created_at->toDayDateTimeString()}}">{{ trans('entities.meta_created', ['timeLength' => $entity->created_at->diffForHumans()]) }}</span>
|
||||
<div>
|
||||
@icon('star')<span title="{{$entity->created_at->toDayDateTimeString()}}">{{ trans('entities.meta_created', ['timeLength' => $entity->created_at->diffForHumans()]) }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<br>
|
||||
|
||||
@if ($entity->updatedBy)
|
||||
@icon('edit'){!! trans('entities.meta_updated_name', [
|
||||
<div>
|
||||
@icon('edit'){!! trans('entities.meta_updated_name', [
|
||||
'timeLength' => '<span title="' . $entity->updated_at->toDayDateTimeString() .'">' . $entity->updated_at->diffForHumans() .'</span>',
|
||||
'user' => "<a href='{$entity->updatedBy->getProfileUrl()}'>".htmlentities($entity->updatedBy->name). "</a>"
|
||||
'user' => "<a href='{$entity->updatedBy->getProfileUrl()}'>".e($entity->updatedBy->name). "</a>"
|
||||
]) !!}
|
||||
</div>
|
||||
@elseif (!$entity->isA('revision'))
|
||||
@icon('edit')<span title="{{ $entity->updated_at->toDayDateTimeString() }}">{{ trans('entities.meta_updated', ['timeLength' => $entity->updated_at->diffForHumans()]) }}</span>
|
||||
<div>
|
||||
@icon('edit')<span title="{{ $entity->updated_at->toDayDateTimeString() }}">{{ trans('entities.meta_updated', ['timeLength' => $entity->updated_at->diffForHumans()]) }}</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user