[FIX] 遷移機台授權為獨立模組:修復變數命名、補齊多語系並強化多租戶數據隔離
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 54s
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 54s
This commit is contained in:
@@ -14,7 +14,6 @@ use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\System\User;
|
||||
|
||||
class MachineSettingController extends AdminController
|
||||
{
|
||||
@@ -46,18 +45,8 @@ class MachineSettingController extends AdminController
|
||||
}
|
||||
$models_list = $modelQuery->latest()->paginate($per_page)->withQueryString();
|
||||
|
||||
// 3. 處理使用者清單 (Accounts Tab - 授權帳號)
|
||||
$userQuery = User::query()->with('machines')->whereNotNull('company_id'); // 僅列出租戶帳號以供分配
|
||||
if ($tab === 'accounts' && $search) {
|
||||
$userQuery->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', "%{$search}%")
|
||||
->orWhere('username', 'like', "%{$search}%")
|
||||
->orWhere('email', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
$users_list = $userQuery->latest()->paginate($per_page)->withQueryString();
|
||||
|
||||
// 4. 基礎下拉資料 (用於新增/編輯機台的彈窗)
|
||||
// 3. 基礎下拉資料 (用於新增/編輯機台的彈窗)
|
||||
$models = MachineModel::select('id', 'name')->get();
|
||||
$paymentConfigs = PaymentConfig::select('id', 'name')->get();
|
||||
$companies = \App\Models\System\Company::select('id', 'name', 'code')->get();
|
||||
@@ -65,7 +54,6 @@ class MachineSettingController extends AdminController
|
||||
return view('admin.basic-settings.machines.index', compact(
|
||||
'machines',
|
||||
'models_list',
|
||||
'users_list',
|
||||
'models',
|
||||
'paymentConfigs',
|
||||
'companies',
|
||||
@@ -222,66 +210,5 @@ class MachineSettingController extends AdminController
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: 取得特定帳號的機台分配狀態 (從 MachineController 遷移)
|
||||
*/
|
||||
public function getAccountMachines(User $user): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$currentUser = auth()->user();
|
||||
|
||||
// 安全檢查:只能操作自己公司的帳號(除非是系統管理員)
|
||||
if (!$currentUser->isSystemAdmin() && $user->company_id !== $currentUser->company_id) {
|
||||
return response()->json(['error' => 'Unauthorized'], 403);
|
||||
}
|
||||
|
||||
// 取得該使用者所屬公司之所有機台
|
||||
$machines = Machine::where('company_id', $user->company_id)
|
||||
->get(['id', 'name', 'serial_no']);
|
||||
|
||||
$assignedIds = $user->machines()->pluck('machines.id')->toArray();
|
||||
|
||||
return response()->json([
|
||||
'user' => $user,
|
||||
'machines' => $machines,
|
||||
'assigned_ids' => $assignedIds
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: 儲存特定帳號的機台分配 (從 MachineController 遷移)
|
||||
*/
|
||||
public function syncAccountMachines(Request $request, User $user): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$currentUser = auth()->user();
|
||||
|
||||
// 安全檢查
|
||||
if (!$currentUser->isSystemAdmin() && $user->company_id !== $currentUser->company_id) {
|
||||
return response()->json(['error' => 'Unauthorized'], 403);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'machine_ids' => 'nullable|array',
|
||||
'machine_ids.*' => 'exists:machines,id'
|
||||
]);
|
||||
|
||||
// 加固驗證:確保所有機台 ID 都屬於該使用者的公司
|
||||
if ($request->has('machine_ids')) {
|
||||
$machineIds = array_unique($request->machine_ids);
|
||||
$validCount = Machine::where('company_id', $user->company_id)
|
||||
->whereIn('id', $machineIds)
|
||||
->count();
|
||||
|
||||
if ($validCount !== count($machineIds)) {
|
||||
return response()->json(['error' => 'Invalid machine IDs provided.'], 422);
|
||||
}
|
||||
}
|
||||
|
||||
$user->machines()->sync($request->machine_ids ?? []);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => __('Permissions updated successfully'),
|
||||
'assigned_machines' => $user->machines()->select('machines.id', 'machines.name', 'machines.serial_no')->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin\Machine;
|
||||
|
||||
use App\Http\Controllers\Admin\AdminController;
|
||||
use App\Models\Machine\Machine;
|
||||
use App\Models\System\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class MachinePermissionController extends AdminController
|
||||
{
|
||||
/**
|
||||
* 顯示機台權限管理列表
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$per_page = $request->input('per_page', 10);
|
||||
$search = $request->input('search');
|
||||
|
||||
$currentUser = auth()->user();
|
||||
|
||||
// 僅列出租戶中具有「is_admin」標記的角色帳號以供分配
|
||||
$userQuery = User::query()
|
||||
->with(['machines' => function($query) {
|
||||
$query->withoutGlobalScope('machine_access')
|
||||
->select('machines.id', 'machines.name', 'machines.serial_no');
|
||||
}])
|
||||
->whereNotNull('company_id');
|
||||
|
||||
// 非系統管理員僅能看到同公司的帳號 (因 User Model 排除 TenantScoped 全域過濾,需手動注入)
|
||||
if (!$currentUser->isSystemAdmin()) {
|
||||
$userQuery->where('company_id', $currentUser->company_id);
|
||||
}
|
||||
|
||||
if ($search) {
|
||||
$userQuery->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', "%{$search}%")
|
||||
->orWhere('username', 'like', "%{$search}%")
|
||||
->orWhere('email', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
$users_list = $userQuery->latest()->paginate($per_page)->withQueryString();
|
||||
|
||||
return view('admin.machines.permissions', compact('users_list'));
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: 取得特定帳號的機台分配狀態
|
||||
*/
|
||||
public function getAccountMachines(User $user): JsonResponse
|
||||
{
|
||||
$currentUser = auth()->user();
|
||||
|
||||
// 安全檢查:只能操作自己公司的帳號(除非是系統管理員)
|
||||
if (!$currentUser->isSystemAdmin() && $user->company_id !== $currentUser->company_id) {
|
||||
return response()->json(['error' => 'Unauthorized'], 403);
|
||||
}
|
||||
|
||||
// 取得該使用者所屬公司之所有機台 (忽略個別帳號的 machine_access 限制,以公司為單位顯示)
|
||||
$machines = Machine::withoutGlobalScope('machine_access')
|
||||
->where('company_id', $user->company_id)
|
||||
->get(['id', 'name', 'serial_no']);
|
||||
|
||||
$assignedIds = $user->machines()->pluck('machines.id')->toArray();
|
||||
|
||||
return response()->json([
|
||||
'user' => $user,
|
||||
'machines' => $machines,
|
||||
'assigned_ids' => $assignedIds
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: 儲存特定帳號的機台分配
|
||||
*/
|
||||
public function syncAccountMachines(Request $request, User $user): JsonResponse
|
||||
{
|
||||
$currentUser = auth()->user();
|
||||
|
||||
// 安全檢查
|
||||
if (!$currentUser->isSystemAdmin() && $user->company_id !== $currentUser->company_id) {
|
||||
return response()->json(['error' => 'Unauthorized'], 403);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'machine_ids' => 'nullable|array',
|
||||
'machine_ids.*' => 'exists:machines,id'
|
||||
]);
|
||||
|
||||
// 加固驗證:確保所有機台 ID 都屬於該使用者的公司 (使用 withoutGlobalScope 避免管理員自身權限影響驗證邏輯)
|
||||
if ($request->has('machine_ids')) {
|
||||
$machineIds = array_unique($request->machine_ids);
|
||||
$validCount = Machine::withoutGlobalScope('machine_access')
|
||||
->where('company_id', $user->company_id)
|
||||
->whereIn('id', $machineIds)
|
||||
->count();
|
||||
|
||||
if ($validCount !== count($machineIds)) {
|
||||
return response()->json(['error' => 'Invalid machine IDs provided.'], 422);
|
||||
}
|
||||
}
|
||||
|
||||
$user->machines()->sync($request->machine_ids ?? []);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => __('Permissions updated successfully'),
|
||||
'assigned_machines' => $user->machines()->select('machines.id', 'machines.name', 'machines.serial_no')->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -195,11 +195,13 @@ class PermissionController extends Controller
|
||||
|
||||
$is_system = auth()->user()->isSystemAdmin() ? $request->boolean('is_system') : $role->is_system;
|
||||
|
||||
$role->update([
|
||||
$updateData = [
|
||||
'name' => $validated['name'],
|
||||
'is_system' => $is_system,
|
||||
'company_id' => $is_system ? null : $role->company_id,
|
||||
]);
|
||||
];
|
||||
|
||||
$role->update($updateData);
|
||||
|
||||
$perms = $validated['permissions'] ?? [];
|
||||
|
||||
@@ -363,6 +365,7 @@ class PermissionController extends Controller
|
||||
'status' => $validated['status'],
|
||||
'company_id' => $company_id,
|
||||
'phone' => $validated['phone'] ?? null,
|
||||
'is_admin' => (auth()->user()->isSystemAdmin() && !empty($validated['company_id'])),
|
||||
]);
|
||||
|
||||
$user->assignRole($role);
|
||||
@@ -430,6 +433,18 @@ class PermissionController extends Controller
|
||||
'phone' => $validated['phone'] ?? null,
|
||||
];
|
||||
|
||||
// 只有系統管理員在編輯租戶帳號時,且該帳號原本不是管理員,才可能觸發標記(視需求而定)
|
||||
// 這裡我們維持 storeAccount 的邏輯:如果是系統管理員幫公司「開站」或「首配」,才自動標記
|
||||
// 為求嚴謹,我們檢查該公司是否已經有 is_admin,如果沒有,當前這個人可以是第一個
|
||||
if (auth()->user()->isSystemAdmin() && !empty($validated['company_id']) && !$user->is_admin) {
|
||||
$hasAdmin = \App\Models\System\User::where('company_id', $validated['company_id'])
|
||||
->where('is_admin', true)
|
||||
->exists();
|
||||
if (!$hasAdmin) {
|
||||
$updateData['is_admin'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (auth()->user()->isSystemAdmin()) {
|
||||
// 防止超級管理員不小心把自己綁定到租客公司或降級
|
||||
if ($user->id === auth()->id()) {
|
||||
@@ -459,6 +474,7 @@ class PermissionController extends Controller
|
||||
'guard_name' => 'web',
|
||||
'company_id' => $target_company_id,
|
||||
'is_system' => false,
|
||||
'is_admin' => true,
|
||||
]);
|
||||
$newRole->syncPermissions($roleObj->getPermissionNames());
|
||||
$roleObj = $newRole;
|
||||
|
||||
@@ -31,6 +31,7 @@ class User extends Authenticatable
|
||||
'avatar',
|
||||
'role',
|
||||
'status',
|
||||
'is_admin',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -51,6 +52,7 @@ class User extends Authenticatable
|
||||
protected $casts = [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
'is_admin' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user