new file: src/Controllers/AuthController.php
This commit is contained in:
@@ -0,0 +1,321 @@
|
|||||||
|
<?php
|
||||||
|
/* Smarty version 5.4.2, created on 2024-12-18 20:10:06
|
||||||
|
from 'file:index.tpl' */
|
||||||
|
|
||||||
|
/* @var \Smarty\Template $_smarty_tpl */
|
||||||
|
if ($_smarty_tpl->getCompiled()->isFresh($_smarty_tpl, array (
|
||||||
|
'version' => '5.4.2',
|
||||||
|
'unifunc' => 'content_67632c1ed9f985_55329758',
|
||||||
|
'has_nocache_code' => false,
|
||||||
|
'file_dependency' =>
|
||||||
|
array (
|
||||||
|
'12e7c104d0458c0f98059f5061a369703f954f4a' =>
|
||||||
|
array (
|
||||||
|
0 => 'index.tpl',
|
||||||
|
1 => 1734552581,
|
||||||
|
2 => 'file',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'includes' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
))) {
|
||||||
|
function content_67632c1ed9f985_55329758 (\Smarty\Template $_smarty_tpl) {
|
||||||
|
$_smarty_current_dir = '/home/upw/clients/kpopping/xbotcontrol/smarty/template';
|
||||||
|
?><!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>XBotControl</title>
|
||||||
|
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
|
||||||
|
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous">
|
||||||
|
<?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/bootstrap-table.min.css">
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
src="https://code.jquery.com/jquery-3.7.1.min.js"><?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
<!-- Latest compiled and minified JavaScript -->
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/bootstrap-table.min.js"><?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
<!-- Latest compiled and minified Locales -->
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/locale/bootstrap-table-en-US.min.js"><?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
<link rel="stylesheet" type="text/css"
|
||||||
|
href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/extensions/filter-control/bootstrap-table-filter-control.css">
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
|
||||||
|
src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/extensions/filter-control/bootstrap-table-filter-control.js">
|
||||||
|
<?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.1/css/all.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="main-menu " style="background-color: #003366;">
|
||||||
|
|
||||||
|
<div class="container text-center text-light">
|
||||||
|
<nav class="navbar navbar-expand-lg text-light">
|
||||||
|
<div class="container">
|
||||||
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="btn text-light" onclick="initializeTable('latest_requests');">Latest</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="btn text-light" onclick="initializeTable('count_requests_by_ip');">Top by
|
||||||
|
IP</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="btn text-light" onclick="initializeTable('count_requests_by_ua');">Top by
|
||||||
|
UA</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="btn text-light" onclick="initializeTable('top_ip_ua_path');">IP+UA+Path</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="btn text-light" onclick="initializeTable('top_ip_by_load');">IP+Load</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="btn text-light" onclick="initializeTable('top_ip_by_rps');">IP+RPS</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div id="main-body">
|
||||||
|
<div class="container" style="max-width: 95%;">
|
||||||
|
<div class="row p-3">
|
||||||
|
<div class="col-10">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div id="toolbar" class="row ">
|
||||||
|
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-text">Limit</div>
|
||||||
|
|
||||||
|
|
||||||
|
<select id="limit" name="limit" class="form-control mr-3">
|
||||||
|
<option value="10">10</option>
|
||||||
|
<option value="50">50</option>
|
||||||
|
<option value="100" selected>100</option>
|
||||||
|
<option value="200">200</option>
|
||||||
|
<option value="500">500</option>
|
||||||
|
<option value="1000">1000</option>
|
||||||
|
<option value="100000">100000</option>
|
||||||
|
<option value="0">0</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-text">From</div>
|
||||||
|
|
||||||
|
<input type="datetime-local" id="date-from" name="date-from" class="form-control mr-3">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-text">To</div>
|
||||||
|
|
||||||
|
<input type="datetime-local" id="date-to" name="date-to" class="form-control mr-3">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table id="table">
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
>
|
||||||
|
document.getElementById('date-from').addEventListener('change', refreshTable);
|
||||||
|
|
||||||
|
document.getElementById('limit').addEventListener('change', refreshTable);
|
||||||
|
|
||||||
|
function refreshTable() {
|
||||||
|
$('#table').bootstrapTable('refresh');
|
||||||
|
}
|
||||||
|
window.onload = function() {
|
||||||
|
const dateFrom = document.getElementById('date-from');
|
||||||
|
const dateTo = document.getElementById('date-to');
|
||||||
|
|
||||||
|
const today = new Date();
|
||||||
|
const yesterday = new Date(today);
|
||||||
|
yesterday.setDate(today.getDate() - 1);
|
||||||
|
|
||||||
|
const tomorrow = new Date(today);
|
||||||
|
tomorrow.setDate(today.getDate() + 1);
|
||||||
|
|
||||||
|
dateFrom.value = yesterday.toISOString().slice(0, 16);
|
||||||
|
dateTo.value = tomorrow.toISOString().slice(0, 16);
|
||||||
|
};
|
||||||
|
document.getElementById('date-to').addEventListener('change', refreshTable);
|
||||||
|
|
||||||
|
|
||||||
|
function initializeTable(latest_requests) {
|
||||||
|
var url = location.pathname + '/api/report/' + latest_requests;
|
||||||
|
var $table = $('#table');
|
||||||
|
|
||||||
|
if ($table.length) {
|
||||||
|
$table.bootstrapTable('destroy');
|
||||||
|
}
|
||||||
|
|
||||||
|
$.get(url, function(response) {
|
||||||
|
$table.bootstrapTable({
|
||||||
|
url: url,
|
||||||
|
sortable: true,
|
||||||
|
toolbar: '#toolbar',
|
||||||
|
showRefresh: true,
|
||||||
|
iconsPrefix: 'fa',
|
||||||
|
showColumns: true,
|
||||||
|
classes: ['table', 'table-borderless', 'table-hover', 'table-striped'],
|
||||||
|
filterControl: true,
|
||||||
|
searchable: true,
|
||||||
|
pagination: false,
|
||||||
|
sidePagination: "server",
|
||||||
|
serverSort: false,
|
||||||
|
columns: response.columns,
|
||||||
|
queryParams: queryParams,
|
||||||
|
loadingFontSize: '12px'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryParams(params) {
|
||||||
|
const limit = document.getElementById('limit').value;
|
||||||
|
const from = document.getElementById('date-from').value;
|
||||||
|
const to = document.getElementById('date-to').value;
|
||||||
|
|
||||||
|
params.limit = limit;
|
||||||
|
params.from = from;
|
||||||
|
params.to = to;
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function listFormatter(value, row, index) {
|
||||||
|
var editBtn = '<a class="btn" href="<?php echo htmlspecialchars((string) ($_ENV['BASEURI']), ENT_QUOTES, 'UTF-8');?>
|
||||||
|
/lists/edit/' + row.list_id + '" title="Edit"><i class="fa-solid fa-pen-to-square"></i></a> ';
|
||||||
|
|
||||||
|
var showBtn = '<a class="btn" href="<?php echo htmlspecialchars((string) ($_ENV['BASEURI']), ENT_QUOTES, 'UTF-8');?>
|
||||||
|
/lists/show/' + row.list_id + '" title="Show"><i class="fa-solid fa-eye"></i></a>';
|
||||||
|
<?php if ($_SESSION['user_role'] == 'admin') {?>
|
||||||
|
return [showBtn, editBtn, value, ].join('')
|
||||||
|
<?php } else { ?>
|
||||||
|
return [showBtn, value, ].join('')
|
||||||
|
|
||||||
|
<?php }?>
|
||||||
|
}
|
||||||
|
<?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
>
|
||||||
|
function ipFormatter(value) {
|
||||||
|
return `<span class="ip-address" data-ip="${value}">${value}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('mouseover', async (event) => {
|
||||||
|
const target = event.target;
|
||||||
|
if (target.classList.contains('ip-address')) {
|
||||||
|
const ipAddress = target.getAttribute('data-ip');
|
||||||
|
const popupId = `popup-${ipAddress.replace(/\./g, '-')}`;
|
||||||
|
let popup = document.getElementById(popupId);
|
||||||
|
|
||||||
|
if (!popup) {
|
||||||
|
popup = document.createElement('div');
|
||||||
|
popup.id = popupId;
|
||||||
|
popup.style.position = 'absolute';
|
||||||
|
popup.style.background = '#f9f9f9';
|
||||||
|
popup.style.border = '1px solid #ccc';
|
||||||
|
popup.style.padding = '10px';
|
||||||
|
popup.style.borderRadius = '5px';
|
||||||
|
popup.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.2)';
|
||||||
|
popup.style.zIndex = '1000';
|
||||||
|
popup.style.whiteSpace = 'nowrap';
|
||||||
|
popup.style.display = 'none';
|
||||||
|
document.body.appendChild(popup);
|
||||||
|
|
||||||
|
fetch(location.pathname + `/api/ipinfo/${ipAddress}`)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
const location = data.geo.continent?.names?.en + ' > ' + data.geo.country
|
||||||
|
?.names?.en + ' > ' + data.geo.city?.names?.en || 'Unknown';
|
||||||
|
const reverseDns = data.reverse_dns || 'N/A';
|
||||||
|
popup.innerHTML = `
|
||||||
|
<strong>Location:</strong> ${location}<br>
|
||||||
|
<strong>Reverse DNS:</strong> ${reverseDns}
|
||||||
|
`;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
popup.innerHTML = 'Error fetching data.';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.style.display = 'block';
|
||||||
|
popup.style.left = `${event.pageX + 10}px`;
|
||||||
|
popup.style.top = `${event.pageY + 10}px`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('mouseout', (event) => {
|
||||||
|
const target = event.target;
|
||||||
|
if (target.classList.contains('ip-address')) {
|
||||||
|
const ipAddress = target.getAttribute('data-ip');
|
||||||
|
const popupId = `popup-${ipAddress.replace(/\./g, '-')}`;
|
||||||
|
const popup = document.getElementById(popupId);
|
||||||
|
if (popup) {
|
||||||
|
popup.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
<?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
|
||||||
|
<footer class="centro-blue text-white text-center py-3">
|
||||||
|
<div class="footer">
|
||||||
|
<div class="container text-center centro-blue text-light">
|
||||||
|
<h6>Copyright 2024
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body><?php }
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
/* Smarty version 5.4.2, created on 2024-12-18 19:19:42
|
||||||
|
from 'file:login.tpl' */
|
||||||
|
|
||||||
|
/* @var \Smarty\Template $_smarty_tpl */
|
||||||
|
if ($_smarty_tpl->getCompiled()->isFresh($_smarty_tpl, array (
|
||||||
|
'version' => '5.4.2',
|
||||||
|
'unifunc' => 'content_6763204e824e49_51557939',
|
||||||
|
'has_nocache_code' => false,
|
||||||
|
'file_dependency' =>
|
||||||
|
array (
|
||||||
|
'b56b63fa35b4c8d6169eae7042db3ea0125ea5bf' =>
|
||||||
|
array (
|
||||||
|
0 => 'login.tpl',
|
||||||
|
1 => 1734549413,
|
||||||
|
2 => 'file',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'includes' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
))) {
|
||||||
|
function content_6763204e824e49_51557939 (\Smarty\Template $_smarty_tpl) {
|
||||||
|
$_smarty_current_dir = '/home/upw/clients/kpopping/xbotcontrol/smarty/template';
|
||||||
|
?><!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>XBotControl</title>
|
||||||
|
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
|
||||||
|
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous">
|
||||||
|
<?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/bootstrap-table.min.css">
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
src="https://code.jquery.com/jquery-3.7.1.min.js"><?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
<!-- Latest compiled and minified JavaScript -->
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/bootstrap-table.min.js"><?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
<!-- Latest compiled and minified Locales -->
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/locale/bootstrap-table-zh-CN.min.js"><?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
<link rel="stylesheet" type="text/css"
|
||||||
|
href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/extensions/filter-control/bootstrap-table-filter-control.css">
|
||||||
|
<?php echo '<script'; ?>
|
||||||
|
|
||||||
|
src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/extensions/filter-control/bootstrap-table-filter-control.js">
|
||||||
|
<?php echo '</script'; ?>
|
||||||
|
>
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.1/css/all.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center justify-content-center vh-100">
|
||||||
|
<form id="form" enctype="multipart/form-data" action="login" method="post" class="p-4 border rounded">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="api_key" class="form-label">API Key</label>
|
||||||
|
<input type="text" class="form-control" id="api_key" name="api_key">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-success w-100">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="text-white text-center py-3">
|
||||||
|
<div class="footer">
|
||||||
|
<div class="container text-center text-light">
|
||||||
|
<h6>Copyright 2024
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body><?php }
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
<!-- Latest compiled and minified JavaScript -->
|
<!-- Latest compiled and minified JavaScript -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/bootstrap-table.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/bootstrap-table.min.js"></script>
|
||||||
<!-- Latest compiled and minified Locales -->
|
<!-- Latest compiled and minified Locales -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/locale/bootstrap-table-zh-CN.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/locale/bootstrap-table-en-US.min.js"></script>
|
||||||
<link rel="stylesheet" type="text/css"
|
<link rel="stylesheet" type="text/css"
|
||||||
href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/extensions/filter-control/bootstrap-table-filter-control.css">
|
href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/extensions/filter-control/bootstrap-table-filter-control.css">
|
||||||
<script
|
<script
|
||||||
@@ -58,9 +58,7 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="btn text-light" onclick="initializeTable('top_ip_by_rps');">IP+RPS</a>
|
<a class="btn text-light" onclick="initializeTable('top_ip_by_rps');">IP+RPS</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
|
||||||
<a class="btn text-light" onclick="initializeTable('top_net_28_by_rps');">IP+RPS</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
@@ -196,57 +194,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
function buttons() {
|
|
||||||
{if $smarty.session.user_role == 'admin'}
|
|
||||||
return {
|
|
||||||
btnAdd: {
|
|
||||||
text: 'Add new list',
|
|
||||||
icon: 'fa-plus',
|
|
||||||
event: function() {
|
|
||||||
// Prompt the user for a new list name
|
|
||||||
const newListName = prompt('Enter new list name:');
|
|
||||||
|
|
||||||
// Only proceed if the user provides a valid list name
|
|
||||||
if (newListName) {
|
|
||||||
// Define the URL where the form needs to be posted
|
|
||||||
const url = '{$smarty.env.BASEURI}/lists/create'; // Replace with actual URL
|
|
||||||
|
|
||||||
// Create a new hidden form element
|
|
||||||
const form = document.createElement('form');
|
|
||||||
form.method = 'POST';
|
|
||||||
form.action = url;
|
|
||||||
|
|
||||||
// Create hidden input to store the list name
|
|
||||||
const input = document.createElement('input');
|
|
||||||
input.type = 'hidden';
|
|
||||||
input.name = 'listName'; // The name expected by the server
|
|
||||||
input.value = newListName;
|
|
||||||
|
|
||||||
// Append the input to the form
|
|
||||||
form.appendChild(input);
|
|
||||||
|
|
||||||
// Append the form to the body to make it part of the DOM
|
|
||||||
document.body.appendChild(form);
|
|
||||||
|
|
||||||
// Submit the form automatically
|
|
||||||
form.submit();
|
|
||||||
} else {
|
|
||||||
// Handle case where user cancels or enters an empty name
|
|
||||||
alert('List creation was cancelled or name was empty.');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
attributes: {
|
|
||||||
title: 'Add a new list to the table'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{else}
|
|
||||||
return {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
{/if}
|
|
||||||
}
|
|
||||||
|
|
||||||
function listFormatter(value, row, index) {
|
function listFormatter(value, row, index) {
|
||||||
var editBtn = '<a class="btn" href="{$smarty.env.BASEURI}/lists/edit/' + row.list_id + '" title="Edit"><i class="fa-solid fa-pen-to-square"></i></a> ';
|
var editBtn = '<a class="btn" href="{$smarty.env.BASEURI}/lists/edit/' + row.list_id + '" title="Edit"><i class="fa-solid fa-pen-to-square"></i></a> ';
|
||||||
|
|||||||
57
smarty/template/login.tpl
Normal file
57
smarty/template/login.tpl
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>XBotControl</title>
|
||||||
|
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
|
||||||
|
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous">
|
||||||
|
</script>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/bootstrap-table.min.css">
|
||||||
|
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||||
|
<!-- Latest compiled and minified JavaScript -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/bootstrap-table.min.js"></script>
|
||||||
|
<!-- Latest compiled and minified Locales -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/locale/bootstrap-table-zh-CN.min.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css"
|
||||||
|
href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/extensions/filter-control/bootstrap-table-filter-control.css">
|
||||||
|
<script
|
||||||
|
src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.5/dist/extensions/filter-control/bootstrap-table-filter-control.js">
|
||||||
|
</script>
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.1/css/all.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center justify-content-center vh-100">
|
||||||
|
<form id="form" enctype="multipart/form-data" action="login" method="post" class="p-4 border rounded">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="api_key" class="form-label">API Key</label>
|
||||||
|
<input type="text" class="form-control" id="api_key" name="api_key">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-success w-100">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="text-white text-center py-3">
|
||||||
|
<div class="footer">
|
||||||
|
<div class="container text-center text-light">
|
||||||
|
<h6>Copyright 2024
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
@@ -61,7 +61,7 @@ class Report
|
|||||||
{
|
{
|
||||||
$columnsDefinition = self::generateColumns([
|
$columnsDefinition = self::generateColumns([
|
||||||
["title" => "id", "field" => "id", "visible" => false],
|
["title" => "id", "field" => "id", "visible" => false],
|
||||||
["title" => "ip", "field" => "ip", 'formatter'=> 'ipFormatter'],
|
["title" => "ip", "field" => "ip", 'formatter' => 'ipFormatter'],
|
||||||
["title" => "domain", "field" => "domain", "visible" => false],
|
["title" => "domain", "field" => "domain", "visible" => false],
|
||||||
["title" => "path", "field" => "path"],
|
["title" => "path", "field" => "path"],
|
||||||
["title" => "useragent", "field" => "useragent"],
|
["title" => "useragent", "field" => "useragent"],
|
||||||
@@ -70,6 +70,12 @@ class Report
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$queryParams = self::parseQueryParams($request);
|
$queryParams = self::parseQueryParams($request);
|
||||||
|
if (!isset($queryParams['limit'])) {
|
||||||
|
return [
|
||||||
|
"columns" => $columnsDefinition,
|
||||||
|
"rows" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT
|
SELECT
|
||||||
req.rowid AS id, ip.data AS ip, domain.data AS domain,
|
req.rowid AS id, ip.data AS ip, domain.data AS domain,
|
||||||
@@ -97,11 +103,17 @@ class Report
|
|||||||
public static function count_requests_by_ip(ServerRequestInterface $request): PromiseInterface
|
public static function count_requests_by_ip(ServerRequestInterface $request): PromiseInterface
|
||||||
{
|
{
|
||||||
$columnsDefinition = self::generateColumns([
|
$columnsDefinition = self::generateColumns([
|
||||||
["title" => "ip", "field" => "ip_address", 'formatter'=> 'ipFormatter'],
|
["title" => "ip", "field" => "ip_address", 'formatter' => 'ipFormatter'],
|
||||||
["title" => "request_count", "field" => "request_count"],
|
["title" => "request_count", "field" => "request_count"],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$queryParams = self::parseQueryParams($request);
|
$queryParams = self::parseQueryParams($request);
|
||||||
|
if (!isset($queryParams['limit'])) {
|
||||||
|
return [
|
||||||
|
"columns" => $columnsDefinition,
|
||||||
|
"rows" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT
|
SELECT
|
||||||
ip.data AS ip_address,
|
ip.data AS ip_address,
|
||||||
@@ -110,16 +122,14 @@ class Report
|
|||||||
request
|
request
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
ip ON request.id_ip = ip.rowid
|
ip ON request.id_ip = ip.rowid
|
||||||
WHERE
|
|
||||||
request.timestamp BETWEEN ? AND ?
|
WHERE 1=1
|
||||||
GROUP BY
|
|
||||||
ip.data
|
|
||||||
ORDER BY
|
|
||||||
request_count DESC
|
|
||||||
LIMIT ?;
|
|
||||||
";
|
";
|
||||||
|
|
||||||
$params = [$queryParams['from'], $queryParams['to'], $queryParams['limit']];
|
list($filterSQL, $filterParams) = self::prepareFilterClauses($queryParams['filter']);
|
||||||
|
$sql .= $filterSQL . " AND request.timestamp BETWEEN ? AND ? GROUP BY
|
||||||
|
ip.data ORDER BY request_count DESC LIMIT ?;";
|
||||||
|
$params = array_merge($filterParams, [$queryParams['from'], $queryParams['to'], $queryParams['limit']]);
|
||||||
|
|
||||||
return self::executeQuery($sql, $params, $columnsDefinition);
|
return self::executeQuery($sql, $params, $columnsDefinition);
|
||||||
}
|
}
|
||||||
@@ -132,6 +142,12 @@ class Report
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$queryParams = self::parseQueryParams($request);
|
$queryParams = self::parseQueryParams($request);
|
||||||
|
if (!isset($queryParams['limit'])) {
|
||||||
|
return [
|
||||||
|
"columns" => $columnsDefinition,
|
||||||
|
"rows" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT
|
SELECT
|
||||||
useragent.data AS id_useragent,
|
useragent.data AS id_useragent,
|
||||||
@@ -140,16 +156,12 @@ class Report
|
|||||||
request
|
request
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
useragent ON request.id_useragent = useragent.rowid
|
useragent ON request.id_useragent = useragent.rowid
|
||||||
WHERE
|
WHERE 1=1
|
||||||
request.timestamp BETWEEN ? AND ?
|
|
||||||
GROUP BY
|
|
||||||
useragent.data
|
|
||||||
ORDER BY
|
|
||||||
request_count DESC
|
|
||||||
LIMIT ?;
|
|
||||||
";
|
";
|
||||||
|
|
||||||
$params = [$queryParams['from'], $queryParams['to'], $queryParams['limit']];
|
list($filterSQL, $filterParams) = self::prepareFilterClauses($queryParams['filter']);
|
||||||
|
$sql .= $filterSQL . " AND req.timestamp BETWEEN ? AND ? GROUP BY useragent.data ORDER BY request_count DESC LIMIT ?;";
|
||||||
|
$params = array_merge($filterParams, [$queryParams['from'], $queryParams['to'], $queryParams['limit']]);
|
||||||
|
|
||||||
return self::executeQuery($sql, $params, $columnsDefinition);
|
return self::executeQuery($sql, $params, $columnsDefinition);
|
||||||
}
|
}
|
||||||
@@ -157,13 +169,19 @@ class Report
|
|||||||
public static function top_ip_ua_path(ServerRequestInterface $request): PromiseInterface
|
public static function top_ip_ua_path(ServerRequestInterface $request): PromiseInterface
|
||||||
{
|
{
|
||||||
$columnsDefinition = self::generateColumns([
|
$columnsDefinition = self::generateColumns([
|
||||||
["title" => "ip", "field" => "ip", 'formatter'=> 'ipFormatter'],
|
["title" => "ip", "field" => "ip", 'formatter' => 'ipFormatter'],
|
||||||
["title" => "useragent", "field" => "user_agent"],
|
["title" => "useragent", "field" => "user_agent"],
|
||||||
["title" => "path", "field" => "path"],
|
["title" => "path", "field" => "path"],
|
||||||
["title" => "count", "field" => "count"],
|
["title" => "count", "field" => "count"],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$queryParams = self::parseQueryParams($request);
|
$queryParams = self::parseQueryParams($request);
|
||||||
|
if (!isset($queryParams['limit'])) {
|
||||||
|
return [
|
||||||
|
"columns" => $columnsDefinition,
|
||||||
|
"rows" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT
|
SELECT
|
||||||
ip.data AS ip,
|
ip.data AS ip,
|
||||||
@@ -175,16 +193,14 @@ class Report
|
|||||||
JOIN ip ON request.id_ip = ip.rowid
|
JOIN ip ON request.id_ip = ip.rowid
|
||||||
JOIN useragent ON request.id_useragent = useragent.rowid
|
JOIN useragent ON request.id_useragent = useragent.rowid
|
||||||
JOIN path ON request.id_path = path.rowid
|
JOIN path ON request.id_path = path.rowid
|
||||||
WHERE
|
|
||||||
request.timestamp BETWEEN ? AND ?
|
WHERE 1=1
|
||||||
GROUP BY
|
|
||||||
ip.data, useragent.data, path.data
|
|
||||||
ORDER BY
|
|
||||||
count DESC
|
|
||||||
LIMIT ?;
|
|
||||||
";
|
";
|
||||||
|
|
||||||
$params = [$queryParams['from'], $queryParams['to'], $queryParams['limit']];
|
list($filterSQL, $filterParams) = self::prepareFilterClauses($queryParams['filter']);
|
||||||
|
$sql .= $filterSQL . " AND request.timestamp BETWEEN ? AND ? GROUP BY ip.data, useragent.data, path.data ORDER BY count DESC LIMIT ?;";
|
||||||
|
|
||||||
|
$params = array_merge($filterParams, [$queryParams['from'], $queryParams['to'], $queryParams['limit']]);
|
||||||
|
|
||||||
return self::executeQuery($sql, $params, $columnsDefinition);
|
return self::executeQuery($sql, $params, $columnsDefinition);
|
||||||
}
|
}
|
||||||
@@ -192,12 +208,18 @@ class Report
|
|||||||
public static function top_ip_by_load(ServerRequestInterface $request): PromiseInterface
|
public static function top_ip_by_load(ServerRequestInterface $request): PromiseInterface
|
||||||
{
|
{
|
||||||
$columnsDefinition = self::generateColumns([
|
$columnsDefinition = self::generateColumns([
|
||||||
["title" => "ip", "field" => "data", 'formatter'=> 'ipFormatter'],
|
["title" => "ip", "field" => "data", 'formatter' => 'ipFormatter'],
|
||||||
["title" => "avg_load", "field" => "avg_load"],
|
["title" => "avg_load", "field" => "avg_load"],
|
||||||
["title" => "request_count", "field" => "request_count"],
|
["title" => "request_count", "field" => "request_count"],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$queryParams = self::parseQueryParams($request);
|
$queryParams = self::parseQueryParams($request);
|
||||||
|
if (!isset($queryParams['limit'])) {
|
||||||
|
return [
|
||||||
|
"columns" => $columnsDefinition,
|
||||||
|
"rows" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT
|
SELECT
|
||||||
ip.data,
|
ip.data,
|
||||||
@@ -211,17 +233,13 @@ class Report
|
|||||||
FROM load AS load_sub
|
FROM load AS load_sub
|
||||||
WHERE load_sub.rowid > request.timestamp
|
WHERE load_sub.rowid > request.timestamp
|
||||||
)
|
)
|
||||||
WHERE
|
WHERE load.load1 > 1
|
||||||
load.load1 > 1
|
|
||||||
AND request.timestamp BETWEEN ? AND ?
|
|
||||||
GROUP BY
|
|
||||||
ip.data
|
|
||||||
ORDER BY
|
|
||||||
avg_load DESC, request_count DESC
|
|
||||||
LIMIT ?;
|
|
||||||
";
|
";
|
||||||
|
|
||||||
$params = [$queryParams['from'], $queryParams['to'], $queryParams['limit']];
|
list($filterSQL, $filterParams) = self::prepareFilterClauses($queryParams['filter']);
|
||||||
|
$sql .= $filterSQL . " AND request.timestamp BETWEEN ? AND ? GROUP BY ip.data ORDER BY avg_load DESC LIMIT ?;";
|
||||||
|
|
||||||
|
$params = array_merge($filterParams, [$queryParams['from'], $queryParams['to'], $queryParams['limit']]);
|
||||||
|
|
||||||
return self::executeQuery($sql, $params, $columnsDefinition);
|
return self::executeQuery($sql, $params, $columnsDefinition);
|
||||||
}
|
}
|
||||||
@@ -229,11 +247,17 @@ class Report
|
|||||||
public static function top_ip_by_rps(ServerRequestInterface $request): PromiseInterface
|
public static function top_ip_by_rps(ServerRequestInterface $request): PromiseInterface
|
||||||
{
|
{
|
||||||
$columnsDefinition = self::generateColumns([
|
$columnsDefinition = self::generateColumns([
|
||||||
["title" => "ip", "field" => "ip_address", 'formatter'=> 'ipFormatter'],
|
["title" => "ip", "field" => "ip_address", 'formatter' => 'ipFormatter'],
|
||||||
["title" => "avg_request_per_second", "field" => "avg_request_per_second"],
|
["title" => "avg_request_per_second", "field" => "avg_request_per_second"],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$queryParams = self::parseQueryParams($request);
|
$queryParams = self::parseQueryParams($request);
|
||||||
|
if (!isset($queryParams['limit'])) {
|
||||||
|
return [
|
||||||
|
"columns" => $columnsDefinition,
|
||||||
|
"rows" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
$sql = "
|
$sql = "
|
||||||
WITH TimestampIPRequests AS (
|
WITH TimestampIPRequests AS (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -266,13 +290,13 @@ SELECT
|
|||||||
FROM
|
FROM
|
||||||
IPRequestPerSecond
|
IPRequestPerSecond
|
||||||
JOIN ip ON IPRequestPerSecond.id_ip = ip.rowid
|
JOIN ip ON IPRequestPerSecond.id_ip = ip.rowid
|
||||||
ORDER BY
|
|
||||||
avg_request_per_second DESC
|
|
||||||
LIMIT ?;
|
|
||||||
|
|
||||||
|
WHERE 1 = 1
|
||||||
";
|
";
|
||||||
|
|
||||||
$params = [$queryParams['from'], $queryParams['to'], $queryParams['limit']];
|
list($filterSQL, $filterParams) = self::prepareFilterClauses($queryParams['filter']);
|
||||||
|
$sql .= $filterSQL . " GROUP BY ip.data ORDER BY avg_request_per_second DESC LIMIT ?;";
|
||||||
|
$params = array_merge($filterParams, [$queryParams['from'], $queryParams['to'], $queryParams['limit']]);
|
||||||
|
|
||||||
return self::executeQuery($sql, $params, $columnsDefinition);
|
return self::executeQuery($sql, $params, $columnsDefinition);
|
||||||
}
|
}
|
||||||
@@ -285,6 +309,12 @@ LIMIT ?;
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$queryParams = self::parseQueryParams($request);
|
$queryParams = self::parseQueryParams($request);
|
||||||
|
if (!isset($queryParams['limit'])) {
|
||||||
|
return [
|
||||||
|
"columns" => $columnsDefinition,
|
||||||
|
"rows" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
$sql = "
|
$sql = "
|
||||||
CREATE FUNCTION cidr_to_network(cidr VARCHAR(30), prefix INT) RETURNS VARCHAR(30)
|
CREATE FUNCTION cidr_to_network(cidr VARCHAR(30), prefix INT) RETURNS VARCHAR(30)
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace XBotControl;
|
namespace XBotControl;
|
||||||
|
|
||||||
use MaxMind\Db\Reader;
|
|
||||||
|
|
||||||
class Config
|
class Config
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -32,7 +30,7 @@ class Config
|
|||||||
]);
|
]);
|
||||||
$this->smarty->compile_check = 1;
|
$this->smarty->compile_check = 1;
|
||||||
if (isset($_ENV['GEOIP_DB_FILE_PATH'])) {
|
if (isset($_ENV['GEOIP_DB_FILE_PATH'])) {
|
||||||
$this->geoipreader = new Reader($_ENV['APP_DIR'].'/'.$_ENV['GEOIP_DB_FILE']);
|
$this->geoipreader = new \MaxMind\Db\Reader($_ENV['APP_DIR'].'/'.$_ENV['GEOIP_DB_FILE']);
|
||||||
}
|
}
|
||||||
$dnsConfig = \React\Dns\Config\Config::loadSystemConfigBlocking();
|
$dnsConfig = \React\Dns\Config\Config::loadSystemConfigBlocking();
|
||||||
$dnsConfig->nameservers[] = '8.8.8.8';
|
$dnsConfig->nameservers[] = '8.8.8.8';
|
||||||
|
|||||||
30
src/Controllers/AuthController.php
Normal file
30
src/Controllers/AuthController.php
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace XBotControl\Controllers;
|
||||||
|
|
||||||
|
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use React\Http\Message\Response;
|
||||||
|
|
||||||
|
|
||||||
|
class AuthController
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public function __invoke(ServerRequestInterface $request, callable $next)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
if (isset($_SESSION['API_KEY']) && $_SESSION['API_KEY'] === $_ENV['API_KEY']) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
return new Response(
|
||||||
|
Response::STATUS_FOUND,
|
||||||
|
[
|
||||||
|
'Location' => $_ENV['BASE_URI'] . '/login'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/Controllers/LoginController.php
Normal file
34
src/Controllers/LoginController.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace XBotControl\Controllers;
|
||||||
|
|
||||||
|
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use React\Http\Message\Response;
|
||||||
|
|
||||||
|
class LoginController
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public function __invoke(ServerRequestInterface $request): \React\Http\Message\Response
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = $request->getParsedBody();
|
||||||
|
if ($data['api_key'] === $_ENV['API_KEY']) {
|
||||||
|
$_SESSION['API_KEY'] = $_ENV['API_KEY'];
|
||||||
|
$uri = $request->getUri();
|
||||||
|
var_dump($uri->getPath() );
|
||||||
|
return new Response(
|
||||||
|
Response::STATUS_FOUND,
|
||||||
|
[
|
||||||
|
'Location' => $_ENV['BASE_URI'] . '/'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Response::html(
|
||||||
|
\XBotControl\Config::getInstance()->smarty->fetch('login.tpl')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,10 +20,10 @@ $app->any(
|
|||||||
return XBotControl\Request::save($request);
|
return XBotControl\Request::save($request);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
$app->any('/login', XBotControl\Controllers\LoginController::class);
|
||||||
|
$app->any('/', XBotControl\Controllers\AuthController::class, XBotControl\Controllers\IndexController::class);
|
||||||
|
|
||||||
$app->any('/', XBotControl\Controllers\IndexController::class);
|
$app->any('/api/{action}/{resource}', XBotControl\Controllers\AuthController::class, XBotControl\Controllers\APIController::class);
|
||||||
|
|
||||||
$app->any('/api/{action}/{resource}', XBotControl\Controllers\APIController::class);
|
|
||||||
|
|
||||||
|
|
||||||
XBotControl\Classes\Schedule::run();
|
XBotControl\Classes\Schedule::run();
|
||||||
|
|||||||
Reference in New Issue
Block a user