聊天室管理权限统一为职务权限
This commit is contained in:
@@ -2,13 +2,8 @@
|
||||
|
||||
/**
|
||||
* 文件功能:用户中心与管理控制器
|
||||
* 接管原版 USERinfo.ASP, USERSET.ASP, chpasswd.asp, KILLUSER.ASP, LOCKIP.ASP
|
||||
*
|
||||
* 权限等级通过 sysparam 表动态配置:
|
||||
* level_kick - 踢人所需等级
|
||||
* level_mute - 禁言所需等级
|
||||
* level_ban - 封号所需等级
|
||||
* level_banip - 封IP所需等级
|
||||
* 接管原版 USERinfo.ASP, USERSET.ASP 与 chpasswd.asp。
|
||||
* 聊天室管理动作已统一迁移到 AdminCommandController 的职务权限链路。
|
||||
*
|
||||
* @author ChatRoom Laravel
|
||||
*
|
||||
@@ -18,25 +13,23 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Enums\CurrencySource;
|
||||
use App\Events\UserKicked;
|
||||
use App\Events\UserMuted;
|
||||
use App\Events\UserStatusUpdated;
|
||||
use App\Http\Requests\ChangePasswordRequest;
|
||||
use App\Http\Requests\RevealProfileInfoRequest;
|
||||
use App\Http\Requests\UpdateChatPreferencesRequest;
|
||||
use App\Http\Requests\UpdateDailyStatusRequest;
|
||||
use App\Http\Requests\UpdateProfileRequest;
|
||||
use App\Models\Room;
|
||||
use App\Models\Sysparam;
|
||||
use App\Models\User;
|
||||
use App\Services\ChatStateService;
|
||||
use App\Services\ChatUserPresenceService;
|
||||
use App\Services\PositionPermissionService;
|
||||
use App\Services\UserCurrencyService;
|
||||
use App\Support\PositionPermissionRegistry;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
/**
|
||||
* 类功能:处理用户资料、聊天室偏好、当日状态与基础管理动作。
|
||||
@@ -65,6 +58,7 @@ class UserController extends Controller
|
||||
private readonly ChatStateService $chatState,
|
||||
private readonly ChatUserPresenceService $chatUserPresenceService,
|
||||
private readonly UserCurrencyService $currencyService,
|
||||
private readonly PositionPermissionService $positionPermissionService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -166,9 +160,10 @@ class UserController extends Controller
|
||||
] : null,
|
||||
];
|
||||
|
||||
// 拥有封禁IP(level_banip)或踢人以上权限的管理,可以查看IP和归属地
|
||||
$levelBanIp = (int) Sysparam::getValue('level_banip', '15');
|
||||
if ($operator && $operator->user_level >= $levelBanIp) {
|
||||
// 管理员网络信息仅对站长或拥有「封IP」职务权限的操作者展示。
|
||||
$canViewNetworkInfo = $operator
|
||||
&& ($operator->id === 1 || $this->positionPermissionService->hasPermission($operator, PositionPermissionRegistry::USER_BANIP));
|
||||
if ($canViewNetworkInfo) {
|
||||
$data['first_ip'] = $targetUser->first_ip;
|
||||
// last_ip 目前定义为『上次登录IP』(取数据库 previous_ip)
|
||||
$data['last_ip'] = $targetUser->previous_ip;
|
||||
@@ -415,7 +410,7 @@ class UserController extends Controller
|
||||
/**
|
||||
* 生成微信绑定代码
|
||||
*/
|
||||
public function generateWechatCode(\Illuminate\Http\Request $request): JsonResponse
|
||||
public function generateWechatCode(Request $request): JsonResponse
|
||||
{
|
||||
$user = \Illuminate\Support\Facades\Auth::user();
|
||||
if (! $user) {
|
||||
@@ -435,7 +430,7 @@ class UserController extends Controller
|
||||
/**
|
||||
* 取消绑定微信
|
||||
*/
|
||||
public function unbindWechat(\Illuminate\Http\Request $request): JsonResponse
|
||||
public function unbindWechat(Request $request): JsonResponse
|
||||
{
|
||||
$user = \Illuminate\Support\Facades\Auth::user();
|
||||
if (! $user) {
|
||||
@@ -451,162 +446,6 @@ class UserController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用权限校验:检查操作者是否有权操作目标用户
|
||||
*
|
||||
* @param object $operator 操作者
|
||||
* @param string $targetUsername 目标用户名
|
||||
* @param int $roomId 房间ID
|
||||
* @param string $levelKey sysparam中的等级键名(如 level_kick)
|
||||
* @param string $actionName 操作名称(用于错误提示)
|
||||
* @return array{room: Room, target: User}|JsonResponse
|
||||
*/
|
||||
private function checkPermission(object $operator, string $targetUsername, int $roomId, string $levelKey, string $actionName): array|JsonResponse
|
||||
{
|
||||
$room = Room::findOrFail($roomId);
|
||||
$requiredLevel = (int) Sysparam::getValue($levelKey, '15');
|
||||
|
||||
// 鉴权:操作者要是房间房主或达到所需等级
|
||||
if ($room->master !== $operator->username && $operator->user_level < $requiredLevel) {
|
||||
return response()->json(['status' => 'error', 'message' => "权限不足(需要{$requiredLevel}级),无法执行{$actionName}操作。"], 403);
|
||||
}
|
||||
|
||||
$targetUser = User::where('username', $targetUsername)->first();
|
||||
if (! $targetUser) {
|
||||
return response()->json(['status' => 'error', 'message' => '目标用户不存在。'], 404);
|
||||
}
|
||||
|
||||
// 防误伤:不能操作等级 >= 自己的人
|
||||
if ($targetUser->user_level >= $operator->user_level) {
|
||||
return response()->json(['status' => 'error', 'message' => "权限不足,无法对同级或高级用户执行{$actionName}。"], 403);
|
||||
}
|
||||
|
||||
return ['room' => $room, 'target' => $targetUser];
|
||||
}
|
||||
|
||||
/**
|
||||
* 踢出房间 (对应 KILLUSER.ASP)
|
||||
* 所需等级由 sysparam level_kick 配置
|
||||
*/
|
||||
public function kick(Request $request, string $username): JsonResponse
|
||||
{
|
||||
$operator = Auth::user();
|
||||
$roomId = $request->input('room_id');
|
||||
|
||||
if (! $roomId) {
|
||||
return response()->json(['status' => 'error', 'message' => '缺少房间参数。'], 422);
|
||||
}
|
||||
|
||||
$result = $this->checkPermission($operator, $username, $roomId, 'level_kick', '踢出');
|
||||
if ($result instanceof JsonResponse) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// 广播踢出事件
|
||||
broadcast(new UserKicked($roomId, $result['target']->username, "管理员 [{$operator->username}] 将 [{$result['target']->username}] 踢出了聊天室。"));
|
||||
|
||||
return response()->json(['status' => 'success', 'message' => "已成功将 {$result['target']->username} 踢出房间。"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁言 (对应原版限制功能)
|
||||
* 所需等级由 sysparam level_mute 配置
|
||||
* 禁言信息存入 Redis,TTL 到期自动解除
|
||||
*/
|
||||
public function mute(Request $request, string $username): JsonResponse
|
||||
{
|
||||
$operator = Auth::user();
|
||||
$roomId = $request->input('room_id');
|
||||
$duration = (int) $request->input('duration', 5);
|
||||
|
||||
if (! $roomId) {
|
||||
return response()->json(['status' => 'error', 'message' => '缺少房间参数。'], 422);
|
||||
}
|
||||
|
||||
$result = $this->checkPermission($operator, $username, $roomId, 'level_mute', '禁言');
|
||||
if ($result instanceof JsonResponse) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// 写入 Redis 禁言标记,TTL = 禁言分钟数 * 60
|
||||
Redis::setex("mute:{$roomId}:{$username}", $duration * 60, json_encode([
|
||||
'operator' => $operator->username,
|
||||
'reason' => '管理员禁言',
|
||||
'until' => now()->addMinutes($duration)->toDateTimeString(),
|
||||
]));
|
||||
|
||||
// 广播禁言事件
|
||||
broadcast(new UserMuted($roomId, $username, $duration));
|
||||
|
||||
return response()->json(['status' => 'success', 'message' => "已对 {$username} 实施禁言 {$duration} 分钟。"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 封号(禁止登录)
|
||||
* 所需等级由 sysparam level_ban 配置
|
||||
* 将用户等级设为 -1 表示封禁
|
||||
*/
|
||||
public function ban(Request $request, string $username): JsonResponse
|
||||
{
|
||||
$operator = Auth::user();
|
||||
$roomId = $request->input('room_id');
|
||||
|
||||
if (! $roomId) {
|
||||
return response()->json(['status' => 'error', 'message' => '缺少房间参数。'], 422);
|
||||
}
|
||||
|
||||
$result = $this->checkPermission($operator, $username, $roomId, 'level_ban', '封号');
|
||||
if ($result instanceof JsonResponse) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// 封号:设置等级为 -1
|
||||
$result['target']->user_level = -1;
|
||||
$result['target']->save();
|
||||
|
||||
// 踢出聊天室
|
||||
broadcast(new UserKicked($roomId, $username, "管理员 [{$operator->username}] 已封禁用户 [{$username}] 的账号。"));
|
||||
|
||||
return response()->json(['status' => 'success', 'message' => "用户 {$username} 已被封号。"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 封IP(记录IP到黑名单并踢出)
|
||||
* 所需等级由 sysparam level_banip 配置
|
||||
*/
|
||||
public function banIp(Request $request, string $username): JsonResponse
|
||||
{
|
||||
$operator = Auth::user();
|
||||
$roomId = $request->input('room_id');
|
||||
|
||||
if (! $roomId) {
|
||||
return response()->json(['status' => 'error', 'message' => '缺少房间参数。'], 422);
|
||||
}
|
||||
|
||||
$result = $this->checkPermission($operator, $username, $roomId, 'level_banip', '封IP');
|
||||
if ($result instanceof JsonResponse) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$targetIp = $result['target']->last_ip;
|
||||
|
||||
if ($targetIp) {
|
||||
// 将IP加入 Redis 黑名单(永久)
|
||||
Redis::sadd('banned_ips', $targetIp);
|
||||
}
|
||||
|
||||
// 同时封号
|
||||
$result['target']->user_level = -1;
|
||||
$result['target']->save();
|
||||
|
||||
// 踢出聊天室
|
||||
broadcast(new UserKicked($roomId, $username, "管理员 [{$operator->username}] 已封禁用户 [{$username}] 的IP地址。"));
|
||||
|
||||
$ipInfo = $targetIp ? "(IP: {$targetIp})" : '(未记录IP)';
|
||||
|
||||
return response()->json(['status' => 'success', 'message' => "用户 {$username} 已被封号并封IP{$ipInfo}。"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断操作者是否可以免费查看目标用户经验、金币与魅力。
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user