feat: add admin env badge, quick post button, and harden plugin enable
Show local/prod in the Filament topbar, jump to create post in one click, tighten sidebar spacing, and stop Hello World from 500ing when its tables are missing. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-09-17
|
||||
|
||||
- Admin top-right now shows the current environment (`local` / `prod`) and a **写文章** shortcut to create a post.
|
||||
- Tightened Filament sidebar vertical spacing (correct `fi-sidebar-item-btn` selectors + smaller group gaps).
|
||||
- Hello World plugin: enable runs plugin migrations; missing `hello_world_logs` no longer 500s the demo page; plugin boot/hooks are isolated.
|
||||
|
||||
## 2026-09-16
|
||||
|
||||
- Switched new attachments/covers to `xpier/filament-media-library`.
|
||||
|
||||
+12
@@ -12,6 +12,18 @@ Modern blog migrated from SaBlog-X: Filament admin, themes, plugins, sablog impo
|
||||
|
||||
See `README.md` and `docs/` for install, import, plugins, and themes.
|
||||
|
||||
## Admin chrome
|
||||
|
||||
- Top-right badge shows the current app environment (`local` / `prod` / others).
|
||||
- Top-right **写文章** button jumps to `/admin/posts/create`.
|
||||
- Sidebar nav is compacted (Filament default `gap-y-7` / `py-8` is too tall for this site).
|
||||
|
||||
## Hello World plugin
|
||||
|
||||
- Enabling a plugin now runs that plugin's `database/migrations` automatically.
|
||||
- Plugin boot / hook failures are isolated so one plugin cannot take down the whole admin.
|
||||
- `/hello-world` stays available even if `hello_world_logs` is missing.
|
||||
|
||||
## Media library (xpier)
|
||||
|
||||
- Package: `xpier/filament-media-library` (admin Media Library + MediaPicker).
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
- **脚本迁移**:`php artisan sablog:import` 一键从老库迁入全部数据(文章/分类/评论/标签/友链/用户/附件),保留原始 ID,老 URL 全部 301 兼容
|
||||
- **多主题**:`themes/` 目录即皮肤,后台一键切换/上传 ZIP;内置 sablog 经典风 + modern 简约风两套
|
||||
- **插件系统**:`plugins/` 目录 + 钩子系统(action/filter),ZIP 安装 + 可选远程市场
|
||||
- **插件系统**:`plugins/` 目录 + 钩子系统(action/filter),ZIP 安装 + 可选远程市场;启用时自动跑插件迁移
|
||||
- **后台顶栏**:右上角显示当前环境(local/prod)+ 一键写文章
|
||||
- **内置插件**:SEO & GEO(JSON-LD/OG/llms.txt/Markdown 导出)、AI 评论审核 + 内容润色(Workerman 异步)、支付(支付宝/微信/沙箱)、会员(套餐订阅 + 付费文章)
|
||||
- **附件全走 S3**:R2 / COS / OSS 兼容,新上传零落盘,`attachments:sync-s3` 一键同步老附件(大文件 Multipart)
|
||||
|
||||
|
||||
@@ -45,7 +45,11 @@ class PluginManagerServiceProvider extends ServiceProvider
|
||||
$provider = $manager->resolveProvider($key);
|
||||
|
||||
if ($provider && class_exists($provider)) {
|
||||
$provider::bootPlugin($manager);
|
||||
try {
|
||||
$provider::bootPlugin($manager);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ class PostContentRenderer
|
||||
|
||||
// 插件钩子:付费内容过滤、AI 处理等
|
||||
$html = app(\App\Blog\Support\PluginManager::class)->applyFilters('post.rendered', $html, $post);
|
||||
$html = is_string($html) ? $html : '';
|
||||
|
||||
// 兜底:任何情况下不把裸 [paid] 标签输出到页面(如会员插件被停用时)
|
||||
return preg_replace('/\[(\/?paid)\]/i', '', $html);
|
||||
|
||||
@@ -6,6 +6,7 @@ declare(strict_types=1);
|
||||
namespace App\Blog\Support;
|
||||
|
||||
use App\Models\PluginRecord;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
use RuntimeException;
|
||||
@@ -155,6 +156,8 @@ class PluginManager
|
||||
throw new RuntimeException('无法启用 '.$plugin.':'.implode(';', $problems));
|
||||
}
|
||||
|
||||
$this->migratePlugin($plugin);
|
||||
|
||||
[$vendor, $name] = array_pad(explode('.', $plugin), 2, $plugin);
|
||||
PluginRecord::query()->updateOrCreate(
|
||||
['vendor' => $vendor, 'name' => $name],
|
||||
@@ -162,6 +165,29 @@ class PluginManager
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the plugin's own migrations so enabling a demo/third-party plugin
|
||||
* does not 500 on missing tables.
|
||||
*/
|
||||
public function migratePlugin(string $plugin): void
|
||||
{
|
||||
$relativePath = 'plugins/'.$plugin.'/database/migrations';
|
||||
|
||||
if (! is_dir(base_path($relativePath))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$exitCode = Artisan::call('migrate', [
|
||||
'--path' => $relativePath,
|
||||
'--force' => true,
|
||||
'--no-interaction' => true,
|
||||
]);
|
||||
|
||||
if ($exitCode !== 0) {
|
||||
throw new RuntimeException('插件迁移失败:'.$plugin.'。'.trim(Artisan::output()));
|
||||
}
|
||||
}
|
||||
|
||||
public function disable(string $plugin): void
|
||||
{
|
||||
$dependents = $this->dependents($plugin);
|
||||
@@ -243,7 +269,11 @@ class PluginManager
|
||||
{
|
||||
foreach ($this->actions[$hook] ?? [] as $callbacks) {
|
||||
foreach ($callbacks as $callback) {
|
||||
$callback(...$args);
|
||||
try {
|
||||
$callback(...$args);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,7 +282,11 @@ class PluginManager
|
||||
{
|
||||
foreach ($this->filters[$hook] ?? [] as $callbacks) {
|
||||
foreach ($callbacks as $callback) {
|
||||
$value = $callback($value, ...$args);
|
||||
try {
|
||||
$value = $callback($value, ...$args);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Support;
|
||||
|
||||
/**
|
||||
* Admin top-right environment badge: local stays local, production shows as prod.
|
||||
*/
|
||||
class AdminEnvironment
|
||||
{
|
||||
public static function name(): string
|
||||
{
|
||||
$environment = app()->environment();
|
||||
|
||||
return match ($environment) {
|
||||
'production', 'prod' => 'prod',
|
||||
default => $environment,
|
||||
};
|
||||
}
|
||||
|
||||
public static function color(): string
|
||||
{
|
||||
return match (app()->environment()) {
|
||||
'production', 'prod' => 'danger',
|
||||
'local' => 'gray',
|
||||
'staging' => 'warning',
|
||||
default => 'info',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -62,13 +62,21 @@ class AppServiceProvider extends ServiceProvider
|
||||
PanelsRenderHook::STYLES_AFTER,
|
||||
fn () => Blade::render(<<<'HTML'
|
||||
<style>
|
||||
.fi-sidebar { padding-inline: 0.75rem; }
|
||||
.fi-sidebar-nav { padding-inline: 0; }
|
||||
.fi-sidebar-nav-groups { margin-inline: 0; }
|
||||
.fi-sidebar-nav .fi-sidebar-item-button { padding-inline: 0.6rem; border-radius: 0.5rem; }
|
||||
.fi-sidebar-nav .fi-sidebar-item-label { font-size: 0.82rem; }
|
||||
.fi-sidebar-nav .fi-sidebar-group-label { font-size: 0.68rem; letter-spacing: 0.04em; }
|
||||
.fi-sidebar-brand { padding-block: 0.9rem; }
|
||||
.ll-topbar-tools { display: flex; align-items: center; gap: 0.45rem; margin-inline-end: 0.15rem; }
|
||||
.ll-env-badge { text-transform: uppercase; letter-spacing: 0.06em; font-weight: 700; }
|
||||
|
||||
.fi-sidebar { padding-inline: 0.65rem; }
|
||||
.fi-sidebar-nav { padding-inline: 0; padding-block: 0.4rem !important; gap: 0.35rem !important; }
|
||||
.fi-sidebar-nav-groups { margin-inline: 0; gap: 0.35rem !important; }
|
||||
.fi-sidebar-group { gap: 0.08rem !important; }
|
||||
.fi-sidebar-group-items { gap: 0.04rem !important; }
|
||||
.fi-sidebar-nav .fi-sidebar-item-btn,
|
||||
.fi-sidebar-nav .fi-sidebar-item-button { padding-inline: 0.55rem; padding-block: 0.26rem !important; min-height: 0 !important; border-radius: 0.45rem; }
|
||||
.fi-sidebar-nav .fi-sidebar-group-btn { padding-block: 0.12rem !important; padding-inline: 0.55rem; }
|
||||
.fi-sidebar-nav .fi-sidebar-item-label { font-size: 0.82rem; line-height: 1.2; }
|
||||
.fi-sidebar-nav .fi-sidebar-group-label { font-size: 0.66rem; letter-spacing: 0.04em; line-height: 1.2; }
|
||||
.fi-sidebar-brand { padding-block: 0.5rem; }
|
||||
.fi-sidebar-header { height: auto !important; min-height: 2.6rem; }
|
||||
|
||||
/* 表格行紧凑:数据行高度由 .fi-ta-text / .fi-ta-icon 的 padding-block 驱动;操作列按钮禁止换行堆叠 */
|
||||
.fi-ta-text, .fi-ta-icon { padding-block: calc(var(--spacing) * 1.75) !important; }
|
||||
|
||||
@@ -21,6 +21,7 @@ use Filament\Pages\Dashboard;
|
||||
use Filament\Panel;
|
||||
use Filament\PanelProvider;
|
||||
use Filament\Support\Colors\Color;
|
||||
use Filament\View\PanelsRenderHook;
|
||||
use Filament\Widgets\AccountWidget;
|
||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||
use Illuminate\Cookie\Middleware\EncryptCookies;
|
||||
@@ -75,6 +76,10 @@ class AdminPanelProvider extends PanelProvider
|
||||
->icon('heroicon-o-squares-plus')
|
||||
->url(fn (): string => \App\Filament\Pages\ThemeInject::getUrl()),
|
||||
])
|
||||
->renderHook(
|
||||
PanelsRenderHook::USER_MENU_BEFORE,
|
||||
fn (): \Illuminate\Contracts\View\View => view('filament.hooks.topbar-tools')
|
||||
)
|
||||
->navigationGroups([
|
||||
NavigationGroup::make('内容'),
|
||||
NavigationGroup::make('管理'),
|
||||
|
||||
@@ -0,0 +1,582 @@
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
DROP TABLE IF EXISTS `cache`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `cache` (
|
||||
`key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`value` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`expiration` int NOT NULL,
|
||||
PRIMARY KEY (`key`),
|
||||
KEY `cache_expiration_index` (`expiration`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `cache_locks`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `cache_locks` (
|
||||
`key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`owner` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`expiration` int NOT NULL,
|
||||
PRIMARY KEY (`key`),
|
||||
KEY `cache_locks_expiration_index` (`expiration`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `categories`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `categories` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`slug` varchar(120) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`display_order` tinyint NOT NULL DEFAULT '0',
|
||||
`description` text COLLATE utf8mb4_unicode_ci,
|
||||
`cover_media_id` bigint unsigned DEFAULT NULL,
|
||||
`post_count` int unsigned NOT NULL DEFAULT '0',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `categories_slug_unique` (`slug`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `comments`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `comments` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`post_id` bigint unsigned NOT NULL,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`author_name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`author_email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`author_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`content` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`ip` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending',
|
||||
`ai_review` json DEFAULT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `comments_user_id_foreign` (`user_id`),
|
||||
KEY `comments_post_id_status_index` (`post_id`,`status`),
|
||||
KEY `comments_status_index` (`status`),
|
||||
CONSTRAINT `comments_post_id_foreign` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `comments_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `failed_jobs`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `failed_jobs` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`uuid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`connection` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`queue` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`exception` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`failed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `failed_jobs_uuid_unique` (`uuid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `hello_world_logs`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `hello_world_logs` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`comment_id` bigint unsigned DEFAULT NULL,
|
||||
`note` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `hello_world_logs_comment_id_foreign` (`comment_id`),
|
||||
CONSTRAINT `hello_world_logs_comment_id_foreign` FOREIGN KEY (`comment_id`) REFERENCES `comments` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `job_batches`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `job_batches` (
|
||||
`id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`total_jobs` int NOT NULL,
|
||||
`pending_jobs` int NOT NULL,
|
||||
`failed_jobs` int NOT NULL,
|
||||
`failed_job_ids` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`options` mediumtext COLLATE utf8mb4_unicode_ci,
|
||||
`cancelled_at` int DEFAULT NULL,
|
||||
`created_at` int NOT NULL,
|
||||
`finished_at` int DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `jobs`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `jobs` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`queue` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`attempts` tinyint unsigned NOT NULL,
|
||||
`reserved_at` int unsigned DEFAULT NULL,
|
||||
`available_at` int unsigned NOT NULL,
|
||||
`created_at` int unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `jobs_queue_index` (`queue`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `links`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `links` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`url` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`note` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`display_order` tinyint NOT NULL DEFAULT '0',
|
||||
`visible` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `market_packages`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `market_packages` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`item_key` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`item_type` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`price` bigint unsigned NOT NULL,
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending',
|
||||
`payment_id` bigint unsigned DEFAULT NULL,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `market_packages_item_key_item_type_unique` (`item_key`,`item_type`),
|
||||
KEY `market_packages_payment_id_foreign` (`payment_id`),
|
||||
KEY `market_packages_user_id_foreign` (`user_id`),
|
||||
CONSTRAINT `market_packages_payment_id_foreign` FOREIGN KEY (`payment_id`) REFERENCES `payments` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `market_packages_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `media`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `media` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`model_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`model_id` bigint unsigned NOT NULL,
|
||||
`uuid` char(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`collection_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`file_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`mime_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`disk` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`conversions_disk` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`size` bigint unsigned NOT NULL,
|
||||
`manipulations` json NOT NULL,
|
||||
`custom_properties` json NOT NULL,
|
||||
`generated_conversions` json NOT NULL,
|
||||
`responsive_images` json NOT NULL,
|
||||
`order_column` int unsigned DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `media_uuid_unique` (`uuid`),
|
||||
KEY `media_model_type_model_id_index` (`model_type`,`model_id`),
|
||||
KEY `media_order_column_index` (`order_column`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `media_folders`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `media_folders` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`parent_id` bigint unsigned DEFAULT NULL,
|
||||
`code` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`sort` int NOT NULL DEFAULT '0',
|
||||
`is_active` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `media_folders_code_unique` (`code`),
|
||||
KEY `media_folders_parent_id_foreign` (`parent_id`),
|
||||
CONSTRAINT `media_folders_parent_id_foreign` FOREIGN KEY (`parent_id`) REFERENCES `media_folders` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `media_library`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `media_library` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`disk` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'public',
|
||||
`path` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`original_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`extension` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`mime_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`size` bigint unsigned NOT NULL DEFAULT '0',
|
||||
`type` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'image',
|
||||
`source` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'admin',
|
||||
`folder` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`alt_text` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`custom_properties` json DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `media_library_path_unique` (`path`),
|
||||
KEY `media_library_user_id_foreign` (`user_id`),
|
||||
KEY `media_library_type_index` (`type`),
|
||||
KEY `media_library_folder_index` (`folder`),
|
||||
KEY `media_library_source_index` (`source`),
|
||||
CONSTRAINT `media_library_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `membership_plans`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `membership_plans` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`slug` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`description` text COLLATE utf8mb4_unicode_ci,
|
||||
`price` bigint unsigned NOT NULL,
|
||||
`duration_days` int unsigned NOT NULL DEFAULT '30',
|
||||
`permissions` json DEFAULT NULL,
|
||||
`active` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`sort` int unsigned NOT NULL DEFAULT '0',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `membership_plans_slug_unique` (`slug`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `migrations`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `migrations` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||
`migration` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`batch` int NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `model_has_permissions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `model_has_permissions` (
|
||||
`permission_id` bigint unsigned NOT NULL,
|
||||
`model_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`model_id` bigint unsigned NOT NULL,
|
||||
PRIMARY KEY (`permission_id`,`model_id`,`model_type`),
|
||||
KEY `model_has_permissions_model_id_model_type_index` (`model_id`,`model_type`),
|
||||
CONSTRAINT `model_has_permissions_permission_id_foreign` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `model_has_roles`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `model_has_roles` (
|
||||
`role_id` bigint unsigned NOT NULL,
|
||||
`model_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`model_id` bigint unsigned NOT NULL,
|
||||
PRIMARY KEY (`role_id`,`model_id`,`model_type`),
|
||||
KEY `model_has_roles_model_id_model_type_index` (`model_id`,`model_type`),
|
||||
CONSTRAINT `model_has_roles_role_id_foreign` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `password_reset_tokens`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `password_reset_tokens` (
|
||||
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`token` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `payments`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `payments` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`order_no` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`subject` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`description` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`amount` bigint unsigned NOT NULL,
|
||||
`channel` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'alipay',
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending',
|
||||
`gateway_trade_no` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`payload` json DEFAULT NULL,
|
||||
`paid_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
`payable_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`payable_id` bigint unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `payments_order_no_unique` (`order_no`),
|
||||
KEY `payments_user_id_status_index` (`user_id`,`status`),
|
||||
KEY `payments_payable_type_payable_id_index` (`payable_type`,`payable_id`),
|
||||
CONSTRAINT `payments_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `permissions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `permissions` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`guard_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `permissions_name_guard_name_unique` (`name`,`guard_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `personal_access_tokens`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `personal_access_tokens` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`tokenable_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`tokenable_id` bigint unsigned NOT NULL,
|
||||
`name` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`token` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`abilities` text COLLATE utf8mb4_unicode_ci,
|
||||
`last_used_at` timestamp NULL DEFAULT NULL,
|
||||
`expires_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `personal_access_tokens_token_unique` (`token`),
|
||||
KEY `personal_access_tokens_tokenable_type_tokenable_id_index` (`tokenable_type`,`tokenable_id`),
|
||||
KEY `personal_access_tokens_expires_at_index` (`expires_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `plugin_records`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `plugin_records` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`vendor` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`name` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`version` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`enabled` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `plugin_records_vendor_name_unique` (`vendor`,`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `posts`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `posts` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`category_id` bigint unsigned DEFAULT NULL,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`slug` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`excerpt` text COLLATE utf8mb4_unicode_ci,
|
||||
`content` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`content_format` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'markdown',
|
||||
`keywords` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`cover_media_id` bigint unsigned DEFAULT NULL,
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'published',
|
||||
`is_sticky` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`close_comment` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`read_password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`views` bigint unsigned NOT NULL DEFAULT '0',
|
||||
`comment_count` int unsigned NOT NULL DEFAULT '0',
|
||||
`meta` json DEFAULT NULL,
|
||||
`published_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `posts_slug_unique` (`slug`),
|
||||
KEY `posts_category_id_foreign` (`category_id`),
|
||||
KEY `posts_user_id_foreign` (`user_id`),
|
||||
KEY `posts_status_published_at_index` (`status`,`published_at`),
|
||||
KEY `posts_status_index` (`status`),
|
||||
KEY `posts_published_at_index` (`published_at`),
|
||||
CONSTRAINT `posts_category_id_foreign` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `posts_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `redirects`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `redirects` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`hash` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`target_url` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`clicks` bigint unsigned NOT NULL DEFAULT '0',
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'active',
|
||||
`last_clicked_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `redirects_hash_unique` (`hash`),
|
||||
KEY `redirects_target_url_index` (`target_url`(191))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `role_has_permissions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `role_has_permissions` (
|
||||
`permission_id` bigint unsigned NOT NULL,
|
||||
`role_id` bigint unsigned NOT NULL,
|
||||
PRIMARY KEY (`permission_id`,`role_id`),
|
||||
KEY `role_has_permissions_role_id_foreign` (`role_id`),
|
||||
CONSTRAINT `role_has_permissions_permission_id_foreign` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `role_has_permissions_role_id_foreign` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `roles`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `roles` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`guard_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `roles_name_guard_name_unique` (`name`,`guard_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `sessions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sessions` (
|
||||
`id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`ip_address` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`user_agent` text COLLATE utf8mb4_unicode_ci,
|
||||
`payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`last_activity` int NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `sessions_user_id_index` (`user_id`),
|
||||
KEY `sessions_last_activity_index` (`last_activity`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `settings`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `settings` (
|
||||
`key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`value` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `subscriptions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `subscriptions` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint unsigned NOT NULL,
|
||||
`membership_plan_id` bigint unsigned DEFAULT NULL,
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'active',
|
||||
`starts_at` timestamp NULL DEFAULT NULL,
|
||||
`ends_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `subscriptions_membership_plan_id_foreign` (`membership_plan_id`),
|
||||
KEY `subscriptions_user_id_status_index` (`user_id`,`status`),
|
||||
CONSTRAINT `subscriptions_membership_plan_id_foreign` FOREIGN KEY (`membership_plan_id`) REFERENCES `membership_plans` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `subscriptions_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `taggables`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `taggables` (
|
||||
`tag_id` bigint unsigned NOT NULL,
|
||||
`taggable_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`taggable_id` bigint unsigned NOT NULL,
|
||||
UNIQUE KEY `taggables_tag_id_taggable_id_taggable_type_unique` (`tag_id`,`taggable_id`,`taggable_type`),
|
||||
KEY `taggables_taggable_type_taggable_id_index` (`taggable_type`,`taggable_id`),
|
||||
CONSTRAINT `taggables_tag_id_foreign` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `tags`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `tags` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` json NOT NULL,
|
||||
`slug` json NOT NULL,
|
||||
`type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`order_column` int DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `users`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `users` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`email_verified_at` timestamp NULL DEFAULT NULL,
|
||||
`password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
`legacy_md5` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`logincount` int unsigned NOT NULL DEFAULT '0',
|
||||
`loginip` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`regip` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`logintime` timestamp NULL DEFAULT NULL,
|
||||
`lastpost_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `users_email_unique` (`email`),
|
||||
KEY `users_legacy_md5_index` (`legacy_md5`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (1,'0001_01_01_000000_create_users_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (2,'0001_01_01_000001_create_cache_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (3,'0001_01_01_000002_create_jobs_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (4,'2026_08_11_092446_create_permission_tables',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (5,'2026_08_11_092448_create_media_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (6,'2026_08_11_092449_create_tag_tables',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (7,'2026_08_11_100000_create_membership_tables',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (8,'2026_08_11_100000_create_payments_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (9,'2026_08_11_100001_create_categories_and_posts_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (10,'2026_08_11_100002_create_comments_and_trackbacks_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (11,'2026_08_11_100003_create_links_and_settings_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (12,'2026_08_11_100004_add_blog_columns_to_users_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (13,'2026_08_11_100005_add_content_format_to_posts_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (14,'2026_08_11_113537_create_personal_access_tokens_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (15,'2026_08_12_000000_create_hello_world_logs_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (16,'2026_08_12_100000_add_payable_to_payments_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (17,'2026_08_12_200000_create_market_packages_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (18,'2026_08_12_300000_add_description_to_categories_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (19,'2026_08_12_400000_create_redirects_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (20,'2026_08_15_000001_create_media_library_table',2);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (21,'2026_08_15_000002_create_media_folders_table',2);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (22,'2026_08_15_000003_add_soft_deletes_to_media_library_table',2);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (23,'2026_08_15_000004_add_custom_properties_to_media_library_table',2);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (24,'2026_09_16_000001_add_cover_media_id_to_posts_and_categories',2);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (25,'2026_09_16_000002_seed_default_media_folders',2);
|
||||
@@ -0,0 +1,7 @@
|
||||
# Journal
|
||||
|
||||
## 2026-09-17 Hello World plugin 500
|
||||
|
||||
Enabling `demo.hello-world` could 500 if `hello_world_logs` was never migrated, or if a plugin hook/boot exception escaped.
|
||||
|
||||
Fix: run the plugin's migrations on enable; keep `/hello-world` and `comment.created` working without the table; isolate plugin boot and hooks so one plugin cannot take down the admin.
|
||||
+23
-18
@@ -27,15 +27,17 @@ plugins/{vendor}.{name}/
|
||||
"provider": "Plugins\\Vendor\\Name\\ServiceProvider",
|
||||
"requires": ["neatstudio.payment"],
|
||||
"filament_pages": ["Plugins\\Vendor\\Name\\Filament\\Pages\\SettingsPage"],
|
||||
"filament_resources": ["Plugins\\Vendor\\Name\\Filament\\Resources\\OrderResource"]
|
||||
"filament_resources": [
|
||||
"Plugins\\Vendor\\Name\\Filament\\Resources\\OrderResource"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `provider` | 入口类 FQCN;缺省时自动推断 `src/ServiceProvider.php` |
|
||||
| `requires` | 依赖的其他插件(如会员依赖支付),按 `vendor.name` 引用 |
|
||||
| `usage` | 使用说明(换行文本),后台插件卡片可折叠查看 |
|
||||
| 字段 | 说明 |
|
||||
| --------------------------------------- | ------------------------------------------------------------------------ |
|
||||
| `provider` | 入口类 FQCN;缺省时自动推断 `src/ServiceProvider.php` |
|
||||
| `requires` | 依赖的其他插件(如会员依赖支付),按 `vendor.name` 引用 |
|
||||
| `usage` | 使用说明(换行文本),后台插件卡片可折叠查看 |
|
||||
| `filament_pages` / `filament_resources` | 注册到后台的页面/资源(由 `PluginPages` 汇总,统一归入「插件」导航分组) |
|
||||
|
||||
## 依赖管理(requires 强制校验)
|
||||
@@ -82,26 +84,27 @@ class ServiceProvider extends PluginServiceProvider
|
||||
|
||||
### addAction(hook, callback, priority) — 无返回值
|
||||
|
||||
| Hook | 参数 | 用途 |
|
||||
|------|------|------|
|
||||
| `comment.created` | `Comment` | 新评论创建(AI 审核在此监听) |
|
||||
| `payment.paid` | `Payment` | 支付成功(按 `$payment->payable` 分发:订阅激活/解锁) |
|
||||
| `filament.post_form` | `Schema` | 文章编辑表单追加字段(会员付费设置在此注入) |
|
||||
| `filament.post_table` | `Table` | 文章列表追加列/操作/过滤 |
|
||||
| Hook | 参数 | 用途 |
|
||||
| --------------------- | --------- | ------------------------------------------------------ |
|
||||
| `comment.created` | `Comment` | 新评论创建(AI 审核在此监听) |
|
||||
| `payment.paid` | `Payment` | 支付成功(按 `$payment->payable` 分发:订阅激活/解锁) |
|
||||
| `filament.post_form` | `Schema` | 文章编辑表单追加字段(会员付费设置在此注入) |
|
||||
| `filament.post_table` | `Table` | 文章列表追加列/操作/过滤 |
|
||||
|
||||
### addFilter(hook, callback, priority) — 返回值传给下一个过滤器
|
||||
|
||||
| Hook | 签名 | 用途 |
|
||||
|------|------|------|
|
||||
| `post.rendered` | `(string $html, Post $post): string` | 文章渲染后处理(付费内容过滤、paywall) |
|
||||
| `seo.structured_data` | `(array $data): array` | 扩展 JSON-LD 结构化数据 |
|
||||
| `payment.gateway` | `(array $gateways): array` | 注册支付渠道 |
|
||||
| Hook | 签名 | 用途 |
|
||||
| --------------------- | ------------------------------------ | --------------------------------------- |
|
||||
| `post.rendered` | `(string $html, Post $post): string` | 文章渲染后处理(付费内容过滤、paywall) |
|
||||
| `seo.structured_data` | `(array $data): array` | 扩展 JSON-LD 结构化数据 |
|
||||
| `payment.gateway` | `(array $gateways): array` | 注册支付渠道 |
|
||||
|
||||
## 后台注入(Filament 表单 / 表格)
|
||||
|
||||
核心资源的表单/表格会触发 `filament.post_form` / `filament.post_table` 两个钩子,插件可追加自己的字段与列,停用插件后字段自动消失,核心零侵入。
|
||||
|
||||
> 注意:`Schema::components()` 与 `Table::columns()` 都是**整体替换**语义,追加要这样写:
|
||||
>
|
||||
> - 表单:`$schema->components([...$schema->getComponents(), Section::make(...)])`
|
||||
> - 表格:`$table->pushColumns([...])`
|
||||
|
||||
@@ -152,7 +155,9 @@ public function payableUrl(): ?string { return route('filament.admin.resources.
|
||||
|
||||
## 迁移
|
||||
|
||||
插件迁移放在 `database/migrations/`,`app/Providers/AppServiceProvider` 启动时自动注册,`php artisan migrate` 会一并执行(无需手动 --path)。
|
||||
插件迁移放在 `database/migrations/`,`app/Providers/AppServiceProvider` 启动时自动注册,`php artisan migrate` 会一并执行(无需手动 --path)。后台**启用插件**时也会单独跑该插件目录下的迁移,避免启用后立刻访问插件页面因缺表 500。
|
||||
|
||||
插件 `boot` 与钩子(action/filter)失败会被隔离并写入日志,单个插件异常不应拖垮整站。
|
||||
|
||||
## 打包与安装
|
||||
|
||||
|
||||
+13
-11
@@ -28,8 +28,10 @@ plugins/{vendor}.{name}/ # 目录名必须 vendor.name 格式(如 dem
|
||||
"author": "你的名字",
|
||||
"type": "demo",
|
||||
"provider": "Plugins\\Demo\\HelloWorld\\ServiceProvider",
|
||||
"requires": ["neatstudio.payment"], // 可选:依赖的插件
|
||||
"filament_pages": ["Plugins\\Demo\\HelloWorld\\Filament\\Pages\\HelloWorldSettings"],
|
||||
"requires": ["neatstudio.payment"], // 可选:依赖的插件
|
||||
"filament_pages": [
|
||||
"Plugins\\Demo\\HelloWorld\\Filament\\Pages\\HelloWorldSettings"
|
||||
],
|
||||
"filament_resources": ["...\\Resources\\XxxResource"]
|
||||
}
|
||||
```
|
||||
@@ -74,14 +76,14 @@ class ServiceProvider extends PluginServiceProvider
|
||||
|
||||
### 常用钩子
|
||||
|
||||
| Hook | 类型 | 参数 | 用途 |
|
||||
|------|------|------|------|
|
||||
| `post.rendered` | filter | `(string $html, Post) : string` | 文章渲染后处理(短代码/付费过滤) |
|
||||
| `comment.created` | action | `Comment` | 新评论创建 |
|
||||
| `payment.paid` | action | `Payment` | 支付成功(按 `$payment->payable` 分发) |
|
||||
| `filament.post_form` | action | `Schema` | 文章编辑表单追加字段 |
|
||||
| `filament.post_table` | action | `Table` | 文章列表追加列 |
|
||||
| `seo.structured_data` | filter | `(array $data) : array` | 扩展 JSON-LD |
|
||||
| Hook | 类型 | 参数 | 用途 |
|
||||
| --------------------- | ------ | ------------------------------- | --------------------------------------- |
|
||||
| `post.rendered` | filter | `(string $html, Post) : string` | 文章渲染后处理(短代码/付费过滤) |
|
||||
| `comment.created` | action | `Comment` | 新评论创建 |
|
||||
| `payment.paid` | action | `Payment` | 支付成功(按 `$payment->payable` 分发) |
|
||||
| `filament.post_form` | action | `Schema` | 文章编辑表单追加字段 |
|
||||
| `filament.post_table` | action | `Table` | 文章列表追加列 |
|
||||
| `seo.structured_data` | filter | `(array $data) : array` | 扩展 JSON-LD |
|
||||
|
||||
完整列表见 `docs/plugins.md`。
|
||||
|
||||
@@ -119,7 +121,7 @@ return view('demo-hello::hello', compact('logs'));
|
||||
|
||||
## 6. 迁移 + 模型
|
||||
|
||||
迁移放在 `database/migrations/`,**无需手动 --path**,`php artisan migrate` 自动执行(AppServiceProvider 已注册 `plugins/*/database/migrations`)。
|
||||
迁移放在 `database/migrations/`,**无需手动 --path**,`php artisan migrate` 自动执行(AppServiceProvider 已注册 `plugins/*/database/migrations`)。后台启用插件时也会再跑一次该插件自己的迁移。
|
||||
|
||||
模型照常写,命名空间 `Plugins\Demo\HelloWorld\Models`。
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ class HelloWorldSettings extends Page
|
||||
|
||||
protected static ?string $title = 'Hello World 设置';
|
||||
|
||||
protected static ?string $slug = 'hello-world-settings';
|
||||
|
||||
protected string $view = 'filament.pages.plugin-settings';
|
||||
|
||||
public array $data = [];
|
||||
|
||||
@@ -15,7 +15,9 @@ class HelloWorldController
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$logs = HelloWorldLog::query()->with('comment')->latest()->limit(10)->get();
|
||||
$logs = \Illuminate\Support\Facades\Schema::hasTable('hello_world_logs')
|
||||
? HelloWorldLog::query()->with('comment')->latest()->limit(10)->get()
|
||||
: collect();
|
||||
|
||||
$view = view('demo-hello::hello', ['logs' => $logs]);
|
||||
app(\App\Blog\View\Composers\SidebarComposer::class)->compose($view);
|
||||
|
||||
@@ -29,15 +29,21 @@ class ServiceProvider extends PluginServiceProvider
|
||||
$manager->addFilter('post.rendered', function (string $html, Post $post) {
|
||||
$greeting = (string) Setting::get('hello_world_greeting', '你好');
|
||||
|
||||
return preg_replace_callback(
|
||||
'/\[hello\s+([^\]]+)\]/',
|
||||
$replaced = preg_replace_callback(
|
||||
'/\[hello\s+([^\]]+)\]/u',
|
||||
fn (array $m) => '<span class="hello-world">'.$greeting.','.e($m[1]).'!</span>',
|
||||
$html
|
||||
);
|
||||
|
||||
return is_string($replaced) ? $replaced : $html;
|
||||
}, 20);
|
||||
|
||||
// 4. 动作示例:新评论创建时写日志(演示数据关联 + 钩子监听)
|
||||
$manager->addAction('comment.created', function (Comment $comment) {
|
||||
if (! \Illuminate\Support\Facades\Schema::hasTable('hello_world_logs')) {
|
||||
return;
|
||||
}
|
||||
|
||||
HelloWorldLog::create([
|
||||
'comment_id' => $comment->id,
|
||||
'note' => '捕获新评论:'.mb_substr($comment->content, 0, 30),
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
@php
|
||||
$environmentName = \App\Filament\Support\AdminEnvironment::name();
|
||||
$environmentColor = \App\Filament\Support\AdminEnvironment::color();
|
||||
$createPostUrl = \App\Filament\Resources\Posts\PostResource::getUrl('create');
|
||||
@endphp
|
||||
|
||||
<div class="ll-topbar-tools">
|
||||
<x-filament::badge :color="$environmentColor" size="sm" class="ll-env-badge">
|
||||
{{ $environmentName }}
|
||||
</x-filament::badge>
|
||||
|
||||
<x-filament::button
|
||||
tag="a"
|
||||
:href="$createPostUrl"
|
||||
size="sm"
|
||||
color="primary"
|
||||
icon="heroicon-o-pencil-square"
|
||||
wire:navigate
|
||||
>
|
||||
写文章
|
||||
</x-filament::button>
|
||||
</div>
|
||||
@@ -71,4 +71,36 @@ class AdminPagesTest extends TestCase
|
||||
{
|
||||
$this->get('/admin')->assertRedirect('/admin/login');
|
||||
}
|
||||
|
||||
public function test_admin_environment_maps_production_to_prod(): void
|
||||
{
|
||||
$original = app()->environment();
|
||||
app()['env'] = 'production';
|
||||
|
||||
$this->assertSame('prod', \App\Filament\Support\AdminEnvironment::name());
|
||||
$this->assertSame('danger', \App\Filament\Support\AdminEnvironment::color());
|
||||
|
||||
app()['env'] = $original;
|
||||
}
|
||||
|
||||
public function test_admin_topbar_shows_environment_and_create_post_button(): void
|
||||
{
|
||||
$this->actingAs($this->admin)
|
||||
->get('/admin')
|
||||
->assertOk()
|
||||
->assertSee(\App\Filament\Support\AdminEnvironment::name(), false)
|
||||
->assertSee('写文章', false)
|
||||
->assertSee('/admin/posts/create', false);
|
||||
}
|
||||
|
||||
public function test_hello_world_plugin_pages_load_when_enabled(): void
|
||||
{
|
||||
$manager = app(\App\Blog\Support\PluginManager::class);
|
||||
$manager->enable('demo.hello-world');
|
||||
\Plugins\Demo\HelloWorld\ServiceProvider::bootPlugin($manager);
|
||||
|
||||
$this->actingAs($this->admin)->get('/admin')->assertOk();
|
||||
$this->actingAs($this->admin)->get('/admin/posts/create')->assertOk();
|
||||
$this->get('/hello-world')->assertOk();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,4 +67,24 @@ class DemoPluginTest extends TestCase
|
||||
->assertOk()
|
||||
->assertSee('Hello World 演示页');
|
||||
}
|
||||
|
||||
public function test_hello_world_page_survives_missing_log_table(): void
|
||||
{
|
||||
\Illuminate\Support\Facades\Schema::dropIfExists('hello_world_logs');
|
||||
|
||||
$this->get('/hello-world')->assertOk()->assertSee('Hello World 演示页');
|
||||
}
|
||||
|
||||
public function test_enable_hello_world_runs_plugin_migrations(): void
|
||||
{
|
||||
\Illuminate\Support\Facades\Schema::dropIfExists('hello_world_logs');
|
||||
\Illuminate\Support\Facades\DB::table('migrations')
|
||||
->where('migration', 'like', '%hello_world_logs%')
|
||||
->delete();
|
||||
|
||||
app(PluginManager::class)->enable('demo.hello-world');
|
||||
|
||||
$this->assertTrue(\Illuminate\Support\Facades\Schema::hasTable('hello_world_logs'));
|
||||
$this->assertTrue(app(PluginManager::class)->isEnabled('demo.hello-world'));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user