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('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_hides_token_and_transfer_to_addresses(): void { config([ 'coruna.telegram.bot_token' => 'secret-token-should-not-render', 'coruna.telegram.bot_username' => 'ops_bot', 'coruna.transfer.to_address' => 'THiddenToAddressShouldNotRender', '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="panel_admin_hosts"', false) ->assertDontSee('name="channels_domains"', false) ->assertDontSee('后台访问域名') ->assertDontSee('渠道链接') ->assertDontSee('THiddenToAddressShouldNotRender') ->assertDontSee('hidden-cdn.example.com') ->assertSee('TELEGRAM_BOT_TOKEN') ->assertSee('@ops_bot') ->assertDontSee('助记词明文(员工 / 代理)') ->assertDontSee('staff_mnemonic_reveal'); } #[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')) ); } }