mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-10-25 06:37:36 +03:00
API: Started building comments API endpoints
This commit is contained in:
@@ -5,9 +5,9 @@ namespace BookStack\Activity;
|
||||
use BookStack\Activity\Models\Comment;
|
||||
use BookStack\Entities\Models\Entity;
|
||||
use BookStack\Exceptions\NotifyException;
|
||||
use BookStack\Exceptions\PrettyException;
|
||||
use BookStack\Facades\Activity as ActivityService;
|
||||
use BookStack\Util\HtmlDescriptionFilter;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class CommentRepo
|
||||
{
|
||||
@@ -19,6 +19,14 @@ class CommentRepo
|
||||
return Comment::query()->findOrFail($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a query for comments visible to the user.
|
||||
*/
|
||||
public function getQueryForVisible(): Builder
|
||||
{
|
||||
return Comment::query()->scopes('visible');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new comment on an entity.
|
||||
*/
|
||||
|
||||
43
app/Activity/Controllers/CommentApiController.php
Normal file
43
app/Activity/Controllers/CommentApiController.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BookStack\Activity\Controllers;
|
||||
|
||||
use BookStack\Activity\CommentRepo;
|
||||
use BookStack\Http\ApiController;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class CommentApiController extends ApiController
|
||||
{
|
||||
// TODO - Add tree-style comment listing to page-show responses.
|
||||
// TODO - list
|
||||
// TODO - create
|
||||
// TODO - read
|
||||
// TODO - update
|
||||
// TODO - delete
|
||||
|
||||
// TODO - Test visibility controls
|
||||
// TODO - Test permissions of each action
|
||||
|
||||
// TODO - Support intro block for API docs so we can explain the
|
||||
// properties for comments in a shared kind of way?
|
||||
|
||||
public function __construct(
|
||||
protected CommentRepo $commentRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a listing of comments visible to the user.
|
||||
*/
|
||||
public function list(): JsonResponse
|
||||
{
|
||||
$query = $this->commentRepo->getQueryForVisible();
|
||||
|
||||
return $this->apiListingResponse($query, [
|
||||
'id', 'commentable_id', 'commentable_type', 'parent_id', 'local_id', 'content_ref', 'created_by', 'updated_by', 'created_at', 'updated_at'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,15 @@
|
||||
namespace BookStack\Activity\Models;
|
||||
|
||||
use BookStack\App\Model;
|
||||
use BookStack\Permissions\Models\JointPermission;
|
||||
use BookStack\Permissions\PermissionApplicator;
|
||||
use BookStack\Users\Models\HasCreatorAndUpdater;
|
||||
use BookStack\Users\Models\OwnableInterface;
|
||||
use BookStack\Users\Models\User;
|
||||
use BookStack\Util\HtmlContentFilter;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
/**
|
||||
@@ -17,8 +20,8 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
* @property string $html
|
||||
* @property int|null $parent_id - Relates to local_id, not id
|
||||
* @property int $local_id
|
||||
* @property string $entity_type
|
||||
* @property int $entity_id
|
||||
* @property string $commentable_type
|
||||
* @property int $commentable_id
|
||||
* @property string $content_ref
|
||||
* @property bool $archived
|
||||
*/
|
||||
@@ -44,8 +47,8 @@ class Comment extends Model implements Loggable, OwnableInterface
|
||||
public function parent(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Comment::class, 'parent_id', 'local_id', 'parent')
|
||||
->where('entity_type', '=', $this->entity_type)
|
||||
->where('entity_id', '=', $this->entity_id);
|
||||
->where('commentable_type', '=', $this->commentable_type)
|
||||
->where('commentable_id', '=', $this->commentable_id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,11 +61,27 @@ class Comment extends Model implements Loggable, OwnableInterface
|
||||
|
||||
public function logDescriptor(): string
|
||||
{
|
||||
return "Comment #{$this->local_id} (ID: {$this->id}) for {$this->entity_type} (ID: {$this->entity_id})";
|
||||
return "Comment #{$this->local_id} (ID: {$this->id}) for {$this->commentable_type} (ID: {$this->commentable_id})";
|
||||
}
|
||||
|
||||
public function safeHtml(): string
|
||||
{
|
||||
return HtmlContentFilter::removeScriptsFromHtmlString($this->html ?? '');
|
||||
}
|
||||
|
||||
public function jointPermissions(): HasMany
|
||||
{
|
||||
return $this->hasMany(JointPermission::class, 'entity_id', 'commentable_id')
|
||||
->whereColumn('joint_permissions.entity_type', '=', 'comments.commentable_type');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope the query to just the comments visible to the user based upon the
|
||||
* user visibility of what has been commented on.
|
||||
*/
|
||||
public function scopeVisible(Builder $query): Builder
|
||||
{
|
||||
return app()->make(PermissionApplicator::class)
|
||||
->restrictEntityRelationQuery($query, 'comments', 'commentable_id', 'commentable_type');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ abstract class Entity extends Model implements
|
||||
*/
|
||||
public function comments(bool $orderByCreated = true): MorphMany
|
||||
{
|
||||
$query = $this->morphMany(Comment::class, 'entity');
|
||||
$query = $this->morphMany(Comment::class, 'commentable');
|
||||
|
||||
return $orderByCreated ? $query->orderBy('created_at', 'asc') : $query;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('comments', function (Blueprint $table) {
|
||||
$table->renameColumn('entity_id', 'commentable_id');
|
||||
$table->renameColumn('entity_type', 'commentable_type');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('comments', function (Blueprint $table) {
|
||||
$table->renameColumn('commentable_id', 'entity_id');
|
||||
$table->renameColumn('commentable_type', 'entity_type');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -6,7 +6,7 @@
|
||||
* Controllers all end with "ApiController"
|
||||
*/
|
||||
|
||||
use BookStack\Activity\Controllers\AuditLogApiController;
|
||||
use BookStack\Activity\Controllers as ActivityControllers;
|
||||
use BookStack\Api\ApiDocsController;
|
||||
use BookStack\App\SystemApiController;
|
||||
use BookStack\Entities\Controllers as EntityControllers;
|
||||
@@ -70,6 +70,8 @@ Route::delete('image-gallery/{id}', [ImageGalleryApiController::class, 'delete']
|
||||
|
||||
Route::get('search', [SearchApiController::class, 'all']);
|
||||
|
||||
Route::get('comments', [ActivityControllers\CommentApiController::class, 'list']);
|
||||
|
||||
Route::get('shelves', [EntityControllers\BookshelfApiController::class, 'list']);
|
||||
Route::post('shelves', [EntityControllers\BookshelfApiController::class, 'create']);
|
||||
Route::get('shelves/{id}', [EntityControllers\BookshelfApiController::class, 'read']);
|
||||
@@ -101,6 +103,6 @@ Route::delete('recycle-bin/{deletionId}', [EntityControllers\RecycleBinApiContro
|
||||
Route::get('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'read']);
|
||||
Route::put('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'update']);
|
||||
|
||||
Route::get('audit-log', [AuditLogApiController::class, 'list']);
|
||||
Route::get('audit-log', [ActivityControllers\AuditLogApiController::class, 'list']);
|
||||
|
||||
Route::get('system', [SystemApiController::class, 'read']);
|
||||
|
||||
Reference in New Issue
Block a user