聊天室管理权限统一为职务权限

This commit is contained in:
2026-04-26 20:55:11 +08:00
parent b07f4e971a
commit 0402097b59
21 changed files with 590 additions and 395 deletions
+88 -124
View File
@@ -8,11 +8,15 @@
namespace Tests\Feature;
use App\Enums\CurrencySource;
use App\Models\Department;
use App\Models\Position;
use App\Models\Room;
use App\Models\Sysparam;
use App\Models\User;
use App\Models\UserCurrencyLog;
use App\Models\UserPosition;
use App\Services\ChatUserPresenceService;
use App\Support\PositionPermissionRegistry;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Cache;
@@ -39,10 +43,6 @@ class UserControllerTest extends TestCase
Redis::flushall();
Sysparam::updateOrCreate(['alias' => 'superlevel'], ['body' => '100']);
Sysparam::updateOrCreate(['alias' => 'level_kick'], ['body' => '15']);
Sysparam::updateOrCreate(['alias' => 'level_mute'], ['body' => '15']);
Sysparam::updateOrCreate(['alias' => 'level_ban'], ['body' => '15']);
Sysparam::updateOrCreate(['alias' => 'level_banip'], ['body' => '15']);
Sysparam::updateOrCreate(['alias' => 'smtp_enabled'], ['body' => '1']); // Allow email changing in tests
}
@@ -294,6 +294,51 @@ class UserControllerTest extends TestCase
->assertJsonPath('data.bank_jjb_can_reveal', false);
}
/**
* 测试拥有封IP职务权限的用户可以查看名片中的管理员网络信息。
*/
public function test_position_user_with_banip_permission_can_view_admin_network_info(): void
{
$viewer = $this->createUserWithPositionPermissions([
PositionPermissionRegistry::USER_BANIP,
]);
$target = User::factory()->create([
'username' => 'nettarget',
'first_ip' => '10.0.0.1',
'previous_ip' => '10.0.0.2',
'last_ip' => '10.0.0.3',
]);
$response = $this->actingAs($viewer)->getJson("/user/{$target->username}");
$response->assertOk()
->assertJsonPath('data.first_ip', '10.0.0.1')
->assertJsonPath('data.last_ip', '10.0.0.2')
->assertJsonPath('data.login_ip', '10.0.0.3');
}
/**
* 测试普通用户查看别人名片时不会拿到管理员网络信息字段。
*/
public function test_user_without_banip_permission_cannot_view_admin_network_info(): void
{
$viewer = User::factory()->create();
$target = User::factory()->create([
'username' => 'hidden-net',
'first_ip' => '10.0.1.1',
'previous_ip' => '10.0.1.2',
'last_ip' => '10.0.1.3',
]);
$response = $this->actingAs($viewer)->getJson("/user/{$target->username}");
$response->assertOk()
->assertJsonMissingPath('data.first_ip')
->assertJsonMissingPath('data.last_ip')
->assertJsonMissingPath('data.login_ip')
->assertJsonMissingPath('data.location');
}
/**
* 测试不改邮箱时可以正常更新个人资料。
*/
@@ -510,126 +555,6 @@ class UserControllerTest extends TestCase
$this->assertTrue(Hash::check('newpassword123', $user->password));
}
public function test_admin_can_kick_user()
{
$admin = User::factory()->create(['username' => 'admin', 'user_level' => 20]);
$target = User::factory()->create(['username' => 'target', 'user_level' => 1]);
$room = Room::create(['id' => 1, 'room_name' => 'Test Room', 'room_owner' => 'someone']);
$this->actingAs($admin);
$response = $this->postJson("/user/{$target->username}/kick", [
'room_id' => $room->id,
]);
$response->assertStatus(200)
->assertJsonPath('status', 'success');
}
public function test_low_level_user_cannot_kick()
{
$user = User::factory()->create(['username' => 'user', 'user_level' => 1]);
$target = User::factory()->create(['username' => 'target', 'user_level' => 1]);
$room = Room::create(['id' => 1, 'room_name' => 'Test Room', 'room_owner' => 'someone']);
$this->actingAs($user);
$response = $this->postJson("/user/{$target->username}/kick", [
'room_id' => $room->id,
]);
$response->assertStatus(403);
}
public function test_room_master_can_kick()
{
$user = User::factory()->create(['username' => 'user', 'user_level' => 2]);
$target = User::factory()->create(['username' => 'target', 'user_level' => 1]);
$room = Room::create(['id' => 1, 'room_name' => 'Test Room', 'room_owner' => 'user']); // Master is 'user'
$this->actingAs($user);
$response = $this->postJson("/user/{$target->username}/kick", [
'room_id' => $room->id,
]);
if ($response->status() !== 200) {
dump($response->json());
}
$response->assertStatus(200);
}
public function test_cannot_kick_higher_level()
{
$admin = User::factory()->create(['username' => 'admin', 'user_level' => 20]);
$superadmin = User::factory()->create(['username' => 'superadmin', 'user_level' => 100]);
$room = Room::create(['id' => 1, 'room_name' => 'Test Room', 'room_owner' => 'someone']);
$this->actingAs($admin);
$response = $this->postJson("/user/{$superadmin->username}/kick", [
'room_id' => $room->id,
]);
$response->assertStatus(403);
}
public function test_admin_can_mute_user()
{
$admin = User::factory()->create(['username' => 'admin', 'user_level' => 20]);
$target = User::factory()->create(['username' => 'target', 'user_level' => 1]);
$room = Room::create(['id' => 1, 'room_name' => 'Test Room', 'room_owner' => 'someone']);
Redis::shouldReceive('setex')->once();
$this->actingAs($admin);
$response = $this->postJson("/user/{$target->username}/mute", [
'room_id' => $room->id,
'duration' => 10,
]);
$response->assertStatus(200);
}
public function test_admin_can_ban_user()
{
$admin = User::factory()->create(['username' => 'admin', 'user_level' => 20]);
$target = User::factory()->create(['username' => 'target', 'user_level' => 1]);
$room = Room::create(['id' => 1, 'room_name' => 'Test Room', 'room_owner' => 'someone']);
$this->actingAs($admin);
$response = $this->postJson("/user/{$target->username}/ban", [
'room_id' => $room->id,
]);
$response->assertStatus(200);
$target->refresh();
$this->assertEquals(-1, $target->user_level);
}
public function test_admin_can_ban_ip()
{
$admin = User::factory()->create(['username' => 'admin', 'user_level' => 20]);
$target = User::factory()->create(['username' => 'target', 'user_level' => 1, 'last_ip' => '192.168.1.100']);
$room = Room::create(['id' => 1, 'room_name' => 'Test Room', 'room_owner' => 'someone']);
Redis::shouldReceive('sadd')->with('banned_ips', '192.168.1.100')->once();
$this->actingAs($admin);
$response = $this->postJson("/user/{$target->username}/banip", [
'room_id' => $room->id,
]);
$response->assertStatus(200);
$target->refresh();
$this->assertEquals(-1, $target->user_level);
}
/**
* 让指定用户先进入聊天室,满足“仅在线用户可设置状态”的前置条件。
*/
@@ -646,4 +571,43 @@ class UserControllerTest extends TestCase
return $room;
}
/**
* 创建带指定职务权限的测试用户。
*
* @param list<string> $permissions
*/
private function createUserWithPositionPermissions(array $permissions): User
{
$user = User::factory()->create([
'user_level' => 88,
]);
$department = Department::create([
'name' => '资料权限部'.$user->id,
'rank' => 88,
'color' => '#4f46e5',
'sort_order' => 1,
'description' => '资料权限测试部门',
]);
$position = Position::create([
'department_id' => $department->id,
'name' => '资料权限职务'.$user->id,
'icon' => '🛡️',
'rank' => 88,
'level' => 88,
'sort_order' => 1,
'permissions' => $permissions,
]);
UserPosition::create([
'user_id' => $user->id,
'position_id' => $position->id,
'appointed_at' => now(),
'is_active' => true,
]);
return $user->fresh();
}
}