Upload files to "system"
Signed-off-by: kevin <kevin@codelab.nestict.africa>
This commit is contained in:
24
system/.htaccess
Normal file
24
system/.htaccess
Normal file
@@ -0,0 +1,24 @@
|
||||
<Files *.php>
|
||||
Order Deny,Allow
|
||||
Deny from all
|
||||
</Files>
|
||||
|
||||
<Files cron.php>
|
||||
Order Allow,Deny
|
||||
Allow from all
|
||||
</Files>
|
||||
|
||||
<Files api.php>
|
||||
Order Allow,Deny
|
||||
Allow from all
|
||||
</Files>
|
||||
|
||||
<Files cron_reminder.php>
|
||||
Order Allow,Deny
|
||||
Allow from all
|
||||
</Files>
|
||||
|
||||
<Files download.php>
|
||||
Order Allow,Deny
|
||||
Allow from all
|
||||
</Files>
|
||||
127
system/api.php
Normal file
127
system/api.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
*
|
||||
* This File is for API Access
|
||||
**/
|
||||
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === "OPTIONS" || $_SERVER['REQUEST_METHOD'] === "HEAD") {
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization");
|
||||
header("HTTP/1.1 200 OK");
|
||||
die();
|
||||
}
|
||||
|
||||
$isApi = true;
|
||||
|
||||
include "../init.php";
|
||||
|
||||
// Dummy Class
|
||||
$ui = new class($key)
|
||||
{
|
||||
var $assign = [];
|
||||
function display($key)
|
||||
{
|
||||
global $req;
|
||||
showResult(true, $req, $this->getAll());
|
||||
}
|
||||
function assign($key, $value)
|
||||
{
|
||||
$this->assign[$key] = $value;
|
||||
}
|
||||
function get($key)
|
||||
{
|
||||
if (isset($this->assign[$key])) {
|
||||
return $this->assign[$key];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
function getTemplateVars($key)
|
||||
{
|
||||
if (isset($this->assign[$key])) {
|
||||
return $this->assign[$key];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
function getAll()
|
||||
{
|
||||
return $this->assign;
|
||||
}
|
||||
};
|
||||
|
||||
$req = _get('r');
|
||||
# a/c.id.time.md5
|
||||
# md5(a/c.id.time.$api_secret)
|
||||
$token = _req('token');
|
||||
$routes = explode('/', $req);
|
||||
$handler = $routes[0];
|
||||
|
||||
if (!empty($token)) {
|
||||
if ($token == $config['api_key']) {
|
||||
$admin = ORM::for_table('tbl_users')->where('user_type', 'SuperAdmin')->find_one($id);
|
||||
if (empty($admin)) {
|
||||
$admin = ORM::for_table('tbl_users')->where('user_type', 'Admin')->find_one($id);
|
||||
if (empty($admin)) {
|
||||
showResult(false, Lang::T("Token is invalid"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# validate token
|
||||
list($tipe, $uid, $time, $sha1) = explode('.', $token);
|
||||
if (trim($sha1) != sha1($uid . '.' . $time . '.' . $api_secret)) {
|
||||
showResult(false, Lang::T("Token is invalid"));
|
||||
}
|
||||
|
||||
#cek token expiration
|
||||
// 3 bulan
|
||||
if ($time != 0 && time() - $time > 7776000) {
|
||||
die("$time != " . (time() - $time));
|
||||
showResult(false, Lang::T("Token Expired"), [], ['login' => true]);
|
||||
}
|
||||
|
||||
if ($tipe == 'a') {
|
||||
$_SESSION['aid'] = $uid;
|
||||
$admin = Admin::_info();
|
||||
} else if ($tipe == 'c') {
|
||||
$_SESSION['uid'] = $uid;
|
||||
} else {
|
||||
showResult(false, Lang::T("Unknown Token"), [], ['login' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($handler) || empty($handler)) {
|
||||
showResult(true, Lang::T("Token is valid"));
|
||||
}
|
||||
|
||||
|
||||
if ($handler == 'isValid') {
|
||||
showResult(true, Lang::T("Token is valid"));
|
||||
}
|
||||
|
||||
if ($handler == 'me') {
|
||||
$admin = Admin::_info();
|
||||
if (!empty($admin['id'])) {
|
||||
showResult(true, "", $admin);
|
||||
} else {
|
||||
showResult(false, Lang::T("Token is invalid"));
|
||||
}
|
||||
}
|
||||
}else{
|
||||
unset($_COOKIE);
|
||||
unset($_SESSION);
|
||||
}
|
||||
|
||||
try {
|
||||
$sys_render = File::pathFixer($root_path . 'system/controllers/' . $handler . '.php');
|
||||
if (file_exists($sys_render)) {
|
||||
include($sys_render);
|
||||
showResult(true, $req, $ui->getAll());
|
||||
} else {
|
||||
showResult(false, Lang::T('Command not found'));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
showResult(false, $e->getMessage());
|
||||
}
|
||||
169
system/boot.php
Normal file
169
system/boot.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
|
||||
**/
|
||||
|
||||
try {
|
||||
require_once 'init.php';
|
||||
} catch (Throwable $e) {
|
||||
$ui = new Smarty();
|
||||
$ui->setTemplateDir([
|
||||
'custom' => File::pathFixer($UI_PATH . '/ui_custom/'),
|
||||
'default' => File::pathFixer($UI_PATH . '/ui/')
|
||||
]);
|
||||
$ui->assign('_url', APP_URL . '/index.php?_route=');
|
||||
$ui->setCompileDir(File::pathFixer($UI_PATH . '/compiled/'));
|
||||
$ui->setConfigDir(File::pathFixer($UI_PATH . '/conf/'));
|
||||
$ui->setCacheDir(File::pathFixer($UI_PATH . '/cache/'));
|
||||
$ui->assign("error_title", "PHPNuxBill Crash");
|
||||
if (_auth()) {
|
||||
$ui->assign("error_message", $e->getMessage() . '<br>');
|
||||
} else {
|
||||
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
|
||||
}
|
||||
$ui->display('router-error.tpl');
|
||||
die();
|
||||
} catch (Exception $e) {
|
||||
$ui = new Smarty();
|
||||
$ui->setTemplateDir([
|
||||
'custom' => File::pathFixer($UI_PATH . '/ui_custom/'),
|
||||
'default' => File::pathFixer($UI_PATH . '/ui/')
|
||||
]);
|
||||
$ui->assign('_url', APP_URL . '/index.php?_route=');
|
||||
$ui->setCompileDir(File::pathFixer($UI_PATH . '/compiled/'));
|
||||
$ui->setConfigDir(File::pathFixer($UI_PATH . '/conf/'));
|
||||
$ui->setCacheDir(File::pathFixer($UI_PATH . '/cache/'));
|
||||
$ui->assign("error_title", "PHPNuxBill Crash");
|
||||
if (_auth()) {
|
||||
$ui->assign("error_message", $e->getMessage() . '<br>');
|
||||
} else {
|
||||
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
|
||||
}
|
||||
$ui->display('router-error.tpl');
|
||||
die();
|
||||
}
|
||||
|
||||
function _notify($msg, $type = 'e')
|
||||
{
|
||||
$_SESSION['ntype'] = $type;
|
||||
$_SESSION['notify'] = $msg;
|
||||
}
|
||||
|
||||
$ui = new Smarty();
|
||||
$ui->assign('_kolaps', $_COOKIE['kolaps']);
|
||||
if (!empty($config['theme']) && $config['theme'] != 'default') {
|
||||
$_theme = APP_URL . '/' . $UI_PATH . '/themes/' . $config['theme'];
|
||||
$ui->setTemplateDir([
|
||||
'custom' => File::pathFixer($UI_PATH . '/ui_custom/'),
|
||||
'theme' => File::pathFixer($UI_PATH . '/themes/' . $config['theme']),
|
||||
'default' => File::pathFixer($UI_PATH . '/ui/')
|
||||
]);
|
||||
} else {
|
||||
$_theme = APP_URL . '/' . $UI_PATH . '/ui';
|
||||
$ui->setTemplateDir([
|
||||
'custom' => File::pathFixer($UI_PATH . '/ui_custom/'),
|
||||
'default' => File::pathFixer($UI_PATH . '/ui/')
|
||||
]);
|
||||
}
|
||||
$ui->assign('_theme', $_theme);
|
||||
$ui->addTemplateDir($PAYMENTGATEWAY_PATH . File::pathFixer('/ui/'), 'pg');
|
||||
$ui->addTemplateDir($PLUGIN_PATH . File::pathFixer('/ui/'), 'plugin');
|
||||
$ui->setCompileDir(File::pathFixer($UI_PATH . '/compiled/'));
|
||||
$ui->setConfigDir(File::pathFixer($UI_PATH . '/conf/'));
|
||||
$ui->setCacheDir(File::pathFixer($UI_PATH . '/cache/'));
|
||||
$ui->assign('app_url', APP_URL);
|
||||
$ui->assign('_domain', str_replace('www.', '', parse_url(APP_URL, PHP_URL_HOST)));
|
||||
$ui->assign('_url', APP_URL . '/index.php?_route=');
|
||||
$ui->assign('_path', __DIR__);
|
||||
$ui->assign('_c', $config);
|
||||
$ui->assign('UPLOAD_PATH', str_replace($root_path, '', $UPLOAD_PATH));
|
||||
$ui->assign('CACHE_PATH', str_replace($root_path, '', $CACHE_PATH));
|
||||
$ui->assign('PAGES_PATH', str_replace($root_path, '', $PAGES_PATH));
|
||||
$ui->assign('_system_menu', 'dashboard');
|
||||
|
||||
function _msglog($type, $msg)
|
||||
{
|
||||
$_SESSION['ntype'] = $type;
|
||||
$_SESSION['notify'] = $msg;
|
||||
}
|
||||
|
||||
if (isset($_SESSION['notify'])) {
|
||||
$notify = $_SESSION['notify'];
|
||||
$ntype = $_SESSION['ntype'];
|
||||
$ui->assign('notify', $notify);
|
||||
$ui->assign('notify_t', $ntype);
|
||||
unset($_SESSION['notify']);
|
||||
unset($_SESSION['ntype']);
|
||||
}
|
||||
|
||||
// Routing Engine
|
||||
$req = _get('_route');
|
||||
global $routes;
|
||||
$routes = explode('/', $req);
|
||||
$ui->assign('_routes', $routes);
|
||||
$handler = $routes[0];
|
||||
if ($handler == '') {
|
||||
$handler = 'default';
|
||||
}
|
||||
$admin = Admin::_info();
|
||||
try {
|
||||
$sys_render = $root_path . File::pathFixer('system/controllers/' . $handler . '.php');
|
||||
if (file_exists($sys_render)) {
|
||||
$menus = array();
|
||||
// "name" => $name,
|
||||
// "admin" => $admin,
|
||||
// "position" => $position,
|
||||
// "function" => $function
|
||||
$ui->assign('_system_menu', $routes[0]);
|
||||
foreach ($menu_registered as $menu) {
|
||||
if ($menu['admin'] && _admin(false)) {
|
||||
if (count($menu['auth']) == 0 || in_array($admin['user_type'], $menu['auth'])) {
|
||||
$menus[$menu['position']] .= '<li' . (($routes[1] == $menu['function']) ? ' class="active"' : '') . '><a href="' . U . 'plugin/' . $menu['function'] . '">';
|
||||
if (!empty($menu['icon'])) {
|
||||
$menus[$menu['position']] .= '<i class="' . $menu['icon'] . '"></i>';
|
||||
}
|
||||
if (!empty($menu['label'])) {
|
||||
$menus[$menu['position']] .= '<span class="pull-right-container">';
|
||||
$menus[$menu['position']] .= '<small class="label pull-right bg-' . $menu['color'] . '">' . $menu['label'] . '</small></span>';
|
||||
}
|
||||
$menus[$menu['position']] .= '<span class="text">' . $menu['name'] . '</span></a></li>';
|
||||
}
|
||||
} else if (!$menu['admin'] && _auth(false)) {
|
||||
$menus[$menu['position']] .= '<li' . (($routes[1] == $menu['function']) ? ' class="active"' : '') . '><a href="' . U . 'plugin/' . $menu['function'] . '">';
|
||||
if (!empty($menu['icon'])) {
|
||||
$menus[$menu['position']] .= '<i class="' . $menu['icon'] . '"></i>';
|
||||
}
|
||||
if (!empty($menu['label'])) {
|
||||
$menus[$menu['position']] .= '<span class="pull-right-container">';
|
||||
$menus[$menu['position']] .= '<small class="label pull-right bg-' . $menu['color'] . '">' . $menu['label'] . '</small></span>';
|
||||
}
|
||||
$menus[$menu['position']] .= '<span class="text">' . $menu['name'] . '</span></a></li>';
|
||||
}
|
||||
}
|
||||
foreach ($menus as $k => $v) {
|
||||
$ui->assign('_MENU_' . $k, $v);
|
||||
}
|
||||
unset($menus, $menu_registered);
|
||||
include($sys_render);
|
||||
} else {
|
||||
r2(U . 'dashboard', 'e', 'not found');
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
if (!Admin::getID()) {
|
||||
r2(U . 'home', 'e', $e->getMessage());
|
||||
}
|
||||
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
|
||||
$ui->assign("error_title", "PHPNuxBill Crash");
|
||||
$ui->display('router-error.tpl');
|
||||
die();
|
||||
} catch (Exception $e) {
|
||||
if (!Admin::getID()) {
|
||||
r2(U . 'home', 'e', $e->getMessage());
|
||||
}
|
||||
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
|
||||
$ui->assign("error_title", "PHPNuxBill Crash");
|
||||
$ui->display('router-error.tpl');
|
||||
die();
|
||||
}
|
||||
6
system/composer.json
Normal file
6
system/composer.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"require": {
|
||||
"mpdf/mpdf": "^8.1",
|
||||
"smarty/smarty": "^4.3"
|
||||
}
|
||||
}
|
||||
490
system/composer.lock
generated
Normal file
490
system/composer.lock
generated
Normal file
@@ -0,0 +1,490 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "81c1d3c4b2673fdd2922ac32768d59f1",
|
||||
"packages": [
|
||||
{
|
||||
"name": "mpdf/mpdf",
|
||||
"version": "v8.1.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mpdf/mpdf.git",
|
||||
"reference": "146c7c1dfd21c826b9d5bbfe3c15e52fd933c90f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mpdf/mpdf/zipball/146c7c1dfd21c826b9d5bbfe3c15e52fd933c90f",
|
||||
"reference": "146c7c1dfd21c826b9d5bbfe3c15e52fd933c90f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gd": "*",
|
||||
"ext-mbstring": "*",
|
||||
"mpdf/psr-log-aware-trait": "^2.0 || ^3.0",
|
||||
"myclabs/deep-copy": "^1.7",
|
||||
"paragonie/random_compat": "^1.4|^2.0|^9.99.99",
|
||||
"php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0",
|
||||
"psr/http-message": "^1.0",
|
||||
"psr/log": "^1.0 || ^2.0 || ^3.0",
|
||||
"setasign/fpdi": "^2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.3.0",
|
||||
"mpdf/qrcode": "^1.1.0",
|
||||
"squizlabs/php_codesniffer": "^3.5.0",
|
||||
"tracy/tracy": "~2.5",
|
||||
"yoast/phpunit-polyfills": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "Needed for generation of some types of barcodes",
|
||||
"ext-xml": "Needed mainly for SVG manipulation",
|
||||
"ext-zlib": "Needed for compression of embedded resources, such as fonts"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mpdf\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-2.0-only"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Matěj Humpál",
|
||||
"role": "Developer, maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Ian Back",
|
||||
"role": "Developer (retired)"
|
||||
}
|
||||
],
|
||||
"description": "PHP library generating PDF files from UTF-8 encoded HTML",
|
||||
"homepage": "https://mpdf.github.io",
|
||||
"keywords": [
|
||||
"pdf",
|
||||
"php",
|
||||
"utf-8"
|
||||
],
|
||||
"support": {
|
||||
"docs": "http://mpdf.github.io",
|
||||
"issues": "https://github.com/mpdf/mpdf/issues",
|
||||
"source": "https://github.com/mpdf/mpdf"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.paypal.me/mpdf",
|
||||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-03T19:36:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mpdf/psr-log-aware-trait",
|
||||
"version": "v2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mpdf/psr-log-aware-trait.git",
|
||||
"reference": "7a077416e8f39eb626dee4246e0af99dd9ace275"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mpdf/psr-log-aware-trait/zipball/7a077416e8f39eb626dee4246e0af99dd9ace275",
|
||||
"reference": "7a077416e8f39eb626dee4246e0af99dd9ace275",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"psr/log": "^1.0 || ^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mpdf\\PsrLogAwareTrait\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Dorison",
|
||||
"email": "mark@chromatichq.com"
|
||||
},
|
||||
{
|
||||
"name": "Kristofer Widholm",
|
||||
"email": "kristofer@chromatichq.com"
|
||||
}
|
||||
],
|
||||
"description": "Trait to allow support of different psr/log versions.",
|
||||
"support": {
|
||||
"issues": "https://github.com/mpdf/psr-log-aware-trait/issues",
|
||||
"source": "https://github.com/mpdf/psr-log-aware-trait/tree/v2.0.0"
|
||||
},
|
||||
"time": "2023-05-03T06:18:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.11.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/collections": "<1.6.8",
|
||||
"doctrine/common": "<2.13.3 || >=3,<3.2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/collections": "^1.6.8",
|
||||
"doctrine/common": "^2.13.3 || ^3.2.2",
|
||||
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/DeepCopy/deep_copy.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"DeepCopy\\": "src/DeepCopy/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Create deep copies (clones) of your objects",
|
||||
"keywords": [
|
||||
"clone",
|
||||
"copy",
|
||||
"duplicate",
|
||||
"object",
|
||||
"object graph"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-08T13:26:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v9.99.100",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">= 7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*|5.*",
|
||||
"vimeo/psalm": "^1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
||||
"keywords": [
|
||||
"csprng",
|
||||
"polyfill",
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"support": {
|
||||
"email": "info@paragonie.com",
|
||||
"issues": "https://github.com/paragonie/random_compat/issues",
|
||||
"source": "https://github.com/paragonie/random_compat"
|
||||
},
|
||||
"time": "2020-10-15T08:29:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
"version": "1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-message.git",
|
||||
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
|
||||
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Message\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for HTTP messages",
|
||||
"homepage": "https://github.com/php-fig/http-message",
|
||||
"keywords": [
|
||||
"http",
|
||||
"http-message",
|
||||
"psr",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-message/tree/1.1"
|
||||
},
|
||||
"time": "2023-04-04T09:50:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "1.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
|
||||
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Log\\": "Psr/Log/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for logging libraries",
|
||||
"homepage": "https://github.com/php-fig/log",
|
||||
"keywords": [
|
||||
"log",
|
||||
"psr",
|
||||
"psr-3"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/log/tree/1.1.4"
|
||||
},
|
||||
"time": "2021-05-03T11:20:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "setasign/fpdi",
|
||||
"version": "v2.3.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Setasign/FPDI.git",
|
||||
"reference": "bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05",
|
||||
"reference": "bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-zlib": "*",
|
||||
"php": "^5.6 || ^7.0 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"setasign/tfpdf": "<1.31"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~5.7",
|
||||
"setasign/fpdf": "~1.8",
|
||||
"setasign/tfpdf": "1.31",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"tecnickcom/tcpdf": "~6.2"
|
||||
},
|
||||
"suggest": {
|
||||
"setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"setasign\\Fpdi\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jan Slabon",
|
||||
"email": "jan.slabon@setasign.com",
|
||||
"homepage": "https://www.setasign.com"
|
||||
},
|
||||
{
|
||||
"name": "Maximilian Kresse",
|
||||
"email": "maximilian.kresse@setasign.com",
|
||||
"homepage": "https://www.setasign.com"
|
||||
}
|
||||
],
|
||||
"description": "FPDI is a collection of PHP classes facilitating developers to read pages from existing PDF documents and use them as templates in FPDF. Because it is also possible to use FPDI with TCPDF, there are no fixed dependencies defined. Please see suggestions for packages which evaluates the dependencies automatically.",
|
||||
"homepage": "https://www.setasign.com/fpdi",
|
||||
"keywords": [
|
||||
"fpdf",
|
||||
"fpdi",
|
||||
"pdf"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Setasign/FPDI/issues",
|
||||
"source": "https://github.com/Setasign/FPDI/tree/v2.3.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/setasign/fpdi",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-09T10:38:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "smarty/smarty",
|
||||
"version": "v4.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/smarty-php/smarty.git",
|
||||
"reference": "e28cb0915b4e3749bf57d4ebae2984e25395cfe5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/e28cb0915b4e3749bf57d4ebae2984e25395cfe5",
|
||||
"reference": "e28cb0915b4e3749bf57d4ebae2984e25395cfe5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5 || ^7.5",
|
||||
"smarty/smarty-lexer": "^3.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"libs/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-3.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Monte Ohrt",
|
||||
"email": "monte@ohrt.com"
|
||||
},
|
||||
{
|
||||
"name": "Uwe Tews",
|
||||
"email": "uwe.tews@googlemail.com"
|
||||
},
|
||||
{
|
||||
"name": "Rodney Rehm",
|
||||
"email": "rodney.rehm@medialize.de"
|
||||
},
|
||||
{
|
||||
"name": "Simon Wisselink",
|
||||
"homepage": "https://www.iwink.nl/"
|
||||
}
|
||||
],
|
||||
"description": "Smarty - the compiling PHP template engine",
|
||||
"homepage": "https://smarty-php.github.io/smarty/",
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"support": {
|
||||
"forum": "https://github.com/smarty-php/smarty/discussions",
|
||||
"issues": "https://github.com/smarty-php/smarty/issues",
|
||||
"source": "https://github.com/smarty-php/smarty/tree/v4.3.1"
|
||||
},
|
||||
"time": "2023-03-28T19:47:03+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
||||
21
system/create_cron_logs_table.sql
Normal file
21
system/create_cron_logs_table.sql
Normal file
@@ -0,0 +1,21 @@
|
||||
-- Create cron logs table for tracking cron job execution
|
||||
CREATE TABLE IF NOT EXISTS `tbl_cron_logs` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`cron_type` varchar(50) NOT NULL DEFAULT 'main' COMMENT 'Type of cron job (main, reminder, etc.)',
|
||||
`started_at` datetime NOT NULL COMMENT 'When cron job started',
|
||||
`finished_at` datetime DEFAULT NULL COMMENT 'When cron job finished',
|
||||
`status` enum('running','completed','failed') NOT NULL DEFAULT 'running' COMMENT 'Cron job status',
|
||||
`expired_users_found` int(11) NOT NULL DEFAULT 0 COMMENT 'Number of expired users found',
|
||||
`expired_users_processed` int(11) NOT NULL DEFAULT 0 COMMENT 'Number of expired users processed',
|
||||
`notifications_sent` int(11) NOT NULL DEFAULT 0 COMMENT 'Number of notifications sent',
|
||||
`auto_renewals_attempted` int(11) NOT NULL DEFAULT 0 COMMENT 'Number of auto-renewals attempted',
|
||||
`auto_renewals_successful` int(11) NOT NULL DEFAULT 0 COMMENT 'Number of successful auto-renewals',
|
||||
`error_message` text DEFAULT NULL COMMENT 'Error message if cron failed',
|
||||
`execution_time` decimal(10,3) DEFAULT NULL COMMENT 'Execution time in seconds',
|
||||
`memory_usage` varchar(20) DEFAULT NULL COMMENT 'Memory usage at completion',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_cron_type` (`cron_type`),
|
||||
KEY `idx_started_at` (`started_at`),
|
||||
KEY `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Cron job execution logs';
|
||||
24
system/create_monitoring_table.sql
Normal file
24
system/create_monitoring_table.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
-- Create router monitoring table
|
||||
CREATE TABLE IF NOT EXISTS `tbl_router_monitoring` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`router_id` int(11) NOT NULL,
|
||||
`timestamp` datetime NOT NULL,
|
||||
`ping_status` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`api_status` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`uptime` varchar(50) DEFAULT NULL,
|
||||
`free_memory` bigint(20) DEFAULT NULL,
|
||||
`total_memory` bigint(20) DEFAULT NULL,
|
||||
`cpu_load` int(11) DEFAULT NULL,
|
||||
`temperature` varchar(20) DEFAULT NULL,
|
||||
`voltage` varchar(20) DEFAULT NULL,
|
||||
`error` text DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `router_id` (`router_id`),
|
||||
KEY `timestamp` (`timestamp`),
|
||||
KEY `router_timestamp` (`router_id`, `timestamp`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Add monitoring columns to router table if they don't exist
|
||||
ALTER TABLE `tbl_routers`
|
||||
ADD COLUMN IF NOT EXISTS `last_error` text DEFAULT NULL,
|
||||
ADD COLUMN IF NOT EXISTS `offline_since` datetime DEFAULT NULL;
|
||||
268
system/cron.php
Normal file
268
system/cron.php
Normal file
@@ -0,0 +1,268 @@
|
||||
<?php
|
||||
|
||||
include dirname(__DIR__) . "/init.php";
|
||||
$isCli = true;
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
$isCli = false;
|
||||
echo "<pre>";
|
||||
}
|
||||
|
||||
// Start cron logging
|
||||
$logId = CronLog::start('main');
|
||||
$expiredUsersFound = 0;
|
||||
$expiredUsersProcessed = 0;
|
||||
$notificationsSent = 0;
|
||||
$autoRenewalsAttempted = 0;
|
||||
$autoRenewalsSuccessful = 0;
|
||||
|
||||
echo "PHP Time\t" . date('Y-m-d H:i:s') . "\n";
|
||||
$res = ORM::raw_execute('SELECT NOW() AS WAKTU;');
|
||||
$statement = ORM::get_last_statement();
|
||||
$rows = array();
|
||||
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
|
||||
echo "MYSQL Time\t" . $row['WAKTU'] . "\n";
|
||||
}
|
||||
|
||||
$_c = $config;
|
||||
|
||||
$textExpired = Lang::getNotifText('expired');
|
||||
|
||||
// Retrieve routers that are online
|
||||
$onlineRouters = ORM::for_table('tbl_routers')->where('status', 'online')->find_many();
|
||||
|
||||
// Convert the ORM result set to a regular array
|
||||
$onlineRoutersArray = $onlineRouters->as_array();
|
||||
|
||||
// Extract router names using array_map
|
||||
$onlineRouterNames = array_map(function($router) {
|
||||
return $router['name'];
|
||||
}, $onlineRoutersArray);
|
||||
|
||||
// If no online routers are found, skip processing user recharges
|
||||
if (empty($onlineRouterNames)) {
|
||||
echo "No online routers found. Skipping user recharge processing.\n";
|
||||
exit; // Skip further processing
|
||||
}
|
||||
|
||||
echo "Found " . count($onlineRouters) . " online routers.\n";
|
||||
|
||||
// First, handle suspended users that have reached their suspension time
|
||||
$suspendedUsers = ORM::for_table('tbl_user_recharges')->where('status', 'suspended')->where_lte('expiration', date("Y-m-d"))
|
||||
->where_in('routers', $onlineRouterNames)
|
||||
->find_many();
|
||||
|
||||
echo "Found " . count($suspendedUsers) . " suspended user(s) to process.\n";
|
||||
|
||||
foreach ($suspendedUsers as $susUser) {
|
||||
$date_now = strtotime(date("Y-m-d H:i:s"));
|
||||
$expiration = strtotime($susUser['expiration'] . ' ' . $susUser['time']);
|
||||
|
||||
if ($date_now >= $expiration) {
|
||||
echo "Suspending user: " . (($isCli) ? $susUser['username'] : Lang::maskText($susUser['username'])) . "\n";
|
||||
|
||||
$u = ORM::for_table('tbl_user_recharges')->where('id', $susUser['id'])->find_one();
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $susUser['customer_id'])->find_one();
|
||||
$m = ORM::for_table('tbl_routers')->where('name', $susUser['routers'])->find_one();
|
||||
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
|
||||
|
||||
if ($p['is_radius']) {
|
||||
if (empty($p['pool_expired'])) {
|
||||
print_r(Radius::customerDeactivate($c['username']));
|
||||
} else {
|
||||
Radius::upsertCustomerAttr($c['username'], 'Framed-Pool', $p['pool_expired'], ':=');
|
||||
print_r(Radius::disconnectCustomer($c['username']));
|
||||
}
|
||||
} else {
|
||||
$client = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
|
||||
if ($susUser['type'] == 'Hotspot') {
|
||||
if (!empty($p['pool_expired'])) {
|
||||
Mikrotik::setHotspotUserPlan($client, $c['username'], 'EXPIRED NUXBILL ' . $p['pool_expired']);
|
||||
} else {
|
||||
Mikrotik::removeHotspotUser($client, $c['username']);
|
||||
}
|
||||
Mikrotik::removeHotspotActiveUser($client, $c['username']);
|
||||
} else if ($susUser['type'] == 'PPPOE') {
|
||||
if (!empty($p['pool_expired'])) {
|
||||
Mikrotik::setPpoeUserPlan($client, $c['username'], 'EXPIRED NUXBILL ' . $p['pool_expired']);
|
||||
} else {
|
||||
Mikrotik::removePpoeUser($client, $c['username']);
|
||||
}
|
||||
Mikrotik::removePpoeActive($client, $c['username']);
|
||||
}
|
||||
}
|
||||
|
||||
// Update status to 'off' (suspended)
|
||||
$u->status = 'off';
|
||||
$u->save();
|
||||
|
||||
echo "User " . $susUser['username'] . " has been suspended.\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve user recharges with status 'on' and expiration less than or equal to today
|
||||
$d = ORM::for_table('tbl_user_recharges')->where('status', 'on')->where_lte('expiration', date("Y-m-d"))
|
||||
->where_in('routers', $onlineRouterNames) // Filter by routers that are online
|
||||
->find_many();
|
||||
|
||||
echo "Found " . count($d) . " user(s) on online routers.\n";
|
||||
|
||||
run_hook('cronjob'); #HOOK
|
||||
|
||||
foreach ($d as $ds) {
|
||||
if ($ds['type'] == 'Hotspot') { # HOTSPOT
|
||||
$date_now = strtotime(date("Y-m-d H:i:s"));
|
||||
$expiration = strtotime($ds['expiration'] . ' ' . $ds['time']);
|
||||
echo $ds['expiration'] . " : " . (($isCli) ? $ds['username'] : Lang::maskText($ds['username']));
|
||||
if ($date_now >= $expiration) {
|
||||
echo " : EXPIRED \r\n";
|
||||
$expiredUsersFound++;
|
||||
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
|
||||
$m = Mikrotik::info($ds['routers']);
|
||||
|
||||
// Now no need to check the router status again because the query already filters offline routers
|
||||
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
|
||||
if ($p['is_radius']) {
|
||||
if (empty($p['pool_expired'])) {
|
||||
print_r(Radius::customerDeactivate($c['username']));
|
||||
} else {
|
||||
Radius::upsertCustomerAttr($c['username'], 'Framed-Pool', $p['pool_expired'], ':=');
|
||||
print_r(Radius::disconnectCustomer($c['username']));
|
||||
}
|
||||
} else {
|
||||
$client = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
|
||||
if (!empty($p['pool_expired'])) {
|
||||
Mikrotik::setHotspotUserPackage($client, $c['username'], 'EXPIRED NUXBILL ' . $p['pool_expired']);
|
||||
} else {
|
||||
Mikrotik::removeHotspotUser($client, $c['username']);
|
||||
}
|
||||
Mikrotik::removeHotspotActiveUser($client, $c['username']);
|
||||
}
|
||||
echo Message::sendPackageNotification($c, $u['namebp'], $p['price'], 'expired', $config['user_notification_expired'], $p['type']) . "\n";
|
||||
$notificationsSent++;
|
||||
|
||||
// Update database user with status off
|
||||
$u->status = 'off';
|
||||
$u->save();
|
||||
$expiredUsersProcessed++;
|
||||
|
||||
// Autoreneewal from deposit
|
||||
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
|
||||
$autoRenewalsAttempted++;
|
||||
list($bills, $add_cost) = User::getBills($ds['customer_id']);
|
||||
if ($add_cost > 0) {
|
||||
if (!empty($add_cost)) {
|
||||
$p['price'] += $add_cost;
|
||||
}
|
||||
}
|
||||
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
|
||||
if (Package::rechargeUser($ds['customer_id'], $ds['routers'], $p['id'], 'Customer', 'Balance')) {
|
||||
// if success, then get the balance
|
||||
Balance::min($ds['customer_id'], $p['price']);
|
||||
$autoRenewalsSuccessful++;
|
||||
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
|
||||
echo "auto renewall Success\n";
|
||||
} else {
|
||||
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
|
||||
echo "auto renewall Failed\n";
|
||||
Message::sendTelegram("FAILED RENEWAL #cron\n\n#u$c[username] #buy #Hotspot \n" . $p['name_plan'] .
|
||||
"\nRouter: " . $p['routers'] .
|
||||
"\nPrice: " . $p['price']);
|
||||
}
|
||||
} else {
|
||||
echo "no renewall | plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
|
||||
}
|
||||
} else {
|
||||
echo "no renewall | balance $config[enable_balance] auto_renewal $c[auto_renewal]\n";
|
||||
}
|
||||
} else
|
||||
echo " : ACTIVE \r\n";
|
||||
} else { # PPPOE
|
||||
$date_now = strtotime(date("Y-m-d H:i:s"));
|
||||
$expiration = strtotime($ds['expiration'] . ' ' . $ds['time']);
|
||||
echo $ds['expiration'] . " : " . (($isCli) ? $ds['username'] : Lang::maskText($ds['username']));
|
||||
if ($date_now >= $expiration) {
|
||||
echo " : EXPIRED \r\n";
|
||||
$expiredUsersFound++;
|
||||
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
|
||||
$m = ORM::for_table('tbl_routers')->where('name', $ds['routers'])->find_one();
|
||||
|
||||
// No need to check router status here, as we've already filtered offline routers
|
||||
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
|
||||
if ($p['is_radius']) {
|
||||
if (empty($p['pool_expired'])) {
|
||||
print_r(Radius::customerDeactivate($c['username']));
|
||||
} else {
|
||||
Radius::upsertCustomerAttr($c['username'], 'Framed-Pool', $p['pool_expired'], ':=');
|
||||
print_r(Radius::disconnectCustomer($c['username']));
|
||||
}
|
||||
} else {
|
||||
$client = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
|
||||
if (!empty($p['pool_expired'])) {
|
||||
Mikrotik::setPpoeUserPlan($client, $c['username'], 'EXPIRED NUXBILL ' . $p['pool_expired']);
|
||||
} else {
|
||||
Mikrotik::removePpoeUser($client, $c['username']);
|
||||
}
|
||||
Mikrotik::removePpoeActive($client, $c['username']);
|
||||
}
|
||||
echo Message::sendPackageNotification($c, $u['namebp'], $p['price'], 'expired', $config['user_notification_expired'], $p['type']) . "\n";
|
||||
$notificationsSent++;
|
||||
|
||||
// Update database user with status off
|
||||
$u->status = 'off';
|
||||
$u->save();
|
||||
$expiredUsersProcessed++;
|
||||
|
||||
// Autoreneewal from deposit
|
||||
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
|
||||
$autoRenewalsAttempted++;
|
||||
list($bills, $add_cost) = User::getBills($ds['customer_id']);
|
||||
if ($add_cost > 0) {
|
||||
if (!empty($add_cost)) {
|
||||
$p['price'] += $add_cost;
|
||||
}
|
||||
}
|
||||
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
|
||||
if (Package::rechargeUser($ds['customer_id'], $ds['routers'], $p['id'], 'Customer', 'Balance')) {
|
||||
// if success, then get the balance
|
||||
Balance::min($ds['customer_id'], $p['price']);
|
||||
$autoRenewalsSuccessful++;
|
||||
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
|
||||
echo "auto renewall Success\n";
|
||||
} else {
|
||||
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
|
||||
echo "auto renewall Failed\n";
|
||||
Message::sendTelegram("FAILED RENEWAL #cron\n\n#u$c[username] #buy #PPPOE \n" . $p['name_plan'] .
|
||||
"\nRouter: " . $p['routers'] .
|
||||
"\nPrice: " . $p['price']);
|
||||
}
|
||||
} else {
|
||||
echo "no renewall | plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
|
||||
}
|
||||
} else {
|
||||
echo "no renewall | balance $config[enable_balance] auto_renewal $c[auto_renewal]\n";
|
||||
}
|
||||
} else
|
||||
echo " : ACTIVE \r\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Complete cron logging
|
||||
echo "\n=== CRON JOB SUMMARY ===\n";
|
||||
echo "Expired users found: $expiredUsersFound\n";
|
||||
echo "Expired users processed: $expiredUsersProcessed\n";
|
||||
echo "Notifications sent: $notificationsSent\n";
|
||||
echo "Auto-renewals attempted: $autoRenewalsAttempted\n";
|
||||
echo "Auto-renewals successful: $autoRenewalsSuccessful\n";
|
||||
|
||||
// Update final statistics and complete logging
|
||||
CronLog::complete([
|
||||
'expired_users_found' => $expiredUsersFound,
|
||||
'expired_users_processed' => $expiredUsersProcessed,
|
||||
'notifications_sent' => $notificationsSent,
|
||||
'auto_renewals_attempted' => $autoRenewalsAttempted,
|
||||
'auto_renewals_successful' => $autoRenewalsSuccessful
|
||||
]);
|
||||
|
||||
echo "Cron job completed successfully!\n";
|
||||
77
system/cron_reminder.php
Normal file
77
system/cron_reminder.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* This file for reminding user about expiration
|
||||
* Example to run every at 7:00 in the morning
|
||||
* 0 7 * * * /usr/bin/php /var/www/system/cron_reminder.php
|
||||
**/
|
||||
|
||||
include dirname(__DIR__) . "/init.php";
|
||||
|
||||
// Start reminder cron logging
|
||||
$logId = CronLog::start('reminder');
|
||||
$remindersSent = 0;
|
||||
|
||||
$isCli = true;
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
$isCli = false;
|
||||
echo "<pre>";
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_user_recharges')->where('status', 'on')->find_many();
|
||||
|
||||
run_hook('cronjob_reminder'); #HOOK
|
||||
|
||||
|
||||
echo "PHP Time\t" . date('Y-m-d H:i:s') . "\n";
|
||||
$res = ORM::raw_execute('SELECT NOW() AS WAKTU;');
|
||||
$statement = ORM::get_last_statement();
|
||||
$rows = array();
|
||||
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
|
||||
echo "MYSQL Time\t" . $row['WAKTU'] . "\n";
|
||||
}
|
||||
|
||||
|
||||
$day7 = date('Y-m-d', strtotime("+7 day"));
|
||||
$day3 = date('Y-m-d', strtotime("+3 day"));
|
||||
$day1 = date('Y-m-d', strtotime("+1 day"));
|
||||
print_r([$day1, $day3, $day7]);
|
||||
foreach ($d as $ds) {
|
||||
if (in_array($ds['expiration'], [$day1, $day3, $day7])) {
|
||||
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
|
||||
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
|
||||
if ($p['validity_unit'] == 'Period') {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $ds['customer_id']);
|
||||
if (empty ($add_inv) or $add_inv == 0) {
|
||||
$price = $p['price'];
|
||||
} else {
|
||||
$price = $add_inv;
|
||||
}
|
||||
} else {
|
||||
$price = $p['price'];
|
||||
}
|
||||
if ($ds['expiration'] == $day7) {
|
||||
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_7_day'), $config['user_notification_reminder'], $p['type']) . "\n";
|
||||
$remindersSent++;
|
||||
} else if ($ds['expiration'] == $day3) {
|
||||
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_3_day'), $config['user_notification_reminder'], $p['type']) . "\n";
|
||||
$remindersSent++;
|
||||
} else if ($ds['expiration'] == $day1) {
|
||||
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_1_day'), $config['user_notification_reminder'], $p['type']) . "\n";
|
||||
$remindersSent++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Complete reminder cron logging
|
||||
echo "\n=== REMINDER CRON SUMMARY ===\n";
|
||||
echo "Reminders sent: $remindersSent\n";
|
||||
|
||||
CronLog::complete([
|
||||
'notifications_sent' => $remindersSent
|
||||
]);
|
||||
|
||||
echo "Reminder cron job completed successfully!\n";
|
||||
166
system/error_log
Normal file
166
system/error_log
Normal file
@@ -0,0 +1,166 @@
|
||||
[05-Jul-2024 03:20:03 UTC] Alloworigins called
|
||||
[05-Jul-2024 03:20:03 UTC] Type parameter missing
|
||||
[05-Jul-2024 03:25:02 UTC] Alloworigins called
|
||||
[05-Jul-2024 03:25:02 UTC] Type parameter missing
|
||||
[05-Jul-2024 11:36:03 Africa/Nairobi] PHP Fatal error: Uncaught PEAR2\Net\Transmitter\SocketException: stream_socket_client(): Unable to connect to tcp://us.labkom.us:6529 (Connection timed out) in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/Stream.php(145): PEAR2\Net\Transmitter\TcpClient->createException('stream_socket_c...', 0)
|
||||
#1 [internal function]: PEAR2\Net\Transmitter\Stream->handleError(2, 'stream_socket_c...', '/home/codevibe/...', 159)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(159): stream_socket_client('tcp://us.labkom...', 0, '', '60', 4, Resource id #10)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#5 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#6 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#7 {main}
|
||||
|
||||
Next PEAR2\Net\Transmitter\SocketException: Failed to connect with socket. in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(178): PEAR2\Net\Transmitter\TcpClient->createException('Failed to conne...', 8, Object(PEAR2\Net\Transmitter\SocketException))
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#5 {main}
|
||||
|
||||
Next PEAR2\Net\RouterOS\SocketException: Error connecting to RouterOS in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php:169
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#3 {main}
|
||||
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php on line 169
|
||||
[05-Jul-2024 11:40:04 Africa/Nairobi] PHP Fatal error: Uncaught PEAR2\Net\Transmitter\SocketException: stream_socket_client(): Unable to connect to tcp://us.labkom.us:6529 (Network is unreachable) in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/Stream.php(145): PEAR2\Net\Transmitter\TcpClient->createException('stream_socket_c...', 0)
|
||||
#1 [internal function]: PEAR2\Net\Transmitter\Stream->handleError(2, 'stream_socket_c...', '/home/codevibe/...', 159)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(159): stream_socket_client('tcp://us.labkom...', 0, '', '60', 4, Resource id #10)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#5 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#6 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#7 {main}
|
||||
|
||||
Next PEAR2\Net\Transmitter\SocketException: Failed to connect with socket. in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(178): PEAR2\Net\Transmitter\TcpClient->createException('Failed to conne...', 8, Object(PEAR2\Net\Transmitter\SocketException))
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#5 {main}
|
||||
|
||||
Next PEAR2\Net\RouterOS\SocketException: Error connecting to RouterOS in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php:169
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#3 {main}
|
||||
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php on line 169
|
||||
[05-Jul-2024 11:46:02 Africa/Nairobi] PHP Fatal error: Uncaught PEAR2\Net\Transmitter\SocketException: stream_socket_client(): Unable to connect to tcp://us.labkom.us:6529 (Connection timed out) in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/Stream.php(145): PEAR2\Net\Transmitter\TcpClient->createException('stream_socket_c...', 0)
|
||||
#1 [internal function]: PEAR2\Net\Transmitter\Stream->handleError(2, 'stream_socket_c...', '/home/codevibe/...', 159)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(159): stream_socket_client('tcp://us.labkom...', 0, '', '60', 4, Resource id #10)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#5 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#6 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#7 {main}
|
||||
|
||||
Next PEAR2\Net\Transmitter\SocketException: Failed to connect with socket. in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(178): PEAR2\Net\Transmitter\TcpClient->createException('Failed to conne...', 8, Object(PEAR2\Net\Transmitter\SocketException))
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#5 {main}
|
||||
|
||||
Next PEAR2\Net\RouterOS\SocketException: Error connecting to RouterOS in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php:169
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#3 {main}
|
||||
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php on line 169
|
||||
[05-Jul-2024 11:51:03 Africa/Nairobi] PHP Fatal error: Uncaught PEAR2\Net\Transmitter\SocketException: stream_socket_client(): Unable to connect to tcp://us.labkom.us:6529 (Connection timed out) in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/Stream.php(145): PEAR2\Net\Transmitter\TcpClient->createException('stream_socket_c...', 0)
|
||||
#1 [internal function]: PEAR2\Net\Transmitter\Stream->handleError(2, 'stream_socket_c...', '/home/codevibe/...', 159)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(159): stream_socket_client('tcp://us.labkom...', 0, '', '60', 4, Resource id #10)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#5 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#6 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#7 {main}
|
||||
|
||||
Next PEAR2\Net\Transmitter\SocketException: Failed to connect with socket. in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(178): PEAR2\Net\Transmitter\TcpClient->createException('Failed to conne...', 8, Object(PEAR2\Net\Transmitter\SocketException))
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#5 {main}
|
||||
|
||||
Next PEAR2\Net\RouterOS\SocketException: Error connecting to RouterOS in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php:169
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#3 {main}
|
||||
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php on line 169
|
||||
[06-Jul-2024 23:26:04 Africa/Nairobi] PHP Fatal error: Uncaught PEAR2\Net\Transmitter\SocketException: stream_socket_client(): Unable to connect to tcp://us.labkom.us:6529 (Connection timed out) in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/Stream.php(145): PEAR2\Net\Transmitter\TcpClient->createException('stream_socket_c...', 0)
|
||||
#1 [internal function]: PEAR2\Net\Transmitter\Stream->handleError(2, 'stream_socket_c...', '/home/codevibe/...', 159)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(159): stream_socket_client('tcp://us.labkom...', 0, '', '60', 4, Resource id #10)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#5 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#6 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#7 {main}
|
||||
|
||||
Next PEAR2\Net\Transmitter\SocketException: Failed to connect with socket. in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(178): PEAR2\Net\Transmitter\TcpClient->createException('Failed to conne...', 8, Object(PEAR2\Net\Transmitter\SocketException))
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#5 {main}
|
||||
|
||||
Next PEAR2\Net\RouterOS\SocketException: Error connecting to RouterOS in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php:169
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#3 {main}
|
||||
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php on line 169
|
||||
[06-Jul-2024 23:31:04 Africa/Nairobi] PHP Fatal error: Uncaught PEAR2\Net\Transmitter\SocketException: stream_socket_client(): Unable to connect to tcp://us.labkom.us:6529 (Connection timed out) in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/Stream.php(145): PEAR2\Net\Transmitter\TcpClient->createException('stream_socket_c...', 0)
|
||||
#1 [internal function]: PEAR2\Net\Transmitter\Stream->handleError(2, 'stream_socket_c...', '/home/codevibe/...', 159)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(159): stream_socket_client('tcp://us.labkom...', 0, '', '60', 4, Resource id #10)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#5 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#6 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#7 {main}
|
||||
|
||||
Next PEAR2\Net\Transmitter\SocketException: Failed to connect with socket. in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php:225
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/Transmitter/TcpClient.php(178): PEAR2\Net\Transmitter\TcpClient->createException('Failed to conne...', 8, Object(PEAR2\Net\Transmitter\SocketException))
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php(160): PEAR2\Net\Transmitter\TcpClient->__construct('us.labkom.us', '6529', false, '60', 'admin/11', '', Resource id #10)
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#3 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#4 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#5 {main}
|
||||
|
||||
Next PEAR2\Net\RouterOS\SocketException: Error connecting to RouterOS in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php:169
|
||||
Stack trace:
|
||||
#0 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Client.php(162): PEAR2\Net\RouterOS\Communicator->__construct('us.labkom.us', '6529', false, NULL, 'admin/11', '', NULL)
|
||||
#1 /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/Mikrotik.php(24): PEAR2\Net\RouterOS\Client->__construct('us.labkom.us', 'admin', '11', '6529')
|
||||
#2 /home/codevibe/kejos.codevibeisp.co.ke/system/cron.php(45): Mikrotik::getClient('us.labkom.us:65...', 'admin', '11')
|
||||
#3 {main}
|
||||
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/autoload/PEAR2/Net/RouterOS/Communicator.php on line 169
|
||||
58
system/get_resources.php
Normal file
58
system/get_resources.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
require_once 'system/autoload/PEAR2/Autoload.php';
|
||||
|
||||
function mikrotik_get_resources($routerId)
|
||||
{
|
||||
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routerId);
|
||||
|
||||
if (!$mikrotik) {
|
||||
// Handle case where router is not found
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
|
||||
$health = $client->sendSync(new RouterOS\Request('/system health print'));
|
||||
$res = $client->sendSync(new RouterOS\Request('/system resource print'));
|
||||
|
||||
$resourceData = $res->getAllOfType(RouterOS\Response::TYPE_DATA)[0];
|
||||
$uptime = $resourceData->getProperty('uptime');
|
||||
$freeMemory = $resourceData->getProperty('free-memory');
|
||||
$totalMemory = $resourceData->getProperty('total-memory');
|
||||
$cpuLoad = $resourceData->getProperty('cpu-load');
|
||||
|
||||
return [
|
||||
'uptime' => $uptime,
|
||||
'freeMemory' => mikrotik_formatSize($freeMemory),
|
||||
'totalMemory' => mikrotik_formatSize($totalMemory),
|
||||
'cpuLoad' => $cpuLoad . '%'
|
||||
];
|
||||
} catch (Exception $e) {
|
||||
// Handle exceptions, e.g., connection errors
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to round the value and append the appropriate unit
|
||||
function mikrotik_formatSize($size)
|
||||
{
|
||||
$units = ['B', 'KB', 'MB', 'GB'];
|
||||
$unitIndex = 0;
|
||||
while ($size >= 1024 && $unitIndex < count($units) - 1) {
|
||||
$size /= 1024;
|
||||
$unitIndex++;
|
||||
}
|
||||
return round($size, 2) . ' ' . $units[$unitIndex];
|
||||
}
|
||||
|
||||
if (isset($_GET['router_id'])) {
|
||||
$routerId = $_GET['router_id'];
|
||||
$resources = mikrotik_get_resources($routerId);
|
||||
echo json_encode($resources);
|
||||
}
|
||||
8
system/index.html
Normal file
8
system/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Directory access is forbidden.</p>
|
||||
</body>
|
||||
</html>
|
||||
38
system/install_cron_logs.php
Normal file
38
system/install_cron_logs.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Install Cron Logs Table
|
||||
* Run this script to create the cron logs table
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__) . '/init.php';
|
||||
|
||||
echo "Installing Cron Logs Table...\n";
|
||||
|
||||
// Read the SQL file
|
||||
$sqlFile = __DIR__ . '/create_cron_logs_table.sql';
|
||||
if (!file_exists($sqlFile)) {
|
||||
echo "Error: SQL file not found: $sqlFile\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$sql = file_get_contents($sqlFile);
|
||||
|
||||
// Execute the SQL
|
||||
try {
|
||||
ORM::raw_execute($sql);
|
||||
echo "✓ Cron logs table created successfully!\n";
|
||||
|
||||
// Test the table
|
||||
$test = ORM::for_table('tbl_cron_logs')->count();
|
||||
echo "✓ Table test successful - found $test records\n";
|
||||
|
||||
echo "\nCron logs system is now ready!\n";
|
||||
echo "You can view logs at: " . APP_URL . "/settings/cron-logs\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "✗ Error creating table: " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo "\nInstallation completed successfully!\n";
|
||||
112
system/migrate_notifications.php
Normal file
112
system/migrate_notifications.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Migration script for plan-type-specific notification templates
|
||||
* This script converts existing notification templates to the new plan-type-specific structure
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__) . '/init.php';
|
||||
|
||||
// Check if running from command line or web
|
||||
$isCli = php_sapi_name() === 'cli';
|
||||
|
||||
if (!$isCli) {
|
||||
_admin(); // Check admin permissions for web access
|
||||
}
|
||||
|
||||
echo "Starting notification template migration...\n";
|
||||
|
||||
$notifications_file = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.json';
|
||||
$default_file = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.default.json';
|
||||
|
||||
// Load existing notifications
|
||||
$existing_notifications = [];
|
||||
if (file_exists($notifications_file)) {
|
||||
$existing_notifications = json_decode(file_get_contents($notifications_file), true);
|
||||
echo "Found existing notifications.json\n";
|
||||
} else {
|
||||
echo "No existing notifications.json found, using default templates\n";
|
||||
$existing_notifications = json_decode(file_get_contents($default_file), true);
|
||||
}
|
||||
|
||||
// Load new default structure
|
||||
$new_default = json_decode(file_get_contents($default_file), true);
|
||||
|
||||
// Plan-specific keys that need migration
|
||||
$plan_specific_keys = ['expired', 'reminder_7_day', 'reminder_3_day', 'reminder_1_day'];
|
||||
|
||||
$migrated_notifications = [];
|
||||
|
||||
// Migrate plan-specific templates
|
||||
foreach ($plan_specific_keys as $key) {
|
||||
if (isset($existing_notifications[$key])) {
|
||||
$existing_value = $existing_notifications[$key];
|
||||
|
||||
// Check if it's already in new format (array)
|
||||
if (is_array($existing_value)) {
|
||||
echo "Template '$key' is already in new format, keeping as is\n";
|
||||
$migrated_notifications[$key] = $existing_value;
|
||||
} else {
|
||||
// Convert old format to new format
|
||||
echo "Converting template '$key' to plan-type-specific format\n";
|
||||
|
||||
// Use the old template as default for both plan types
|
||||
$migrated_notifications[$key] = [
|
||||
'hotspot' => $existing_value,
|
||||
'pppoe' => $existing_value,
|
||||
'default' => $existing_value
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// Use new default structure
|
||||
echo "Using default template for '$key'\n";
|
||||
$migrated_notifications[$key] = $new_default[$key];
|
||||
}
|
||||
}
|
||||
|
||||
// Copy other notification types as-is
|
||||
$other_keys = ['balance_send', 'balance_received', 'invoice_paid', 'invoice_balance', 'user_registration'];
|
||||
foreach ($other_keys as $key) {
|
||||
if (isset($existing_notifications[$key])) {
|
||||
$migrated_notifications[$key] = $existing_notifications[$key];
|
||||
} else {
|
||||
$migrated_notifications[$key] = $new_default[$key];
|
||||
}
|
||||
}
|
||||
|
||||
// Create backup of original file
|
||||
if (file_exists($notifications_file)) {
|
||||
$backup_file = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.backup.' . date('Y-m-d_H-i-s') . '.json';
|
||||
copy($notifications_file, $backup_file);
|
||||
echo "Created backup: $backup_file\n";
|
||||
}
|
||||
|
||||
// Save migrated notifications
|
||||
$result = file_put_contents($notifications_file, json_encode($migrated_notifications, JSON_PRETTY_PRINT));
|
||||
|
||||
if ($result !== false) {
|
||||
echo "Migration completed successfully!\n";
|
||||
echo "New notification structure saved to: $notifications_file\n";
|
||||
echo "\nMigration Summary:\n";
|
||||
echo "- Converted " . count($plan_specific_keys) . " plan-specific templates\n";
|
||||
echo "- Preserved " . count($other_keys) . " other notification types\n";
|
||||
echo "- Backup created for safety\n";
|
||||
echo "\nYou can now customize plan-type-specific templates in the admin panel.\n";
|
||||
} else {
|
||||
echo "Error: Failed to save migrated notifications\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Test the new structure
|
||||
echo "\nTesting new notification structure...\n";
|
||||
$test_notifications = json_decode(file_get_contents($notifications_file), true);
|
||||
|
||||
foreach ($plan_specific_keys as $key) {
|
||||
if (isset($test_notifications[$key]) && is_array($test_notifications[$key])) {
|
||||
echo "✓ Template '$key' is properly structured\n";
|
||||
} else {
|
||||
echo "✗ Template '$key' has issues\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\nMigration completed!\n";
|
||||
2773
system/orm.php
Normal file
2773
system/orm.php
Normal file
File diff suppressed because it is too large
Load Diff
311
system/router_monitor.php
Normal file
311
system/router_monitor.php
Normal file
@@ -0,0 +1,311 @@
|
||||
<?php
|
||||
/**
|
||||
* Enhanced Router Monitoring Service
|
||||
* Runs every 2 minutes to collect comprehensive router data
|
||||
* Usage: */2 * * * * cd /var/www/html/newdesign1/system && php -f router_monitor.php
|
||||
*/
|
||||
|
||||
include "../init.php";
|
||||
|
||||
$isCli = php_sapi_name() === 'cli';
|
||||
if (!$isCli) {
|
||||
echo "<pre>";
|
||||
}
|
||||
|
||||
echo "Router Monitor Started: " . date('Y-m-d H:i:s') . "\n";
|
||||
|
||||
use PEAR2\Net\RouterOS;
|
||||
use RouterOS\Exceptions\Socket\TimeoutException;
|
||||
use RouterOS\Exceptions\Socket\ConnectionException;
|
||||
|
||||
class RouterMonitor {
|
||||
private $config;
|
||||
private $db;
|
||||
|
||||
public function __construct() {
|
||||
global $config;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitor all enabled routers
|
||||
*/
|
||||
public function monitorAllRouters() {
|
||||
$routers = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
|
||||
|
||||
echo "Monitoring " . count($routers) . " routers...\n";
|
||||
|
||||
foreach ($routers as $router) {
|
||||
$this->monitorRouter($router);
|
||||
}
|
||||
|
||||
echo "Router monitoring completed: " . date('Y-m-d H:i:s') . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitor individual router
|
||||
*/
|
||||
private function monitorRouter($router) {
|
||||
$routerId = $router['id'];
|
||||
$routerName = $router['name'];
|
||||
$ipAddress = $router['ip_address'];
|
||||
|
||||
echo "Checking router: $routerName ($ipAddress)...\n";
|
||||
|
||||
// Check if router is in circuit breaker state
|
||||
if ($this->isCircuitBreakerActive($routerId)) {
|
||||
echo " - Circuit breaker active, skipping\n";
|
||||
$this->updateRouterStatus($router, 'Offline', 'Circuit breaker active');
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform comprehensive check
|
||||
$monitoringData = $this->performRouterCheck($router);
|
||||
|
||||
// Update database with results
|
||||
$this->updateRouterData($router, $monitoringData);
|
||||
|
||||
// Check for alerts
|
||||
$this->checkAlerts($router, $monitoringData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform comprehensive router check
|
||||
*/
|
||||
private function performRouterCheck($router) {
|
||||
$data = [
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'ping_status' => false,
|
||||
'api_status' => false,
|
||||
'uptime' => null,
|
||||
'free_memory' => null,
|
||||
'total_memory' => null,
|
||||
'cpu_load' => null,
|
||||
'temperature' => null,
|
||||
'voltage' => null,
|
||||
'error' => null
|
||||
];
|
||||
|
||||
// Step 1: Ping check
|
||||
$data['ping_status'] = $this->pingRouter($router['ip_address']);
|
||||
|
||||
if (!$data['ping_status']) {
|
||||
$data['error'] = 'Ping failed';
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Step 2: RouterOS API check
|
||||
try {
|
||||
$client = Mikrotik::getClient($router['ip_address'], $router['username'], $router['password'], 8);
|
||||
|
||||
if (!$client) {
|
||||
$data['error'] = 'Failed to create RouterOS client';
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Get system resource data
|
||||
$resourceRequest = new RouterOS\Request('/system resource print');
|
||||
$resourceResponse = $client->sendSync($resourceRequest, 5);
|
||||
$resourceData = $resourceResponse->getAllOfType(RouterOS\Response::TYPE_DATA)[0];
|
||||
|
||||
// Get system health data
|
||||
$healthRequest = new RouterOS\Request('/system health print');
|
||||
$healthResponse = $client->sendSync($healthRequest, 5);
|
||||
$healthData = $healthResponse->getAllOfType(RouterOS\Response::TYPE_DATA)[0];
|
||||
|
||||
// Extract data
|
||||
$data['api_status'] = true;
|
||||
$data['uptime'] = $resourceData->getProperty('uptime');
|
||||
$data['free_memory'] = (int)$resourceData->getProperty('free-memory');
|
||||
$data['total_memory'] = (int)$resourceData->getProperty('total-memory');
|
||||
$data['cpu_load'] = (int)$resourceData->getProperty('cpu-load');
|
||||
$data['temperature'] = $healthData->getProperty('temperature');
|
||||
$data['voltage'] = $healthData->getProperty('voltage');
|
||||
|
||||
// Clear circuit breaker on successful connection
|
||||
$this->clearCircuitBreaker($router['id']);
|
||||
|
||||
} catch (TimeoutException $e) {
|
||||
$data['error'] = 'API timeout';
|
||||
$this->incrementCircuitBreaker($router['id']);
|
||||
} catch (ConnectionException $e) {
|
||||
$data['error'] = 'API connection failed';
|
||||
$this->incrementCircuitBreaker($router['id']);
|
||||
} catch (Exception $e) {
|
||||
$data['error'] = 'API error: ' . $e->getMessage();
|
||||
$this->incrementCircuitBreaker($router['id']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ping router
|
||||
*/
|
||||
private function pingRouter($ipAddress, $timeout = 5, $count = 3) {
|
||||
$ipParts = explode(':', $ipAddress);
|
||||
$ip = $ipParts[0];
|
||||
$escapedIp = escapeshellarg($ip);
|
||||
|
||||
exec("ping -c $count -W $timeout $escapedIp 2>&1", $output, $returnVar);
|
||||
|
||||
return $returnVar === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update router status in database
|
||||
*/
|
||||
private function updateRouterStatus($router, $status, $error = null) {
|
||||
$router->status = $status;
|
||||
$router->last_check = date('Y-m-d H:i:s');
|
||||
|
||||
if ($error) {
|
||||
$router->last_error = $error;
|
||||
}
|
||||
|
||||
$router->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update router data in database
|
||||
*/
|
||||
private function updateRouterData($router, $data) {
|
||||
// Update main router table
|
||||
$router->status = ($data['api_status'] && $data['ping_status']) ? 'Online' : 'Offline';
|
||||
$router->last_check = $data['timestamp'];
|
||||
$router->last_error = $data['error'];
|
||||
$router->save();
|
||||
|
||||
// Store detailed monitoring data
|
||||
$this->storeMonitoringData($router['id'], $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store detailed monitoring data
|
||||
*/
|
||||
private function storeMonitoringData($routerId, $data) {
|
||||
// Create monitoring record
|
||||
$monitoring = ORM::for_table('tbl_router_monitoring')->create();
|
||||
$monitoring->router_id = $routerId;
|
||||
$monitoring->timestamp = $data['timestamp'];
|
||||
$monitoring->ping_status = $data['ping_status'] ? 1 : 0;
|
||||
$monitoring->api_status = $data['api_status'] ? 1 : 0;
|
||||
$monitoring->uptime = $data['uptime'];
|
||||
$monitoring->free_memory = $data['free_memory'];
|
||||
$monitoring->total_memory = $data['total_memory'];
|
||||
$monitoring->cpu_load = $data['cpu_load'];
|
||||
$monitoring->temperature = $data['temperature'];
|
||||
$monitoring->voltage = $data['voltage'];
|
||||
$monitoring->error = $data['error'];
|
||||
$monitoring->save();
|
||||
|
||||
// Clean up old records (keep last 7 days)
|
||||
$cutoffDate = date('Y-m-d H:i:s', strtotime('-7 days'));
|
||||
ORM::for_table('tbl_router_monitoring')
|
||||
->where('timestamp', '<', $cutoffDate)
|
||||
->delete_many();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for alerts
|
||||
*/
|
||||
private function checkAlerts($router, $data) {
|
||||
$alerts = [];
|
||||
|
||||
// CPU load alert
|
||||
if ($data['cpu_load'] && $data['cpu_load'] > 80) {
|
||||
$alerts[] = "High CPU load: {$data['cpu_load']}%";
|
||||
}
|
||||
|
||||
// Memory usage alert
|
||||
if ($data['free_memory'] && $data['total_memory']) {
|
||||
$memoryUsage = (($data['total_memory'] - $data['free_memory']) / $data['total_memory']) * 100;
|
||||
if ($memoryUsage > 90) {
|
||||
$alerts[] = "High memory usage: " . round($memoryUsage, 1) . "%";
|
||||
}
|
||||
}
|
||||
|
||||
// Temperature alert
|
||||
if ($data['temperature'] && $data['temperature'] > 60) {
|
||||
$alerts[] = "High temperature: {$data['temperature']}°C";
|
||||
}
|
||||
|
||||
// Send alerts if any
|
||||
if (!empty($alerts)) {
|
||||
$this->sendAlerts($router, $alerts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send alerts
|
||||
*/
|
||||
private function sendAlerts($router, $alerts) {
|
||||
$message = "Router {$router['name']} alerts:\n" . implode("\n", $alerts);
|
||||
|
||||
// Send to admin users
|
||||
$users = ORM::for_table('tbl_users')->where('user_type', 'Admin')->find_many();
|
||||
foreach ($users as $user) {
|
||||
$this->sendSMS($user['phone'], $message);
|
||||
$this->sendWhatsApp($user['phone'], $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Circuit breaker methods
|
||||
*/
|
||||
private function isCircuitBreakerActive($routerId) {
|
||||
if (!function_exists('apcu_fetch')) return false;
|
||||
|
||||
$key = "router_failures_$routerId";
|
||||
$timeKey = "router_failures_{$routerId}_time";
|
||||
|
||||
$failureCount = apcu_fetch($key) ?: 0;
|
||||
$lastFailure = apcu_fetch($timeKey) ?: 0;
|
||||
|
||||
return $failureCount >= 3 && (time() - $lastFailure) < 300; // 5 minutes
|
||||
}
|
||||
|
||||
private function incrementCircuitBreaker($routerId) {
|
||||
if (!function_exists('apcu_store')) return;
|
||||
|
||||
$key = "router_failures_$routerId";
|
||||
$timeKey = "router_failures_{$routerId}_time";
|
||||
|
||||
$failureCount = apcu_fetch($key) ?: 0;
|
||||
apcu_store($key, $failureCount + 1, 300);
|
||||
apcu_store($timeKey, time(), 300);
|
||||
}
|
||||
|
||||
private function clearCircuitBreaker($routerId) {
|
||||
if (!function_exists('apcu_delete')) return;
|
||||
|
||||
$key = "router_failures_$routerId";
|
||||
$timeKey = "router_failures_{$routerId}_time";
|
||||
|
||||
apcu_delete($key);
|
||||
apcu_delete($timeKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send SMS
|
||||
*/
|
||||
private function sendSMS($phone, $message) {
|
||||
// Implementation depends on your SMS provider
|
||||
// This is a placeholder
|
||||
echo "SMS to $phone: $message\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Send WhatsApp
|
||||
*/
|
||||
private function sendWhatsApp($phone, $message) {
|
||||
// Implementation depends on your WhatsApp provider
|
||||
// This is a placeholder
|
||||
echo "WhatsApp to $phone: $message\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Run the monitor
|
||||
$monitor = new RouterMonitor();
|
||||
$monitor->monitorAllRouters();
|
||||
?>
|
||||
163
system/router_status_check.php
Normal file
163
system/router_status_check.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
// Include necessary files
|
||||
include "../init.php";
|
||||
|
||||
$isCli = php_sapi_name() === 'cli';
|
||||
if (!$isCli) {
|
||||
echo "<pre>";
|
||||
}
|
||||
|
||||
echo "PHP Time\t" . date('Y-m-d H:i:s') . "\n";
|
||||
$res = ORM::raw_execute('SELECT NOW() AS WAKTU;');
|
||||
$statement = ORM::get_last_statement();
|
||||
$rows = array();
|
||||
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
|
||||
echo "MYSQL Time\t" . $row['WAKTU'] . "\n";
|
||||
}
|
||||
$_c = $config;
|
||||
|
||||
function icmp_ping($ip_address, $timeout = 15, $count = 20) { // Updated timeout and count
|
||||
$ip_parts = explode(':', $ip_address);
|
||||
$ip = $ip_parts[0];
|
||||
|
||||
$escaped_ip = escapeshellarg($ip);
|
||||
|
||||
exec("ping -c $count -W $timeout $escaped_ip 2>&1", $output, $return_var);
|
||||
|
||||
// Log ping command output and return status for debugging
|
||||
error_log("Ping command output: " . implode("\n", $output));
|
||||
error_log("Ping command return status: $return_var");
|
||||
|
||||
if ($return_var === 0) {
|
||||
// Parse ping output to check for packet loss and average round-trip time
|
||||
$statistics = implode("\n", $output);
|
||||
if (preg_match('/(\d+)% packet loss/', $statistics, $matches)) {
|
||||
$packet_loss = intval($matches[1]);
|
||||
if ($packet_loss === 0) {
|
||||
return true; // Successful ping with no packet loss
|
||||
} elseif ($packet_loss < 100) {
|
||||
// Packet loss is detected but not 100%, consider as minor issue
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false; // Default to false if ping failed or packet loss detected
|
||||
}
|
||||
|
||||
function get_appconfig_value($setting) {
|
||||
// Retrieve configuration value from database table
|
||||
$config = ORM::for_table('tbl_appconfig')->where('setting', $setting)->find_one();
|
||||
return $config ? $config->value : null;
|
||||
}
|
||||
|
||||
function send_sms($phone_number, $message) {
|
||||
// Send SMS using configured URL template
|
||||
$sms_url_template = get_appconfig_value('sms_url');
|
||||
if (!$sms_url_template) {
|
||||
echo "SMS URL not configured\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$url = str_replace(['[text]', '[number]'], [urlencode($message), urlencode($phone_number)], $sms_url_template);
|
||||
|
||||
// Initiate CURL request to send SMS
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
echo 'Curl error: ' . curl_error($ch) . "\n";
|
||||
} else {
|
||||
echo "SMS sent to $phone_number with response: $response and HTTP code: $http_code\n";
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
function send_whatsapp($phone_number, $message) {
|
||||
// Send WhatsApp message using configured URL template
|
||||
$wa_url_template = get_appconfig_value('wa_url');
|
||||
if (!$wa_url_template) {
|
||||
echo "WhatsApp URL not configured\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$url = str_replace(['[text]', '[number]'], [urlencode($message), urlencode($phone_number)], $wa_url_template);
|
||||
|
||||
// Initiate CURL request to send WhatsApp message
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
echo 'Curl error: ' . curl_error($ch) . "\n";
|
||||
} else {
|
||||
echo "WhatsApp message sent to $phone_number with response: $response and HTTP code: $http_code\n";
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
function check_and_update_router_status($router) {
|
||||
// Check current router status via ICMP ping
|
||||
$current_status = $router->status;
|
||||
$new_status = icmp_ping($router['ip_address'], 15, 20) ? 'Online' : 'Offline'; // Adjusted timeout and count
|
||||
|
||||
$current_time = date('Y-m-d H:i:s');
|
||||
|
||||
if ($current_status !== $new_status) {
|
||||
// Status has changed, notify all users and update status
|
||||
$users = ORM::for_table('tbl_users')->find_many();
|
||||
|
||||
if ($new_status === 'Offline') {
|
||||
// Router is offline, send notifications
|
||||
foreach ($users as $user) {
|
||||
$message = "Router {$router['name']} is Offline at $current_time. Error.";
|
||||
send_sms($user['phone'], $message);
|
||||
send_whatsapp($user['phone'], $message);
|
||||
}
|
||||
$router->offline_since = $current_time; // Record offline time
|
||||
} else {
|
||||
// Router is back online, calculate downtime and notify users
|
||||
$offline_since = new DateTime($router->offline_since);
|
||||
$now = new DateTime($current_time);
|
||||
$interval = $offline_since->diff($now);
|
||||
$downtime = $interval->format('%h h, %i m, and %s s');
|
||||
|
||||
foreach ($users as $user) {
|
||||
$message = "Router {$router['name']} is now Online at $current_time. Fixed. Downtime: $downtime.";
|
||||
send_sms($user['phone'], $message);
|
||||
send_whatsapp($user['phone'], $message);
|
||||
}
|
||||
$router->offline_since = null; // Clear offline_since after coming online
|
||||
}
|
||||
}
|
||||
|
||||
// Update router status and last check time
|
||||
$router->status = $new_status;
|
||||
$router->last_check = $current_time;
|
||||
$router->save();
|
||||
}
|
||||
|
||||
// Get all active routers from database
|
||||
$routers = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
|
||||
|
||||
// Check status for each router
|
||||
foreach ($routers as $router) {
|
||||
check_and_update_router_status($router);
|
||||
}
|
||||
|
||||
echo "Router status check completed at " . date('Y-m-d H:i:s') . "\n";
|
||||
?>
|
||||
106
system/updates.json
Normal file
106
system/updates.json
Normal file
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"2023.8.9": [
|
||||
"ALTER TABLE `tbl_customers` ADD `balance` decimal(15,2) NOT NULL DEFAULT 0.00 COMMENT 'For Money Deposit' AFTER `email`;",
|
||||
"CREATE TABLE `tbl_customers_meta` (`id` int(11) NOT NULL, `customer_id` int(11) NOT NULL,`meta_key` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `meta_value` longtext COLLATE utf8mb4_general_ci) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;",
|
||||
"ALTER TABLE `tbl_customers_meta` ADD PRIMARY KEY (`id`);",
|
||||
"ALTER TABLE `tbl_customers_meta` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;"
|
||||
],
|
||||
"2023.8.14": [
|
||||
"ALTER TABLE `tbl_customers` ADD `pppoe_password` varchar(45) NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `password`;",
|
||||
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
|
||||
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
|
||||
"ALTER TABLE `tbl_customers` ADD `auto_renewal` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Auto renewall using balance' AFTER `balance`;"
|
||||
],
|
||||
"2023.8.23": [
|
||||
"ALTER TABLE `tbl_customers` CHANGE `pppoe_password` `pppoe_password` VARCHAR(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login';"
|
||||
],
|
||||
"2023.8.28": [
|
||||
"ALTER TABLE `tbl_user_recharges` ADD `recharged_time` time NOT NULL DEFAULT '00:00:00' AFTER `recharged_on`;",
|
||||
"ALTER TABLE `tbl_transactions` ADD `recharged_time` time NOT NULL DEFAULT '00:00:00' AFTER `recharged_on`;"
|
||||
],
|
||||
"2023.9.5": [
|
||||
"DROP TABLE `tbl_language`;",
|
||||
"ALTER TABLE `tbl_plans` ADD `pool_expired` varchar(40) NOT NULL DEFAULT '' AFTER `pool`;"
|
||||
],
|
||||
"2023.9.27": [
|
||||
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance','Radius') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
|
||||
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance','Radius') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;"
|
||||
],
|
||||
"2023.9.28": [
|
||||
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
|
||||
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;"
|
||||
],
|
||||
"2023.10.1": [
|
||||
"ALTER TABLE `tbl_plans` ADD `is_radius` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '1 is radius' AFTER `routers`; "
|
||||
],
|
||||
"2023.10.24": [
|
||||
"ALTER TABLE `nas` ADD `routers` VARCHAR(32) NOT NULL DEFAULT '' AFTER `description`;"
|
||||
],
|
||||
"2023.12.15": [
|
||||
"ALTER TABLE `tbl_customers` ADD `service_type` ENUM('Hotspot','PPPoE','Others') DEFAULT 'Others' COMMENT 'For selecting user type' AFTER `balance`;"
|
||||
],
|
||||
"2024.1.11": [
|
||||
"ALTER TABLE `tbl_plans` ADD `allow_purchase` ENUM('yes','no') DEFAULT 'yes' COMMENT 'allow to show package in buy package page' AFTER `enabled`;"
|
||||
],
|
||||
"2024.2.7": [
|
||||
"ALTER TABLE `tbl_voucher` ADD `generated_by` INT NOT NULL DEFAULT '0' COMMENT 'id admin' AFTER `status`;",
|
||||
"ALTER TABLE `tbl_users` ADD `root` INT NOT NULL DEFAULT '0' COMMENT 'for sub account' AFTER `id`;"
|
||||
],
|
||||
"2024.2.12": [
|
||||
"ALTER TABLE `tbl_users` CHANGE `user_type` `user_type` ENUM('SuperAdmin','Admin','Report','Agent','Sales') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;"
|
||||
],
|
||||
"2024.2.15": [
|
||||
"ALTER TABLE `tbl_users` CHANGE `password` `password` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
|
||||
"ALTER TABLE `tbl_users` ADD `phone` VARCHAR(32) NOT NULL DEFAULT '' AFTER `password`, ADD `email` VARCHAR(128) NOT NULL DEFAULT '' AFTER `phone`, ADD `city` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'kota' AFTER `email`, ADD `subdistrict` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'kecamatan' AFTER `city`, ADD `ward` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'kelurahan' AFTER `subdistrict`;"
|
||||
],
|
||||
"2024.2.16": [
|
||||
"ALTER TABLE `tbl_customers` ADD `created_by` INT NOT NULL DEFAULT '0' AFTER `auto_renewal`;"
|
||||
],
|
||||
"2024.2.19": [
|
||||
"CREATE TABLE `tbl_customers_fields` (`id` INT PRIMARY KEY AUTO_INCREMENT, `customer_id` INT NOT NULL, `field_name` VARCHAR(255) NOT NULL, `field_value` VARCHAR(255) NOT NULL, FOREIGN KEY (customer_id) REFERENCES tbl_customers(id));"
|
||||
],
|
||||
"2024.2.20" : [
|
||||
"ALTER TABLE `tbl_plans` ADD `list_expired` VARCHAR(32) NOT NULL DEFAULT '' COMMENT 'address list' AFTER `pool_expired`;",
|
||||
"ALTER TABLE `tbl_bandwidth` ADD `burst` VARCHAR(128) NOT NULL DEFAULT '' AFTER `rate_up_unit`;"
|
||||
],
|
||||
"2024.2.20.1" : [
|
||||
"DROP TABLE IF EXISTS `tbl_customers_meta`;"
|
||||
],
|
||||
"2024.2.23" : [
|
||||
"ALTER TABLE `tbl_transactions` ADD `admin_id` INT NOT NULL DEFAULT '1' AFTER `type`;",
|
||||
"ALTER TABLE `tbl_user_recharges` ADD `admin_id` INT NOT NULL DEFAULT '1' AFTER `type`;"
|
||||
],
|
||||
"2024.3.3" : [
|
||||
"ALTER TABLE `tbl_plans` CHANGE `validity_unit` `validity_unit` ENUM('Mins','Hrs','Days','Months','Period') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;"
|
||||
],
|
||||
"2024.3.12" : [
|
||||
"ALTER TABLE `tbl_plans` CHANGE `allow_purchase` `prepaid` ENUM('yes','no') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'yes' COMMENT 'is prepaid';"
|
||||
],
|
||||
"2024.3.14" : [
|
||||
"ALTER TABLE `tbl_transactions` ADD `note` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'for note' AFTER `type`;"
|
||||
],
|
||||
"2024.3.19" : [
|
||||
"ALTER TABLE `tbl_customers` ADD `coordinates` VARCHAR(50) NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates' AFTER `email`;"
|
||||
],
|
||||
"2024.3.19.1" : [
|
||||
"ALTER TABLE `tbl_customers` ADD `account_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type' AFTER `coordinates`;"
|
||||
],
|
||||
"2024.3.19.2" : [
|
||||
"ALTER TABLE `tbl_plans` ADD `plan_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type' ;"
|
||||
],
|
||||
"2023.3.20": [
|
||||
"ALTER TABLE `tbl_customers` CHANGE `pppoe_password` `pppoe_password` VARCHAR(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login';"
|
||||
],
|
||||
"2024.4.5" : [
|
||||
"ALTER TABLE `tbl_payment_gateway` ADD `trx_invoice` VARCHAR(25) NOT NULL DEFAULT '' COMMENT 'from tbl_transactions' AFTER `paid_date`;"
|
||||
],
|
||||
"2024.5.17" : [
|
||||
"ALTER TABLE `tbl_customers` ADD `status` ENUM('Active','Banned','Disabled') NOT NULL DEFAULT 'Active' AFTER `auto_renewal`;"
|
||||
],
|
||||
"2024.5.18" : [
|
||||
"ALTER TABLE `tbl_customers` CHANGE `status` `status` ENUM('Active','Banned','Disabled','Inactive','Limited','Suspended') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'Active';"
|
||||
],
|
||||
"2024.5.20" : [
|
||||
"ALTER TABLE `tbl_customers` ADD `city` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `address`, ADD `district` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `city`, ADD `state` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `district`, ADD `zip` VARCHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `state`;"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user