[FIX] 取貨碼/通行碼/來店禮:客戶帳號跨未授權機台導致頁面崩潰與越權
1. 列表與操作紀錄查詢加上 whereHas('machine'),依 machine_user 授權過濾,客戶帳號只看得到可存取機台的資料(系統管理員不受影響)
2. pickup_code_logs.machine_id 可為 null,該紀錄查詢改為「machine_id 為 null 或機台可存取」以保留非機台紀錄
3. destroyPickupCode/destroyPassCode/destroyWelcomeGift 加上機台授權守衛,非系統管理員越權刪除回傳 403
4. tab-list blade 將 $x->machine->name 等改為 null-safe,作為縱深防禦
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6e5307933f
commit
38f5071975
@ -194,7 +194,10 @@ class SalesController extends Controller
|
||||
|
||||
// 1. 取貨碼列表 (list)
|
||||
if (!$isAjax || $tab === 'list') {
|
||||
$query = PickupCode::with(['machine.slots.product', 'creator', 'order'])->latest();
|
||||
// 僅顯示目前帳號可存取機台的取貨碼(機台授權以 machine_user 為準,whereHas 會套用 Machine 的 machine_access 全域 scope)
|
||||
$query = PickupCode::with(['machine.slots.product', 'creator', 'order'])
|
||||
->whereHas('machine')
|
||||
->latest();
|
||||
|
||||
if ($request->search) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
@ -219,7 +222,12 @@ class SalesController extends Controller
|
||||
|
||||
// 2. 操作紀錄 (logs)
|
||||
if (!$isAjax || $tab === 'logs') {
|
||||
$logQuery = PickupCodeLog::with(['user:id,name', 'machine:id,name,serial_no', 'pickupCode', 'order']);
|
||||
// 同上:操作紀錄只顯示可存取機台的資料(machine_id 為 null 的非機台紀錄仍保留)
|
||||
$logQuery = PickupCodeLog::with(['user:id,name', 'machine:id,name,serial_no', 'pickupCode', 'order'])
|
||||
->where(function ($q) {
|
||||
$q->whereNull('machine_id')
|
||||
->orWhereHas('machine');
|
||||
});
|
||||
|
||||
if ($request->filled('search_log')) {
|
||||
$search = $request->input('search_log');
|
||||
@ -362,6 +370,11 @@ class SalesController extends Controller
|
||||
*/
|
||||
public function destroyPickupCode(PickupCode $pickupCode)
|
||||
{
|
||||
// 機台授權以 machine_user 為準:非系統管理員若無法存取該取貨碼所屬機台則拒絕
|
||||
if (!Auth::user()->isSystemAdmin() && !Machine::whereKey($pickupCode->machine_id)->exists()) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$oldValues = $pickupCode->toArray();
|
||||
$pickupCode->update(['status' => 'cancelled']);
|
||||
|
||||
@ -411,7 +424,10 @@ class SalesController extends Controller
|
||||
|
||||
// 1. 通行碼列表 (list)
|
||||
if (!$isAjax || $tab === 'list') {
|
||||
$query = PassCode::with(['machine', 'creator'])->latest();
|
||||
// 僅顯示目前帳號可存取機台的通行碼(機台授權以 machine_user 為準,whereHas 會套用 Machine 的 machine_access 全域 scope)
|
||||
$query = PassCode::with(['machine', 'creator'])
|
||||
->whereHas('machine')
|
||||
->latest();
|
||||
|
||||
if ($request->search) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
@ -447,7 +463,9 @@ class SalesController extends Controller
|
||||
|
||||
// 2. 操作紀錄 (logs)
|
||||
if (!$isAjax || $tab === 'logs') {
|
||||
$logQuery = PassCodeLog::with(['user:id,name', 'machine:id,name,serial_no', 'passCode']);
|
||||
// 同上:操作紀錄只顯示可存取機台的資料(pass_code_logs.machine_id 為 NOT NULL)
|
||||
$logQuery = PassCodeLog::with(['user:id,name', 'machine:id,name,serial_no', 'passCode'])
|
||||
->whereHas('machine');
|
||||
|
||||
if ($request->filled('search_log')) {
|
||||
$search = $request->input('search_log');
|
||||
@ -587,6 +605,11 @@ class SalesController extends Controller
|
||||
*/
|
||||
public function destroyPassCode(PassCode $passCode)
|
||||
{
|
||||
// 機台授權以 machine_user 為準:非系統管理員若無法存取該通行碼所屬機台則拒絕
|
||||
if (!Auth::user()->isSystemAdmin() && !Machine::whereKey($passCode->machine_id)->exists()) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$oldValues = $passCode->toArray();
|
||||
$passCode->update(['status' => 'disabled']);
|
||||
|
||||
@ -618,7 +641,10 @@ class SalesController extends Controller
|
||||
|
||||
// 1. 來店禮列表 (list)
|
||||
if (!$isAjax || $tab === 'list') {
|
||||
$query = WelcomeGift::with(['machine', 'creator'])->latest();
|
||||
// 僅顯示目前帳號可存取機台的來店禮(機台授權以 machine_user 為準,whereHas 會套用 Machine 的 machine_access 全域 scope)
|
||||
$query = WelcomeGift::with(['machine', 'creator'])
|
||||
->whereHas('machine')
|
||||
->latest();
|
||||
|
||||
if ($request->search) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
@ -654,7 +680,9 @@ class SalesController extends Controller
|
||||
|
||||
// 2. 操作紀錄 (logs)
|
||||
if (!$isAjax || $tab === 'logs') {
|
||||
$logQuery = WelcomeGiftLog::with(['machine:id,name,serial_no', 'welcomeGift', 'order:id,order_no']);
|
||||
// 同上:操作紀錄只顯示可存取機台的資料(welcome_gift_logs.machine_id 為 NOT NULL)
|
||||
$logQuery = WelcomeGiftLog::with(['machine:id,name,serial_no', 'welcomeGift', 'order:id,order_no'])
|
||||
->whereHas('machine');
|
||||
|
||||
if ($request->filled('search_log')) {
|
||||
$search = $request->input('search_log');
|
||||
@ -846,6 +874,11 @@ class SalesController extends Controller
|
||||
*/
|
||||
public function destroyWelcomeGift(WelcomeGift $welcomeGift)
|
||||
{
|
||||
// 機台授權以 machine_user 為準:非系統管理員若無法存取該來店禮所屬機台則拒絕
|
||||
if (!Auth::user()->isSystemAdmin() && !Machine::whereKey($welcomeGift->machine_id)->exists()) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$oldValues = $welcomeGift->toArray();
|
||||
$welcomeGift->update(['status' => 'disabled']);
|
||||
|
||||
|
||||
@ -109,7 +109,7 @@
|
||||
<div class="text-base font-extrabold text-slate-800 dark:text-slate-100 tracking-tight">
|
||||
{{ $code->name }}</div>
|
||||
<div class="text-xs font-bold text-slate-400 uppercase tracking-widest">{{
|
||||
$code->machine->name }}</div>
|
||||
$code->machine?->name ?? '-' }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-6 whitespace-nowrap">
|
||||
@if($code->expires_at)
|
||||
@ -241,7 +241,7 @@
|
||||
class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1">
|
||||
{{ __('Machine') }}</p>
|
||||
<p class="text-sm font-bold text-slate-700 dark:text-slate-300 truncate">{{
|
||||
$code->machine->name }}</p>
|
||||
$code->machine?->name ?? '-' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p
|
||||
|
||||
@ -117,15 +117,15 @@
|
||||
<td class="px-6 py-6">
|
||||
<div
|
||||
class="text-base font-extrabold text-slate-800 dark:text-slate-100 tracking-tight">
|
||||
{{ $code->machine->name }}</div>
|
||||
{{ $code->machine?->name ?? '-' }}</div>
|
||||
<div
|
||||
class="text-[10px] font-bold text-slate-400 uppercase tracking-[0.2em]">
|
||||
{{
|
||||
$code->machine->serial_no }}</div>
|
||||
$code->machine?->serial_no }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-6">
|
||||
@php
|
||||
$slot = $code->machine->slots->where('slot_no', $code->slot_no)->first();
|
||||
$slot = $code->machine?->slots->where('slot_no', $code->slot_no)->first();
|
||||
$productName = $slot ? ($slot->product?->name ?? __('Empty')) : __('Empty');
|
||||
@endphp
|
||||
<div class="text-sm font-black text-cyan-600 dark:text-cyan-400 mb-0.5">{{
|
||||
@ -251,7 +251,7 @@
|
||||
@endif
|
||||
<p
|
||||
class="text-xs font-mono font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest truncate">
|
||||
{{ $code->machine->name }}
|
||||
{{ $code->machine?->name ?? '-' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -287,7 +287,7 @@
|
||||
<p class="text-sm font-bold text-slate-700 dark:text-slate-300">
|
||||
{{ $code->slot_no }}
|
||||
@php
|
||||
$slotMobile = $code->machine->slots->where('slot_no',
|
||||
$slotMobile = $code->machine?->slots->where('slot_no',
|
||||
$code->slot_no)->first();
|
||||
$prodMobile = $slotMobile ? ($slotMobile->product?->name ?? __('Empty')) :
|
||||
__('Empty');
|
||||
|
||||
@ -108,7 +108,7 @@
|
||||
<div class="text-base font-extrabold text-slate-800 dark:text-slate-100 tracking-tight">
|
||||
{{ $gift->name }}</div>
|
||||
<div class="text-xs font-bold text-slate-400 uppercase tracking-widest">{{
|
||||
$gift->machine->name }}</div>
|
||||
$gift->machine?->name ?? '-' }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-6 whitespace-nowrap">
|
||||
<span class="text-sm font-black text-indigo-600 dark:text-indigo-400 bg-indigo-50 dark:bg-indigo-500/10 px-3 py-1 rounded-lg border border-indigo-100 dark:border-indigo-500/20">
|
||||
@ -258,7 +258,7 @@
|
||||
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1">
|
||||
{{ __('Machine') }}</p>
|
||||
<p class="text-sm font-bold text-slate-700 dark:text-slate-300 truncate">
|
||||
{{ $gift->machine->name }}</p>
|
||||
{{ $gift->machine?->name ?? '-' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user