175 lines
6.0 KiB
PHP
175 lines
6.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Helpers\ResponseHelper;
|
|
use App\Models\Market\PosAccessKey;
|
|
use App\Models\Market\Store;
|
|
use App\Models\User;
|
|
use Hypervel\Http\Request;
|
|
use Hypervel\Support\Facades\Auth;
|
|
use Hyperf\Stringable\Str;
|
|
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
|
|
use App\Enums\UserActions;
|
|
|
|
class PosAccessKeyController
|
|
{
|
|
/**
|
|
* List POS access keys. Auto-expires any past-due keys first.
|
|
* - Ultimate/super operator/operator: see all keys
|
|
* - Store owner/manager: see keys for stores they own or manage
|
|
*/
|
|
public function index(Request $request)
|
|
{
|
|
if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::ViewPosAccessKeys)) {
|
|
return ResponseHelper::returnUnauthorized();
|
|
}
|
|
|
|
// Auto-deactivate any expired keys
|
|
PosAccessKey::autoExpire();
|
|
|
|
$user = Auth::user();
|
|
$acctType = $user->acct_type->value ?? $user->acct_type ?? '';
|
|
|
|
// Ultimate, Super Operator, and Operator see everything
|
|
if (in_array($acctType, ['ult', 'super operator', 'operator'])) {
|
|
$query = PosAccessKey::with(['store:id,name,hashkey,owner_id', 'store.owner:id,name,nickname,hashkey'])
|
|
->orderBy('id', 'desc');
|
|
} else {
|
|
// Non-ultimate users see their own and their descendants' stores' keys
|
|
$descendants = $user->getAllDescendants();
|
|
$descendantIds = $descendants->pluck('id')->push($user->id)->toArray();
|
|
|
|
$storeIds = Store::whereIn('owner_id', $descendantIds)
|
|
->orWhereIn('manager_id', $descendantIds)
|
|
->pluck('id')
|
|
->toArray();
|
|
|
|
$query = PosAccessKey::with(['store:id,name,hashkey,owner_id', 'store.owner:id,name,nickname,hashkey'])
|
|
->whereIn('store_id', $storeIds)
|
|
->orderBy('id', 'desc');
|
|
}
|
|
|
|
$keys = $query->get();
|
|
|
|
return ResponseHelper::returnSuccessResponse($keys, 'pos_access_keys');
|
|
}
|
|
|
|
public function store(Request $request)
|
|
{
|
|
if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::CreatePosAccessKey)) {
|
|
return ResponseHelper::returnUnauthorized();
|
|
}
|
|
|
|
$validated = $request->validate([
|
|
'name' => 'required|string|max:255',
|
|
'store_hash' => 'required|string',
|
|
'expires_at' => 'nullable|string',
|
|
]);
|
|
|
|
$store = Store::where('hashkey', $validated['store_hash'])->first();
|
|
if (!$store) {
|
|
return ResponseHelper::returnError('Store not found', 404);
|
|
}
|
|
|
|
$user = Auth::user();
|
|
$acctType = $user->acct_type->value ?? $user->acct_type ?? '';
|
|
if (!in_array($acctType, ['ult', 'super operator', 'operator'])) {
|
|
$descendants = $user->getAllDescendants();
|
|
$allowedIds = $descendants->pluck('id')->push($user->id)->toArray();
|
|
if (!in_array($store->owner_id, $allowedIds) && !in_array($store->manager_id, $allowedIds)) {
|
|
return ResponseHelper::returnError('Unauthorized to create keys for this store', 403);
|
|
}
|
|
}
|
|
|
|
$data = [
|
|
'access_key' => 'PK-' . Str::upper(Str::random(16)),
|
|
'store_id' => $store->id,
|
|
'name' => $validated['name'],
|
|
'created_by' => Auth::id(),
|
|
'status' => 'active',
|
|
];
|
|
|
|
// Set expiry if provided
|
|
if (!empty($validated['expires_at'])) {
|
|
$data['expires_at'] = $validated['expires_at'];
|
|
}
|
|
|
|
$key = PosAccessKey::create($data);
|
|
|
|
return ResponseHelper::returnSuccessResponse($key, $key->hashkey, 'POS Access Key created');
|
|
}
|
|
|
|
public function destroy(Request $request)
|
|
{
|
|
if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::DeletePosAccessKey)) {
|
|
return ResponseHelper::returnUnauthorized();
|
|
}
|
|
|
|
$hashkey = $request->input('target');
|
|
$key = PosAccessKey::with('store')->where('hashkey', $hashkey)->first();
|
|
|
|
if (!$key) {
|
|
return ResponseHelper::returnError('Key not found', 404);
|
|
}
|
|
|
|
if (!$this->userOwnsKeyStore($key)) {
|
|
return ResponseHelper::returnError('Unauthorized to delete this key', 403);
|
|
}
|
|
|
|
$key->delete();
|
|
return ResponseHelper::returnSuccessResponse([], $hashkey, 'Key deleted');
|
|
}
|
|
|
|
public function toggleStatus(Request $request)
|
|
{
|
|
if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::TogglePosAccessKey)) {
|
|
return ResponseHelper::returnUnauthorized();
|
|
}
|
|
|
|
$hashkey = $request->input('target');
|
|
$key = PosAccessKey::with('store')->where('hashkey', $hashkey)->first();
|
|
|
|
if (!$key) {
|
|
return ResponseHelper::returnError('Key not found', 404);
|
|
}
|
|
|
|
if (!$this->userOwnsKeyStore($key)) {
|
|
return ResponseHelper::returnError('Unauthorized to modify this key', 403);
|
|
}
|
|
|
|
$key->status = $key->status === 'active' ? 'inactive' : 'active';
|
|
$key->save();
|
|
return ResponseHelper::returnSuccessResponse($key, $hashkey, 'Status updated');
|
|
}
|
|
|
|
/**
|
|
* Ownership gate shared by destroy/toggleStatus: Big 3 always pass;
|
|
* everyone else must own or manage (directly or via descendants) the
|
|
* store the key belongs to.
|
|
*/
|
|
private function userOwnsKeyStore(PosAccessKey $key): bool
|
|
{
|
|
$user = Auth::user();
|
|
if (!$user) {
|
|
return false;
|
|
}
|
|
|
|
$acctType = $user->acct_type->value ?? $user->acct_type ?? '';
|
|
if (in_array($acctType, ['ult', 'super operator', 'operator'])) {
|
|
return true;
|
|
}
|
|
|
|
$store = $key->store;
|
|
if (!$store) {
|
|
return false;
|
|
}
|
|
|
|
$allowedIds = $user->getAllDescendants()->pluck('id')->push($user->id)->toArray();
|
|
return in_array($store->owner_id, $allowedIds) || in_array($store->manager_id, $allowedIds);
|
|
}
|
|
}
|
|
|