fix: add factories, fix HtmlSanitiser HTML5 elements, fix TestCase
- Create Database/Factories for ContentWebhookEndpoint, ContentWebhookLog, ContentItem, ContentTaxonomy, ContentBrief - Register HTML5 elements (section, article, figure, figcaption, mark) with HTMLPurifier custom definitions - Use RefreshDatabase trait in TestCase with SQLite in-memory DB - Update Pest.php to use custom Tests\TestCase Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4d66f0b101
commit
e7e7e5be89
8 changed files with 175 additions and 9 deletions
24
Database/Factories/ContentBriefFactory.php
Normal file
24
Database/Factories/ContentBriefFactory.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Content\Database\Factories;
|
||||
|
||||
use Core\Mod\Content\Models\ContentBrief;
|
||||
use Core\Tenant\Models\Workspace;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class ContentBriefFactory extends Factory
|
||||
{
|
||||
protected $model = ContentBrief::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'workspace_id' => Workspace::factory(),
|
||||
'title' => $this->faker->sentence(),
|
||||
'description' => $this->faker->paragraph(),
|
||||
'status' => ContentBrief::STATUS_PENDING,
|
||||
];
|
||||
}
|
||||
}
|
||||
29
Database/Factories/ContentItemFactory.php
Normal file
29
Database/Factories/ContentItemFactory.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Content\Database\Factories;
|
||||
|
||||
use Core\Mod\Content\Enums\ContentType;
|
||||
use Core\Mod\Content\Models\ContentItem;
|
||||
use Core\Tenant\Models\Workspace;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class ContentItemFactory extends Factory
|
||||
{
|
||||
protected $model = ContentItem::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'workspace_id' => Workspace::factory(),
|
||||
'content_type' => ContentType::NATIVE->value,
|
||||
'type' => 'post',
|
||||
'status' => 'publish',
|
||||
'slug' => $this->faker->slug(),
|
||||
'title' => $this->faker->sentence(),
|
||||
'excerpt' => $this->faker->paragraph(),
|
||||
'content_html' => '<p>' . $this->faker->paragraphs(3, true) . '</p>',
|
||||
];
|
||||
}
|
||||
}
|
||||
25
Database/Factories/ContentTaxonomyFactory.php
Normal file
25
Database/Factories/ContentTaxonomyFactory.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Content\Database\Factories;
|
||||
|
||||
use Core\Mod\Content\Models\ContentTaxonomy;
|
||||
use Core\Tenant\Models\Workspace;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class ContentTaxonomyFactory extends Factory
|
||||
{
|
||||
protected $model = ContentTaxonomy::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'workspace_id' => Workspace::factory(),
|
||||
'type' => $this->faker->randomElement(['category', 'tag']),
|
||||
'name' => $this->faker->word(),
|
||||
'slug' => $this->faker->slug(),
|
||||
'count' => $this->faker->numberBetween(0, 100),
|
||||
];
|
||||
}
|
||||
}
|
||||
42
Database/Factories/ContentWebhookEndpointFactory.php
Normal file
42
Database/Factories/ContentWebhookEndpointFactory.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Content\Database\Factories;
|
||||
|
||||
use Core\Mod\Content\Models\ContentWebhookEndpoint;
|
||||
use Core\Tenant\Models\Workspace;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class ContentWebhookEndpointFactory extends Factory
|
||||
{
|
||||
protected $model = ContentWebhookEndpoint::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'workspace_id' => Workspace::factory(),
|
||||
'name' => $this->faker->company(),
|
||||
'secret' => $this->faker->sha256(),
|
||||
'require_signature' => true,
|
||||
'allowed_types' => [],
|
||||
'is_enabled' => true,
|
||||
'failure_count' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
public function circuitBroken(): static
|
||||
{
|
||||
return $this->state([
|
||||
'failure_count' => ContentWebhookEndpoint::MAX_FAILURES,
|
||||
'is_enabled' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
public function disabled(): static
|
||||
{
|
||||
return $this->state([
|
||||
'is_enabled' => false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
31
Database/Factories/ContentWebhookLogFactory.php
Normal file
31
Database/Factories/ContentWebhookLogFactory.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Content\Database\Factories;
|
||||
|
||||
use Core\Mod\Content\Models\ContentWebhookEndpoint;
|
||||
use Core\Mod\Content\Models\ContentWebhookLog;
|
||||
use Core\Tenant\Models\Workspace;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class ContentWebhookLogFactory extends Factory
|
||||
{
|
||||
protected $model = ContentWebhookLog::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'workspace_id' => Workspace::factory(),
|
||||
'endpoint_id' => ContentWebhookEndpoint::factory(),
|
||||
'event_type' => $this->faker->randomElement([
|
||||
'wordpress.post_created',
|
||||
'wordpress.post_updated',
|
||||
'cms.content_created',
|
||||
]),
|
||||
'payload' => ['title' => $this->faker->sentence()],
|
||||
'status' => 'pending',
|
||||
'source_ip' => $this->faker->ipv4(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -97,12 +97,16 @@ class HtmlSanitiser
|
|||
$config->set('HTML.Nofollow', true);
|
||||
$config->set('HTML.TargetNoopener', true);
|
||||
|
||||
// Disable cache in development, enable via config in production
|
||||
$cacheDir = config('content.purifier_cache_dir');
|
||||
if ($cacheDir && is_dir($cacheDir) && is_writable($cacheDir)) {
|
||||
$config->set('Cache.SerializerPath', $cacheDir);
|
||||
} else {
|
||||
$config->set('Cache.DefinitionImpl', null);
|
||||
// Disable cache to allow custom HTML definitions
|
||||
$config->set('Cache.DefinitionImpl', null);
|
||||
|
||||
// Register HTML5 elements that HTMLPurifier doesn't know about
|
||||
if ($def = $config->maybeGetRawHTMLDefinition()) {
|
||||
$def->addElement('section', 'Block', 'Flow', 'Common');
|
||||
$def->addElement('article', 'Block', 'Flow', 'Common');
|
||||
$def->addElement('figure', 'Block', 'Flow', 'Common');
|
||||
$def->addElement('figcaption', 'Inline', 'Flow', 'Common');
|
||||
$def->addElement('mark', 'Inline', 'Inline', 'Common');
|
||||
}
|
||||
|
||||
// Safe URI schemes only
|
||||
|
|
|
|||
|
|
@ -2,6 +2,4 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Orchestra\Testbench\TestCase;
|
||||
|
||||
uses(TestCase::class)->in('Feature', 'Unit');
|
||||
uses(Tests\TestCase::class)->in('Feature', 'Unit');
|
||||
|
|
|
|||
|
|
@ -4,10 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace Tests;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Orchestra\Testbench\TestCase as BaseTestCase;
|
||||
|
||||
abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function getPackageProviders($app): array
|
||||
{
|
||||
return [
|
||||
|
|
@ -15,4 +18,14 @@ abstract class TestCase extends BaseTestCase
|
|||
\Core\Mod\Content\Boot::class,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getEnvironmentSetUp($app): void
|
||||
{
|
||||
$app['config']->set('database.default', 'testing');
|
||||
$app['config']->set('database.connections.testing', [
|
||||
'driver' => 'sqlite',
|
||||
'database' => ':memory:',
|
||||
'prefix' => '',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue