From b493becadfd0acf177decb796b460f92ca56f4e1 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 30 Dec 2020 18:25:35 +0000 Subject: [PATCH] Started change for entities to have concept of owners --- app/Actions/Comment.php | 14 +++--- app/Auth/Permissions/PermissionService.php | 42 ++++++++-------- app/Entities/Models/Entity.php | 8 ++- app/Http/Controllers/Controller.php | 5 +- .../HasCreatorAndUpdater.php} | 11 ++--- app/Traits/HasOwner.php | 19 +++++++ app/Uploads/Attachment.php | 7 ++- app/Uploads/Image.php | 6 ++- app/helpers.php | 4 +- ..._173528_add_owned_by_field_to_entities.php | 49 +++++++++++++++++++ resources/lang/en/entities.php | 1 + .../views/partials/entity-meta.blade.php | 42 +++++++++++----- 12 files changed, 151 insertions(+), 57 deletions(-) rename app/{Ownable.php => Traits/HasCreatorAndUpdater.php} (59%) create mode 100644 app/Traits/HasOwner.php create mode 100644 database/migrations/2020_12_30_173528_add_owned_by_field_to_entities.php diff --git a/app/Actions/Comment.php b/app/Actions/Comment.php index 655d45221..f5269e253 100644 --- a/app/Actions/Comment.php +++ b/app/Actions/Comment.php @@ -1,6 +1,8 @@ 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; } diff --git a/app/Auth/Permissions/PermissionService.php b/app/Auth/Permissions/PermissionService.php index 5f4648d58..bd4066936 100644 --- a/app/Auth/Permissions/PermissionService.php +++ b/app/Auth/Permissions/PermissionService.php @@ -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); }); }); }); diff --git a/app/Entities/Models/Entity.php b/app/Entities/Models/Entity.php index e681a4e22..c6b2468b0 100644 --- a/app/Entities/Models/Entity.php +++ b/app/Entities/Models/Entity.php @@ -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 diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 758c85dda..479d5ac15 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -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(); diff --git a/app/Ownable.php b/app/Traits/HasCreatorAndUpdater.php similarity index 59% rename from app/Ownable.php rename to app/Traits/HasCreatorAndUpdater.php index b118bc742..ad6c3035f 100644 --- a/app/Ownable.php +++ b/app/Traits/HasCreatorAndUpdater.php @@ -1,27 +1,26 @@ -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'); } diff --git a/app/Traits/HasOwner.php b/app/Traits/HasOwner.php new file mode 100644 index 000000000..9d1eb3df7 --- /dev/null +++ b/app/Traits/HasOwner.php @@ -0,0 +1,19 @@ +belongsTo(User::class, 'owned_by'); + } + +} diff --git a/app/Uploads/Attachment.php b/app/Uploads/Attachment.php index 77c7925db..d1060477d 100644 --- a/app/Uploads/Attachment.php +++ b/app/Uploads/Attachment.php @@ -1,7 +1,8 @@ can($permission); diff --git a/database/migrations/2020_12_30_173528_add_owned_by_field_to_entities.php b/database/migrations/2020_12_30_173528_add_owned_by_field_to_entities.php new file mode 100644 index 000000000..bf8bf281f --- /dev/null +++ b/database/migrations/2020_12_30_173528_add_owned_by_field_to_entities.php @@ -0,0 +1,49 @@ +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'); + }); + } +} diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index 485ecb7bc..5e6a63deb 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -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', diff --git a/resources/views/partials/entity-meta.blade.php b/resources/views/partials/entity-meta.blade.php index f759ea25b..8996df9bb 100644 --- a/resources/views/partials/entity-meta.blade.php +++ b/resources/views/partials/entity-meta.blade.php @@ -1,34 +1,50 @@
@if($entity->isA('revision')) - @icon('history'){{ trans('entities.pages_revision') }} - {{ trans('entities.pages_revisions_number') }}{{ $entity->revision_number == 0 ? '' : $entity->revision_number }} -
+
+ @icon('history'){{ trans('entities.pages_revision') }} + {{ trans('entities.pages_revisions_number') }}{{ $entity->revision_number == 0 ? '' : $entity->revision_number }} +
@endif @if ($entity->isA('page')) - @if (userCan('page-update', $entity)) @endif - @icon('history'){{ trans('entities.meta_revision', ['revisionCount' => $entity->revision_count]) }}
+
+ @if (userCan('page-update', $entity)) @endif + @icon('history'){{ trans('entities.meta_revision', ['revisionCount' => $entity->revision_count]) }} @if (userCan('page-update', $entity))@endif +
@endif + @if ($entity->ownedBy && $entity->ownedBy->id !== $entity->createdBy->id) +
+ @icon('user'){!! trans('entities.meta_owned_name', [ + 'user' => "".e($entity->ownedBy->name). "" + ]) !!} +
+ @endif @if ($entity->createdBy) - @icon('star'){!! trans('entities.meta_created_name', [ +
+ @icon('star'){!! trans('entities.meta_created_name', [ 'timeLength' => ''.$entity->created_at->diffForHumans() . '', - 'user' => "".htmlentities($entity->createdBy->name). "" + 'user' => "".e($entity->createdBy->name). "" ]) !!} +
@else - @icon('star'){{ trans('entities.meta_created', ['timeLength' => $entity->created_at->diffForHumans()]) }} +
+ @icon('star'){{ trans('entities.meta_created', ['timeLength' => $entity->created_at->diffForHumans()]) }} +
@endif -
- @if ($entity->updatedBy) - @icon('edit'){!! trans('entities.meta_updated_name', [ +
+ @icon('edit'){!! trans('entities.meta_updated_name', [ 'timeLength' => '' . $entity->updated_at->diffForHumans() .'', - 'user' => "".htmlentities($entity->updatedBy->name). "" + 'user' => "".e($entity->updatedBy->name). "" ]) !!} +
@elseif (!$entity->isA('revision')) - @icon('edit'){{ trans('entities.meta_updated', ['timeLength' => $entity->updated_at->diffForHumans()]) }} +
+ @icon('edit'){{ trans('entities.meta_updated', ['timeLength' => $entity->updated_at->diffForHumans()]) }} +
@endif
\ No newline at end of file