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\Activity\Models\Comment;
|
||||||
use BookStack\Entities\Models\Entity;
|
use BookStack\Entities\Models\Entity;
|
||||||
use BookStack\Exceptions\NotifyException;
|
use BookStack\Exceptions\NotifyException;
|
||||||
use BookStack\Exceptions\PrettyException;
|
|
||||||
use BookStack\Facades\Activity as ActivityService;
|
use BookStack\Facades\Activity as ActivityService;
|
||||||
use BookStack\Util\HtmlDescriptionFilter;
|
use BookStack\Util\HtmlDescriptionFilter;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
|
||||||
class CommentRepo
|
class CommentRepo
|
||||||
{
|
{
|
||||||
@@ -19,6 +19,14 @@ class CommentRepo
|
|||||||
return Comment::query()->findOrFail($id);
|
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.
|
* 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;
|
namespace BookStack\Activity\Models;
|
||||||
|
|
||||||
use BookStack\App\Model;
|
use BookStack\App\Model;
|
||||||
|
use BookStack\Permissions\Models\JointPermission;
|
||||||
|
use BookStack\Permissions\PermissionApplicator;
|
||||||
use BookStack\Users\Models\HasCreatorAndUpdater;
|
use BookStack\Users\Models\HasCreatorAndUpdater;
|
||||||
use BookStack\Users\Models\OwnableInterface;
|
use BookStack\Users\Models\OwnableInterface;
|
||||||
use BookStack\Users\Models\User;
|
|
||||||
use BookStack\Util\HtmlContentFilter;
|
use BookStack\Util\HtmlContentFilter;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,8 +20,8 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
|
|||||||
* @property string $html
|
* @property string $html
|
||||||
* @property int|null $parent_id - Relates to local_id, not id
|
* @property int|null $parent_id - Relates to local_id, not id
|
||||||
* @property int $local_id
|
* @property int $local_id
|
||||||
* @property string $entity_type
|
* @property string $commentable_type
|
||||||
* @property int $entity_id
|
* @property int $commentable_id
|
||||||
* @property string $content_ref
|
* @property string $content_ref
|
||||||
* @property bool $archived
|
* @property bool $archived
|
||||||
*/
|
*/
|
||||||
@@ -44,8 +47,8 @@ class Comment extends Model implements Loggable, OwnableInterface
|
|||||||
public function parent(): BelongsTo
|
public function parent(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Comment::class, 'parent_id', 'local_id', 'parent')
|
return $this->belongsTo(Comment::class, 'parent_id', 'local_id', 'parent')
|
||||||
->where('entity_type', '=', $this->entity_type)
|
->where('commentable_type', '=', $this->commentable_type)
|
||||||
->where('entity_id', '=', $this->entity_id);
|
->where('commentable_id', '=', $this->commentable_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,11 +61,27 @@ class Comment extends Model implements Loggable, OwnableInterface
|
|||||||
|
|
||||||
public function logDescriptor(): string
|
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
|
public function safeHtml(): string
|
||||||
{
|
{
|
||||||
return HtmlContentFilter::removeScriptsFromHtmlString($this->html ?? '');
|
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
|
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;
|
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"
|
* Controllers all end with "ApiController"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use BookStack\Activity\Controllers\AuditLogApiController;
|
use BookStack\Activity\Controllers as ActivityControllers;
|
||||||
use BookStack\Api\ApiDocsController;
|
use BookStack\Api\ApiDocsController;
|
||||||
use BookStack\App\SystemApiController;
|
use BookStack\App\SystemApiController;
|
||||||
use BookStack\Entities\Controllers as EntityControllers;
|
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('search', [SearchApiController::class, 'all']);
|
||||||
|
|
||||||
|
Route::get('comments', [ActivityControllers\CommentApiController::class, 'list']);
|
||||||
|
|
||||||
Route::get('shelves', [EntityControllers\BookshelfApiController::class, 'list']);
|
Route::get('shelves', [EntityControllers\BookshelfApiController::class, 'list']);
|
||||||
Route::post('shelves', [EntityControllers\BookshelfApiController::class, 'create']);
|
Route::post('shelves', [EntityControllers\BookshelfApiController::class, 'create']);
|
||||||
Route::get('shelves/{id}', [EntityControllers\BookshelfApiController::class, 'read']);
|
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::get('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'read']);
|
||||||
Route::put('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'update']);
|
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']);
|
Route::get('system', [SystemApiController::class, 'read']);
|
||||||
|
|||||||
Reference in New Issue
Block a user