refactor: 外链中转拆为内置插件 neatstudio.link-tracker

- 插件承载全部逻辑:redirects 迁移(hasTable 兼容旧库)、Redirect 模型、UrlRedirector、/go 路由+控制器、Filament 外链中转资源
- 核心只留 hook 接入点:
  - tracked_url() 助手走 link.redirect 过滤器(评论正文/作者网址/友链模板统一调用)
  - 正文外链改写移到插件的 post.rendered 过滤器(优先级 20,晚于会员付费过滤)
- 停用插件:链接恢复直连、内容不受影响;后台「管理 → 外链中转」查看点击量/启停
- 测试更新为插件上下文(含无过滤器降级断言);97 通过
This commit is contained in:
ak
2026-08-13 02:05:32 +08:00
parent 8f1ff6e3f9
commit f1b9d1e1c3
20 changed files with 118 additions and 62 deletions
+17 -11
View File
@@ -5,25 +5,31 @@ declare(strict_types=1);
namespace Tests\Feature;
use App\Blog\Services\PostContentRenderer;
use App\Blog\Services\UrlRedirector;
use App\Models\Post;
use App\Models\Redirect;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Plugins\Neatstudio\LinkTracker\Models\Redirect;
use Tests\TestCase;
class GoRedirectTest extends TestCase
{
use RefreshDatabase;
public function test_go_url_rewrites_external_but_keeps_internal(): void
public function test_tracked_url_rewrites_external_but_keeps_internal(): void
{
$go = app(UrlRedirector::class);
// 外链中转插件默认启用,link.redirect 过滤器生效
$this->assertStringContainsString('/go/', tracked_url('https://example.com/path'));
$this->assertSame('http://laralog.test/posts/1', tracked_url('http://laralog.test/posts/1'));
$this->assertSame('/posts/1', tracked_url('/posts/1'));
$this->assertSame('mailto:a@b.com', tracked_url('mailto:a@b.com'));
$this->assertSame('#anchor', tracked_url('#anchor'));
}
$this->assertStringContainsString('/go/', $go->goUrl('https://example.com/path'));
$this->assertSame('http://laralog.test/posts/1', $go->goUrl('http://laralog.test/posts/1'));
$this->assertSame('/posts/1', $go->goUrl('/posts/1'));
$this->assertSame('mailto:a@b.com', $go->goUrl('mailto:a@b.com'));
$this->assertSame('#anchor', $go->goUrl('#anchor'));
public function test_tracked_url_returns_original_without_plugin_filter(): void
{
// 无插件注册 link.redirect 过滤器时(插件停用/未装),核心视图原样返回外链
$manager = new \App\Blog\Support\PluginManager();
$this->assertSame('https://example.com/path', $manager->applyFilters('link.redirect', 'https://example.com/path'));
}
public function test_go_redirect_counts_clicks(): void
@@ -54,8 +60,8 @@ class GoRedirectTest extends TestCase
public function test_same_url_reuses_same_hash(): void
{
$a = app(UrlRedirector::class)->goUrl('https://example.com/dup');
$b = app(UrlRedirector::class)->goUrl('https://example.com/dup');
$a = tracked_url('https://example.com/dup');
$b = tracked_url('https://example.com/dup');
$this->assertSame($a, $b);
$this->assertSame(1, Redirect::query()->where('target_url', 'https://example.com/dup')->count());