PHP WebShell
Текущая директория: /var/www/bitcardoApp/backyard/user/rates
Просмотр файла: rates_fees.php
<?php
// backyard/user/rates/rates_fees.php
include '../common/header.php';
if (!isset($conn)) {
include_once '../../config/db_config.php';
}
require_once '../../models/rates/rates.php';
date_default_timezone_set('Africa/Lagos');
function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
$flash = null;
/* ------------------------------ POST HANDLERS ------------------------------ */
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$action = $_POST['action'] ?? '';
if ($action === 'save_coin_rate') {
$rate_id = isset($_POST['rate_id']) && $_POST['rate_id'] !== '' ? (int)$_POST['rate_id'] : null;
$data = [
'coin' => $_POST['coin'] ?? null,
'coin_name' => $_POST['coin_name'] ?? null,
'coin_icon' => $_POST['coin_icon'] ?? null,
'sell_rate' => $_POST['sell_rate'] ?? null,
'buy_rate' => $_POST['buy_rate'] ?? null,
'min_swap' => $_POST['min_swap'] ?? null,
'margin_percent' => $_POST['margin_percent'] ?? null,
'use_online_rate' => isset($_POST['use_online_rate']) ? 1 : 0,
'auto_update' => isset($_POST['auto_update']) ? 1 : 0,
];
$res = rr_coin_rate_upsert($conn, $rate_id, $data);
if (!empty($res['ok'])) {
$flash = ['type'=>'success','msg'=> $rate_id ? 'Coin rate updated.' : 'Coin rate added.'];
} else {
$flash = ['type'=>'danger','msg'=> 'Save failed: '.($res['error'] ?? 'Unknown error')];
}
} elseif ($action === 'toggle_flags') {
$rate_id = (int)($_POST['rate_id'] ?? 0);
$use_online = isset($_POST['use_online_rate']) ? (int)$_POST['use_online_rate'] : null;
$auto_update = isset($_POST['auto_update']) ? (int)$_POST['auto_update'] : null;
$ok = rr_coin_rate_toggle_flags($conn, $rate_id, $use_online, $auto_update);
$flash = ['type'=>$ok?'success':'danger', 'msg'=>$ok?'Flags updated.':'Failed to update flags.'];
} elseif ($action === 'save_fee') {
$fee_id = isset($_POST['fee_id']) && $_POST['fee_id']!=='' ? (int)$_POST['fee_id'] : null;
$data = [
'coin' => $_POST['fee_coin'] ?? null,
'type' => $_POST['fee_type'] ?? null, // crypto|fiat
'threshold' => $_POST['threshold'] ?? null,
'percent_fee' => $_POST['percent_fee'] ?? null,
'flat_fee' => $_POST['flat_fee'] ?? null,
'max_fee' => $_POST['max_fee'] ?? null,
'note' => $_POST['note'] ?? null,
];
$res = rr_withdraw_fee_upsert($conn, $fee_id, $data);
if (!empty($res['ok'])) {
$flash = ['type'=>'success','msg'=> $fee_id ? 'Withdraw fee updated.' : 'Withdraw fee added.'];
} else {
$flash = ['type'=>'danger','msg'=> 'Save failed: '.($res['error'] ?? 'Unknown error')];
}
} elseif ($action === 'delete_fee') {
$fee_id = (int)($_POST['fee_id'] ?? 0);
$ok = rr_withdraw_fee_delete($conn, $fee_id);
$flash = ['type'=>$ok?'success':'danger', 'msg'=>$ok?'Fee deleted.':'Failed to delete fee.'];
}
} catch (Throwable $e) {
$flash = ['type'=>'danger','msg'=>'Error: '.$e->getMessage()];
}
}
/* ------------------------------ DATA LOAD ------------------------------ */
$coin_rates = rr_coin_rates_all($conn);
$online_rows = rr_online_rates_all($conn); // read-only snapshot
$fees = rr_withdraw_fees_all($conn);
?>
<style>
.table td, .table th { vertical-align: middle; }
.form-switch .form-check-input { cursor: pointer; }
@media (max-width: 767.98px){
.stack-sm > * { margin-bottom: .5rem; }
}
</style>
<div class="nk-content nk-content-fluid mt-5">
<div class="container-xl wide-lg">
<div class="nk-content-body">
<div class="nk-block-head">
<div class="nk-block-between-md g-4">
<div class="nk-block-head-content">
<h4 class="nk-block-title fw-normal">Rates & Fees Console</h4>
<p class="text-soft mb-0">Manage coin rates (buy/sell), flags, and withdraw fees. Online snapshot is read-only.</p>
</div>
</div>
</div>
<?php if ($flash): ?>
<div class="alert alert-<?= h($flash['type']); ?>"><?= h($flash['msg']); ?></div>
<?php endif; ?>
<!-- Coin Rates -->
<div class="nk-block">
<div class="card card-bordered">
<div class="card-inner">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0">Coin Rates</h6>
<button class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#coinRateModal" onclick="CR.resetForm()">Add Coin</button>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead class="small text-soft">
<tr>
<th>Coin</th>
<th>Name</th>
<th class="text-end">Sell</th>
<th class="text-end">Buy</th>
<th class="text-end">Min Swap</th>
<th class="text-end">Margin %</th>
<th>Use Online</th>
<th>Auto Update</th>
<th>Updated</th>
<th class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($coin_rates)): ?>
<tr><td colspan="10" class="text-center text-muted py-4">No coins configured.</td></tr>
<?php else: foreach ($coin_rates as $r): ?>
<tr>
<td class="fw-semibold"><?= h($r['coin']); ?></td>
<td><?= h($r['coin_name'] ?? ''); ?></td>
<td class="text-end"><?= h($r['sell_rate']); ?></td>
<td class="text-end"><?= h($r['buy_rate']); ?></td>
<td class="text-end"><?= h($r['min_swap']); ?></td>
<td class="text-end"><?= h($r['margin_percent']); ?></td>
<td>
<form method="post" class="m-0">
<input type="hidden" name="action" value="toggle_flags">
<input type="hidden" name="rate_id" value="<?= (int)$r['rate_id']; ?>">
<input type="hidden" name="use_online_rate" value="<?= $r['use_online_rate'] ? 0 : 1; ?>">
<button class="btn btn-xs <?= $r['use_online_rate']?'btn-success':'btn-outline-secondary'; ?>">
<?= $r['use_online_rate']?'ON':'OFF'; ?>
</button>
</form>
</td>
<td>
<form method="post" class="m-0">
<input type="hidden" name="action" value="toggle_flags">
<input type="hidden" name="rate_id" value="<?= (int)$r['rate_id']; ?>">
<input type="hidden" name="auto_update" value="<?= $r['auto_update'] ? 0 : 1; ?>">
<button class="btn btn-xs <?= $r['auto_update']?'btn-success':'btn-outline-secondary'; ?>">
<?= $r['auto_update']?'ON':'OFF'; ?>
</button>
</form>
</td>
<td class="small"><?= h($r['updated_at']); ?></td>
<td class="text-end">
<button class="btn btn-xs btn-outline-primary"
data-bs-toggle="modal"
data-bs-target="#coinRateModal"
onclick='CR.edit(<?= json_encode($r, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_AMP|JSON_HEX_QUOT); ?>)'>
Edit
</button>
</td>
</tr>
<?php endforeach; endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Online Rates Snapshot (read-only) -->
<div class="nk-block">
<div class="card card-bordered">
<div class="card-inner">
<h6 class="mb-2">Online Rates Snapshot (read-only)</h6>
<div class="table-responsive">
<table class="table table-sm">
<thead class="small text-soft">
<tr>
<th>Coin</th>
<th class="text-end">Rate</th>
<th class="text-end">Sell</th>
<th class="text-end">Buy</th>
<th class="text-end">Margin %</th>
<th>Source</th>
<th>Fetched</th>
</tr>
</thead>
<tbody>
<?php if (empty($online_rows)): ?>
<tr><td colspan="7" class="text-center text-muted py-3">No snapshots yet.</td></tr>
<?php else: foreach ($online_rows as $o): ?>
<tr>
<td class="fw-semibold"><?= h(strtoupper($o['coin'])); ?></td>
<td class="text-end"><?= h($o['rate']); ?></td>
<td class="text-end"><?= h($o['sell_rate']); ?></td>
<td class="text-end"><?= h($o['buy_rate']); ?></td>
<td class="text-end"><?= h($o['margin_percent']); ?></td>
<td><?= h($o['source'] ?? ''); ?></td>
<td class="small"><?= h($o['fetched_at']); ?></td>
</tr>
<?php endforeach; endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Withdraw Fees -->
<div class="nk-block">
<div class="card card-bordered">
<div class="card-inner">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0">Withdraw Fees</h6>
<button class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#feeModal" onclick="WF.resetForm()">Add Fee</button>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead class="small text-soft">
<tr>
<th>Coin</th>
<th>Type</th>
<th class="text-end">Threshold</th>
<th class="text-end">Percent</th>
<th class="text-end">Flat</th>
<th class="text-end">Max</th>
<th>Note</th>
<th>Updated</th>
<th class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($fees)): ?>
<tr><td colspan="9" class="text-center text-muted py-4">No fees configured.</td></tr>
<?php else: foreach ($fees as $f): ?>
<tr>
<td class="fw-semibold"><?= h(strtoupper($f['coin'])); ?></td>
<td><?= h($f['type']); ?></td>
<td class="text-end"><?= h($f['threshold']); ?></td>
<td class="text-end"><?= h($f['percent_fee']); ?></td>
<td class="text-end"><?= h($f['flat_fee']); ?></td>
<td class="text-end"><?= h($f['max_fee']); ?></td>
<td class="small"><?= h($f['note']); ?></td>
<td class="small"><?= h($f['updated_at']); ?></td>
<td class="text-end stack-sm">
<button class="btn btn-xs btn-outline-primary"
data-bs-toggle="modal"
data-bs-target="#feeModal"
onclick='WF.edit(<?= json_encode($f, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_AMP|JSON_HEX_QUOT); ?>)'>
Edit
</button>
<form method="post" class="d-inline" onsubmit="return confirm('Delete this fee?')">
<input type="hidden" name="action" value="delete_fee">
<input type="hidden" name="fee_id" value="<?= (int)$f['fee_id']; ?>">
<button class="btn btn-xs btn-outline-danger">Delete</button>
</form>
</td>
</tr>
<?php endforeach; endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div><!-- .nk-content-body -->
</div>
</div>
<!-- Coin Rate Modal -->
<div class="modal fade" id="coinRateModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<form method="post" class="modal-content">
<input type="hidden" name="action" value="save_coin_rate">
<input type="hidden" name="rate_id" id="cr_rate_id">
<div class="modal-header">
<h6 class="modal-title">Coin Rate</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row g-2">
<div class="col-4">
<label class="form-label small">Coin *</label>
<input type="text" class="form-control" name="coin" id="cr_coin" placeholder="BTC, ETH">
</div>
<div class="col-8">
<label class="form-label small">Name</label>
<input type="text" class="form-control" name="coin_name" id="cr_coin_name" placeholder="Bitcoin">
</div>
<div class="col-12">
<label class="form-label small">Icon (path or filename)</label>
<input type="text" class="form-control" name="coin_icon" id="cr_coin_icon" placeholder="btc.svg">
</div>
<div class="col-6">
<label class="form-label small">Sell Rate</label>
<input type="number" step="0.00000001" class="form-control" name="sell_rate" id="cr_sell_rate">
</div>
<div class="col-6">
<label class="form-label small">Buy Rate</label>
<input type="number" step="0.00000001" class="form-control" name="buy_rate" id="cr_buy_rate">
</div>
<div class="col-6">
<label class="form-label small">Min Swap</label>
<input type="number" step="0.00000001" class="form-control" name="min_swap" id="cr_min_swap">
</div>
<div class="col-6">
<label class="form-label small">Margin %</label>
<input type="number" step="0.01" class="form-control" name="margin_percent" id="cr_margin_percent">
</div>
<div class="col-6">
<div class="form-check form-switch mt-3">
<input class="form-check-input" type="checkbox" name="use_online_rate" id="cr_use_online">
<label class="form-check-label" for="cr_use_online">Use Online Rate</label>
</div>
</div>
<div class="col-6">
<div class="form-check form-switch mt-3">
<input class="form-check-input" type="checkbox" name="auto_update" id="cr_auto_update">
<label class="form-check-label" for="cr_auto_update">Auto Update</label>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary">Save</button>
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
</div>
</form>
</div>
</div>
<!-- Withdraw Fee Modal -->
<div class="modal fade" id="feeModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<form method="post" class="modal-content">
<input type="hidden" name="action" value="save_fee">
<input type="hidden" name="fee_id" id="wf_fee_id">
<div class="modal-header">
<h6 class="modal-title">Withdraw Fee</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row g-2">
<div class="col-4">
<label class="form-label small">Coin *</label>
<input type="text" class="form-control" name="fee_coin" id="wf_coin" placeholder="BTC, NGN">
</div>
<div class="col-8">
<label class="form-label small">Type *</label>
<select class="form-select" name="fee_type" id="wf_type">
<option value="crypto">crypto</option>
<option value="fiat">fiat</option>
</select>
</div>
<div class="col-6">
<label class="form-label small">Threshold</label>
<input type="number" step="0.01" class="form-control" name="threshold" id="wf_threshold">
</div>
<div class="col-6">
<label class="form-label small">Percent Fee</label>
<input type="number" step="0.0001" class="form-control" name="percent_fee" id="wf_percent">
</div>
<div class="col-6">
<label class="form-label small">Flat Fee</label>
<input type="number" step="0.01" class="form-control" name="flat_fee" id="wf_flat">
</div>
<div class="col-6">
<label class="form-label small">Max Fee</label>
<input type="number" step="0.01" class="form-control" name="max_fee" id="wf_max">
</div>
<div class="col-12">
<label class="form-label small">Note</label>
<input type="text" class="form-control" name="note" id="wf_note" placeholder="Optional note">
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary">Save</button>
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
</div>
</form>
</div>
</div>
<script>
// Coin Rate modal helpers
const CR = {
resetForm(){
document.getElementById('cr_rate_id').value = '';
document.getElementById('cr_coin').value = '';
document.getElementById('cr_coin_name').value = '';
document.getElementById('cr_coin_icon').value = '';
document.getElementById('cr_sell_rate').value = '';
document.getElementById('cr_buy_rate').value = '';
document.getElementById('cr_min_swap').value = '';
document.getElementById('cr_margin_percent').value = '';
document.getElementById('cr_use_online').checked = false;
document.getElementById('cr_auto_update').checked = false;
},
edit(row){
CR.resetForm();
document.getElementById('cr_rate_id').value = row.rate_id || '';
document.getElementById('cr_coin').value = row.coin || '';
document.getElementById('cr_coin_name').value = row.coin_name || '';
document.getElementById('cr_coin_icon').value = row.coin_icon || '';
document.getElementById('cr_sell_rate').value = row.sell_rate || '';
document.getElementById('cr_buy_rate').value = row.buy_rate || '';
document.getElementById('cr_min_swap').value = row.min_swap || '';
document.getElementById('cr_margin_percent').value = row.margin_percent || '';
document.getElementById('cr_use_online').checked = (row.use_online_rate == 1);
document.getElementById('cr_auto_update').checked = (row.auto_update == 1);
}
};
// Withdraw Fee modal helpers
const WF = {
resetForm(){
document.getElementById('wf_fee_id').value = '';
document.getElementById('wf_coin').value = '';
document.getElementById('wf_type').value = 'crypto';
document.getElementById('wf_threshold').value = '';
document.getElementById('wf_percent').value = '';
document.getElementById('wf_flat').value = '';
document.getElementById('wf_max').value = '';
document.getElementById('wf_note').value = '';
},
edit(row){
WF.resetForm();
document.getElementById('wf_fee_id').value = row.fee_id || '';
document.getElementById('wf_coin').value = row.coin || '';
document.getElementById('wf_type').value = row.type || 'crypto';
document.getElementById('wf_threshold').value = row.threshold || '';
document.getElementById('wf_percent').value = row.percent_fee || '';
document.getElementById('wf_flat').value = row.flat_fee || '';
document.getElementById('wf_max').value = row.max_fee || '';
document.getElementById('wf_note').value = row.note || '';
}
};
</script>
<?php include '../common/footer.php'; ?>
Выполнить команду
Для локальной разработки. Не используйте в интернете!