Initialer Laravel Commit für BetiX
This commit is contained in:
56
app/Http/Controllers/Admin/GeoBlockController.php
Normal file
56
app/Http/Controllers/Admin/GeoBlockController.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\AppSetting;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class GeoBlockController extends Controller
|
||||
{
|
||||
private const KEY = 'geo.settings';
|
||||
|
||||
private array $defaults = [
|
||||
'enabled' => false,
|
||||
'blocked_countries' => [],
|
||||
'allowed_countries' => [],
|
||||
'mode' => 'blacklist', // 'blacklist' or 'whitelist'
|
||||
'vpn_block' => false,
|
||||
'vpn_provider' => 'none', // 'none', 'ipqualityscore', 'proxycheck'
|
||||
'vpn_api_key' => '',
|
||||
'block_message' => 'This service is not available in your region.',
|
||||
'redirect_url' => '',
|
||||
];
|
||||
|
||||
public function show()
|
||||
{
|
||||
$saved = AppSetting::get(self::KEY, []);
|
||||
$settings = array_merge($this->defaults, is_array($saved) ? $saved : []);
|
||||
|
||||
return Inertia::render('Admin/GeoBlock', [
|
||||
'settings' => $settings,
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'enabled' => 'boolean',
|
||||
'mode' => 'required|in:blacklist,whitelist',
|
||||
'blocked_countries' => 'array',
|
||||
'blocked_countries.*' => 'string|size:2',
|
||||
'allowed_countries' => 'array',
|
||||
'allowed_countries.*' => 'string|size:2',
|
||||
'vpn_block' => 'boolean',
|
||||
'vpn_provider' => 'required|in:none,ipqualityscore,proxycheck',
|
||||
'vpn_api_key' => 'nullable|string|max:200',
|
||||
'block_message' => 'required|string|max:500',
|
||||
'redirect_url' => 'nullable|url|max:500',
|
||||
]);
|
||||
|
||||
AppSetting::put(self::KEY, $data);
|
||||
|
||||
return back()->with('success', 'GeoBlock settings saved.');
|
||||
}
|
||||
}
|
||||
130
app/Http/Controllers/Admin/PaymentsSettingsController.php
Normal file
130
app/Http/Controllers/Admin/PaymentsSettingsController.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\AppSetting;
|
||||
use App\Services\DepositService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class PaymentsSettingsController extends Controller
|
||||
{
|
||||
public function __construct(private readonly DepositService $deposits)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /admin/payments/settings
|
||||
*/
|
||||
public function show()
|
||||
{
|
||||
$user = Auth::user();
|
||||
abort_unless($user && in_array(strtolower((string) $user->role), ['admin', 'owner']), 403);
|
||||
|
||||
$settings = $this->deposits->getSettings();
|
||||
|
||||
return Inertia::render('Admin/PaymentsSettings', [
|
||||
'settings' => $settings,
|
||||
'defaults' => [
|
||||
'commonCurrencies' => ['BTC','ETH','LTC','SOL','USDT_ERC20','USDT_TRC20','BCH','DOGE'],
|
||||
'modes' => ['live','sandbox'],
|
||||
'addressModes' => ['per_payment','per_user'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /admin/payments/settings
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
abort_unless($user && in_array(strtolower((string) $user->role), ['admin', 'owner']), 403);
|
||||
|
||||
$data = $request->validate([
|
||||
'mode' => ['required','in:live,sandbox'],
|
||||
'api_key' => ['nullable','string','max:200'],
|
||||
'ipn_secret' => ['nullable','string','max:200'],
|
||||
'enabled_currencies' => ['required','array','min:1'],
|
||||
'enabled_currencies.*' => ['string','max:32'],
|
||||
'global_min_usd' => ['required','numeric','min:0'],
|
||||
'global_max_usd' => ['required','numeric','gt:global_min_usd'],
|
||||
'btx_per_usd' => ['required','numeric','min:0.00000001'],
|
||||
'per_currency_overrides' => ['sometimes','array'],
|
||||
'per_currency_overrides.*.min_usd' => ['nullable','numeric','min:0'],
|
||||
'per_currency_overrides.*.max_usd' => ['nullable','numeric'],
|
||||
'per_currency_overrides.*.btx_per_usd' => ['nullable','numeric','min:0.00000001'],
|
||||
'success_url' => ['required','string','max:255'],
|
||||
'cancel_url' => ['required','string','max:255'],
|
||||
'address_mode' => ['required','in:per_payment,per_user'],
|
||||
]);
|
||||
|
||||
// Normalize overrides structure as map keyed by currency
|
||||
$overrides = [];
|
||||
if (!empty($data['per_currency_overrides']) && is_array($data['per_currency_overrides'])) {
|
||||
foreach ($data['per_currency_overrides'] as $cur => $vals) {
|
||||
if (is_array($vals)) {
|
||||
$entry = [];
|
||||
if (array_key_exists('min_usd', $vals) && $vals['min_usd'] !== null) $entry['min_usd'] = (float) $vals['min_usd'];
|
||||
if (array_key_exists('max_usd', $vals) && $vals['max_usd'] !== null) $entry['max_usd'] = (float) $vals['max_usd'];
|
||||
if (array_key_exists('btx_per_usd', $vals) && $vals['btx_per_usd'] !== null) $entry['btx_per_usd'] = (float) $vals['btx_per_usd'];
|
||||
if (!empty($entry)) {
|
||||
$overrides[strtoupper($cur)] = $entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preserve existing api_key/ipn_secret if not re-submitted (masked fields)
|
||||
$existing = AppSetting::get('payments.nowpayments', []);
|
||||
$apiKey = $data['api_key'] ?? null;
|
||||
$ipnSecret = $data['ipn_secret'] ?? null;
|
||||
|
||||
$payload = [
|
||||
'mode' => $data['mode'],
|
||||
'api_key' => $apiKey ?: ($existing['api_key'] ?? ''),
|
||||
'ipn_secret' => $ipnSecret ?: ($existing['ipn_secret'] ?? ''),
|
||||
'enabled_currencies' => array_values(array_map('strtoupper', $data['enabled_currencies'])),
|
||||
'global_min_usd' => (float) $data['global_min_usd'],
|
||||
'global_max_usd' => (float) $data['global_max_usd'],
|
||||
'btx_per_usd' => (float) $data['btx_per_usd'],
|
||||
'per_currency_overrides' => $overrides,
|
||||
'success_url' => (string) $data['success_url'],
|
||||
'cancel_url' => (string) $data['cancel_url'],
|
||||
'address_mode' => (string) $data['address_mode'],
|
||||
];
|
||||
|
||||
AppSetting::put('payments.nowpayments', $payload);
|
||||
|
||||
return back()->with('success', 'Payment settings saved.');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /admin/payments/test
|
||||
*/
|
||||
public function test(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
abort_unless($user && in_array(strtolower((string) $user->role), ['admin', 'owner']), 403);
|
||||
|
||||
$data = $request->validate(['api_key' => 'required|string|max:200']);
|
||||
|
||||
try {
|
||||
$res = Http::timeout(8)->withHeaders([
|
||||
'x-api-key' => $data['api_key'],
|
||||
'Accept' => 'application/json',
|
||||
])->get('https://api.nowpayments.io/v1/status');
|
||||
|
||||
if ($res->ok()) {
|
||||
return response()->json(['ok' => true, 'message' => 'Verbindung erfolgreich! NOWPayments API erreichbar.']);
|
||||
}
|
||||
|
||||
return response()->json(['ok' => false, 'message' => 'API antwortet mit Status ' . $res->status() . '. API Key prüfen.'], 422);
|
||||
} catch (\Throwable $e) {
|
||||
return response()->json(['ok' => false, 'message' => 'Verbindung fehlgeschlagen: ' . $e->getMessage()], 422);
|
||||
}
|
||||
}
|
||||
}
|
||||
130
app/Http/Controllers/Admin/PromoAdminController.php
Normal file
130
app/Http/Controllers/Admin/PromoAdminController.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Concerns\ProxiesBackend;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\BackendHttpClient;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
class PromoAdminController extends Controller
|
||||
{
|
||||
use ProxiesBackend;
|
||||
|
||||
public function __construct(private readonly BackendHttpClient $client)
|
||||
{
|
||||
}
|
||||
|
||||
private function assertAdmin(): void
|
||||
{
|
||||
if (!Auth::check() || strtolower((string) Auth::user()->role) !== 'admin') {
|
||||
abort(403, 'Nur für Admins');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show simple admin page to manage promos (data from upstream)
|
||||
*/
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$this->assertAdmin();
|
||||
|
||||
$promos = [];
|
||||
try {
|
||||
$res = $this->client->get($request, '/admin/promos', ['per_page' => 20], retry: true);
|
||||
if ($res->successful()) {
|
||||
$j = $res->json() ?: [];
|
||||
$promos = $j['data'] ?? $j['promos'] ?? $j;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// show empty list with error message on page via flash if desired
|
||||
}
|
||||
|
||||
return Inertia::render('Admin/Promos', [
|
||||
'promos' => $promos,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new promo via upstream
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$this->assertAdmin();
|
||||
|
||||
$data = $this->validateData($request);
|
||||
$data['code'] = strtoupper(trim($data['code']));
|
||||
$data['is_active'] = $data['is_active'] ?? true;
|
||||
|
||||
try {
|
||||
$res = $this->client->post($request, '/admin/promos', $data);
|
||||
if ($res->successful()) {
|
||||
return back()->with('success', 'Promo erstellt.');
|
||||
}
|
||||
if ($res->clientError()) {
|
||||
$msg = data_get($res->json(), 'message', 'Ungültige Eingabe');
|
||||
return back()->withErrors(['promo' => $msg]);
|
||||
}
|
||||
if ($res->serverError()) {
|
||||
return back()->withErrors(['promo' => 'Service temporär nicht verfügbar']);
|
||||
}
|
||||
return back()->withErrors(['promo' => 'API Server nicht erreichbar']);
|
||||
} catch (\Throwable $e) {
|
||||
return back()->withErrors(['promo' => 'API Server nicht erreichbar']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing promo via upstream
|
||||
*/
|
||||
public function update(Request $request, int $id)
|
||||
{
|
||||
$this->assertAdmin();
|
||||
|
||||
$data = $this->validateData($request, $id);
|
||||
if (isset($data['code'])) {
|
||||
$data['code'] = strtoupper(trim($data['code']));
|
||||
}
|
||||
|
||||
try {
|
||||
$res = $this->client->patch($request, "/admin/promos/{$id}", $data);
|
||||
if ($res->successful()) {
|
||||
return back()->with('success', 'Promo aktualisiert.');
|
||||
}
|
||||
if ($res->clientError()) {
|
||||
$msg = data_get($res->json(), 'message', 'Ungültige Eingabe');
|
||||
return back()->withErrors(['promo' => $msg]);
|
||||
}
|
||||
if ($res->serverError()) {
|
||||
return back()->withErrors(['promo' => 'Service temporär nicht verfügbar']);
|
||||
}
|
||||
return back()->withErrors(['promo' => 'API Server nicht erreichbar']);
|
||||
} catch (\Throwable $e) {
|
||||
return back()->withErrors(['promo' => 'API Server nicht erreichbar']);
|
||||
}
|
||||
}
|
||||
|
||||
private function validateData(Request $request, ?int $ignoreId = null): array
|
||||
{
|
||||
$isUpdate = $request->isMethod('patch') || $request->isMethod('put');
|
||||
|
||||
$rules = [
|
||||
'code' => [($isUpdate ? 'sometimes' : 'required'), 'string', 'max:64'],
|
||||
'description' => [($isUpdate ? 'sometimes' : 'nullable'), 'nullable', 'string', 'max:255'],
|
||||
'bonus_amount' => [($isUpdate ? 'sometimes' : 'required'), 'numeric', 'min:0'],
|
||||
'wager_multiplier' => [($isUpdate ? 'sometimes' : 'required'), 'integer', 'min:0', 'max:1000'],
|
||||
'per_user_limit' => [($isUpdate ? 'sometimes' : 'required'), 'integer', 'min:1', 'max:1000'],
|
||||
'global_limit' => [($isUpdate ? 'sometimes' : 'nullable'), 'nullable', 'integer', 'min:1', 'max:1000000'],
|
||||
'starts_at' => [($isUpdate ? 'sometimes' : 'nullable'), 'nullable', 'date'],
|
||||
'ends_at' => [($isUpdate ? 'sometimes' : 'nullable'), 'nullable', 'date', 'after_or_equal:starts_at'],
|
||||
'min_deposit' => [($isUpdate ? 'sometimes' : 'nullable'), 'nullable', 'numeric', 'min:0'],
|
||||
'bonus_expires_days' => [($isUpdate ? 'sometimes' : 'nullable'), 'nullable', 'integer', 'min:1', 'max:365'],
|
||||
'is_active' => [($isUpdate ? 'sometimes' : 'nullable'), 'boolean'],
|
||||
];
|
||||
|
||||
return $request->validate($rules);
|
||||
}
|
||||
}
|
||||
79
app/Http/Controllers/Admin/SiteSettingsController.php
Normal file
79
app/Http/Controllers/Admin/SiteSettingsController.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\AppSetting;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class SiteSettingsController extends Controller
|
||||
{
|
||||
private const KEY = 'site.settings';
|
||||
|
||||
private array $defaults = [
|
||||
'site_name' => 'BetiX Casino',
|
||||
'site_tagline' => 'Play. Win. Repeat.',
|
||||
'primary_color' => '#df006a',
|
||||
'logo_url' => '',
|
||||
'favicon_url' => '',
|
||||
'maintenance_mode' => false,
|
||||
'registration_open' => true,
|
||||
'min_deposit_usd' => 10,
|
||||
'max_deposit_usd' => 50000,
|
||||
'min_withdrawal_usd' => 20,
|
||||
'max_withdrawal_usd' => 100000,
|
||||
'max_bet_usd' => 5000,
|
||||
'house_edge_percent' => 1.0,
|
||||
'footer_text' => '',
|
||||
'support_email' => '',
|
||||
'terms_url' => '/terms',
|
||||
'privacy_url' => '/privacy',
|
||||
'currency_symbol' => 'BTX',
|
||||
];
|
||||
|
||||
public function show()
|
||||
{
|
||||
$saved = AppSetting::get(self::KEY, []);
|
||||
$settings = array_merge($this->defaults, is_array($saved) ? $saved : []);
|
||||
|
||||
return Inertia::render('Admin/SiteSettings', [
|
||||
'settings' => $settings,
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(Request $request)
|
||||
{
|
||||
// Normalize empty strings to null so URL/email validation doesn't fail on blank fields
|
||||
foreach (['logo_url', 'favicon_url', 'terms_url', 'privacy_url', 'support_email', 'site_tagline', 'footer_text'] as $field) {
|
||||
if ($request->input($field) === '') {
|
||||
$request->merge([$field => null]);
|
||||
}
|
||||
}
|
||||
|
||||
$data = $request->validate([
|
||||
'site_name' => 'required|string|max:100',
|
||||
'site_tagline' => 'nullable|string|max:200',
|
||||
'primary_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
|
||||
'logo_url' => 'nullable|url|max:500',
|
||||
'favicon_url' => 'nullable|url|max:500',
|
||||
'maintenance_mode' => 'boolean',
|
||||
'registration_open' => 'boolean',
|
||||
'min_deposit_usd' => 'required|numeric|min:0',
|
||||
'max_deposit_usd' => 'required|numeric|min:0',
|
||||
'min_withdrawal_usd' => 'required|numeric|min:0',
|
||||
'max_withdrawal_usd' => 'required|numeric|min:0',
|
||||
'max_bet_usd' => 'required|numeric|min:0',
|
||||
'house_edge_percent' => 'required|numeric|min:0|max:100',
|
||||
'footer_text' => 'nullable|string|max:1000',
|
||||
'support_email' => 'nullable|email|max:200',
|
||||
'terms_url' => 'nullable|string|max:500',
|
||||
'privacy_url' => 'nullable|string|max:500',
|
||||
'currency_symbol' => 'required|string|max:10',
|
||||
]);
|
||||
|
||||
AppSetting::put(self::KEY, $data);
|
||||
|
||||
return back()->with('success', 'Site settings saved.');
|
||||
}
|
||||
}
|
||||
127
app/Http/Controllers/Admin/SupportAdminController.php
Normal file
127
app/Http/Controllers/Admin/SupportAdminController.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Str;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
class SupportAdminController extends Controller
|
||||
{
|
||||
private function assertAdmin(): void
|
||||
{
|
||||
if (!Auth::check() || strtolower((string) Auth::user()->role) !== 'admin') {
|
||||
abort(403, 'Nur für Admins');
|
||||
}
|
||||
}
|
||||
|
||||
private function ollamaStatus(): array
|
||||
{
|
||||
$host = rtrim(env('OLLAMA_HOST', 'http://127.0.0.1:11434'), '/');
|
||||
$model = env('OLLAMA_MODEL', 'llama3');
|
||||
try {
|
||||
$res = Http::timeout(2)->get($host . '/api/tags');
|
||||
return ['healthy' => $res->ok(), 'host' => $host, 'model' => $model, 'error' => $res->ok() ? null : 'Keine Verbindung'];
|
||||
} catch (\Throwable $e) {
|
||||
return ['healthy' => false, 'host' => $host, 'model' => $model, 'error' => $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
private function getThreads(): array
|
||||
{
|
||||
$index = cache()->get('support_threads_index', []);
|
||||
$threads = [];
|
||||
foreach (array_reverse($index) as $row) {
|
||||
$full = cache()->get('support_threads:' . $row['id']);
|
||||
if (is_array($full)) {
|
||||
$threads[] = $full;
|
||||
} else {
|
||||
$threads[] = $row;
|
||||
}
|
||||
}
|
||||
return $threads;
|
||||
}
|
||||
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$this->assertAdmin();
|
||||
|
||||
$enabled = (bool) (cache()->get('support_chat_enabled') ?? config('app.support_chat_enabled', true));
|
||||
|
||||
return Inertia::render('Admin/Support', [
|
||||
'enabled' => $enabled,
|
||||
'threads' => $this->getThreads(),
|
||||
'ollama' => $this->ollamaStatus(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function settings(Request $request)
|
||||
{
|
||||
$this->assertAdmin();
|
||||
$data = $request->validate(['enabled' => 'required|boolean']);
|
||||
cache()->put('support_chat_enabled', (bool) $data['enabled'], now()->addYear());
|
||||
return back()->with('success', 'Support-Chat Einstellungen gespeichert.');
|
||||
}
|
||||
|
||||
public function reply(Request $request, string $thread)
|
||||
{
|
||||
$this->assertAdmin();
|
||||
$data = $request->validate(['text' => 'required|string|min:1|max:1000']);
|
||||
|
||||
$record = cache()->get('support_threads:' . $thread);
|
||||
if (!is_array($record)) {
|
||||
return back()->withErrors(['text' => 'Thread nicht gefunden.']);
|
||||
}
|
||||
|
||||
$record['messages'][] = [
|
||||
'id' => Str::uuid()->toString(),
|
||||
'sender' => 'agent',
|
||||
'body' => $data['text'],
|
||||
'at' => now()->toIso8601String(),
|
||||
];
|
||||
$record['status'] = 'agent';
|
||||
$record['updated_at'] = now()->toIso8601String();
|
||||
|
||||
cache()->put('support_threads:' . $thread, $record, now()->addDay());
|
||||
|
||||
// Update index entry
|
||||
$index = cache()->get('support_threads_index', []);
|
||||
foreach ($index as &$row) {
|
||||
if (($row['id'] ?? null) === $thread) {
|
||||
$row['status'] = 'agent';
|
||||
$row['updated_at'] = $record['updated_at'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
cache()->put('support_threads_index', $index, now()->addDay());
|
||||
|
||||
return back()->with('success', 'Nachricht gesendet.');
|
||||
}
|
||||
|
||||
public function close(Request $request, string $thread)
|
||||
{
|
||||
$this->assertAdmin();
|
||||
|
||||
$record = cache()->get('support_threads:' . $thread);
|
||||
if (is_array($record)) {
|
||||
$record['status'] = 'closed';
|
||||
$record['updated_at'] = now()->toIso8601String();
|
||||
cache()->put('support_threads:' . $thread, $record, now()->addDay());
|
||||
}
|
||||
|
||||
$index = cache()->get('support_threads_index', []);
|
||||
foreach ($index as &$row) {
|
||||
if (($row['id'] ?? null) === $thread) {
|
||||
$row['status'] = 'closed';
|
||||
break;
|
||||
}
|
||||
}
|
||||
cache()->put('support_threads_index', $index, now()->addDay());
|
||||
|
||||
return back()->with('success', 'Chat geschlossen.');
|
||||
}
|
||||
}
|
||||
73
app/Http/Controllers/Admin/WalletsAdminController.php
Normal file
73
app/Http/Controllers/Admin/WalletsAdminController.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\AppSetting;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class WalletsAdminController extends Controller
|
||||
{
|
||||
/**
|
||||
* GET /admin/wallets/settings — Wallet/Vault policies and limits.
|
||||
*/
|
||||
public function show()
|
||||
{
|
||||
$user = Auth::user();
|
||||
abort_unless($user && ($user->role === 'Admin' || $user->role === 'Owner'), 403);
|
||||
|
||||
$defaults = [
|
||||
'pin_max_attempts' => 5,
|
||||
'pin_lock_minutes' => 15,
|
||||
'min_tx_btx' => 0.0001,
|
||||
'max_tx_btx' => 100000,
|
||||
'daily_max_btx' => 100000,
|
||||
'actions_per_minute' => 20,
|
||||
'reason_required' => true,
|
||||
];
|
||||
$settings = AppSetting::get('wallet.settings', $defaults) ?: $defaults;
|
||||
// Ensure defaults filled
|
||||
$settings = array_replace($defaults, is_array($settings) ? $settings : []);
|
||||
|
||||
return Inertia::render('Admin/WalletsSettings', [
|
||||
'settings' => $settings,
|
||||
'defaults' => $defaults,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /admin/wallets/settings — Save policies and limits.
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
abort_unless($user && ($user->role === 'Admin' || $user->role === 'Owner'), 403);
|
||||
|
||||
$data = $request->validate([
|
||||
'pin_max_attempts' => ['required','integer','min:1','max:20'],
|
||||
'pin_lock_minutes' => ['required','integer','min:1','max:1440'],
|
||||
'min_tx_btx' => ['required','numeric','min:0'],
|
||||
'max_tx_btx' => ['required','numeric','gt:min_tx_btx'],
|
||||
'daily_max_btx' => ['required','numeric','gte:max_tx_btx'],
|
||||
'actions_per_minute' => ['required','integer','min:1','max:600'],
|
||||
'reason_required' => ['required','boolean'],
|
||||
]);
|
||||
|
||||
// Normalize numeric precision (BTX uses 4 decimals commonly)
|
||||
$payload = [
|
||||
'pin_max_attempts' => (int) $data['pin_max_attempts'],
|
||||
'pin_lock_minutes' => (int) $data['pin_lock_minutes'],
|
||||
'min_tx_btx' => round((float) $data['min_tx_btx'], 4),
|
||||
'max_tx_btx' => round((float) $data['max_tx_btx'], 4),
|
||||
'daily_max_btx' => round((float) $data['daily_max_btx'], 4),
|
||||
'actions_per_minute' => (int) $data['actions_per_minute'],
|
||||
'reason_required' => (bool) $data['reason_required'],
|
||||
];
|
||||
|
||||
AppSetting::put('wallet.settings', $payload);
|
||||
|
||||
return back()->with('success', 'Wallet settings saved.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user