fix: allow owner role to access all admin api endpoints and see stats

This commit is contained in:
dyzulk
2025-12-30 20:29:35 +07:00
parent a14d788400
commit 1eabedcb5b
6 changed files with 34 additions and 30 deletions

View File

@@ -40,14 +40,14 @@ class DashboardController extends Controller
// Tickets (Role Based) // Tickets (Role Based)
$ticketQuery = Ticket::query()->whereIn('status', ['open', 'answered']); $ticketQuery = Ticket::query()->whereIn('status', ['open', 'answered']);
if (!$user->isAdmin()) { if (!$user->isAdminOrOwner()) {
$ticketQuery->where('user_id', $user->id); $ticketQuery->where('user_id', $user->id);
} }
$activeTickets = $ticketQuery->count(); $activeTickets = $ticketQuery->count();
// Previous Tickets (Role Based) // Previous Tickets (Role Based)
$prevTicketQuery = Ticket::query()->whereIn('status', ['open', 'answered'])->where('created_at', '<', $currentMonth); $prevTicketQuery = Ticket::query()->whereIn('status', ['open', 'answered'])->where('created_at', '<', $currentMonth);
if (!$user->isAdmin()) { if (!$user->isAdminOrOwner()) {
$prevTicketQuery->where('user_id', $user->id); $prevTicketQuery->where('user_id', $user->id);
} }
$prevActiveTickets = $prevTicketQuery->count(); $prevActiveTickets = $prevTicketQuery->count();
@@ -76,7 +76,7 @@ class DashboardController extends Controller
]; ];
// Admin only stats // Admin only stats
if ($user->isAdmin()) { if ($user->isAdminOrOwner()) {
$totalUsers = User::count(); $totalUsers = User::count();
$prevUsers = User::where('created_at', '<', $currentMonth)->count(); $prevUsers = User::where('created_at', '<', $currentMonth)->count();
@@ -108,7 +108,7 @@ class DashboardController extends Controller
->latest() ->latest()
->take(10); ->take(10);
if (!$user->isAdmin()) { if (!$user->isAdminOrOwner()) {
$activityLogQuery->where('user_id', $user->id); $activityLogQuery->where('user_id', $user->id);
} }
@@ -128,7 +128,7 @@ class DashboardController extends Controller
for ($i = 6; $i >= 0; $i--) { for ($i = 6; $i >= 0; $i--) {
$date = now()->subDays($i)->format('Y-m-d'); $date = now()->subDays($i)->format('Y-m-d');
$countQuery = Certificate::whereDate('created_at', $date); $countQuery = Certificate::whereDate('created_at', $date);
if (!$user->isAdmin()) { if (!$user->isAdminOrOwner()) {
$countQuery->where('user_id', $user->id); $countQuery->where('user_id', $user->id);
} }

View File

@@ -34,8 +34,8 @@ class InquiryController extends Controller
$inquiry = Inquiry::create($request->all()); $inquiry = Inquiry::create($request->all());
try { try {
// Notify all admins // Notify all admins and owners
$admins = User::where('role', 'admin')->get(); $admins = User::whereIn('role', [User::ROLE_ADMIN, User::ROLE_OWNER])->get();
Notification::send($admins, new NewInquiryNotification($inquiry)); Notification::send($admins, new NewInquiryNotification($inquiry));
} catch (\Exception $e) { } catch (\Exception $e) {
// Log the error but fail silently to the user, as the inquiry was saved. // Log the error but fail silently to the user, as the inquiry was saved.

View File

@@ -18,7 +18,7 @@ class RootCaApiController extends Controller
public function index() public function index()
{ {
$this->authorizeAdmin(); $this->authorizeAdminOrOwner();
$certificates = CaCertificate::all()->map(function($cert) { $certificates = CaCertificate::all()->map(function($cert) {
$cert->status = $cert->valid_to->isFuture() ? 'valid' : 'expired'; $cert->status = $cert->valid_to->isFuture() ? 'valid' : 'expired';
@@ -33,7 +33,7 @@ class RootCaApiController extends Controller
public function renew(Request $request, CaCertificate $certificate) public function renew(Request $request, CaCertificate $certificate)
{ {
$this->authorizeAdmin(); $this->authorizeAdminOrOwner();
$days = (int) $request->input('days', 3650); $days = (int) $request->input('days', 3650);
@@ -60,10 +60,10 @@ class RootCaApiController extends Controller
} }
} }
protected function authorizeAdmin() protected function authorizeAdminOrOwner()
{ {
if (auth()->user()->role !== 'admin') { if (!auth()->user()->isAdminOrOwner()) {
abort(403, 'Unauthorized action.'); abort(403, 'Unauthorized action. Admin/Owner access required.');
} }
} }
} }

View File

@@ -28,7 +28,7 @@ class TicketController extends Controller
$query = Ticket::with(['user:id,first_name,last_name,email,avatar', 'replies.user:id,first_name,last_name,avatar', 'replies.attachments']); $query = Ticket::with(['user:id,first_name,last_name,email,avatar', 'replies.user:id,first_name,last_name,avatar', 'replies.attachments']);
// Only show all tickets if user is admin AND explicitly asks for all // Only show all tickets if user is admin AND explicitly asks for all
if ($user->isAdmin() && $request->has('all')) { if ($user->isAdminOrOwner() && $request->has('all')) {
// No additional where clause needed // No additional where clause needed
} else { } else {
// Everyone else (including admins in personal view) only sees their own // Everyone else (including admins in personal view) only sees their own
@@ -96,7 +96,7 @@ class TicketController extends Controller
// Notify Admins // Notify Admins
try { try {
$admins = User::where('role', 'admin') $admins = User::whereIn('role', ['admin', 'owner'])
->where('id', '!=', $user->id) ->where('id', '!=', $user->id)
->get(); ->get();
if ($admins->isNotEmpty()) { if ($admins->isNotEmpty()) {
@@ -126,7 +126,7 @@ class TicketController extends Controller
$user = $request->user(); $user = $request->user();
$ticket = Ticket::with(['user:id,first_name,last_name,email,avatar', 'replies.user:id,first_name,last_name,avatar', 'replies.attachments'])->findOrFail($id); $ticket = Ticket::with(['user:id,first_name,last_name,email,avatar', 'replies.user:id,first_name,last_name,avatar', 'replies.attachments'])->findOrFail($id);
if (!$user->isAdmin() && $ticket->user_id !== $user->id) { if (!$user->isAdminOrOwner() && $ticket->user_id !== $user->id) {
return response()->json(['message' => 'Unauthorized'], 403); return response()->json(['message' => 'Unauthorized'], 403);
} }
@@ -141,7 +141,7 @@ class TicketController extends Controller
$user = $request->user(); $user = $request->user();
$ticket = Ticket::findOrFail($id); $ticket = Ticket::findOrFail($id);
if (!$user->isAdmin() && $ticket->user_id !== $user->id) { if (!$user->isAdminOrOwner() && $ticket->user_id !== $user->id) {
return response()->json(['message' => 'Unauthorized'], 403); return response()->json(['message' => 'Unauthorized'], 403);
} }
@@ -184,7 +184,7 @@ class TicketController extends Controller
// Update ticket status & Notify // Update ticket status & Notify
try { try {
if ($user->isAdmin()) { if ($user->isAdminOrOwner()) {
$ticket->update(['status' => 'answered']); $ticket->update(['status' => 'answered']);
// Notify Customer // Notify Customer
$ticketUser = $ticket->user; $ticketUser = $ticket->user;
@@ -192,19 +192,19 @@ class TicketController extends Controller
$ticketUser->notify(new TicketReplyNotification($ticket, $reply, true)); $ticketUser->notify(new TicketReplyNotification($ticket, $reply, true));
} }
// Also notify OTHER admins // Also notify OTHER admins/owners
$otherAdmins = User::where('role', 'admin') $otherStaff = User::whereIn('role', ['admin', 'owner'])
->where('id', '!=', $user->id) ->where('id', '!=', $user->id)
->get(); ->get();
if ($otherAdmins->isNotEmpty()) { if ($otherStaff->isNotEmpty()) {
Notification::send($otherAdmins, new TicketReplyNotification($ticket, $reply, true)); Notification::send($otherStaff, new TicketReplyNotification($ticket, $reply, true));
} }
} else { } else {
$ticket->update(['status' => 'open']); $ticket->update(['status' => 'open']);
// Notify All Admins // Notify All Staff (Admins & Owners)
$admins = User::where('role', 'admin')->get(); $staff = User::whereIn('role', ['admin', 'owner'])->get();
if ($admins->isNotEmpty()) { if ($staff->isNotEmpty()) {
Notification::send($admins, new TicketReplyNotification($ticket, $reply, false)); Notification::send($staff, new TicketReplyNotification($ticket, $reply, false));
} }
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
@@ -225,7 +225,7 @@ class TicketController extends Controller
$user = $request->user(); $user = $request->user();
$ticket = Ticket::findOrFail($id); $ticket = Ticket::findOrFail($id);
if (!$user->isAdmin() && $ticket->user_id !== $user->id) { if (!$user->isAdminOrOwner() && $ticket->user_id !== $user->id) {
return response()->json(['message' => 'Unauthorized'], 403); return response()->json(['message' => 'Unauthorized'], 403);
} }

View File

@@ -16,7 +16,10 @@ class AdminMiddleware
public function handle(Request $request, Closure $next): Response public function handle(Request $request, Closure $next): Response
{ {
if (!$request->user() || !$request->user()->isAdminOrOwner()) { if (!$request->user() || !$request->user()->isAdminOrOwner()) {
return response()->json(['message' => 'Unauthorized. Admin access required.'], 403); $role = $request->user() ? $request->user()->role : 'guest';
return response()->json([
'message' => "Unauthorized. Admin access required. (Current role: {$role})"
], 403);
} }
return $next($request); return $next($request);

View File

@@ -103,7 +103,7 @@ class User extends Authenticatable implements MustVerifyEmail
*/ */
public function isOwner(): bool public function isOwner(): bool
{ {
return $this->role === self::ROLE_OWNER; return strtolower($this->role) === self::ROLE_OWNER;
} }
/** /**
@@ -111,7 +111,7 @@ class User extends Authenticatable implements MustVerifyEmail
*/ */
public function isAdmin(): bool public function isAdmin(): bool
{ {
return $this->role === self::ROLE_ADMIN; return strtolower($this->role) === self::ROLE_ADMIN;
} }
/** /**
@@ -119,7 +119,8 @@ class User extends Authenticatable implements MustVerifyEmail
*/ */
public function isAdminOrOwner(): bool public function isAdminOrOwner(): bool
{ {
return in_array($this->role, [self::ROLE_OWNER, self::ROLE_ADMIN]); $role = strtolower($this->role);
return in_array($role, [self::ROLE_OWNER, self::ROLE_ADMIN]);
} }
/** /**