<?php namespace BookStack\Actions;
-use BookStack\Ownable;
+use BookStack\Model;
+use BookStack\Traits\HasCreatorAndUpdater;
+use Illuminate\Database\Eloquent\Relations\MorphTo;
/**
* @property string text
* @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;
}
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;
});
// 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);
});
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']);
}]);
}
});
// 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);
});
'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';
$query->where('has_permission', '=', 1)
->orWhere(function ($query2) use ($userId) {
$query2->where('has_permission_own', '=', 1)
- ->where('created_by', '=', $userId);
+ ->where('owned_by', '=', $userId);
});
});
$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);
});
});
});
$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);
});
});
});
$query->where('draft', '=', false)
->orWhere(function (Builder $query) {
$query->where('draft', '=', true)
- ->where('created_by', '=', $this->currentUser()->id);
+ ->where('owned_by', '=', $this->currentUser()->id);
});
});
}
$query->where('draft', '=', false)
->orWhere(function ($query) {
$query->where('draft', '=', true)
- ->where('created_by', '=', $this->currentUser()->id);
+ ->where('owned_by', '=', $this->currentUser()->id);
});
});
}
->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);
});
});
});
->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);
});
});
});
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;
* @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
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;
/**
* 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();
-<?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');
}
--- /dev/null
+<?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');
+ }
+
+}
<?php namespace BookStack\Uploads;
use BookStack\Entities\Models\Page;
-use BookStack\Ownable;
+use BookStack\Model;
+use BookStack\Traits\HasCreatorAndUpdater;
/**
* @property int id
* @property string extension
* @property bool external
*/
-class Attachment extends Ownable
+class Attachment extends Model
{
+ use HasCreatorAndUpdater;
+
protected $fillable = ['name', 'order'];
/**
<?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 = [];
use BookStack\Auth\Permissions\PermissionService;
use BookStack\Auth\User;
-use BookStack\Ownable;
+use BookStack\Model;
use BookStack\Settings\SettingService;
/**
* 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);
--- /dev/null
+<?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');
+ });
+ }
+}
'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',
<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>
\ No newline at end of file