feat: use xpier media library for uploads and markdown embeds
Store media:ID in article bodies instead of CDN URLs, and keep sablog attach tokens as a fallback. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Domain\Blog\ContentFormat;
|
||||
use App\Domain\Blog\ContentRenderer;
|
||||
use App\Domain\Media\ArticleCoverService;
|
||||
use App\Models\Article;
|
||||
use App\Models\Category;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Tests\TestCase;
|
||||
use Xpier\FilamentMediaLibrary\Models\MediaLibrary;
|
||||
|
||||
class MarkdownMediaLibraryTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_markdown_body_renders_media_protocol_to_image_without_storing_url(): void
|
||||
{
|
||||
$media = $this->createLibraryImage(12, 'Hero shot');
|
||||
$article = $this->makeArticle([
|
||||
'content' => "Intro\n\n\n",
|
||||
'content_format' => ContentFormat::MARKDOWN,
|
||||
]);
|
||||
|
||||
$html = app(ContentRenderer::class)->toHtml(
|
||||
(string) $article->content,
|
||||
ContentFormat::MARKDOWN,
|
||||
$article->id,
|
||||
);
|
||||
|
||||
$this->assertStringContainsString((string) $media->url, $html);
|
||||
$this->assertStringContainsString('<img', $html);
|
||||
$this->assertStringNotContainsString('media:'.$media->id, $html);
|
||||
$this->assertStringContainsString("", (string) $article->fresh()->content);
|
||||
}
|
||||
|
||||
public function test_html_body_hydrates_media_shortcode(): void
|
||||
{
|
||||
$media = $this->createLibraryImage(21, 'Inline');
|
||||
$html = app(ContentRenderer::class)->toHtml(
|
||||
'<p>see [media='.$media->id.']</p>',
|
||||
ContentFormat::HTML,
|
||||
);
|
||||
|
||||
$this->assertStringContainsString((string) $media->url, $html);
|
||||
$this->assertStringNotContainsString('[media='.$media->id.']', $html);
|
||||
}
|
||||
|
||||
public function test_article_page_shows_library_image_and_cover(): void
|
||||
{
|
||||
$media = $this->createLibraryImage(33, 'Cover art');
|
||||
$article = $this->makeArticle([
|
||||
'content' => "",
|
||||
'content_format' => ContentFormat::MARKDOWN,
|
||||
'cover_media_id' => $media->id,
|
||||
]);
|
||||
|
||||
$this->get('/show-'.$article->id.'.shtml')
|
||||
->assertOk()
|
||||
->assertSee((string) $media->url, false)
|
||||
->assertDontSee('media:'.$media->id, false);
|
||||
|
||||
$article->refresh();
|
||||
$this->assertTrue($article->hasCover());
|
||||
$this->assertSame((string) $media->url, $article->coverUrl());
|
||||
}
|
||||
|
||||
public function test_auto_cover_prefers_media_protocol_in_markdown(): void
|
||||
{
|
||||
$media = $this->createLibraryImage(44, 'First image');
|
||||
$article = $this->makeArticle([
|
||||
'content' => "Hello\n\n\n",
|
||||
'content_format' => ContentFormat::MARKDOWN,
|
||||
]);
|
||||
|
||||
app(ArticleCoverService::class)->apply($article, 'from_content');
|
||||
$article->refresh();
|
||||
|
||||
$this->assertTrue($article->hasCover());
|
||||
$this->assertSame(ArticleCoverService::SOURCE_CONTENT_IMAGE, $article->cover_source);
|
||||
$this->assertSame((string) $media->url, $article->cover_path);
|
||||
}
|
||||
|
||||
public function test_admin_media_library_pages_load(): void
|
||||
{
|
||||
Role::findOrCreate('admin');
|
||||
$admin = User::factory()->create([
|
||||
'email' => 'admin-media@larablog.test',
|
||||
]);
|
||||
$admin->assignRole('admin');
|
||||
|
||||
$this->actingAs($admin)->get('/admin/media-library')->assertOk();
|
||||
$this->actingAs($admin)->get('/admin/media-folders')->assertOk();
|
||||
$this->actingAs($admin)->get('/admin/articles/create')
|
||||
->assertOk()
|
||||
->assertSee('media:ID', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $overrides
|
||||
*/
|
||||
protected function makeArticle(array $overrides = []): Article
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$category = Category::query()->create(['name' => 'Media', 'display_order' => 0]);
|
||||
|
||||
return Article::query()->create(array_merge([
|
||||
'category_id' => $category->id,
|
||||
'user_id' => $user->id,
|
||||
'title' => 'Media post',
|
||||
'content' => 'Body',
|
||||
'content_format' => ContentFormat::MARKDOWN,
|
||||
'published_at' => now()->subMinute(),
|
||||
'visible' => true,
|
||||
], $overrides));
|
||||
}
|
||||
|
||||
private function createLibraryImage(int $id, string $alt): MediaLibrary
|
||||
{
|
||||
$media = new MediaLibrary;
|
||||
$media->forceFill([
|
||||
'id' => $id,
|
||||
'disk' => 'public',
|
||||
'path' => 'media/library/articles/image/test-'.$id.'.jpg',
|
||||
'original_name' => 'test-'.$id.'.jpg',
|
||||
'extension' => 'jpg',
|
||||
'mime_type' => 'image/jpeg',
|
||||
'size' => 128,
|
||||
'type' => MediaLibrary::TYPE_IMAGE,
|
||||
'source' => MediaLibrary::SOURCE_ADMIN,
|
||||
'folder' => 'articles',
|
||||
'alt_text' => $alt,
|
||||
]);
|
||||
$media->save();
|
||||
|
||||
return $media->fresh();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user