新增职务权限管理与聊天室管理权限控制
This commit is contained in:
@@ -16,9 +16,13 @@ use App\Jobs\SaveMessageJob;
|
||||
use App\Models\BaccaratLossCoverEvent;
|
||||
use App\Models\BaccaratLossCoverRecord;
|
||||
use App\Models\BaccaratRound;
|
||||
use App\Models\Department;
|
||||
use App\Models\GameConfig;
|
||||
use App\Models\Position;
|
||||
use App\Models\User;
|
||||
use App\Models\UserPosition;
|
||||
use App\Services\BaccaratLossCoverService;
|
||||
use App\Support\PositionPermissionRegistry;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
@@ -57,7 +61,7 @@ class BaccaratLossCoverControllerTest extends TestCase
|
||||
{
|
||||
Queue::fake();
|
||||
|
||||
$admin = User::factory()->create(['user_level' => 100]);
|
||||
$admin = User::factory()->create(['id' => 1, 'user_level' => 100]);
|
||||
|
||||
$response = $this->actingAs($admin)->postJson(route('command.baccarat_loss_cover.store'), [
|
||||
'title' => '你玩游戏我买单',
|
||||
@@ -76,6 +80,46 @@ class BaccaratLossCoverControllerTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证拥有买单活动权限的职务用户也可以创建活动。
|
||||
*/
|
||||
public function test_position_user_with_loss_cover_permission_can_create_event(): void
|
||||
{
|
||||
Queue::fake();
|
||||
|
||||
$admin = $this->createUserWithPermissions([
|
||||
PositionPermissionRegistry::ROOM_BACCARAT_LOSS_COVER,
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($admin)->postJson(route('command.baccarat_loss_cover.store'), [
|
||||
'title' => '职务买单活动',
|
||||
'description' => '职务权限测试',
|
||||
'starts_at' => now()->addMinutes(3)->toDateTimeString(),
|
||||
'ends_at' => now()->addMinutes(33)->toDateTimeString(),
|
||||
'claim_deadline_at' => now()->addHours(6)->toDateTimeString(),
|
||||
]);
|
||||
|
||||
$response->assertOk()->assertJson(['ok' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证高等级但无买单活动权限的用户会被拒绝。
|
||||
*/
|
||||
public function test_high_level_user_without_loss_cover_permission_cannot_create_event(): void
|
||||
{
|
||||
$admin = User::factory()->create(['user_level' => 100]);
|
||||
|
||||
$response = $this->actingAs($admin)->postJson(route('command.baccarat_loss_cover.store'), [
|
||||
'title' => '无权限活动',
|
||||
'description' => '测试活动',
|
||||
'starts_at' => now()->addMinutes(5)->toDateTimeString(),
|
||||
'ends_at' => now()->addMinutes(35)->toDateTimeString(),
|
||||
'claim_deadline_at' => now()->addDay()->toDateTimeString(),
|
||||
]);
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证活动进行中下注会挂到活动并写入用户聚合记录。
|
||||
*/
|
||||
@@ -331,4 +375,45 @@ class BaccaratLossCoverControllerTest extends TestCase
|
||||
'source' => CurrencySource::BACCARAT_LOSS_COVER_CLAIM->value,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带指定聊天室权限的在职职务用户。
|
||||
*
|
||||
* @param list<string> $permissions
|
||||
*/
|
||||
private function createUserWithPermissions(array $permissions): User
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'user_level' => 90,
|
||||
]);
|
||||
|
||||
$department = Department::create([
|
||||
'name' => '买单活动部'.$user->id,
|
||||
'rank' => 90,
|
||||
'color' => '#15803d',
|
||||
'sort_order' => 1,
|
||||
'description' => '买单活动权限测试',
|
||||
]);
|
||||
|
||||
$position = Position::create([
|
||||
'department_id' => $department->id,
|
||||
'name' => '买单活动职务'.$user->id,
|
||||
'icon' => '🎁',
|
||||
'rank' => 90,
|
||||
'level' => 90,
|
||||
'sort_order' => 1,
|
||||
'permissions' => $permissions,
|
||||
]);
|
||||
|
||||
UserPosition::create([
|
||||
'user_id' => $user->id,
|
||||
'position_id' => $position->id,
|
||||
'appointed_by_user_id' => null,
|
||||
'appointed_at' => now(),
|
||||
'remark' => '买单活动权限测试',
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
return $user->fresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,12 @@
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Events\MessageSent;
|
||||
use App\Models\Department;
|
||||
use App\Models\Position;
|
||||
use App\Models\Room;
|
||||
use App\Models\User;
|
||||
use App\Models\UserPosition;
|
||||
use App\Support\PositionPermissionRegistry;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
@@ -157,6 +161,60 @@ class ChatControllerTest extends TestCase
|
||||
$response->assertSee('toggleBlockedSystemSender');
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试无聊天室权限的职务用户看不到顶部管理按钮。
|
||||
*/
|
||||
public function test_room_view_hides_admin_menu_for_position_without_room_permissions(): void
|
||||
{
|
||||
$room = Room::create(['room_name' => 'nomenu']);
|
||||
$user = $this->createUserWithPositionPermissions([]);
|
||||
|
||||
$response = $this->actingAs($user)->get(route('chat.room', $room->id));
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertDontSee('🛠 管理', false);
|
||||
$response->assertDontSee('🪧 设公告', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试只授予公告权限时,顶部管理菜单仅显示对应按钮。
|
||||
*/
|
||||
public function test_room_view_renders_only_granted_room_management_buttons(): void
|
||||
{
|
||||
$room = Room::create(['room_name' => 'annmenu']);
|
||||
$user = $this->createUserWithPositionPermissions([
|
||||
PositionPermissionRegistry::ROOM_ANNOUNCEMENT,
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)->get(route('chat.room', $room->id));
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertSee('🛠 管理', false);
|
||||
$response->assertSee('🪧 设公告', false);
|
||||
$response->assertDontSee("runAdminAction('announce-message')", false);
|
||||
$response->assertDontSee("selectEffect('fireworks')", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试仅有全屏特效权限时,只显示特效分组。
|
||||
*/
|
||||
public function test_room_view_renders_fullscreen_effect_group_only_when_permission_exists(): void
|
||||
{
|
||||
$room = Room::create(['room_name' => 'effectmenu']);
|
||||
$user = $this->createUserWithPositionPermissions([
|
||||
PositionPermissionRegistry::ROOM_FULLSCREEN_EFFECT,
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)->get(route('chat.room', $room->id));
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertSee('🛠 管理', false);
|
||||
$response->assertSee('全屏特效');
|
||||
$response->assertSee('🎆 烟花', false);
|
||||
$response->assertDontSee("runAdminAction('announcement')", false);
|
||||
$response->assertDontSee("runAdminAction('announce-message')", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试用户可以发送普通文本消息。
|
||||
*/
|
||||
@@ -593,9 +651,9 @@ class ChatControllerTest extends TestCase
|
||||
/**
|
||||
* 测试管理员可以设置房间公告。
|
||||
*/
|
||||
public function test_can_set_announcement()
|
||||
public function test_site_owner_can_set_announcement()
|
||||
{
|
||||
$user = User::factory()->create(['user_level' => 100]); // superadmin
|
||||
$user = User::factory()->create(['id' => 1, 'user_level' => 100]);
|
||||
$room = Room::create(['room_name' => 'test_ann', 'room_owner' => 'someone']);
|
||||
|
||||
$response = $this->actingAs($user)->postJson(route('chat.announcement', $room->id), [
|
||||
@@ -609,12 +667,29 @@ class ChatControllerTest extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试无权限用户不能设置房间公告。
|
||||
* 测试拥有公告权限的职务用户可以设置房间公告。
|
||||
*/
|
||||
public function test_cannot_set_announcement_without_permission()
|
||||
public function test_position_user_with_room_announcement_permission_can_set_announcement(): void
|
||||
{
|
||||
$user = User::factory()->create(['user_level' => 0]);
|
||||
$room = Room::create(['room_name' => 'test_ann2', 'room_owner' => 'someone']);
|
||||
$user = $this->createUserWithPositionPermissions([
|
||||
PositionPermissionRegistry::ROOM_ANNOUNCEMENT,
|
||||
]);
|
||||
$room = Room::create(['room_name' => 'test_ann2', 'room_owner' => 'other']);
|
||||
|
||||
$response = $this->actingAs($user)->postJson(route('chat.announcement', $room->id), [
|
||||
'announcement' => 'This is a new test announcement',
|
||||
]);
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试房主但无公告权限时也不能设置房间公告。
|
||||
*/
|
||||
public function test_room_owner_without_announcement_permission_cannot_set_announcement(): void
|
||||
{
|
||||
$user = $this->createUserWithPositionPermissions([]);
|
||||
$room = Room::create(['room_name' => 'test_ann3', 'room_owner' => $user->username]);
|
||||
|
||||
$response = $this->actingAs($user)->postJson(route('chat.announcement', $room->id), [
|
||||
'announcement' => 'This is a new test announcement',
|
||||
@@ -622,4 +697,60 @@ class ChatControllerTest extends TestCase
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试无权限用户不能设置房间公告。
|
||||
*/
|
||||
public function test_cannot_set_announcement_without_permission()
|
||||
{
|
||||
$user = User::factory()->create(['user_level' => 0]);
|
||||
$room = Room::create(['room_name' => 'test_ann4', 'room_owner' => 'someone']);
|
||||
|
||||
$response = $this->actingAs($user)->postJson(route('chat.announcement', $room->id), [
|
||||
'announcement' => 'This is a new test announcement',
|
||||
]);
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带指定聊天室权限的在职职务用户。
|
||||
*
|
||||
* @param list<string> $permissions
|
||||
*/
|
||||
private function createUserWithPositionPermissions(array $permissions): User
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'user_level' => 70,
|
||||
]);
|
||||
|
||||
$department = Department::create([
|
||||
'name' => '聊天室测试部门'.$user->id,
|
||||
'rank' => 70,
|
||||
'color' => '#1d4ed8',
|
||||
'sort_order' => 1,
|
||||
'description' => '聊天室权限测试',
|
||||
]);
|
||||
|
||||
$position = Position::create([
|
||||
'department_id' => $department->id,
|
||||
'name' => '聊天室测试职务'.$user->id,
|
||||
'icon' => '🛡️',
|
||||
'rank' => 70,
|
||||
'level' => 70,
|
||||
'sort_order' => 1,
|
||||
'permissions' => $permissions,
|
||||
]);
|
||||
|
||||
UserPosition::create([
|
||||
'user_id' => $user->id,
|
||||
'position_id' => $position->id,
|
||||
'appointed_by_user_id' => null,
|
||||
'appointed_at' => now(),
|
||||
'remark' => '聊天室权限测试',
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
return $user->fresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,12 @@
|
||||
namespace Tests\Feature\Feature;
|
||||
|
||||
use App\Jobs\SaveMessageJob;
|
||||
use App\Models\Department;
|
||||
use App\Models\Position;
|
||||
use App\Models\Room;
|
||||
use App\Models\User;
|
||||
use App\Models\UserPosition;
|
||||
use App\Support\PositionPermissionRegistry;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
@@ -17,7 +21,7 @@ use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* 管理员聊天命令功能测试
|
||||
* 覆盖全屏特效命令的新增特效校验。
|
||||
* 覆盖聊天室顶部管理菜单对应接口的权限校验与关键行为。
|
||||
*/
|
||||
class AdminCommandControllerTest extends TestCase
|
||||
{
|
||||
@@ -38,6 +42,7 @@ class AdminCommandControllerTest extends TestCase
|
||||
public function test_super_admin_can_trigger_all_new_effect_types(): void
|
||||
{
|
||||
$admin = User::factory()->create([
|
||||
'id' => 1,
|
||||
'user_level' => 100,
|
||||
]);
|
||||
$room = Room::create([
|
||||
@@ -58,6 +63,116 @@ class AdminCommandControllerTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试拥有全屏特效权限的职务用户可以触发特效。
|
||||
*/
|
||||
public function test_position_user_with_fullscreen_effect_permission_can_trigger_effect(): void
|
||||
{
|
||||
$admin = $this->createPositionedManager([
|
||||
PositionPermissionRegistry::ROOM_FULLSCREEN_EFFECT,
|
||||
]);
|
||||
$room = Room::create([
|
||||
'room_name' => '特效权限房',
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($admin)->postJson(route('command.effect'), [
|
||||
'room_id' => $room->id,
|
||||
'type' => 'fireworks',
|
||||
]);
|
||||
|
||||
$response->assertOk()->assertJson([
|
||||
'status' => 'success',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试高等级但无全屏特效权限的用户会被拒绝。
|
||||
*/
|
||||
public function test_high_level_user_without_fullscreen_effect_permission_cannot_trigger_effect(): void
|
||||
{
|
||||
$admin = User::factory()->create([
|
||||
'user_level' => 100,
|
||||
]);
|
||||
$room = Room::create([
|
||||
'room_name' => '无权限特效房',
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($admin)->postJson(route('command.effect'), [
|
||||
'room_id' => $room->id,
|
||||
'type' => 'fireworks',
|
||||
]);
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试拥有公屏讲话权限的职务用户可以发送公屏公告。
|
||||
*/
|
||||
public function test_position_user_with_public_broadcast_permission_can_announce(): void
|
||||
{
|
||||
Queue::fake();
|
||||
|
||||
$admin = $this->createPositionedManager([
|
||||
PositionPermissionRegistry::ROOM_PUBLIC_BROADCAST,
|
||||
]);
|
||||
$admin->load('activePosition.position.department');
|
||||
$room = Room::create([
|
||||
'room_name' => '公屏权限房',
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($admin)->postJson(route('command.announce'), [
|
||||
'room_id' => $room->id,
|
||||
'content' => '今晚八点准时集合',
|
||||
]);
|
||||
|
||||
$response->assertOk()->assertJson([
|
||||
'status' => 'success',
|
||||
]);
|
||||
|
||||
$messages = Redis::lrange("room:{$room->id}:messages", 0, -1);
|
||||
$publicMessage = collect($messages)
|
||||
->map(fn (string $item) => json_decode($item, true))
|
||||
->first(fn (array $item) => ($item['from_user'] ?? null) === '系统公告'
|
||||
&& str_contains((string) ($item['content'] ?? ''), '今晚八点准时集合'));
|
||||
|
||||
$this->assertNotNull($publicMessage);
|
||||
$this->assertStringContainsString(
|
||||
$admin->activePosition->position->department->name.$admin->activePosition->position->name,
|
||||
(string) $publicMessage['content']
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
"{$admin->username}</b> 发布公告",
|
||||
(string) $publicMessage['content']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试拥有全员清屏权限的职务用户可以清空房间普通消息。
|
||||
*/
|
||||
public function test_position_user_with_clear_screen_permission_can_clear_room_messages(): void
|
||||
{
|
||||
$admin = $this->createPositionedManager([
|
||||
PositionPermissionRegistry::ROOM_CLEAR_SCREEN,
|
||||
]);
|
||||
$room = Room::create([
|
||||
'room_name' => '清屏权限房',
|
||||
]);
|
||||
|
||||
Redis::rpush("room:{$room->id}:messages", json_encode([
|
||||
'id' => 1,
|
||||
'content' => '待清除的消息',
|
||||
], JSON_UNESCAPED_UNICODE));
|
||||
|
||||
$response = $this->actingAs($admin)->postJson(route('command.clear_screen'), [
|
||||
'room_id' => $room->id,
|
||||
]);
|
||||
|
||||
$response->assertOk()->assertJson([
|
||||
'status' => 'success',
|
||||
]);
|
||||
$this->assertSame([], Redis::lrange("room:{$room->id}:messages", 0, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试管理操作中的奖励金币会给接收方写入带右下角提示的私聊消息。
|
||||
*/
|
||||
@@ -246,6 +361,47 @@ class AdminCommandControllerTest extends TestCase
|
||||
return [$admin, $target, $room];
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带指定聊天室权限的职务管理员。
|
||||
*
|
||||
* @param list<string> $permissions
|
||||
*/
|
||||
private function createPositionedManager(array $permissions): User
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'user_level' => 90,
|
||||
]);
|
||||
|
||||
$department = Department::create([
|
||||
'name' => '命令权限部'.$user->id,
|
||||
'rank' => 90,
|
||||
'color' => '#7c3aed',
|
||||
'sort_order' => 1,
|
||||
'description' => '聊天室命令权限测试',
|
||||
]);
|
||||
|
||||
$position = Position::create([
|
||||
'department_id' => $department->id,
|
||||
'name' => '命令权限职务'.$user->id,
|
||||
'icon' => '🛠️',
|
||||
'rank' => 90,
|
||||
'level' => 90,
|
||||
'sort_order' => 1,
|
||||
'permissions' => $permissions,
|
||||
]);
|
||||
|
||||
UserPosition::create([
|
||||
'user_id' => $user->id,
|
||||
'position_id' => $position->id,
|
||||
'appointed_by_user_id' => null,
|
||||
'appointed_at' => now(),
|
||||
'remark' => '聊天室命令权限测试',
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
return $user->fresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从房间消息缓存中定位目标用户收到的系统私聊提示。
|
||||
*
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 文件功能:后台职务权限管理功能测试
|
||||
*
|
||||
* 覆盖职务权限字段的保存、更新、校验与页面展示,
|
||||
* 确保后台配置可以稳定驱动聊天室顶部管理菜单。
|
||||
*/
|
||||
|
||||
namespace Tests\Feature\Feature;
|
||||
|
||||
use App\Models\Department;
|
||||
use App\Models\Position;
|
||||
use App\Models\User;
|
||||
use App\Support\PositionPermissionRegistry;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* 类功能:验证后台职务权限管理页的关键行为。
|
||||
*/
|
||||
class AdminPositionPermissionTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
/**
|
||||
* 验证站长可以创建带聊天室权限的职务。
|
||||
*/
|
||||
public function test_site_owner_can_store_position_with_room_permissions(): void
|
||||
{
|
||||
$owner = $this->createSiteOwner();
|
||||
$department = $this->createDepartment();
|
||||
|
||||
$response = $this->actingAs($owner)->post(route('admin.positions.store'), [
|
||||
'department_id' => $department->id,
|
||||
'name' => '值班主持',
|
||||
'icon' => '🎙️',
|
||||
'rank' => 66,
|
||||
'level' => 66,
|
||||
'max_persons' => 2,
|
||||
'max_reward' => 100,
|
||||
'daily_reward_limit' => 300,
|
||||
'recipient_daily_limit' => 2,
|
||||
'sort_order' => 8,
|
||||
'permissions' => [
|
||||
PositionPermissionRegistry::ROOM_ANNOUNCEMENT,
|
||||
PositionPermissionRegistry::ROOM_PUBLIC_BROADCAST,
|
||||
],
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('admin.positions.index'));
|
||||
|
||||
$position = Position::query()->where('name', '值班主持')->firstOrFail();
|
||||
|
||||
$this->assertSame([
|
||||
PositionPermissionRegistry::ROOM_ANNOUNCEMENT,
|
||||
PositionPermissionRegistry::ROOM_PUBLIC_BROADCAST,
|
||||
], $position->permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证非法权限码会被后台校验拒绝。
|
||||
*/
|
||||
public function test_invalid_permission_code_is_rejected_when_storing_position(): void
|
||||
{
|
||||
$owner = $this->createSiteOwner();
|
||||
$department = $this->createDepartment();
|
||||
|
||||
$response = $this->from(route('admin.positions.index'))->actingAs($owner)->post(route('admin.positions.store'), [
|
||||
'department_id' => $department->id,
|
||||
'name' => '巡查主持',
|
||||
'icon' => '🛰️',
|
||||
'rank' => 55,
|
||||
'level' => 55,
|
||||
'max_persons' => 1,
|
||||
'sort_order' => 2,
|
||||
'permissions' => [
|
||||
PositionPermissionRegistry::ROOM_ANNOUNCEMENT,
|
||||
'room.invalid_permission',
|
||||
],
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('admin.positions.index'));
|
||||
$response->assertSessionHasErrors('permissions.1');
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证站长可以更新职务的聊天室权限配置。
|
||||
*/
|
||||
public function test_site_owner_can_update_position_permissions(): void
|
||||
{
|
||||
$owner = $this->createSiteOwner();
|
||||
$department = $this->createDepartment();
|
||||
$position = Position::create([
|
||||
'department_id' => $department->id,
|
||||
'name' => '公告员',
|
||||
'icon' => '📣',
|
||||
'rank' => 60,
|
||||
'level' => 60,
|
||||
'sort_order' => 1,
|
||||
'permissions' => [
|
||||
PositionPermissionRegistry::ROOM_ANNOUNCEMENT,
|
||||
],
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($owner)->put(route('admin.positions.update', $position), [
|
||||
'department_id' => $department->id,
|
||||
'name' => '公告员',
|
||||
'icon' => '📣',
|
||||
'rank' => 60,
|
||||
'level' => 60,
|
||||
'max_persons' => null,
|
||||
'max_reward' => null,
|
||||
'daily_reward_limit' => null,
|
||||
'recipient_daily_limit' => null,
|
||||
'sort_order' => 1,
|
||||
'permissions' => [
|
||||
PositionPermissionRegistry::ROOM_RED_PACKET,
|
||||
PositionPermissionRegistry::ROOM_FULLSCREEN_EFFECT,
|
||||
],
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('admin.positions.index'));
|
||||
|
||||
$position->refresh();
|
||||
|
||||
$this->assertSame([
|
||||
PositionPermissionRegistry::ROOM_RED_PACKET,
|
||||
PositionPermissionRegistry::ROOM_FULLSCREEN_EFFECT,
|
||||
], $position->permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证职务管理页面会渲染权限配置与摘要文案。
|
||||
*/
|
||||
public function test_positions_index_renders_permission_form_and_summary(): void
|
||||
{
|
||||
$owner = $this->createSiteOwner();
|
||||
$department = $this->createDepartment();
|
||||
|
||||
Position::create([
|
||||
'department_id' => $department->id,
|
||||
'name' => '活动主持',
|
||||
'icon' => '🎁',
|
||||
'rank' => 70,
|
||||
'level' => 70,
|
||||
'sort_order' => 1,
|
||||
'permissions' => [
|
||||
PositionPermissionRegistry::ROOM_ANNOUNCEMENT,
|
||||
PositionPermissionRegistry::ROOM_RED_PACKET,
|
||||
],
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($owner)->get(route('admin.positions.index'));
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertSee('权限管理');
|
||||
$response->assertSee('设置公告');
|
||||
$response->assertSee('礼包红包');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建站长账号。
|
||||
*/
|
||||
private function createSiteOwner(): User
|
||||
{
|
||||
return User::factory()->create([
|
||||
'id' => 1,
|
||||
'user_level' => 100,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建测试用部门。
|
||||
*/
|
||||
private function createDepartment(): Department
|
||||
{
|
||||
return Department::create([
|
||||
'name' => '测试部门',
|
||||
'rank' => 90,
|
||||
'color' => '#334155',
|
||||
'sort_order' => 1,
|
||||
'description' => '后台权限测试部门',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,13 @@
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Events\RedPacketClaimed;
|
||||
use App\Models\Department;
|
||||
use App\Models\Position;
|
||||
use App\Models\RedPacketEnvelope;
|
||||
use App\Models\Sysparam;
|
||||
use App\Models\User;
|
||||
use App\Models\UserPosition;
|
||||
use App\Support\PositionPermissionRegistry;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
@@ -44,12 +48,27 @@ class RedPacketControllerTest extends TestCase
|
||||
$response->assertJson(['status' => 'error']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 方法功能:验证高等级但无职务权限的用户仍不能发送礼包。
|
||||
*/
|
||||
public function test_high_level_user_without_red_packet_permission_cannot_send_red_packet(): void
|
||||
{
|
||||
$user = User::factory()->create(['user_level' => 100]);
|
||||
|
||||
$response = $this->actingAs($user)->postJson(route('command.red_packet.send'), [
|
||||
'room_id' => 1,
|
||||
'type' => 'gold',
|
||||
]);
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* 方法功能:验证站长可以成功发出礼包并写入 Redis 拆包结果。
|
||||
*/
|
||||
public function test_superadmin_can_send_red_packet(): void
|
||||
{
|
||||
$admin = User::factory()->create(['user_level' => 100]);
|
||||
$admin = $this->createSiteOwner();
|
||||
|
||||
$response = $this->actingAs($admin)->postJson(route('command.red_packet.send'), [
|
||||
'room_id' => 1,
|
||||
@@ -71,12 +90,31 @@ class RedPacketControllerTest extends TestCase
|
||||
$this->assertEquals(10, Redis::llen("red_packet:{$envelope->id}:amounts"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 方法功能:验证拥有礼包权限的职务用户可以发礼包。
|
||||
*/
|
||||
public function test_position_user_with_red_packet_permission_can_send_red_packet(): void
|
||||
{
|
||||
$user = $this->createUserWithPermissions([
|
||||
PositionPermissionRegistry::ROOM_RED_PACKET,
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)->postJson(route('command.red_packet.send'), [
|
||||
'room_id' => 1,
|
||||
'type' => 'exp',
|
||||
]);
|
||||
|
||||
$response->assertOk()->assertJson([
|
||||
'status' => 'success',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 方法功能:验证同一房间内不可重复发送未结束的礼包。
|
||||
*/
|
||||
public function test_cannot_send_multiple_active_packets_in_same_room(): void
|
||||
{
|
||||
$admin = User::factory()->create(['user_level' => 100]);
|
||||
$admin = $this->createSiteOwner();
|
||||
|
||||
$this->actingAs($admin)->postJson(route('command.red_packet.send'), [
|
||||
'room_id' => 1,
|
||||
@@ -96,7 +134,7 @@ class RedPacketControllerTest extends TestCase
|
||||
*/
|
||||
public function test_user_can_claim_red_packet(): void
|
||||
{
|
||||
$admin = User::factory()->create(['user_level' => 100]);
|
||||
$admin = $this->createSiteOwner();
|
||||
$user = User::factory()->create(['jjb' => 100]);
|
||||
|
||||
// Send packet
|
||||
@@ -131,7 +169,7 @@ class RedPacketControllerTest extends TestCase
|
||||
{
|
||||
Event::fake([RedPacketClaimed::class]);
|
||||
|
||||
$admin = User::factory()->create(['user_level' => 100]);
|
||||
$admin = $this->createSiteOwner();
|
||||
$user = User::factory()->create(['jjb' => 100]);
|
||||
|
||||
$this->actingAs($admin)->postJson(route('command.red_packet.send'), [
|
||||
@@ -165,7 +203,7 @@ class RedPacketControllerTest extends TestCase
|
||||
*/
|
||||
public function test_user_cannot_claim_same_packet_twice(): void
|
||||
{
|
||||
$admin = User::factory()->create(['user_level' => 100]);
|
||||
$admin = $this->createSiteOwner();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($admin)->postJson(route('command.red_packet.send'), [
|
||||
@@ -194,7 +232,7 @@ class RedPacketControllerTest extends TestCase
|
||||
*/
|
||||
public function test_can_check_packet_status(): void
|
||||
{
|
||||
$admin = User::factory()->create(['user_level' => 100]);
|
||||
$admin = $this->createSiteOwner();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($admin)->postJson(route('command.red_packet.send'), [
|
||||
@@ -224,4 +262,56 @@ class RedPacketControllerTest extends TestCase
|
||||
'has_claimed' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建站长账号。
|
||||
*/
|
||||
private function createSiteOwner(): User
|
||||
{
|
||||
return User::factory()->create([
|
||||
'id' => 1,
|
||||
'user_level' => 100,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带指定聊天室权限的在职职务用户。
|
||||
*
|
||||
* @param list<string> $permissions
|
||||
*/
|
||||
private function createUserWithPermissions(array $permissions): User
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'user_level' => 80,
|
||||
]);
|
||||
|
||||
$department = Department::create([
|
||||
'name' => '红包权限部'.$user->id,
|
||||
'rank' => 80,
|
||||
'color' => '#dc2626',
|
||||
'sort_order' => 1,
|
||||
'description' => '红包权限测试',
|
||||
]);
|
||||
|
||||
$position = Position::create([
|
||||
'department_id' => $department->id,
|
||||
'name' => '红包权限职务'.$user->id,
|
||||
'icon' => '🧧',
|
||||
'rank' => 80,
|
||||
'level' => 80,
|
||||
'sort_order' => 1,
|
||||
'permissions' => $permissions,
|
||||
]);
|
||||
|
||||
UserPosition::create([
|
||||
'user_id' => $user->id,
|
||||
'position_id' => $position->id,
|
||||
'appointed_by_user_id' => null,
|
||||
'appointed_at' => now(),
|
||||
'remark' => '红包权限测试',
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
return $user->fresh();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user