feat: use xpier media library for uploads and markdown embeds

Store media:ID in post 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:
gouki
2026-09-16 19:03:52 +00:00
co-authored by Cursor
parent f6a9a8ea50
commit f81397a289
38 changed files with 5390 additions and 2059 deletions
@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
if (! Schema::hasColumn('posts', 'cover_media_id')) {
Schema::table('posts', function (Blueprint $table): void {
$table->unsignedBigInteger('cover_media_id')->nullable()->after('keywords');
});
}
if (! Schema::hasColumn('categories', 'cover_media_id')) {
Schema::table('categories', function (Blueprint $table): void {
$table->unsignedBigInteger('cover_media_id')->nullable()->after('description');
});
}
}
public function down(): void
{
if (Schema::hasColumn('posts', 'cover_media_id')) {
Schema::table('posts', function (Blueprint $table): void {
$table->dropColumn('cover_media_id');
});
}
if (Schema::hasColumn('categories', 'cover_media_id')) {
Schema::table('categories', function (Blueprint $table): void {
$table->dropColumn('cover_media_id');
});
}
}
};
@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
if (! Schema::hasTable('media_folders')) {
return;
}
$now = now();
$folders = [
['code' => 'general', 'name' => 'General', 'sort' => 0],
['code' => 'articles', 'name' => 'Articles', 'sort' => 1],
['code' => 'banners', 'name' => 'Banners', 'sort' => 2],
];
foreach ($folders as $folder) {
$exists = DB::table('media_folders')->where('code', $folder['code'])->exists();
if ($exists) {
continue;
}
DB::table('media_folders')->insert([
'parent_id' => null,
'code' => $folder['code'],
'name' => $folder['name'],
'sort' => $folder['sort'],
'is_active' => true,
'created_at' => $now,
'updated_at' => $now,
]);
}
}
public function down(): void
{
if (! Schema::hasTable('media_folders')) {
return;
}
DB::table('media_folders')
->whereIn('code', ['general', 'articles', 'banners'])
->whereNull('parent_id')
->delete();
}
};