Compare commits

..

No commits in common. "master" and "2025.1.16" have entirely different histories.

289 changed files with 25790 additions and 13758 deletions

8
.gitignore vendored
View File

@ -53,10 +53,4 @@ docker-compose.yml
docs/**
!docs/*.html
!docs/*.md
.htaccess
.idea
!docs/insomnia.rest.json
!system/uploads/paid.png
system/uploads/invoices/**
!system/uploads/invoices/
!system/uploads/invoices/index.html
.htaccess

View File

@ -36,7 +36,7 @@ Most current web servers with PHP & MySQL installed will be capable of running P
Minimum Requirements
- Linux or Windows OS
- Minimum PHP Version 8.2
- Minimum PHP Version 7.4
- Both PDO & MySQLi Support
- PHP-GD2 Image Library
- PHP-CURL
@ -83,4 +83,28 @@ Contact me at [Telegram](https://t.me/ibnux)
GNU General Public License version 2 or later
see [LICENSE](LICENSE) file
see [LICENSE](LICENSE) file
## Donate to ibnux
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://paypal.me/ibnux)
BCA: 5410454825
Mandiri: 163-000-1855-793
a.n Ibnu Maksum
## SPONSORS
- [mixradius.com](https://mixradius.com/) Paid Services Billing Radius
- [mlink.id](https://mlink.id)
- [https://github.com/sonyinside](https://github.com/sonyinside)
## Thanks
We appreciate all people who are participating in this project.
<a href="https://github.com/hotspotbilling/phpnuxbill/graphs/contributors">
<img src="https://contrib.rocks/image?repo=hotspotbilling/phpnuxbill" />
</a>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -42,7 +42,7 @@ spl_autoload_register('_autoloader');
if (!file_exists($root_path . 'config.php')) {
$root_path .= '..' . DIRECTORY_SEPARATOR;
if (!file_exists($root_path . 'config.php')) {
r2('./install');
r2('install');
}
}
@ -56,7 +56,6 @@ $UPLOAD_PATH = $root_path . File::pathFixer('system/uploads');
$CACHE_PATH = $root_path . File::pathFixer('system/cache');
$PAGES_PATH = $root_path . File::pathFixer('pages');
$PLUGIN_PATH = $root_path . File::pathFixer('system/plugin');
$WIDGET_PATH = $root_path . File::pathFixer('system/widgets');
$PAYMENTGATEWAY_PATH = $root_path . File::pathFixer('system/paymentgateway');
$UI_PATH = 'ui';
@ -112,24 +111,6 @@ $result = ORM::for_table('tbl_appconfig')->find_many();
foreach ($result as $value) {
$config[$value['setting']] = $value['value'];
}
if(empty($config['dashboard_Admin'])){
$config['dashboard_Admin'] = "12.7,5.12";
}
if(empty($config['dashboard_Agent'])){
$config['dashboard_Agent'] = "12.7,5.12";
}
if(empty($config['dashboard_Sales'])){
$config['dashboard_Sales'] = "12.7,5.12";
}
if(empty($config['dashboard_Customer'])){
$config['dashboard_Customer'] = "6,6";
}
$_c = $config;
if (empty($http_proxy) && !empty($config['http_proxy'])) {
$http_proxy = $config['http_proxy'];
@ -215,7 +196,7 @@ function _auth($login = true)
return true;
} else {
if ($login) {
r2(getUrl('login'));
r2(U . 'login');
} else {
return false;
}
@ -228,7 +209,7 @@ function _admin($login = true)
return true;
} else {
if ($login) {
r2(getUrl('login'));
r2(U . 'login');
} else {
return false;
}
@ -280,13 +261,6 @@ function showResult($success, $message = '', $result = [], $meta = [])
die();
}
/**
* make url canonical or standar
*/
function getUrl($url)
{
return Text::url($url);
}
function generateUniqueNumericVouchers($totalVouchers, $length = 8)
{
@ -359,16 +333,16 @@ function _alert($text, $type = 'success', $url = "home", $time = 3)
if (!isset($ui)) return;
if (strlen($url) > 4) {
if (substr($url, 0, 4) != "http") {
$url = getUrl($url);
$url = U . $url;
}
} else {
$url = getUrl($url);
$url = U . $url;
}
$ui->assign('text', $text);
$ui->assign('type', $type);
$ui->assign('time', $time);
$ui->assign('url', $url);
$ui->display('admin/alert.tpl');
$ui->display('alert.tpl');
die();
}
@ -386,7 +360,7 @@ function displayMaintenanceMessage(): void
}
http_response_code(503);
$ui->assign('companyName', $config['CompanyName']);
$ui->display('admin/maintenance.tpl');
$ui->display('maintenance.tpl');
die();
}

View File

@ -1374,7 +1374,7 @@ pre {
color: #333;
word-break: break-all;
word-wrap: break-word;
background-color: #f6f8fa;
background-color: #f5f5f5;
border: 1px solid #ccc;
border-radius: 4px;
}
@ -2126,7 +2126,7 @@ th {
}
.table-hover > tbody > tr:hover > td,
.table-hover > tbody > tr:hover > th {
background-color: #f6f8fa;
background-color: #f5f5f5;
}
table col[class*="col-"] {
position: static;
@ -2151,7 +2151,7 @@ table th[class*="col-"] {
.table > thead > tr.active > th,
.table > tbody > tr.active > th,
.table > tfoot > tr.active > th {
background-color: #f6f8fa;
background-color: #f5f5f5;
}
.table-hover > tbody > tr > td.active:hover,
.table-hover > tbody > tr > th.active:hover,
@ -3170,7 +3170,7 @@ tbody.collapse.in {
.dropdown-menu > li > a:focus {
color: #262626;
text-decoration: none;
background-color: #f6f8fa;
background-color: #f5f5f5;
}
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
@ -4293,7 +4293,7 @@ fieldset[disabled] .navbar-inverse .btn-link:focus {
padding: 8px 15px;
margin-bottom: 20px;
list-style: none;
background-color: #f6f8fa;
background-color: #f5f5f5;
border-radius: 4px;
}
.breadcrumb > li {
@ -4711,7 +4711,7 @@ a.thumbnail.active {
height: 20px;
margin-bottom: 20px;
overflow: hidden;
background-color: #f6f8fa;
background-color: #f5f5f5;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
@ -4854,7 +4854,7 @@ a.list-group-item:hover,
a.list-group-item:focus {
color: #555;
text-decoration: none;
background-color: #f6f8fa;
background-color: #f5f5f5;
}
.list-group-item.disabled,
.list-group-item.disabled:hover,
@ -5023,7 +5023,7 @@ a.list-group-item-danger.active:focus {
}
.panel-footer {
padding: 10px 15px;
background-color: #f6f8fa;
background-color: #f5f5f5;
border-top: 1px solid #ddd;
border-bottom-right-radius: 3px;
border-bottom-left-radius: 3px;
@ -5197,7 +5197,7 @@ a.list-group-item-danger.active:focus {
}
.panel-default > .panel-heading {
color: #333;
background-color: #f6f8fa;
background-color: #f5f5f5;
border-color: #ddd;
}
.panel-default > .panel-heading + .panel-collapse > .panel-body {
@ -5329,7 +5329,7 @@ a.list-group-item-danger.active:focus {
min-height: 20px;
padding: 19px;
margin-bottom: 20px;
background-color: #f6f8fa;
background-color: #f5f5f5;
border: 1px solid #e3e3e3;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);

View File

@ -230,7 +230,6 @@ CREATE TABLE `rad_acct` (
`nasportid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`nasporttype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`framedipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`acctsessiontime` BIGINT NOT NULL DEFAULT '0',
`acctinputoctets` BIGINT NOT NULL DEFAULT '0',
`acctoutputoctets` BIGINT NOT NULL DEFAULT '0',
`acctstatustype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
@ -251,16 +250,6 @@ CREATE TABLE `tbl_customers_inbox` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
DROP TABLE IF EXISTS `tbl_port_pool`;
CREATE TABLE IF NOT EXISTS `tbl_port_pool` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`public_ip` varchar(40) NOT NULL,
`port_name` varchar(40) NOT NULL,
`range_port` varchar(40) NOT NULL,
`routers` varchar(40) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE IF NOT EXISTS `tbl_meta` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`tbl` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Table name',
@ -287,28 +276,6 @@ CREATE TABLE IF NOT EXISTS `tbl_coupons` (
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE IF NOT EXISTS `tbl_widgets` (
`id` int NOT NULL AUTO_INCREMENT,
`orders` int NOT NULL DEFAULT '99',
`position` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1. top 2. left 3. right 4. bottom',
`user` ENUM('Admin','Agent','Sales','Customer') NOT NULL DEFAULT 'Admin',
`enabled` tinyint(1) NOT NULL DEFAULT '1',
`title` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`widget` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`content` text COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE tbl_message_logs (
`id` SERIAL PRIMARY KEY,
`message_type` VARCHAR(50),
`recipient` VARCHAR(255),
`message_content` TEXT,
`status` VARCHAR(50),
`error_message` TEXT,
`sent_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
ALTER TABLE `rad_acct`
ADD PRIMARY KEY (`id`),
ADD KEY `username` (`username`),
@ -429,48 +396,3 @@ VALUES (
'2022-09-06 16:09:50',
'2014-06-23 01:43:07'
);
INSERT INTO `tbl_widgets` (`id`, `orders`, `position`, `user`, `enabled`, `title`, `widget`, `content`) VALUES
(1, 1, 1, 'Admin', 1, 'Top Widget', 'top_widget', ''),
(2, 2, 1, 'Admin', 1, 'Default Info', 'default_info_row', ''),
(3, 1, 2, 'Admin', 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''),
(4, 2, 2, 'Admin', 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''),
(5, 3, 2, 'Admin', 1, 'Voucher Stocks', 'voucher_stocks', ''),
(6, 4, 2, 'Admin', 1, 'Customer Expired', 'customer_expired', ''),
(7, 1, 3, 'Admin', 1, 'Cron Monitor', 'cron_monitor', ''),
(8, 2, 3, 'Admin', 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''),
(9, 3, 3, 'Admin', 1, 'Info Payment Gateway', 'info_payment_gateway', ''),
(10, 4, 3, 'Admin', 1, 'Graph Customers Insight', 'graph_customers_insight', ''),
(11, 5, 3, 'Admin', 1, 'Activity Log', 'activity_log', ''),
(30, 1, 1, 'Agent', 1, 'Top Widget', 'top_widget', ''),
(31, 2, 1, 'Agent', 1, 'Default Info', 'default_info_row', ''),
(32, 1, 2, 'Agent', 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''),
(33, 2, 2, 'Agent', 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''),
(34, 3, 2, 'Agent', 1, 'Voucher Stocks', 'voucher_stocks', ''),
(35, 4, 2, 'Agent', 1, 'Customer Expired', 'customer_expired', ''),
(36, 1, 3, 'Agent', 1, 'Cron Monitor', 'cron_monitor', ''),
(37, 2, 3, 'Agent', 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''),
(38, 3, 3, 'Agent', 1, 'Info Payment Gateway', 'info_payment_gateway', ''),
(39, 4, 3, 'Agent', 1, 'Graph Customers Insight', 'graph_customers_insight', ''),
(40, 5, 3, 'Agent', 1, 'Activity Log', 'activity_log', ''),
(41, 1, 1, 'Sales', 1, 'Top Widget', 'top_widget', ''),
(42, 2, 1, 'Sales', 1, 'Default Info', 'default_info_row', ''),
(43, 1, 2, 'Sales', 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''),
(44, 2, 2, 'Sales', 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''),
(45, 3, 2, 'Sales', 1, 'Voucher Stocks', 'voucher_stocks', ''),
(46, 4, 2, 'Sales', 1, 'Customer Expired', 'customer_expired', ''),
(47, 1, 3, 'Sales', 1, 'Cron Monitor', 'cron_monitor', ''),
(48, 2, 3, 'Sales', 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''),
(49, 3, 3, 'Sales', 1, 'Info Payment Gateway', 'info_payment_gateway', ''),
(50, 4, 3, 'Sales', 1, 'Graph Customers Insight', 'graph_customers_insight', ''),
(51, 5, 3, 'Sales', 1, 'Activity Log', 'activity_log', ''),
(60, 1, 2, 'Customer', 1, 'Account Info', 'account_info', ''),
(61, 3, 1, 'Customer', 1, 'Active Internet Plan', 'active_internet_plan', ''),
(62, 4, 1, 'Customer', 1, 'Balance Transfer', 'balance_transfer', ''),
(63, 1, 1, 'Customer', 1, 'Unpaid Order', 'unpaid_order', ''),
(64, 2, 1, 'Customer', 1, 'Announcement', 'announcement', ''),
(65, 5, 1, 'Customer', 1, 'Recharge A Friend', 'recharge_a_friend', ''),
(66, 2, 2, 'Customer', 1, 'Voucher Activation', 'voucher_activation', '');

View File

@ -1,643 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>yatmack</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/3.8.3/core.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link href='https://fonts.googleapis.com/css2?family=Lexend:wght@300;400;500;600;700&display=swap' rel='stylesheet'>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
navy: {
DEFAULT: '#023047',
50: '#e6f0f5',
100: '#cce1eb',
200: '#99c3d7',
300: '#66a5c3',
400: '#3387af',
500: '#023047',
600: '#022640',
700: '#011d39',
800: '#011332',
900: '#010a2b'
},
orange: {
DEFAULT: '#fb8500',
50: '#fff4e6',
100: '#ffe9cc',
200: '#ffd399',
300: '#ffbd66',
400: '#ffa733',
500: '#fb8500',
600: '#cc6d00',
700: '#995200',
800: '#663600',
900: '#331b00'
}
},
fontFamily: {
'lexend': ['Lexend', 'sans-serif'],
},
animation: {
'spin-fast': 'spin 0.5s linear infinite',
'fade-in': 'fadeIn 0.3s ease-in-out',
'slide-up': 'slideUp 0.3s ease-out'
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' }
},
slideUp: {
'0%': { transform: 'translateY(10px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' }
}
}
}
}
}
</script>
</head>
<body class="font-lexend min-h-screen bg-gradient-to-b from-navy to-navy/95 text-gray-100">
<div class="container mx-auto px-2 py-4 max-w-3xl">
<div class="bg-white/10 backdrop-blur-lg rounded-2xl shadow-xl mb-6 overflow-hidden border border-white/10">
<div class="p-3 relative">
<h1 class="text-2xl font-bold text-center text-orange mb-3">YATMACK HOTSPOT</h1>
<p class="text-gray-100/90 text-center text-sm mb-4">
Select package ? Enter M-Pesa number ? Complete payment
</p>
<div class="flex items-center justify-center gap-2 py-2 px-4 bg-white/5 rounded-xl">
<i class="fas fa-headset text-orange"></i>
<p class="text-sm font-medium">Support: 254705042522</p>
</div>
</div>
</div>
<div class="py-2 sm:py-1 lg:py-1">
<div class="mx-auto max-w-screen-2xl px-1 md:px-1">
<div class="mx-auto max-w-lg grid grid-cols-2 sm:grid-cols-2 md:grid-cols-3 gap-4 p-1" id="cards-container">
</div>
</div>
</div>
<button onclick="redeemVoucher()" class="w-full bg-orange hover:bg-orange/90 text-white font-medium py-4 px-6 rounded-xl shadow-lg transition duration-200 flex items-center justify-center gap-3 mb-6">
<i class="fas fa-ticket-alt"></i>
<span>Redeem Voucher</span>
</button>
<div class="bg-white/10 backdrop-blur-lg rounded-2xl shadow-xl overflow-hidden border border-white/10 mb-6">
<div class="p-6 space-y-8">
<!-- Reconnect with M-Pesa -->
<div class="space-y-4">
<h3 class="text-lg font-semibold text-orange">Reconnect with M-Pesa</h3>
<div class="flex flex-col sm:flex-row gap-3">
<input id="mpesaCodeInput" type="text" placeholder="Enter M-Pesa code (e.g., SCK15SKB4Z)" class="flex-grow px-4 py-3 bg-white/5 border border-white/10 rounded-xl focus:outline-none focus:ring-2 focus:ring-orange/50 text-white placeholder:text-gray-400">
<button id="reconnectBtn" class="bg-orange hover:bg-orange/90 text-white font-medium py-3 px-6 rounded-xl transition duration-200">Reconnect</button>
</div>
</div>
<div class="space-y-4">
<h3 class="text-lg font-semibold text-orange">Active Package Login</h3>
<form id="loginForm" action="$(link-login-only)" method="post" $(if chap-id)onSubmit="return doLogin()" $(endif)>
<input type="hidden" name="dst" value="$(link-orig)">
<input type="hidden" name="popup" value="true">
<input type="hidden" name="mac" id="mac" value="$(mac)">
<div class="flex flex-col sm:flex-row gap-3">
<input id="usernameInput" name="username" type="text" placeholder="Enter Username (e.g., ACC123456)" class="flex-grow px-4 py-3 bg-white/5 border border-white/10 rounded-xl focus:outline-none focus:ring-2 focus:ring-orange/50 text-white placeholder:text-gray-400">
<button id="submitBtn" type="button" onclick="submitLogin()" class="bg-orange hover:bg-orange/90 text-white font-medium py-3 px-6 rounded-xl transition duration-200">Connect</button>
</div>
<input type="hidden" name="password" value="1234">
</form>
</div>
</div>
</div>
<div class="text-center">
<p class="text-sm text-gray-400">&copy; 2025 yatmack. Created by Smartisp</p>
</div>
</div>
<script>
function fetchData() {
var domain = 'https://yatmack2.smartisp.co.ke/';
var siteUrl = domain + "/index.php?_route=plugin/hotspot_plan";
var routerName = encodeURIComponent("yatmack");
var dataparams = `routername=${routerName}`;
fetch(siteUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: dataparams
})
.then(response => {
if (!response.ok) {
throw new Error(`Error ${response.status}: ${response.statusText}`);
}
return response.json();
})
.then(data => {
populateCards(data);
})
.catch(error => {
console.error('Fetch error:', error);
});
}
function populateCards(data) {
var cardsContainer = document.getElementById('cards-container');
cardsContainer.innerHTML = ''; // Clear existing content
// Sort the plans by price in ascending order
data.data.forEach(router => {
// Sort hotspot plans by price
router.plans_hotspot.sort((a, b) => parseFloat(a.price) - parseFloat(b.price));
router.plans_hotspot.forEach(item => {
var cardDiv = document.createElement('div');
cardDiv.className = 'bg-white border border-black rounded-lg shadow-md overflow-hidden transition duration-300 hover:shadow-lg flex flex-col items-center justify-between mx-auto mb-4 w-40';
cardDiv.innerHTML = `
<div class="bg-blue-500 text-white w-full py-1">
<h2 class="text-sm font-medium uppercase text-center" style="font-size: clamp(0.75rem, 1.5vw, 1rem); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
${item.planname}
</h2>
</div>
<div class="px-4 py-2 flex-grow">
<p class="text-2xl font-bold text-blue-600 mb-1">
<span class="text-lg font-medium text-black">${item.currency}</span>
${item.price}
</p>
<p class="text-sm text-black mb-2">
Valid for ${item.validity} ${item.timelimit}
</p>
<hr class="border-black mb-2">
</div>
<div class="px-4 py-2 flex-shrink-0">
<a href="#" class="inline-block bg-gray-900 text-white hover:bg-blue-600 font-semibold py-1 px-4 rounded-lg transition duration-300 text-md"
onclick="handlePhoneNumberSubmission('${item.planId}', '${item.routerId}'); return false;"
data-plan-id="${item.planId}"
data-router-id="${item.routerId}">
Buy
</a>
</div>
`;
cardsContainer.appendChild(cardDiv);
});
});
}
fetchData();
function getMacAddress() {
return "$(mac)"; // MikroTik replaces this with the user's MAC address
}
function getOrCreateAccountId() {
var radiaxid = localStorage.getItem('radiaxid');
if (!radiaxid) {
radiaxid = getMacAddress();
localStorage.setItem('radiaxid', radiaxid);
setCookie('radiaxid', radiaxid, 365);
}
return radiaxid;
}
function getAccountId() {
return localStorage.getItem('radiaxid') || getCookie('radiaxid') || getMacAddress();
}
function formatPhoneNumber(phoneNumber) {
if (phoneNumber.startsWith('+')) {
phoneNumber = phoneNumber.substring(1);
}
if (phoneNumber.startsWith('0')) {
phoneNumber = '254' + phoneNumber.substring(1);
}
if (phoneNumber.match(/^(7|1)/)) {
phoneNumber = '254' + phoneNumber;
}
return phoneNumber;
}
function setCookie(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
var loginTimeout;
function handlePhoneNumberSubmission(planId, routerId, price) {
var accountId = getOrCreateAccountId();
var modalHtml = `
<div id="paymentModal" class='fixed inset-0 bg-black/30 backdrop-blur-sm z-50 animate-fade-in'>
<div class="fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-md">
<div class="bg-white text-black rounded-lg shadow-xl">
<div class="flex items-center justify-between p-4 border-b border-gray-300">
<h5 class="text-xl font-semibold">
Enter Your Mpesa Number
</h5>
<button class="text-gray-500 hover:text-black" onclick="closeModal('paymentModal')">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="p-4">
<div class="bg-navy-50 border-l-4 border-navy-400 p-4 rounded-md mb-4"> <div class="flex"> <div class="flex-shrink-0"> <svg class="h-5 w-5 text-navy-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1 4v.01m6.938-2.162A9 9 0 1111 3v0a9 9 0 018.938 10.838z" /> </svg> </div> <div class="ml-3"> <p class="text-sm text-navy-700"> You are about to initiate M-pesa payment. Enter phone number below and click Pay Now to initialize payment. </p> </div> </div></div> <input type="text" class="w-full px-4 py-3 border border-orange-300 rounded-lg focus:ring-2 focus:ring-navy-400 focus:border-blue-500 text-black" id="phoneNumberInput" required placeholder="e.g. 0712345678">
<div class="text-red-500 mt-1 hidden" id="invalidPhone">Please enter a valid phone number!</div>
</div>
<div class="flex justify-end space-x-2 p-4 border-t border-gray-300">
<button onclick="closeModal('paymentModal')" class="px-4 py-2 bg-orange text-black rounded-lg hover:bg-gray-300">Close</button>
<button id="payNowBtn" class="px-4 py-2 bg-navy text-white font-semibold hover:from-blue-600 hover:to-blue-500 flex items-center rounded-lg">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 9V7a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2m2 4h10a2 2 0 002-2v-6a2 2 0 00-2-2H9a2 2 0 00-2 2v6a2 2 0 002 2zm7-5a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
Pay Now
</button>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', modalHtml);
var modal = document.getElementById('paymentModal');
modal.classList.remove('hidden');
var payNowBtn = document.getElementById('payNowBtn');
var phoneInput = document.getElementById('phoneNumberInput');
phoneInput.focus();
payNowBtn.addEventListener('click', function() { handlePayment(); });
function handlePayment() {
if (!phoneInput.value) {
document.getElementById('invalidPhone').classList.remove('hidden');
return;
}
payNowBtn.disabled = true;
payNowBtn.innerHTML = `
<svg class='animate-spin -ml-1 mr-3 h-5 w-5 text-white' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'>
<circle class='opacity-25' cx='12' cy='12' r='10' stroke='currentColor' stroke-width='4'></circle>
<path class='opacity-75' fill='currentColor' d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z'></path>
</svg>
Processing...
`;
var formattedPhoneNumber = formatPhoneNumber(phoneInput.value);
document.getElementById('usernameInput').value = accountId;
fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/CreateHotspotuser&type=grant', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
phone_number: formattedPhoneNumber,
plan_id: planId,
router_id: routerId,
account_id: accountId
})
})
.then(response => response.json())
.then(data => {
if (data.status === 'error') throw new Error(data.message);
closeModal('paymentModal');
showProcessingModal();
checkPaymentStatus(formattedPhoneNumber);
})
.catch(error => {
closeModal('paymentModal');
showErrorModal(error.message);
});
}
}
function showProcessingModal() {
var processingModalHtml = `
<div id='processingModal' class='fixed inset-0 bg-black/30 backdrop-blur-sm z-50 animate-fade-in'>
<div class='fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-md animate-slide-up'>
<div class='bg-gradient-to-br from-white to-gray-50 shadow-2xl rounded-2xl p-8 text-center border border-gray-100'>
<div class='flex justify-center'>
<svg class='animate-spin h-20 w-20 text-navy-500' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'>
<circle class='opacity-25' cx='12' cy='12' r='10' stroke='currentColor' stroke-width='4'></circle>
<path class='opacity-75' fill='currentColor' d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z'></path>
</svg>
</div>
<div class="mt-6 bg-navy-50/50 backdrop-blur-xs border border-navy-200 rounded-xl p-6 shadow-lg"> <div class="flex items-center space-x-4"> <svg class="h-8 w-8 text-navy-400 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1 4v.01m6.938-2.162A9 9 0 1111 3v0a9 9 0 018.938 10.838z" /> </svg> <div class="flex-1"> <h2 class="text-xl font-semibold text-navy-600 font-lexend">Initializing Payment</h2> <p class="text-navy-500 mt-2">A payment request has been sent to your phone. Please wait while we process your payment.</p> </div> </div> <div class="mt-4 h-2 w-full bg-navy-100 rounded-full overflow-hidden"> <div class="h-2 bg-navy-400 rounded-full animate-pulse"></div> </div> </div> </div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', processingModalHtml);
}
function closeModal(modalId) {
var modal = document.getElementById(modalId);
if (modal) {
modal.classList.add('hidden');
setTimeout(function() { modal.remove(); }, 300);
}
}
function showSuccessModal() {
var successModalHtml = `
<div id='successModal' class='fixed inset-0 bg-black/60 backdrop-blur-sm z-50 transition-all duration-300'>
<div class='fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-lg transition-all duration-300 ease-out'>
<div class='bg-white/95 backdrop-blur-md shadow-2xl rounded-3xl p-8 text-center border border-gray-200/50 ring-1 ring-gray-900/5'>
<div class='flex justify-center mb-6'>
<div class='relative'>
<div class='absolute inset-0 rounded-full bg-green-500/20 animate-pulse'></div>
<svg class='h-16 w-16 text-green-500' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z'/>
</svg>
</div>
</div>
<div class='space-y-4'>
<h2 class='text-2xl font-semibold text-gray-900'>Payment Successful</h2>
<div class='bg-green-50 rounded-2xl p-6 border border-green-100'>
<div class='flex items-center gap-4'>
<svg class='h-6 w-6 text-green-500 flex-shrink-0' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 12l2 2 4-4'/>
</svg>
<p class='text-sm text-green-700'>Your transaction has been completed successfully. You will be redirected shortly.</p>
</div>
</div>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', successModalHtml);
setTimeout(function() { closeModal('successModal'); }, 2000);
}
function showErrorModal(errorMsg) {
var errorModalHtml = `
<div id='errorModal' class='fixed inset-0 bg-black/60 backdrop-blur-sm z-50 transition-all duration-300'>
<div class='fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-lg transition-all duration-300 ease-out'>
<div class='bg-white/95 backdrop-blur-md shadow-2xl rounded-3xl p-8 text-center border border-gray-200/50 ring-1 ring-gray-900/5'>
<div class='flex justify-center mb-6'>
<div class='relative'>
<div class='absolute inset-0 rounded-full bg-red-500/20 animate-pulse'></div>
<svg class='h-16 w-16 text-red-500' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 18L18 6M6 6l12 12'/>
</svg>
</div>
</div>
<div class='space-y-4'>
<h2 class='text-2xl font-semibold text-gray-900'>Payment Failed</h2>
<div class='bg-red-50 rounded-2xl p-6 border border-red-100'>
<div class='flex items-center gap-4'>
<svg class='h-6 w-6 text-red-500 flex-shrink-0' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z'/>
</svg>
<p class='text-sm text-red-700'>An error occurred while processing your payment. Please try again.</p>
</div>
</div>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', errorModalHtml);
setTimeout(function() { closeModal('errorModal'); }, 2000);
}
function checkPaymentStatus(phoneNumber) {
var accountId = getOrCreateAccountId();
var checkInterval = setInterval(function() {
fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/CreateHotspotuser&type=verify', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({account_id: accountId})
})
.then(function(response) { return response.json(); })
.then(function(data) {
console.log('Raw Response:', data);
if (data.Resultcode === '3') {
clearInterval(checkInterval);
closeModal('processingModal');
showSuccessModal();
if (loginTimeout) clearTimeout(loginTimeout);
loginTimeout = setTimeout(function() { document.getElementById('loginForm').submit(); }, 2000);
} else if (data.Resultcode === '2') {
clearInterval(checkInterval);
closeModal('processingModal');
showErrorModal(data.Message);
} else {
console.error('Unexpected result code:', data.Resultcode);
}
})
.catch(function(error) {
console.error('Error during fetch request:', error);
clearInterval(checkInterval);
closeModal('processingModal');
showErrorModal('An error occurred while checking payment status.');
});
}, 1000);
setTimeout(function() {
clearInterval(checkInterval);
closeModal('processingModal');
showErrorModal('Timeout while waiting for payment confirmation.');
}, 300000); // 5 minutes
}
document.addEventListener('DOMContentLoaded', function() {
var accountId = getOrCreateAccountId();
var usernameInput = document.getElementById('usernameInput');
if (usernameInput && !usernameInput.value) {
usernameInput.value = accountId;
}
var submitBtn = document.getElementById('submitBtn');
if (submitBtn) {
submitBtn.addEventListener('click', function() {
document.getElementById('loginForm').submit();
});
}
});
var loginTimeout; // Variable to store the timeout ID
function redeemVoucher() {
Swal.fire({
title: 'Redeem Voucher',
input: 'text',
inputPlaceholder: 'Enter voucher code',
inputValidator: function(value) {
if (!value) {
return 'You need to enter a voucher code!';
}
},
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Redeem',
showLoaderOnConfirm: true,
preConfirm: (voucherCode) => {
var accountId = voucherCode;
return fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/CreateHotspotuser&type=voucher', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({voucher_code: voucherCode, account_id: accountId}),
})
.then(response => {
if (!response.ok) throw new Error('Network response was not ok');
return response.json();
})
.then(data => {
if (data.status === 'error') throw new Error(data.message);
return data;
});
},
allowOutsideClick: () => !Swal.isLoading()
}).then((result) => {
if (result.isConfirmed) {
Swal.fire({
icon: 'success',
title: 'Voucher Redeemed',
text: result.value.message,
showConfirmButton: false,
allowOutsideClick: false,
didOpen: () => {
Swal.showLoading();
var username = result.value.username;
console.log('Received username from server:', username);
var usernameInput = document.querySelector('input[name="username"]');
if (usernameInput) {
console.log('Found username input element.');
usernameInput.value = username;
loginTimeout = setTimeout(function() {
var loginForm = document.getElementById('loginForm');
if (loginForm) {
loginForm.submit();
} else {
console.error('Login form not found.');
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Login form not found. Please try again.',
});
}
}, 2000);
} else {
console.error('Username input element not found.');
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Username input not found. Please try again.',
});
}
}
});
}
}).catch(error => {
Swal.fire({
icon: 'error',
title: 'Oops...',
text: error.message,
});
});
}
document.addEventListener('DOMContentLoaded', function() {
var reconnectBtn = document.getElementById('reconnectBtn');
var mpesaCodeInput = document.getElementById('mpesaCodeInput');
var macInput = document.getElementById('mac');
var loginForm = document.getElementById('loginForm');
if (reconnectBtn) {
reconnectBtn.addEventListener('click', function() {
// Validate inputs before processing
if (!mpesaCodeInput || !macInput || !loginForm) {
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Required form elements are missing'
});
return;
}
var mpesaCode = mpesaCodeInput.value.trim().split(' ')[0];
var mac = macInput.value.trim();
fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/ReconnectUser', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ mpesa_code: mpesaCode, mac: mac }),
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
console.log('Response data:', data);
var resultCode = data.Resultcode;
var message = data.Message;
var status = data.Status;
var username = data.username;
if (resultCode === '1') {
Swal.fire({
icon: 'error',
title: 'Invalid Code',
text: message
});
}
else if (resultCode === '3') {
Swal.fire({
icon: 'error',
title: 'Expired Package',
text: message
});
}
else if (resultCode === '2') {
Swal.fire({
icon: 'success',
title: status,
text: message,
showConfirmButton: false,
allowOutsideClick: false,
didOpen: () => {
Swal.showLoading();
console.log('Received username from server:', username);
var usernameInput = document.querySelector('input[name="username"]');
if (usernameInput) {
console.log('Found username input element.');
usernameInput.value = username;
setTimeout(function() {
var loginForm = document.getElementById('loginForm');
if (loginForm) {
loginForm.submit();
} else {
console.error('Login form not found.');
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Login form not found. Please try again.',
});
}
}, 2000);
} else {
console.error('Username input element not found.');
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Username input not found. Please try again.',
});
}
}
});
}
})
.catch(error => {
Swal.fire({
icon: 'error',
title: 'Oops...',
text: error.message
});
});
});
} else {
console.error('Reconnect button not found');
}
});
</script>
</html>

View File

@ -207,7 +207,7 @@ try {
if (!$tur) {
// if check if pppoe_username
$c = ORM::for_table('tbl_customers')->select('username')->select('pppoe_password')->whereRaw("BINARY pppoe_username = '$username'")->find_one();
if ($c) {
if($c){
$username = $c['username'];
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->find_one();
}
@ -274,7 +274,7 @@ try {
}
header("HTTP/1.1 200 ok");
$d = ORM::for_table('rad_acct')
->whereRaw("BINARY username = '$username' AND macaddr = '" . _post('macAddr') . "' AND nasid = '" . _post('nasid') . "'")
->whereRaw("BINARY username = '$username' AND macaddr = '"._post('macAddr')."' AND nasid = '"._post('nasid')."'")
->findOne();
if (!$d) {
$d = ORM::for_table('rad_acct')->create();
@ -291,28 +291,19 @@ try {
$d->acctsessionid = _post('acctSessionId');
$d->username = $username;
$d->realm = _post('realm');
$d->nasipaddress = _post('nasIpAddress');
$d->acctsessiontime = intval(_post('acctSessionTime'));
$d->nasipaddress = _post('nasip');
$d->nasid = _post('nasid');
$d->nasportid = _post('nasPortId');
$d->nasporttype = _post('nasPortType');
$d->framedipaddress = _post('framedIPAddress');
if (in_array(_post('acctStatusType'), ['Start', 'Stop'])) {
if(in_array(_post('acctStatusType'), ['Start', 'Stop'])){
$d->acctstatustype = _post('acctStatusType');
}
$d->macaddr = _post('macAddr');
$d->dateAdded = date('Y-m-d H:i:s');
// pastikan data akunting yang disimpan memang customer aktif phpnuxbill
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username' AND `status` = 'on' AND `routers` = 'radius'")->find_one();
if (!$tur) {
// check if pppoe_username
$c = ORM::for_table('tbl_customers')->select('username')->whereRaw("BINARY pppoe_username = '$username'")->find_one();
if ($c) {
$username = $c['username'];
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->find_one();
}
}
if ($tur) {
if($tur){
$d->save();
if (_post('acctStatusType') == 'Start') {
$plan = ORM::for_table('tbl_plans')->where('id', $tur['plan_id'])->find_one();
@ -357,15 +348,15 @@ function process_radiust_rest($tur, $code)
$plan = ORM::for_table('tbl_plans')->where('id', $tur['plan_id'])->find_one();
$bw = ORM::for_table("tbl_bandwidth")->find_one($plan['id_bw']);
// Count User Onlines
$USRon = ORM::for_table('rad_acct')
->whereRaw("BINARY username = '" . $tur['username'] . "' AND acctStatusType = 'Start'")
$USRon = ORM::for_table('rad_acct')
->whereRaw("BINARY username = '".$tur['username']."' AND acctStatusType = 'Start'")
->find_array();
// get all the IP
$ips = array_column($USRon, 'framedipaddress');
// check if user reach shared_users limit but IP is not in the list active
if (count($USRon) >= $plan['shared_users'] && $plan['type'] == 'Hotspot' && !in_array(_post('framedIPAddress'), $ips)) {
show_radius_result(["control:Auth-Type" => "Accept", 'Reply-Message' => 'You are already logged in - access denied (' . $USRon . ')'], 401);
}
if (count($USRon) >= $plan['shared_users'] && $plan['type'] == 'Hotspot' && !in_array(_post('framedIPAddress'), $ips)) {
show_radius_result(["control:Auth-Type" => "Accept", 'Reply-Message' => 'You are already logged in - access denied ('.$USRon.')'], 401);
}
if ($bw['rate_down_unit'] == 'Kbps') {
$unitdown = 'K';
} else {
@ -461,4 +452,4 @@ function show_radius_result($array, $code = 200)
die();
}
die(json_encode($array));
}
}

View File

@ -4,66 +4,25 @@
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>QR Code Scanner</title>
<title>QRCode Scanner</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f2f2f2;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
#container {
background-color: #ffffff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
text-align: center;
}
#qr-reader {
width: 100%;
height: auto;
margin-bottom: 20px;
}
#qr-reader-results {
padding: 10px;
background-color: #f8f8f8;
border: 1px solid #ddd;
border-radius: 5px;
}
button {
margin-top: 30px;
margin-bottom: 30px;
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<div id="container">
<h2>QR Code Scanner</h2>
<div id="qr-reader"></div>
<div id="qr-reader-results"></div>
<button id="camera-button">Open Camera</button>
</div>
<div id="qr-reader" style="width:100%; height:auto"></div>
<div id="qr-reader-results"></div>
<script src="qrcode.min.js"></script>
<script>
function docReady(fn) {
// lihat apakah DOM sudah tersedia
// see if DOM is already available
if (document.readyState === "complete" ||
document.readyState === "interactive") {
// panggil di detik berikutnya yang tersedia
// call on next available tick
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
@ -92,9 +51,6 @@
docReady(function() {
var resultContainer = document.getElementById('qr-reader-results');
var lastResult, countResults = 0;
var html5QrcodeScanner;
var isCameraOpen = false;
function onScanSuccess(decodedText, decodedResult) {
if (decodedText !== lastResult) {
++countResults;
@ -111,26 +67,14 @@
}
}
function toggleCamera() {
if (isCameraOpen) {
html5QrcodeScanner.clear();
document.getElementById('camera-button').textContent = "Open Camera";
isCameraOpen = false;
} else {
html5QrcodeScanner = new Html5QrcodeScanner(
"qr-reader", {
fps: 10,
qrbox: 250
});
html5QrcodeScanner.render(onScanSuccess);
document.getElementById('camera-button').textContent = "Close Camera";
isCameraOpen = true;
}
}
document.getElementById('camera-button').addEventListener('click', toggleCamera);
var html5QrcodeScanner = new Html5QrcodeScanner(
"qr-reader", {
fps: 10,
qrbox: 250
});
html5QrcodeScanner.render(onScanSuccess);
});
</script>
</body>
</html>
</html>

View File

@ -48,28 +48,7 @@ $ui = new class($key)
}
function getAll()
{
$result = [];
foreach ($this->assign as $key => $value) {
if($value instanceof ORM){
$result[$key] = $value->as_array();
}else if($value instanceof IdiormResultSet){
$count = count($value);
for($n=0;$n<$count;$n++){
foreach ($value[$n] as $k=>$v) {
$result[$key][$n][$k] = $v;
}
}
}else{
$result[$key] = $value;
}
}
return $result;
}
function fetch()
{
return "";
return $this->assign;
}
};

View File

@ -22,8 +22,8 @@ class Csrf
public static function check($token)
{
global $config, $isApi;
if($config['csrf_enabled'] == 'yes' && !$isApi) {
global $config;
if($config['csrf_enabled'] == 'yes') {
if (isset($_SESSION['csrf_token'], $_SESSION['csrf_token_time'], $token)) {
$storedToken = $_SESSION['csrf_token'];
$tokenTime = $_SESSION['csrf_token_time'];

View File

@ -87,7 +87,7 @@ class File
$src_img = $image_create($source_file);
imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $nwidth, $nheight, $width, $height);
imagepng($dst_img, $dst_dir);
$image($dst_img, $dst_dir, $quality);
if ($dst_img) imagedestroy($dst_img);
if ($src_img) imagedestroy($src_img);

View File

@ -14,14 +14,14 @@
class Http
{
public static function getData($url, $headers = [], $connect_timeout = 3000, $wait_timeout = 3000)
public static function getData($url, $headers = [])
{
global $http_proxy, $http_proxyauth, $admin;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $wait_timeout);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 100);
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
if (is_array($headers) && count($headers) > 0) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
@ -49,15 +49,15 @@ class Http
return (!empty($server_output)) ? $server_output : $error_msg;
}
public static function postJsonData($url, $array_post, $headers = [], $basic = null, $connect_timeout = 3000, $wait_timeout = 3000)
public static function postJsonData($url, $array_post, $headers = [], $basic = null)
{
global $http_proxy, $http_proxyauth, $admin;
$headers[] = 'Content-Type: application/json';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $wait_timeout);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 100);
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLINFO_HEADER_OUT, false);
if (!empty($http_proxy)) {
@ -92,15 +92,15 @@ class Http
}
public static function postData($url, $array_post, $headers = [], $basic = null, $connect_timeout = 3000, $wait_timeout = 3000)
public static function postData($url, $array_post, $headers = [], $basic = null)
{
global $http_proxy, $http_proxyauth, $admin;
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $wait_timeout);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 100);
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLINFO_HEADER_OUT, false);
if (!empty($http_proxy)) {

View File

@ -1,347 +0,0 @@
<?php
use Mpdf\Mpdf;
class Invoice
{
public static function generateInvoice($invoiceData)
{
try {
if (empty($invoiceData['invoice'])) {
throw new Exception(Lang::T("Invoice No is required"));
}
$template = Lang::getNotifText('email_invoice');
if (!$template) {
throw new Exception(Lang::T("Invoice template not found"));
}
if (strpos($template, '<body') === false) {
$template = "<html><body>$template</body></html>";
}
$processedHtml = self::renderTemplate($template, $invoiceData);
// Debugging: Save processed HTML to file for review
// file_put_contents('debug_invoice.html', $processedHtml);
// Generate PDF
$mpdf = new Mpdf([
'mode' => 'utf-8',
'format' => 'A4',
'margin_left' => 10,
'margin_right' => 10,
'margin_top' => 10,
'margin_bottom' => 10,
'default_font' => 'helvetica',
'orientation' => 'P',
]);
$mpdf->SetDisplayMode('fullpage');
$mpdf->SetProtection(['print']);
$mpdf->shrink_tables_to_fit = 1;
$mpdf->SetWatermarkText(strtoupper($invoiceData['status'] ?? 'UNPAID'), 0.15);
$mpdf->showWatermarkText = true;
$mpdf->WriteHTML($processedHtml);
// Save PDF
$filename = "invoice_{$invoiceData['invoice']}.pdf";
$outputPath = "system/uploads/invoices/{$filename}";
$dir = dirname($outputPath);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
$mpdf->Output($outputPath, 'F');
if (!file_exists($outputPath)) {
throw new Exception(Lang::T("Failed to save PDF file"));
}
return $filename;
} catch (\Exception $e) {
_log("Invoice generation failed: " . $e->getMessage());
sendTelegram("Invoice generation failed: " . $e->getMessage());
return false;
}
}
private static function renderTemplate($template, $invoiceData)
{
return preg_replace_callback('/\[\[(\w+)\]\]/', function ($matches) use ($invoiceData) {
$key = $matches[1];
if (!isset($invoiceData[$key])) {
_log(Lang::T("Missing invoice key: ") . $key);
return '';
}
if (in_array($key, ['created_at', 'due_date'])) {
return date('F j, Y', strtotime($invoiceData[$key]));
}
if (in_array($key, ['amount', 'total', 'subtotal', 'tax'])) {
return $invoiceData['currency_code'] . number_format((float) $invoiceData[$key], 2);
}
if ($key === 'bill_rows') {
return $invoiceData[$key];
}
return htmlspecialchars($invoiceData[$key] ?? '');
}, $template);
}
/**
* Send invoice to user
*
* @param int $userId
* @param array $invoice
* @param array $bills
* @param string $status
* @param string $invoiceNo
* @return bool
*/
public static function sendInvoice($userId, $invoice = null, $bills = [], $status = "Unpaid", $invoiceNo = null)
{
global $config, $root_path, $UPLOAD_PATH;
// Set default currency code
$config['currency_code'] ??= '$';
$account = ORM::for_table('tbl_customers')->find_one($userId);
self::validateAccount($account);
if (!$invoiceNo) {
$invoiceNo = "INV-" . Package::_raid();
}
// Fetch invoice if not provided
if ($status === "Unpaid" && !$invoice) {
$data = ORM::for_table('tbl_user_recharges')->where('customer_id', $userId)
->where('status', 'off')
->left_outer_join('tbl_plans', 'tbl_user_recharges.namebp = tbl_plans.name_plan')
->select('tbl_plans.price', 'price')
->select('tbl_plans.name_plan', 'namebp')
->find_one();
if (!$data) {
$data = ORM::for_table('tbl_user_recharges')->where('username', $account->username)
->left_outer_join('tbl_plans', 'tbl_user_recharges.namebp = tbl_plans.name_plan')
->select('tbl_plans.price', 'price')
->select('tbl_plans.name_plan', 'namebp')
->where('status', 'off')
->find_one();
}
if (!$data) {
throw new Exception(Lang::T("No unpaid invoice found for username:") . $account->username);
}
$invoice = [
'price' => $data->price,
'plan_name' => $data->namebp,
'routers' => $data->routers,
];
} else if ($status === "Paid" && !$invoice) {
$invoice = ORM::for_table("tbl_transactions")->where("username", $account->username)->find_one();
}
if (!$invoice) {
throw new Exception(Lang::T("Transaction not found for username: ") . $account->username);
}
// Get additional bills if not provided
if (empty($bills)) {
[$bills, $add_cost] = User::getBills($account->id);
}
$invoiceItems = self::generateInvoiceItems($invoice, $bills, $add_cost);
$subtotal = array_sum(array_column($invoiceItems, 'amount'));
$tax = $config['enable_tax'] ? Package::tax($subtotal) : 0;
$tax_rate = $config['tax_rate'] ?? 0;
$total = $subtotal + $tax;
$payLink = self::generatePaymentLink($account, $invoice, $status);
$logo = self::getCompanyLogo($UPLOAD_PATH, $root_path);
$invoiceData = [
'invoice' => $invoiceNo,
'fullname' => $account->fullname,
'email' => $account->email,
'address' => $account->address,
'phone' => $account->phonenumber,
'bill_rows' => self::generateBillRows($invoiceItems, $config['currency_code'], $subtotal, $tax_rate, $tax, $total),
'status' => $status,
'created_at' => date('Y-m-d H:i:s'),
'due_date' => date('Y-m-d H:i:s', strtotime('+7 days')),
'currency' => $config['currency_code'],
'company_address' => $config['address'],
'company_name' => $config['CompanyName'],
'company_phone' => $config['phone'],
'logo' => $logo,
'payment_link' => $payLink
];
if (empty($invoiceData['bill_rows'])) {
throw new Exception(Lang::T("Bill rows data is empty."));
}
$filename = self::generateInvoice($invoiceData);
if (!$filename) {
throw new Exception(Lang::T("Failed to generate invoice PDF"));
}
$pdfPath = "system/uploads/invoices/{$filename}";
self::saveToDatabase($filename, $account->id, $invoiceData, $total);
try {
Message::sendEmail(
$account->email,
Lang::T("Invoice for Account {$account->fullname}"),
Lang::T("Please find your invoice attached"),
$pdfPath
);
return true;
} catch (\Exception $e) {
throw new Exception(Lang::T("Failed to send email invoice to ") . $account->email . ". " . Lang::T("Reason: ") . $e->getMessage());
}
}
private static function validateAccount($account)
{
if (!$account) {
throw new Exception(Lang::T("User not found"));
}
if (!$account->email || !filter_var($account->email, FILTER_VALIDATE_EMAIL)) {
throw new Exception(Lang::T("Invalid user email"));
}
}
private static function generateInvoiceItems($invoice, $bills, $add_cost)
{
$items = [
[
'description' => $invoice['plan_name'],
'details' => Lang::T('Subscription'),
'amount' => (float) $invoice['price']
]
];
if ($invoice->routers != 'balance') {
foreach ($bills as $description => $amount) {
if (is_numeric($amount)) {
$items[] = [
'description' => $description,
'details' => Lang::T('Additional Bill'),
'amount' => (float) $amount
];
} else {
_log(Lang::T("Invalid bill amount for {$description}: {$amount}"));
}
}
}
return $items;
}
private static function generatePaymentLink($account, $invoice, $status)
{
$token = User::generateToken($account->id, 1);
if (empty($token['token'])) {
return '?_route=home';
}
$tur = ORM::for_table('tbl_user_recharges')
->where('customer_id', $account->id)
->where('namebp', $invoice->plan_name);
$tur->where('status', $status === 'Paid' ? 'on' : 'off');
$turResult = $tur->find_one();
return $turResult ? '?_route=home&recharge=' . $turResult['id'] . '&uid=' . urlencode($token['token']) : '?_route=home';
}
private static function getCompanyLogo($UPLOAD_PATH, $root_path)
{
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
return file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png') ?
$UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png?' . time() :
$UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.default.png';
}
private static function generateBillRows($items, $currency, $subtotal, $tax_rate, $tax, $total)
{
$html = "<table style='width: 100%; border-collapse: collapse; margin: 20px 0;'>
<thead>
<tr>
<th style='background: #3498db; color: white; padding: 12px; text-align: left;'>Description</th>
<th style='background: #3498db; color: white; padding: 12px; text-align: left;'>Details</th>
<th style='background: #3498db; color: white; padding: 12px; text-align: left;'>Amount</th>
</tr>
</thead>
<tbody>";
foreach ($items as $item) {
$desc = htmlspecialchars($item['description'], ENT_QUOTES);
$details = htmlspecialchars($item['details'], ENT_QUOTES);
$html .= "<tr>
<td style='padding: 10px; border-bottom: 1px solid #ddd;'>{$desc}</td>
<td style='padding: 10px; border-bottom: 1px solid #ddd;'>{$details}</td>
<td style='padding: 10px; border-bottom: 1px solid #ddd;'>{$currency}" . number_format((float) $item['amount'], 2) . "</td>
</tr>";
}
$html .= "<tr>
<td colspan='2' style='text-align: right; padding: 10px; border-top: 2px solid #3498db;'>Subtotal:</td>
<td style='padding: 10px; border-top: 2px solid #3498db;'>{$currency}" . number_format($subtotal, 2) . "</td>
</tr>
<tr>
<td colspan='2' style='text-align: right; padding: 10px;'>TAX ({$tax_rate}%):</td>
<td style='padding: 10px;'>{$currency}" . number_format($tax, 2) . "</td>
</tr>
<tr>
<td colspan='2' style='text-align: right; padding: 10px; font-weight: bold;'>Total:</td>
<td style='padding: 10px; font-weight: bold;'>{$currency}" . number_format($total, 2) . "</td>
</tr>";
$html .= "</tbody></table>";
return $html;
}
private static function saveToDatabase($filename, $customer_id, $invoiceData, $total)
{
$invoice = ORM::for_table('tbl_invoices')->create();
$invoice->number = $invoiceData['invoice'];
$invoice->customer_id = $customer_id;
$invoice->fullname = $invoiceData['fullname'];
$invoice->email = $invoiceData['email'];
$invoice->address = $invoiceData['address'];
$invoice->status = $invoiceData['status'];
$invoice->due_date = $invoiceData['due_date'];
$invoice->filename = $filename;
$invoice->amount = $total;
$invoice->data = json_encode($invoiceData);
$invoice->created_at = date('Y-m-d H:i:s');
$invoice->save();
return $invoice->id;
}
public static function getAll()
{
return ORM::for_table('tbl_invoices')->order_by_desc('id')->find_many();
}
public static function getById($id)
{
return ORM::for_table('tbl_invoices')->find_one($id);
}
public static function getByNumber($number)
{
return ORM::for_table('tbl_invoices')->where('number', $number)->find_one();
}
public static function delete($id)
{
$invoice = ORM::for_table('tbl_invoices')->find_one($id);
if ($invoice) {
$invoice->delete();
return true;
}
return false;
}
}

View File

@ -17,18 +17,15 @@ require $root_path . 'system/autoload/mail/SMTP.php';
class Message
{
public static function sendTelegram($txt, $chat_id = null, $topik = '')
public static function sendTelegram($txt, $chat_id = null)
{
global $config;
run_hook('send_telegram', [$txt, $chat_id, $topik]); #HOOK
run_hook('send_telegram', [$txt, $chat_id = null]); #HOOK
if (!empty($config['telegram_bot'])) {
if (empty($chat_id)) {
$chat_id = $config['telegram_target_id'];
}
if (!empty($topik)) {
$topik = "message_thread_id=$topik&";
}
return Http::getData('https://api.telegram.org/bot' . $config['telegram_bot'] . '/sendMessage?' . $topik . 'chat_id=' . $chat_id . '&text=' . urlencode($txt));
return Http::getData('https://api.telegram.org/bot' . $config['telegram_bot'] . '/sendMessage?chat_id=' . $chat_id . '&text=' . urlencode($txt));
}
}
@ -46,32 +43,24 @@ class Message
$txts = str_split($txt, 160);
try {
foreach ($txts as $txt) {
self::sendSMS($phone, $txt);
self::logMessage('SMS', $phone, $txt, 'Success');
self::sendSMS($config['sms_url'], $phone, $txt);
}
} catch (Throwable $e) {
} catch (Exception $e) {
// ignore, add to logs
self::logMessage('SMS', $phone, $txt, 'Error', $e->getMessage());
_log("Failed to send SMS using Mikrotik.\n" . $e->getMessage(), 'SMS', 0);
}
} else {
try {
self::MikrotikSendSMS($config['sms_url'], $phone, $txt);
self::logMessage('MikroTikSMS', $phone, $txt, 'Success');
} catch (Throwable $e) {
} catch (Exception $e) {
// ignore, add to logs
self::logMessage('MikroTikSMS', $phone, $txt, 'Error', $e->getMessage());
_log("Failed to send SMS using Mikrotik.\n" . $e->getMessage(), 'SMS', 0);
}
}
} else {
$smsurl = str_replace('[number]', urlencode($phone), $config['sms_url']);
$smsurl = str_replace('[text]', urlencode($txt), $smsurl);
try {
$response = Http::getData($smsurl);
self::logMessage('SMS HTTP Response', $phone, $txt, 'Success', $response);
return $response;
} catch (Throwable $e) {
self::logMessage('SMS HTTP Request', $phone, $txt, 'Error', $e->getMessage());
}
return Http::getData($smsurl);
}
}
}
@ -103,24 +92,15 @@ class Message
if (empty($txt)) {
return "kosong";
}
run_hook('send_whatsapp', [$phone, $txt]); // HOOK
run_hook('send_whatsapp', [$phone, $txt]); #HOOK
if (!empty($config['wa_url'])) {
$waurl = str_replace('[number]', urlencode(Lang::phoneFormat($phone)), $config['wa_url']);
$waurl = str_replace('[text]', urlencode($txt), $waurl);
try {
$response = Http::getData($waurl);
self::logMessage('WhatsApp HTTP Response', $phone, $txt, 'Success', $response);
return $response;
} catch (Throwable $e) {
self::logMessage('WhatsApp HTTP Request', $phone, $txt, 'Error', $e->getMessage());
}
return Http::getData($waurl);
}
}
public static function sendEmail($to, $subject, $body, $attachmentPath = null)
public static function sendEmail($to, $subject, $body)
{
global $config, $PAGES_PATH, $debug_mail;
if (empty($body)) {
@ -139,20 +119,18 @@ class Message
$attr .= "Reply-To: " . $config['mail_reply_to'] . "\r\n";
}
mail($to, $subject, $body, $attr);
self::logMessage('Email', $to, $body, 'Success');
return true;
} else {
$mail = new PHPMailer();
$mail->isSMTP();
if (isset($debug_mail) && $debug_mail == 'Dev') {
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
}
$mail->Host = $config['smtp_host'];
$mail->SMTPAuth = true;
$mail->Username = $config['smtp_user'];
$mail->Password = $config['smtp_pass'];
$mail->Host = $config['smtp_host'];
$mail->SMTPAuth = true;
$mail->Username = $config['smtp_user'];
$mail->Password = $config['smtp_pass'];
$mail->SMTPSecure = $config['smtp_ssltls'];
$mail->Port = $config['smtp_port'];
$mail->Port = $config['smtp_port'];
if (!empty($config['mail_from'])) {
$mail->setFrom($config['mail_from']);
}
@ -162,10 +140,6 @@ class Message
$mail->addAddress($to);
$mail->Subject = $subject;
// Attachments
if (!empty($attachmentPath)) {
$mail->addAttachment($attachmentPath);
}
if (!file_exists($PAGES_PATH . DIRECTORY_SEPARATOR . 'Email.html')) {
if (!copy($PAGES_PATH . '_template' . DIRECTORY_SEPARATOR . 'Email.html', $PAGES_PATH . DIRECTORY_SEPARATOR . 'Email.html')) {
@ -180,19 +154,13 @@ class Message
$html = str_replace('[[Company_Name]]', nl2br($config['CompanyName']), $html);
$html = str_replace('[[Body]]', nl2br($body), $html);
$mail->isHTML(true);
$mail->Body = $html;
$mail->Body = $html;
$mail->Body = $html;
} else {
$mail->isHTML(false);
$mail->Body = $body;
$mail->Body = $body;
}
if (!$mail->send()) {
$errorMessage = Lang::T("Email not sent, Mailer Error: ") . $mail->ErrorInfo;
self::logMessage('Email', $to, $body, 'Error', $errorMessage);
return false;
} else {
self::logMessage('Email', $to, $body, 'Success');
return true;
_log(Lang::T("Email not sent, Mailer Error: ") . $mail->ErrorInfo);
}
//<p style="font-family: Helvetica, sans-serif; font-size: 16px; font-weight: normal; margin: 0; margin-bottom: 16px;">
@ -230,7 +198,7 @@ class Message
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
if ($tax_enable === 'yes') {
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float) $config['custom_tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
$tax_rate = ($tax_rate_setting === 'custom') ? $custom_tax_rate : $tax_rate_setting;
$tax = Package::tax($price, $tax_rate);
@ -311,7 +279,7 @@ class Message
public static function sendInvoice($cust, $trx)
{
global $config, $db_pass;
global $config;
$textInvoice = Lang::getNotifText('invoice_paid');
$textInvoice = str_replace('[[company_name]]', $config['CompanyName'], $textInvoice);
$textInvoice = str_replace('[[address]]', $config['address'], $textInvoice);
@ -327,7 +295,7 @@ class Message
$textInvoice = str_replace('[[payment_channel]]', trim($gc[1]), $textInvoice);
$textInvoice = str_replace('[[type]]', $trx['type'], $textInvoice);
$textInvoice = str_replace('[[plan_name]]', $trx['plan_name'], $textInvoice);
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($trx['price']), $textInvoice);
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($trx['price']), $textInvoice);
$textInvoice = str_replace('[[name]]', $cust['fullname'], $textInvoice);
$textInvoice = str_replace('[[note]]', $cust['note'], $textInvoice);
$textInvoice = str_replace('[[user_name]]', $trx['username'], $textInvoice);
@ -337,46 +305,6 @@ class Message
$textInvoice = str_replace('[[expired_date]]', Lang::dateAndTimeFormat($trx['expiration'], $trx['time']), $textInvoice);
$textInvoice = str_replace('[[footer]]', $config['note'], $textInvoice);
$inv_url = "?_route=voucher/invoice/$trx[id]/" . md5($trx['id'] . $db_pass);
$textInvoice = str_replace('[[invoice_link]]', $inv_url, $textInvoice);
// Calculate bills and additional costs
list($bills, $add_cost) = User::getBills($cust['id']);
// Initialize note and total variables
$note = "";
$total = $trx['price'];
// Add bills to the note if there are any additional costs
if ($add_cost != 0) {
foreach ($bills as $k => $v) {
$note .= $k . " : " . Lang::moneyFormat($v) . "\n";
}
$total += $add_cost;
}
// Calculate tax
$tax = 0;
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
if ($tax_enable === 'yes') {
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float) $config['custom_tax_rate'] : null;
$tax_rate = ($tax_rate_setting === 'custom') ? $custom_tax_rate : $tax_rate_setting;
$tax = Package::tax($trx['price'], $tax_rate);
if ($tax != 0) {
$note .= "Tax : " . Lang::moneyFormat($tax) . "\n";
$total += $tax;
}
}
// Add total to the note
$note .= "Total : " . Lang::moneyFormat($total) . "\n";
// Replace placeholders in the message
$textInvoice = str_replace('[[bills]]', $note, $textInvoice);
if ($config['user_notification_payment'] == 'sms') {
Message::sendSMS($cust['phonenumber'], $textInvoice);
} else if ($config['user_notification_payment'] == 'email') {
@ -389,45 +317,12 @@ class Message
public static function addToInbox($to_customer_id, $subject, $body, $from = 'System')
{
$user = User::find($to_customer_id);
try {
$v = ORM::for_table('tbl_customers_inbox')->create();
$v->from = $from;
$v->customer_id = $to_customer_id;
$v->subject = $subject;
$v->date_created = date('Y-m-d H:i:s');
$v->body = nl2br($body);
$v->save();
self::logMessage("Inbox", $user->username, $body, "Success");
return true;
} catch (Throwable $e) {
$errorMessage = Lang::T("Error adding message to inbox: " . $e->getMessage());
self::logMessage('Inbox', $user->username, $body, 'Error', $errorMessage);
return false;
}
}
public static function getMessageType($type, $message)
{
if (strpos($message, "<divider>") === false) {
return $message;
}
$msgs = explode("<divider>", $message);
if ($type == "PPPOE") {
return $msgs[1];
} else {
return $msgs[0];
}
}
public static function logMessage($messageType, $recipient, $messageContent, $status, $errorMessage = null)
{
$log = ORM::for_table('tbl_message_logs')->create();
$log->message_type = $messageType;
$log->recipient = $recipient;
$log->message_content = $messageContent;
$log->status = $status;
$log->error_message = $errorMessage;
$log->save();
$v = ORM::for_table('tbl_customers_inbox')->create();
$v->from = $from;
$v->customer_id = $to_customer_id;
$v->subject = $subject;
$v->date_created = date('Y-m-d H:i:s');
$v->body = nl2br($body);
$v->save();
}
}

View File

@ -46,11 +46,7 @@ class Response extends Message
/**
* The last response for a request.
*/
const TYPE_FINAL = '!done';/**
* The empty response for a request.
*/
const TYPE_EMPTY = '!empty';
const TYPE_FINAL = '!done';
/**
* A response with data.
@ -250,7 +246,6 @@ class Response extends Message
{
switch ($type) {
case self::TYPE_FINAL:
case self::TYPE_EMPTY:
case self::TYPE_DATA:
case self::TYPE_ERROR:
case self::TYPE_FATAL:

View File

@ -74,10 +74,10 @@ class Package
if (!$p['enabled']) {
if (!isset($admin) || !isset($admin['id']) || empty($admin['id'])) {
r2(getUrl('home'), 'e', Lang::T('Plan Not found'));
r2(U . 'home', 'e', Lang::T('Plan Not found'));
}
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
r2(getUrl('dashboard'), 'e', Lang::T('You do not have permission to access this page'));
r2(U . 'dashboard', 'e', Lang::T('You do not have permission to access this page'));
}
}

View File

@ -10,16 +10,15 @@ class Paginator
{
public static function findMany($query, $search = [], $per_page = '10', $append_url = "", $toArray = false)
{
global $routes, $ui, $isApi;
global $routes, $ui;
$adjacents = "2";
$page = _get('p', 1);
$page = (empty($page) ? 1 : $page);
$url = getUrl(implode('/', $routes));
$url = U . implode('/', $routes);
if (count($search) > 0) {
$url .= '&' . http_build_query($search);
}
$url .= $append_url.'&p=';
$url = Text::fixUrl($url);
$totalReq = $query->count();
$lastpage = ceil($totalReq / $per_page);
$lpm1 = $lastpage - 1;
@ -72,7 +71,7 @@ class Paginator
if ($ui) {
$ui->assign('paginator', $result);
}
if($toArray || $isApi){
if($toArray){
return $query->offset($startpoint)->limit($per_page)->find_array();
}else{
return $query->offset($startpoint)->limit($per_page)->find_many();
@ -84,7 +83,7 @@ class Paginator
{
global $routes;
global $_L;
$url = getUrl(implode('/', $routes));
$url = U . implode('/', $routes);
$query = urlencode($query);
$adjacents = "2";
$page = (int)(empty(_get('p')) ? 1 : _get('p'));
@ -170,7 +169,7 @@ class Paginator
{
global $routes;
global $_L;
$url = getUrl($routes['0'] . '/' . $routes['1'] . '/');
$url = U . $routes['0'] . '/' . $routes['1'] . '/';
$adjacents = "2";
$page = (int)(!isset($routes['2']) ? 1 : $routes['2']);
$pagination = "";
@ -278,7 +277,7 @@ class Paginator
{
global $routes;
global $_L;
$url = getUrl($routes['0'] . '/' . $routes['1'] . '/');
$url = U . $routes['0'] . '/' . $routes['1'] . '/';
$adjacents = "2";
$page = (int)(!isset($routes['2']) ? 1 : $routes['2']);
$pagination = "";

View File

@ -109,44 +109,4 @@ class Text
}
return $result;
}
/**
* ...$data means it can take any number of arguments.
* it can url($var1, $var2, $var3) or url($var1)
* and variable will be merge with implode
* @return string the URL with all the arguments combined.
*/
public static function url(...$data){
global $config;
$url = implode("", $data);
if ($config['url_canonical'] == 'yes') {
$u = str_replace('?_route=', '', U);
$pos = strpos($url, '&');
if ($pos === false) {
return $u . $url;
} else {
return $u . substr($url, 0, $pos) . '?' . substr($url, $pos + 1);
}
} else {
return U . $url;
}
}
public static function fixUrl($url){
//if url dont have ? then add it with replace first & to ?
if(strpos($url, '?') === false && strpos($url, '&')!== false){
return substr($url, 0, strpos($url, '&')). '?'. substr($url, strpos($url, '&')+1);
}
return $url;
}
// this will return & or ?
public static function isQA(){
global $config;
if ($config['url_canonical'] == 'yes') {
return '?';
} else {
return '&';
}
}
}

View File

@ -29,7 +29,7 @@ class User
public static function getTawkToHash($email)
{
global $config;
if (!empty($config['tawkto_api_key']) && !empty($email)) {
if (!empty($config['tawkto_api_key']) && !Empty($email)) {
return hash_hmac('sha256', $email, $config['tawkto_api_key']);
}
return '';
@ -169,11 +169,11 @@ class User
public static function generateToken($uid, $validDays = 30)
{
global $db_pass;
if ($validDays >= 30) {
if($validDays>=30){
$time = time();
} else {
}else{
// for customer, deafult expired is 30 days
$time = strtotime('+ ' . (30 - $validDays) . ' days');
$time = strtotime('+ '.(30 - $validDays).' days');
}
return [
@ -187,7 +187,7 @@ class User
global $db_pass;
if (isset($uid)) {
$token = self::generateToken($uid);
setcookie('uid', $token['token'], time() + 86400 * 30, "/");
setcookie('uid', $token['token'], time() + 86400 * 30);
return $token;
} else {
return false;
@ -197,7 +197,7 @@ class User
public static function removeCookie()
{
if (isset($_COOKIE['uid'])) {
setcookie('uid', '', time() - 86400, "/");
setcookie('uid', '', time() - 86400);
}
}
@ -206,7 +206,7 @@ class User
global $config;
if ($config['maintenance_mode'] == true) {
if ($config['maintenance_mode_logout'] == true) {
r2(getUrl('logout'), 'd', '');
r2(U . 'logout', 'd', '');
} else {
displayMaintenanceMessage();
}
@ -226,7 +226,7 @@ class User
global $config;
if ($config['maintenance_mode'] == true) {
if ($config['maintenance_mode_logout'] == true) {
r2(getUrl('logout'), 'd', '');
r2(U . 'logout', 'd', '');
} else {
displayMaintenanceMessage();
}
@ -277,53 +277,45 @@ class User
return $d;
}
public static function setFormCustomField($uid = 0)
{
public static function setFormCustomField($uid = 0){
global $UPLOAD_PATH;
$fieldPath = $UPLOAD_PATH . DIRECTORY_SEPARATOR . "customer_field.json";
if (!file_exists($fieldPath)) {
if(!file_exists($fieldPath)){
return '';
}
$fields = json_decode(file_get_contents($fieldPath), true);
foreach ($fields as $field) {
if (!empty(_post($field['name']))) {
foreach($fields as $field){
if(!empty(_post($field['name']))){
self::setAttribute($field['name'], _post($field['name']), $uid);
}
}
}
public static function getFormCustomField($ui, $register = false, $uid = 0)
{
public static function getFormCustomField($ui, $register = false, $uid = 0){
global $UPLOAD_PATH;
$fieldPath = $UPLOAD_PATH . DIRECTORY_SEPARATOR . "customer_field.json";
if (!file_exists($fieldPath)) {
if(!file_exists($fieldPath)){
return '';
}
$fields = json_decode(file_get_contents($fieldPath), true);
$attrs = [];
if (!$register) {
if(!$register){
$attrs = self::getAttributes('', $uid);
$ui->assign('attrs', $attrs);
}
$html = '';
$ui->assign('register', $register);
foreach ($fields as $field) {
if ($register) {
if ($field['register']) {
foreach($fields as $field){
if($register){
if($field['register']){
$ui->assign('field', $field);
$html .= $ui->fetch('customer/custom_field.tpl');
}
} else {
}else{
$ui->assign('field', $field);
$html .= $ui->fetch('customer/custom_field.tpl');
}
}
return $html;
}
public static function find($id)
{
return ORM::for_table('tbl_customers')->find_one($id);
}
}

View File

@ -1,50 +0,0 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
**/
/**
* Validator class
*/
class Widget
{
public static function rows($rows, $result){
$result .= '<div class="row">';
foreach($rows as $row){
}
$result .= '</div>';
}
public static function columns($cols, $result){
$c = count($cols);
switch($c){
case 1:
$result .= '<div class="col-md-12">';
break;
case 2:
$result .= '<div class="col-md-6">';
break;
case 3:
$result .= '<div class="col-md-4">';
break;
case 4:
$result .= '<div class="col-md-4">';
break;
case 5:
$result .= '<div class="col-md-4">';
break;
default:
$result .= '<div class="col-md-1">';
break;
}
foreach($cols as $col){
}
$result .= '</div>';
}
}

View File

@ -67,25 +67,21 @@ if (isset($_SESSION['notify'])) {
unset($_SESSION['ntype']);
}
if (!isset($_GET['_route'])) {
$req = ltrim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
$len = strlen(ltrim(parse_url(APP_URL, PHP_URL_PATH), '/'));
if ($len > 0) {
$req = ltrim(substr($req, $len), '/');
}
} else {
if(!isset($_GET['_route'])) {
$req = ltrim(parse_url($_SERVER['REQUEST_URI'])['path'], '/');
}else{
// Routing Engine
$req = _get('_route');
}
$routes = explode('/', $req);
$ui->assign('_routes', $routes);
$handler = $routes[0];
if ($handler == '') {
$handler = 'default';
}
try {
if (!empty($_GET['uid'])) {
if(!empty($_GET['uid'])){
$_COOKIE['uid'] = $_GET['uid'];
}
$admin = Admin::_info();
@ -100,7 +96,7 @@ try {
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="' . getUrl('plugin/' . $menu['function']) . '">';
$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>';
}
@ -111,7 +107,7 @@ try {
$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="' . getUrl('plugin/' . $menu['function']) . '">';
$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>';
}
@ -128,15 +124,7 @@ try {
unset($menus, $menu_registered);
include($sys_render);
} else {
if( empty($_SERVER["HTTP_SEC_FETCH_DEST"]) || $_SERVER["HTTP_SEC_FETCH_DEST"] != 'document' ){
// header 404
header("HTTP/1.0 404 Not Found");
header("Content-Type: text/html; charset=utf-8");
echo "404 Not Found";
die();
}else{
r2(getUrl('login'));
}
r2(U . 'dashboard', 'e', 'not found');
}
} catch (Throwable $e) {
Message::sendTelegram(
@ -145,12 +133,11 @@ try {
$e->getTraceAsString()
);
if (empty($_SESSION['aid'])) {
$ui->display('customer/error.tpl');
die();
$ui->display('customer/error.tpl'); die();
}
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
$ui->assign("error_title", "PHPNuxBill Crash");
$ui->display('admin/error.tpl');
$ui->display('error.tpl');
die();
} catch (Exception $e) {
Message::sendTelegram(
@ -159,11 +146,10 @@ try {
$e->getTraceAsString()
);
if (empty($_SESSION['aid'])) {
$ui->display('customer/error.tpl');
die();
$ui->display('customer/error.tpl'); die();
}
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
$ui->assign("error_title", "PHPNuxBill Crash");
$ui->display('admin/error.tpl');
$ui->display('error.tpl');
die();
}

View File

@ -27,7 +27,7 @@ switch ($action) {
$password = _post('password');
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('accounts/change-password'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'accounts/change-password', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
run_hook('customer_change_password'); #HOOK
if ($password != '') {
@ -36,10 +36,10 @@ switch ($action) {
$cnpass = _post('cnpass');
if ($password == $d_pass) {
if (!Validator::Length($password, 36, 2)) {
r2(getUrl('accounts/change-password'), 'e', 'New Password must be 2 to 35 character');
r2(U . 'accounts/change-password', 'e', 'New Password must be 2 to 35 character');
}
if ($npass != $cnpass) {
r2(getUrl('accounts/change-password'), 'e', 'Both Password should be same');
r2(U . 'accounts/change-password', 'e', 'Both Password should be same');
}
$user->password = $npass;
$turs = ORM::for_table('tbl_user_recharges')->where('customer_id', $user['id'])->find_many();
@ -64,10 +64,10 @@ switch ($action) {
_log('[' . $user['username'] . ']: Password changed successfully', 'User', $user['id']);
_alert(Lang::T('Password changed successfully, Please login again'), 'success', "login");
} else {
r2(getUrl('accounts/change-password'), 'e', Lang::T('Incorrect Current Password'));
r2(U . 'accounts/change-password', 'e', Lang::T('Incorrect Current Password'));
}
} else {
r2(getUrl('accounts/change-password'), 'e', Lang::T('Incorrect Current Password'));
r2(U . 'accounts/change-password', 'e', Lang::T('Incorrect Current Password'));
}
break;
@ -81,7 +81,7 @@ switch ($action) {
case 'edit-profile-post':
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('accounts/profile'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'accounts/profile', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$fullname = _post('fullname');
$address = _post('address');
@ -142,7 +142,7 @@ switch ($action) {
}
if (file_exists($_FILES['photo']['tmp_name'])) unlink($_FILES['photo']['tmp_name']);
} else {
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
r2(U . 'settings/app', 'e', 'PHP GD is not installed');
}
}
@ -160,9 +160,9 @@ switch ($action) {
$user->save();
_log('[' . $user['username'] . ']: ' . Lang::T('User Updated Successfully'), 'User', $user['id']);
r2(getUrl('accounts/profile'), 's', Lang::T('User Updated Successfully'));
r2(U . 'accounts/profile', 's', Lang::T('User Updated Successfully'));
}else{
r2(getUrl('accounts/profile'), 'e', $msg);
r2(U . 'accounts/profile', 'e', $msg);
}
break;
@ -177,7 +177,7 @@ switch ($action) {
case 'phone-update-otp':
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'accounts/phone-update', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$phone = Lang::phoneFormat(_post('phone'));
$username = $user['username'];
@ -185,16 +185,16 @@ switch ($action) {
$_SESSION['new_phone'] = $phone;
// Validate the phone number format
if (!preg_match('/^[0-9]{10,}$/', $phone) || empty($phone)) {
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid phone number format'));
r2(U . 'accounts/phone-update', 'e', Lang::T('Invalid phone number format'));
}
if (empty($config['sms_url'])) {
r2(getUrl('accounts/phone-update'), 'e', Lang::T('SMS server not Available, Please try again later'));
r2(U . 'accounts/phone-update', 'e', Lang::T('SMS server not Available, Please try again later'));
}
$d = ORM::for_table('tbl_customers')->whereNotEqual('username', $username)->where('phonenumber', $phone)->find_one();
if ($d) {
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Phone number already registered by another customer'));
r2(U . 'accounts/phone-update', 'e', Lang::T('Phone number already registered by another customer'));
}
if (!file_exists($otpPath)) {
mkdir($otpPath);
@ -205,7 +205,7 @@ switch ($action) {
// expired 10 minutes
if (file_exists($otpFile) && time() - filemtime($otpFile) < 600) {
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Please wait ') . (600 - (time() - filemtime($otpFile))) . Lang::T(' seconds before sending another SMS'));
r2(U . 'accounts/phone-update', 'e', Lang::T('Please wait ') . (600 - (time() - filemtime($otpFile))) . Lang::T(' seconds before sending another SMS'));
} else {
$otp = rand(100000, 999999);
file_put_contents($otpFile, $otp);
@ -220,7 +220,7 @@ switch ($action) {
Message::sendWhatsapp($phone, $config['CompanyName'] . "\n\n" . Lang::T("Verification code") . "\n$otp");
}
//redirect after sending OTP
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Verification code has been sent to your phone'));
r2(U . 'accounts/phone-update', 'e', Lang::T('Verification code has been sent to your phone'));
}
break;
@ -228,7 +228,7 @@ switch ($action) {
case 'phone-update-post':
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'accounts/phone-update', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$phone = Lang::phoneFormat(_post('phone'));
$otp_code = _post('otp');
@ -237,11 +237,11 @@ switch ($action) {
// Validate the phone number format
if (!preg_match('/^[0-9]{10,}$/', $phone)) {
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid phone number format'));
r2(U . 'accounts/phone-update', 'e', Lang::T('Invalid phone number format'));
}
if (empty($config['sms_url'])) {
r2(getUrl('accounts/phone-update'), 'e', Lang::T('SMS server not Available, Please try again later'));
r2(U . 'accounts/phone-update', 'e', Lang::T('SMS server not Available, Please try again later'));
}
$otpFile = $otpPath . sha1($username . $db_pass) . ".txt";
@ -249,7 +249,7 @@ switch ($action) {
// Check if OTP file exists
if (!file_exists($otpFile)) {
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Please request OTP first'));
r2(U . 'accounts/phone-update', 'e', Lang::T('Please request OTP first'));
exit();
}
@ -257,21 +257,21 @@ switch ($action) {
if (time() - filemtime($otpFile) > 1200) {
unlink($otpFile);
unlink($phoneFile);
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Verification code expired'));
r2(U . 'accounts/phone-update', 'e', Lang::T('Verification code expired'));
exit();
} else {
$code = file_get_contents($otpFile);
// Check if OTP code matches
if ($code != $otp_code) {
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Wrong Verification code'));
r2(U . 'accounts/phone-update', 'e', Lang::T('Wrong Verification code'));
exit();
}
// Check if the phone number matches the one that requested the OTP
$savedPhone = file_get_contents($phoneFile);
if ($savedPhone !== $phone) {
r2(getUrl('accounts/phone-update'), 'e', Lang::T('The phone number does not match the one that requested the OTP'));
r2(U . 'accounts/phone-update', 'e', Lang::T('The phone number does not match the one that requested the OTP'));
exit();
}
@ -284,7 +284,7 @@ switch ($action) {
$user->phonenumber = Lang::phoneFormat($phone);
$user->save();
r2(getUrl('accounts/profile'), 's', Lang::T('Phone number updated successfully'));
r2(U . 'accounts/profile', 's', Lang::T('Phone number updated successfully'));
break;
case 'email-update':
@ -296,7 +296,7 @@ switch ($action) {
case 'email-update-otp':
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'accounts/email-update', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$email = trim(_post('email'));
$username = $user['username'];
@ -304,16 +304,16 @@ switch ($action) {
$_SESSION['new_email'] = $email;
// Validate the phone number format
if (!Validator::Email($email)) {
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid Email address format'));
r2(U . 'accounts/email-update', 'e', Lang::T('Invalid Email address format'));
}
if (empty($config['smtp_host'])) {
r2(getUrl('accounts/email-update'), 'e', Lang::T('Email server not Available, Please ask admin to configure it'));
r2(U . 'accounts/email-update', 'e', Lang::T('Email server not Available, Please ask admin to configure it'));
}
$d = ORM::for_table('tbl_customers')->whereNotEqual('username', $username)->where('email', $email)->find_one();
if ($d) {
r2(getUrl('accounts/email-update'), 'e', Lang::T('Email already used by another Customer'));
r2(U . 'accounts/email-update', 'e', Lang::T('Email already used by another Customer'));
}
if (!file_exists($otpPath)) {
mkdir($otpPath);
@ -324,7 +324,7 @@ switch ($action) {
// expired 10 minutes
if (file_exists($otpFile) && time() - filemtime($otpFile) < 600) {
r2(getUrl('accounts/email-update'), 'e', Lang::T('Please wait ') . (600 - (time() - filemtime($otpFile))) . Lang::T(' seconds before sending another Email'));
r2(U . 'accounts/email-update', 'e', Lang::T('Please wait ') . (600 - (time() - filemtime($otpFile))) . Lang::T(' seconds before sending another Email'));
} else {
$otp = rand(100000, 999999);
file_put_contents($otpFile, $otp);
@ -333,7 +333,7 @@ switch ($action) {
$body = Lang::T("Hello") . ' ' . $user['fullname'] . ",\n\n" . Lang::T("Your Email Verification Code is:") . " $otp";
Message::sendEmail($email, Lang::T('Change Email Verification Code'), $body);
//redirect after sending OTP
r2(getUrl('accounts/email-update'), 'e', Lang::T('Verification code has been sent to your email. Check Spam folder if not found.'));
r2(U . 'accounts/email-update', 'e', Lang::T('Verification code has been sent to your email. Check Spam folder if not found.'));
}
break;
@ -341,7 +341,7 @@ switch ($action) {
case 'email-update-post':
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'accounts/email-update', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$email = trim(_post('email'));
$otp_code = _post('otp');
@ -349,12 +349,12 @@ switch ($action) {
$otpPath = $CACHE_PATH . '/email/';
// Validate the phone number format
if (!Validator::Email($email)) {
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid Email address format'));
r2(U . 'accounts/email-update', 'e', Lang::T('Invalid Email address format'));
exit();
}
if (empty($config['smtp_host'])) {
r2(getUrl('accounts/email-update'), 'e', Lang::T('Email server not Available, Please ask admin to configure it'));
r2(U . 'accounts/email-update', 'e', Lang::T('Email server not Available, Please ask admin to configure it'));
}
$otpFile = $otpPath . sha1($username . $db_pass) . ".txt";
@ -362,7 +362,7 @@ switch ($action) {
// Check if OTP file exists
if (!file_exists($otpFile)) {
r2(getUrl('accounts/email-update'), 'e', Lang::T('Please request OTP first'));
r2(U . 'accounts/email-update', 'e', Lang::T('Please request OTP first'));
exit();
}
@ -370,21 +370,21 @@ switch ($action) {
if (time() - filemtime($otpFile) > 1200) {
unlink($otpFile);
unlink($emailFile);
r2(getUrl('accounts/email-update'), 'e', Lang::T('Verification code expired'));
r2(U . 'accounts/email-update', 'e', Lang::T('Verification code expired'));
exit();
} else {
$code = file_get_contents($otpFile);
// Check if OTP code matches
if ($code != $otp_code) {
r2(getUrl('accounts/email-update'), 'e', Lang::T('Wrong Verification code'));
r2(U . 'accounts/email-update', 'e', Lang::T('Wrong Verification code'));
exit();
}
// Check if the phone number matches the one that requested the OTP
$savedEmail = file_get_contents($emailFile);
if ($savedEmail !== $email) {
r2(getUrl('accounts/email-update'), 'e', Lang::T('The Email Address does not match the one that requested the OTP'));
r2(U . 'accounts/email-update', 'e', Lang::T('The Email Address does not match the one that requested the OTP'));
exit();
}
@ -396,7 +396,7 @@ switch ($action) {
$user->email = $email;
$user->save();
r2(getUrl('accounts/profile'), 's', Lang::T('Email Address updated successfully'));
r2(U . 'accounts/profile', 's', Lang::T('Email Address updated successfully'));
break;
case 'language-update-post':
@ -420,5 +420,5 @@ switch ($action) {
break;
default:
$ui->display('admin/404.tpl');
$ui->display('a404.tpl');
}

View File

@ -10,7 +10,7 @@ header("Expires: Tue, 01 Jan 2000 00:00:00 GMT");
header("Pragma: no-cache");
if (Admin::getID()) {
r2(getUrl('dashboard'), "s", Lang::T("You are already logged in"));
r2(U . 'dashboard', "s", Lang::T("You are already logged in"));
}
if (isset($routes['1'])) {
@ -63,6 +63,6 @@ switch ($do) {
run_hook('view_login'); #HOOK
$csrf_token = Csrf::generateAndStoreToken();
$ui->assign('csrf_token', $csrf_token);
$ui->display('admin/admin/login.tpl');
$ui->display('admin-login.tpl');
break;
}

View File

@ -26,7 +26,7 @@ switch ($action) {
}
$ui->assign('routers', $routers);
$ui->assign('d', $d);
$ui->display('admin/autoload/pool.tpl');
$ui->display('autoload-pool.tpl');
break;
case 'bw_name':
$bw = ORM::for_table('tbl_bandwidth')->select("name_bw")->find_one($routes['2']);
@ -44,7 +44,7 @@ switch ($action) {
$d = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
$ui->assign('d', $d);
$ui->display('admin/autoload/server.tpl');
$ui->display('autoload-server.tpl');
break;
case 'pppoe_ip_used':
if (!empty(_get('ip'))) {
@ -100,7 +100,7 @@ switch ($action) {
}
$ui->assign('d', $d);
$ui->display('admin/autoload/plan.tpl');
$ui->display('autoload.tpl');
break;
case 'customer_is_active':
if ($config['check_customer_online'] == 'yes') {
@ -181,5 +181,5 @@ switch ($action) {
echo json_encode(['results' => $json]);
die();
default:
$ui->display('admin/404.tpl');
$ui->display('a404.tpl');
}

View File

@ -25,10 +25,10 @@ switch ($action) {
if (file_exists($dvc)) {
require_once $dvc;
if ((new $p['device'])->online_customer($user, $bill['routers'])) {
die('<a href="' . getUrl('home&mikrotik=logout&id=' . $bill['id']) . '" onclick="return confirm(\'' . Lang::T('Disconnect Internet?') . '\')" class="btn btn-success btn-xs btn-block">' . Lang::T('You are Online, Logout?') . '</a>');
die('<a href="' . U . 'home&mikrotik=logout&id=' . $bill['id'] . '" onclick="return confirm(\'' . Lang::T('Disconnect Internet?') . '\')" class="btn btn-success btn-xs btn-block">' . Lang::T('You are Online, Logout?') . '</a>');
} else {
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'])) {
die('<a href="' . getUrl('home&mikrotik=login&id=' . $bill['id']) . '" onclick="return confirm(\'' . Lang::T('Connect to Internet?') . '\')" class="btn btn-danger btn-xs btn-block">' . Lang::T('Not Online, Login now?') . '</a>');
die('<a href="' . U . 'home&mikrotik=login&id=' . $bill['id'] . '" onclick="return confirm(\'' . Lang::T('Connect to Internet?') . '\')" class="btn btn-danger btn-xs btn-block">' . Lang::T('Not Online, Login now?') . '</a>');
} else {
die(Lang::T('-'));
}
@ -58,7 +58,7 @@ switch ($action) {
case 'inbox':
$inboxs = ORM::for_table('tbl_customers_inbox')->selects(['id', 'subject', 'date_created'])->where('customer_id', $user['id'])->whereRaw('date_read is null')->order_by_desc('date_created')->limit(10)->find_many();
foreach ($inboxs as $inbox) {
echo '<li><a href="' . getUrl('mail/view/' . $inbox['id']) . '">' . $inbox['subject'] . '<br><sub class="text-muted">' . Lang::dateTimeFormat($inbox['date_created']) . '</sub></a></li>';
echo '<li><a href="' . U . 'mail/view/' . $inbox['id'] . '">' . $inbox['subject'] . '<br><sub class="text-muted">' . Lang::dateTimeFormat($inbox['date_created']) . '</sub></a></li>';
}
die();
case 'language':
@ -69,7 +69,7 @@ switch ($action) {
if (is_file('system/lan/' . $file) && !in_array($file, ['index.html', 'country.json', '.DS_Store'])) {
$file = str_replace(".json", "", $file);
if(!empty($file)){
echo '<li><a href="' . getUrl('accounts/language-update-post&lang=' . $file) . '">';
echo '<li><a href="' . U . 'accounts/language-update-post&lang=' . $file. '">';
if($select == $file){
echo '<span class="glyphicon glyphicon-ok"></span> ';
}
@ -79,5 +79,5 @@ switch ($action) {
}
die();
default:
die();
$ui->display('404.tpl');
}

View File

@ -13,11 +13,12 @@ $action = $routes['1'];
$ui->assign('_admin', $admin);
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
r2(getUrl('dashboard'), 'e', Lang::T('You do not have permission to access this page'));
r2(U . "dashboard", 'e', Lang::T('You do not have permission to access this page'));
}
switch ($action) {
case 'list':
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/bandwidth.js"></script>');
run_hook('view_list_bandwidth'); #HOOK
$name = _post('name');
if ($name != '') {
@ -29,7 +30,7 @@ switch ($action) {
}
$ui->assign('d', $d);
$ui->display('admin/bandwidth/list.tpl');
$ui->display('bandwidth.tpl');
break;
case 'add':
@ -37,7 +38,7 @@ switch ($action) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
run_hook('view_add_bandwidth'); #HOOK
$ui->display('admin/bandwidth/add.tpl');
$ui->display('bandwidth-add.tpl');
break;
case 'edit':
@ -50,9 +51,9 @@ switch ($action) {
if ($d) {
$ui->assign('burst', explode(" ", $d['burst']));
$ui->assign('d', $d);
$ui->display('admin/bandwidth/edit.tpl');
$ui->display('bandwidth-edit.tpl');
} else {
r2(getUrl('bandwidth/list'), 'e', Lang::T('Account Not Found'));
r2(U . 'bandwidth/list', 'e', Lang::T('Account Not Found'));
}
break;
@ -65,7 +66,7 @@ switch ($action) {
$d = ORM::for_table('tbl_bandwidth')->find_one($id);
if ($d) {
$d->delete();
r2(getUrl('bandwidth/list'), 's', Lang::T('Data Deleted Successfully'));
r2(U . 'bandwidth/list', 's', Lang::T('Data Deleted Successfully'));
}
break;
@ -122,9 +123,9 @@ switch ($action) {
$d->burst = $burst;
$d->save();
r2(getUrl('bandwidth/list'), 's', Lang::T('Data Created Successfully'));
r2(U . 'bandwidth/list', 's', Lang::T('Data Created Successfully'));
} else {
r2(getUrl('bandwidth/add'), 'e', $msg);
r2(U . 'bandwidth/add', 'e', $msg);
}
break;
@ -178,12 +179,12 @@ switch ($action) {
$d->burst = $burst;
$d->save();
r2(getUrl('bandwidth/list'), 's', Lang::T('Data Updated Successfully'));
r2(U . 'bandwidth/list', 's', Lang::T('Data Updated Successfully'));
} else {
r2(getUrl('bandwidth/edit/') . $id, 'e', $msg);
r2(U . 'bandwidth/edit/' . $id, 'e', $msg);
}
break;
default:
$ui->display('admin/404.tpl');
$ui->display('a404.tpl');
}

View File

@ -19,8 +19,8 @@ switch ($action) {
$ui->assign('masters', $masters);
$ui->assign('devs', $devs);
$ui->display('admin/rollback.tpl');
$ui->display('community-rollback.tpl');
break;
default:
$ui->display('admin/community.tpl');
$ui->display('community.tpl');
}

View File

@ -22,7 +22,7 @@ switch ($action) {
}
$ui->assign('_title', Lang::T('Add Coupon'));
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
$ui->display('admin/coupons/add.tpl');
$ui->display('coupons-add.tpl');
break;
case 'add-post':
@ -79,14 +79,14 @@ switch ($action) {
}
if (!empty($error)) {
r2(getUrl('coupons/add'), 'e', implode('<br>', $error));
r2(U . 'coupons/add', 'e', implode('<br>', $error));
exit;
}
//check if coupon code already exists
$coupon = ORM::for_table('tbl_coupons')->where('code', $code)->find_one();
if ($coupon) {
r2(getUrl('coupons/add'), 'e', Lang::T('Coupon Code already exists'));
r2(U . 'coupons/add', 'e', Lang::T('Coupon Code already exists'));
exit;
}
@ -104,10 +104,10 @@ switch ($action) {
$coupon->created_at = date('Y-m-d H:i:s');
try {
$coupon->save();
r2(getUrl('coupons'), 's', Lang::T('Coupon has been added successfully'));
r2(U . 'coupons', 's', Lang::T('Coupon has been added successfully'));
} catch (Exception $e) {
_log(Lang::T('Error adding coupon: ' . $e->getMessage()));
r2(getUrl('coupons/add'), 'e', Lang::T('Error adding coupon: ' . $e->getMessage()));
r2(U . 'coupons/add', 'e', Lang::T('Error adding coupon: ' . $e->getMessage()));
}
break;
@ -120,18 +120,18 @@ switch ($action) {
$coupon_id = intval($routes['2']);
if (empty($coupon_id)) {
r2(getUrl('coupons'), 'e', Lang::T('Invalid Coupon ID'));
r2(U . 'coupons', 'e', Lang::T('Invalid Coupon ID'));
exit;
}
$coupon = ORM::for_table('tbl_coupons')->find_one($coupon_id);
if (!$coupon) {
r2(getUrl('coupons'), 'e', Lang::T('Coupon Not Found'));
r2(U . 'coupons', 'e', Lang::T('Coupon Not Found'));
exit;
}
$ui->assign('coupon', $coupon);
$ui->assign('_title', Lang::T('Edit Coupon: ' . $coupon['code']));
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
$ui->display('admin/coupons/edit.tpl');
$ui->display('coupons-edit.tpl');
break;
case 'edit-post':
@ -189,7 +189,7 @@ switch ($action) {
$error[] = Lang::T('Coupon end date is required');
}
if (!empty($error)) {
r2(getUrl('coupons/edit/') . $coupon_id, 'e', implode('<br>', $error));
r2(U . 'coupons/edit/' . $coupon_id, 'e', implode('<br>', $error));
exit;
}
$coupon = ORM::for_table('tbl_coupons')->find_one($coupon_id);
@ -206,10 +206,10 @@ switch ($action) {
$coupon->updated_at = date('Y-m-d H:i:s');
try {
$coupon->save();
r2(getUrl('coupons'), 's', Lang::T('Coupon has been updated successfully'));
r2(U . 'coupons', 's', Lang::T('Coupon has been updated successfully'));
} catch (Exception $e) {
_log(Lang::T('Error updating coupon: ') . $e->getMessage());
r2(getUrl('coupons/edit/') . $coupon_id, 'e', Lang::T('Error updating coupon: ') . $e->getMessage());
r2(U . 'coupons/edit/' . $coupon_id, 'e', Lang::T('Error updating coupon: ') . $e->getMessage());
}
break;
@ -310,6 +310,6 @@ switch ($action) {
$coupons = Paginator::findMany($couponsData, ['search' => $search], 5, '');
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
$ui->assign('coupons', $coupons);
$ui->display('admin/coupons/list.tpl');
$ui->display('coupons.tpl');
break;
}

View File

@ -27,7 +27,7 @@ switch ($action) {
}
$csrf_token = _req('token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('customers'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'customers', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$cs = ORM::for_table('tbl_customers')
@ -158,7 +158,7 @@ switch ($action) {
$ui->assign('xheader', $leafletpickerHeader);
run_hook('view_add_customer'); #HOOK
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
$ui->display('admin/customers/add.tpl');
$ui->display('customers-add.tpl');
break;
case 'recharge':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
@ -168,7 +168,7 @@ switch ($action) {
$plan_id = $routes['3'];
$csrf_token = _req('token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('customers/view/') . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'customers/view/' . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('plan_id', $plan_id)->find_one();
if ($b) {
@ -176,10 +176,6 @@ switch ($action) {
$channel = $admin['fullname'];
$cust = User::_info($id_customer);
$plan = ORM::for_table('tbl_plans')->find_one($b['plan_id']);
$add_inv = User::getAttribute("Invoice", $id_customer);
if (!empty($add_inv)) {
$plan['price'] = $add_inv;
}
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
@ -196,13 +192,13 @@ switch ($action) {
list($bills, $add_cost) = User::getBills($id_customer);
if ($using == 'balance' && $config['enable_balance'] == 'yes') {
if (!$cust) {
r2(getUrl('plan/recharge'), 'e', Lang::T('Customer not found'));
r2(U . 'plan/recharge', 'e', Lang::T('Customer not found'));
}
if (!$plan) {
r2(getUrl('plan/recharge'), 'e', Lang::T('Plan not found'));
r2(U . 'plan/recharge', 'e', Lang::T('Plan not found'));
}
if ($cust['balance'] < ($plan['price'] + $add_cost + $tax)) {
r2(getUrl('plan/recharge'), 'e', Lang::T('insufficient balance'));
r2(U . 'plan/recharge', 'e', Lang::T('insufficient balance'));
}
$gateway = 'Recharge Balance';
}
@ -228,11 +224,10 @@ switch ($action) {
$ui->assign('channel', $channel);
$ui->assign('server', $b['routers']);
$ui->assign('plan', $plan);
$ui->assign('add_inv', $add_inv);
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
$ui->display('admin/plan/recharge-confirm.tpl');
$ui->display('recharge-confirm.tpl');
} else {
r2(getUrl('customers/view/') . $id_customer, 'e', 'Cannot find active plan');
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
}
break;
case 'deactivate':
@ -243,7 +238,7 @@ switch ($action) {
$plan_id = $routes['3'];
$csrf_token = _req('token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('customers/view/') . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'customers/view/' . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('plan_id', $plan_id)->find_one();
if ($b) {
@ -266,16 +261,16 @@ switch ($action) {
$b->save();
_log('Admin ' . $admin['username'] . ' Deactivate ' . $b['namebp'] . ' for ' . $b['username'], 'User', $b['customer_id']);
Message::sendTelegram('Admin ' . $admin['username'] . ' Deactivate ' . $b['namebp'] . ' for u' . $b['username']);
r2(getUrl('customers/view/') . $id_customer, 's', 'Success deactivate customer to Mikrotik');
r2(U . 'customers/view/' . $id_customer, 's', 'Success deactivate customer to Mikrotik');
}
}
r2(getUrl('customers/view/') . $id_customer, 'e', 'Cannot find active plan');
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
break;
case 'sync':
$id_customer = $routes['2'];
$csrf_token = _req('token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('customers/view/') . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'customers/view/' . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$bs = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('status', 'on')->findMany();
if ($bs) {
@ -300,9 +295,9 @@ switch ($action) {
}
}
}
r2(getUrl('customers/view/') . $id_customer, 's', 'Sync success to ' . implode(", ", $routers));
r2(U . 'customers/view/' . $id_customer, 's', 'Sync success to ' . implode(", ", $routers));
}
r2(getUrl('customers/view/') . $id_customer, 'e', 'Cannot find active plan');
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
break;
case 'login':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
@ -311,7 +306,7 @@ switch ($action) {
$id = $routes['2'];
$csrf_token = _req('token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('customers/view/') . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'customers/view/' . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$customer = ORM::for_table('tbl_customers')->find_one($id);
if ($customer) {
@ -369,9 +364,9 @@ switch ($action) {
$ui->assign('customFields', $customFields);
$ui->assign('xheader', $leafletpickerHeader);
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
$ui->display('admin/customers/view.tpl');
$ui->display('customers-view.tpl');
} else {
r2(getUrl('customers/list'), 'e', Lang::T('Account Not Found'));
r2(U . 'customers/list', 'e', Lang::T('Account Not Found'));
}
break;
case 'edit':
@ -408,9 +403,9 @@ switch ($action) {
$ui->assign('customFields', $customFields);
$ui->assign('xheader', $leafletpickerHeader);
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
$ui->display('admin/customers/edit.tpl');
$ui->display('customers-edit.tpl');
} else {
r2(getUrl('customers/list'), 'e', Lang::T('Account Not Found'));
r2(U . 'customers/list', 'e', Lang::T('Account Not Found'));
}
break;
@ -421,7 +416,7 @@ switch ($action) {
$id = $routes['2'];
$csrf_token = _req('token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('customers/view/') . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'customers/view/' . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
run_hook('delete_customer'); #HOOK
$c = ORM::for_table('tbl_customers')->find_one($id);
@ -453,7 +448,7 @@ switch ($action) {
$c->delete();
} catch (Exception $e) {
}
r2(getUrl('customers/list'), 's', Lang::T('User deleted Successfully'));
r2(U . 'customers/list', 's', Lang::T('User deleted Successfully'));
}
break;
@ -461,7 +456,7 @@ switch ($action) {
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('customers/add'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'customers/add', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$username = alphanumeric(_post('username'), ":+_.@-");
$fullname = _post('fullname');
@ -580,9 +575,9 @@ switch ($action) {
}
}
}
r2(getUrl('customers/list'), 's', Lang::T('Account Created Successfully'));
r2(U . 'customers/list', 's', Lang::T('Account Created Successfully'));
} else {
r2(getUrl('customers/add'), 'e', $msg);
r2(U . 'customers/add', 'e', $msg);
}
break;
@ -590,7 +585,7 @@ switch ($action) {
$id = _post('id');
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('customers/edit/') . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'customers/edit/' . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$username = alphanumeric(_post('username'), ":+_.@-");
$fullname = _post('fullname');
@ -713,7 +708,7 @@ switch ($action) {
}
if (file_exists($_FILES['photo']['tmp_name'])) unlink($_FILES['photo']['tmp_name']);
} else {
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
r2(U . 'settings/app', 'e', 'PHP GD is not installed');
}
}
if ($userDiff) {
@ -820,9 +815,9 @@ switch ($action) {
$tur->save();
}
}
r2(getUrl('customers/view/') . $id, 's', 'User Updated Successfully');
r2(U . 'customers/view/' . $id, 's', 'User Updated Successfully');
} else {
r2(getUrl('customers/edit/') . $id, 'e', $msg);
r2(U . 'customers/edit/' . $id, 'e', $msg);
}
break;
@ -861,7 +856,7 @@ switch ($action) {
if (_post('export', '') == 'csv') {
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('customers'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'customers', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$d = $query->findMany();
$h = false;
@ -913,6 +908,6 @@ switch ($action) {
$ui->assign('order_pos', $order_pos[$order]);
$ui->assign('orderby', $orderby);
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
$ui->display('admin/customers/list.tpl');
$ui->display('customers.tpl');
break;
}

View File

@ -38,9 +38,9 @@ switch ($action) {
});
}
if(file_put_contents($fieldPath, json_encode($datas))){
r2(getUrl('customfield'), 's', 'Successfully saved custom fields!');
r2(U . 'customfield', 's', 'Successfully saved custom fields!');
}else{
r2(getUrl('customfield'), 'e', 'Failed to save custom fields!');
r2(U . 'customfield', 'e', 'Failed to save custom fields!');
}
default:
$fields = [];
@ -48,6 +48,6 @@ switch ($action) {
$fields = json_decode(file_get_contents($fieldPath), true);
}
$ui->assign('fields', $fields);
$ui->display('admin/settings/customfield.tpl');
$ui->display('customfield.tpl');
break;
}

View File

@ -1,66 +1,233 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
**/
_admin();
$ui->assign('_title', Lang::T('Dashboard'));
$ui->assign('_admin', $admin);
if (isset($_GET['refresh'])) {
$files = scandir($CACHE_PATH);
foreach ($files as $file) {
$ext = pathinfo($file, PATHINFO_EXTENSION);
if (is_file($CACHE_PATH . DIRECTORY_SEPARATOR . $file) && $ext == 'temp') {
unlink($CACHE_PATH . DIRECTORY_SEPARATOR . $file);
}
}
r2(getUrl('dashboard'), 's', 'Data Refreshed');
}
$tipeUser = _req("user");
if (empty($tipeUser)) {
$tipeUser = 'Admin';
}
$ui->assign('tipeUser', $tipeUser);
$reset_day = $config['reset_day'];
if (empty($reset_day)) {
$reset_day = 1;
}
//first day of month
if (date("d") >= $reset_day) {
$start_date = date('Y-m-' . $reset_day);
} else {
$start_date = date('Y-m-' . $reset_day, strtotime("-1 MONTH"));
}
$current_date = date('Y-m-d');
$ui->assign('start_date', $start_date);
$ui->assign('current_date', $current_date);
$tipeUser = $admin['user_type'];
if (in_array($tipeUser, ['SuperAdmin', 'Admin'])) {
$tipeUser = 'Admin';
}
$widgets = ORM::for_table('tbl_widgets')->where("enabled", 1)->where('user', $tipeUser)->order_by_asc("orders")->findArray();
$count = count($widgets);
for ($i = 0; $i < $count; $i++) {
try{
if(file_exists($WIDGET_PATH . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php")){
require_once $WIDGET_PATH . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php";
$widgets[$i]['content'] = (new $widgets[$i]['widget'])->getWidget($widgets[$i]);
}else{
$widgets[$i]['content'] = "Widget not found";
}
} catch (Throwable $e) {
$widgets[$i]['content'] = $e->getMessage();
}
}
$ui->assign('widgets', $widgets);
run_hook('view_dashboard'); #HOOK
$ui->display('admin/dashboard.tpl');
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
**/
_admin();
$ui->assign('_title', Lang::T('Dashboard'));
$ui->assign('_admin', $admin);
if (isset($_GET['refresh'])) {
$files = scandir($CACHE_PATH);
foreach ($files as $file) {
$ext = pathinfo($file, PATHINFO_EXTENSION);
if (is_file($CACHE_PATH . DIRECTORY_SEPARATOR . $file) && $ext == 'temp') {
unlink($CACHE_PATH . DIRECTORY_SEPARATOR . $file);
}
}
r2(U . 'dashboard', 's', 'Data Refreshed');
}
$reset_day = $config['reset_day'];
if (empty($reset_day)) {
$reset_day = 1;
}
//first day of month
if (date("d") >= $reset_day) {
$start_date = date('Y-m-' . $reset_day);
} else {
$start_date = date('Y-m-' . $reset_day, strtotime("-1 MONTH"));
}
$current_date = date('Y-m-d');
$month_n = date('n');
$iday = ORM::for_table('tbl_transactions')
->where('recharged_on', $current_date)
->where_not_equal('method', 'Customer - Balance')
->where_not_equal('method', 'Recharge Balance - Administrator')
->sum('price');
if ($iday == '') {
$iday = '0.00';
}
$ui->assign('iday', $iday);
$imonth = ORM::for_table('tbl_transactions')
->where_not_equal('method', 'Customer - Balance')
->where_not_equal('method', 'Recharge Balance - Administrator')
->where_gte('recharged_on', $start_date)
->where_lte('recharged_on', $current_date)->sum('price');
if ($imonth == '') {
$imonth = '0.00';
}
$ui->assign('imonth', $imonth);
if ($config['enable_balance'] == 'yes'){
$cb = ORM::for_table('tbl_customers')->whereGte('balance', 0)->sum('balance');
$ui->assign('cb', $cb);
}
$u_act = ORM::for_table('tbl_user_recharges')->where('status', 'on')->count();
if (empty($u_act)) {
$u_act = '0';
}
$ui->assign('u_act', $u_act);
$u_all = ORM::for_table('tbl_user_recharges')->count();
if (empty($u_all)) {
$u_all = '0';
}
$ui->assign('u_all', $u_all);
$c_all = ORM::for_table('tbl_customers')->count();
if (empty($c_all)) {
$c_all = '0';
}
$ui->assign('c_all', $c_all);
if ($config['hide_uet'] != 'yes') {
//user expire
$query = ORM::for_table('tbl_user_recharges')
->where_lte('expiration', $current_date)
->order_by_desc('expiration');
$expire = Paginator::findMany($query);
// Get the total count of expired records for pagination
$totalCount = ORM::for_table('tbl_user_recharges')
->where_lte('expiration', $current_date)
->count();
// Pass the total count and current page to the paginator
$paginator['total_count'] = $totalCount;
// Assign the pagination HTML to the template variable
$ui->assign('expire', $expire);
}
//activity log
$dlog = ORM::for_table('tbl_logs')->limit(5)->order_by_desc('id')->find_many();
$ui->assign('dlog', $dlog);
$log = ORM::for_table('tbl_logs')->count();
$ui->assign('log', $log);
if ($config['hide_vs'] != 'yes') {
$cacheStocksfile = $CACHE_PATH . File::pathFixer('/VoucherStocks.temp');
$cachePlanfile = $CACHE_PATH . File::pathFixer('/VoucherPlans.temp');
//Cache for 5 minutes
if (file_exists($cacheStocksfile) && time() - filemtime($cacheStocksfile) < 600) {
$stocks = json_decode(file_get_contents($cacheStocksfile), true);
$plans = json_decode(file_get_contents($cachePlanfile), true);
} else {
// Count stock
$tmp = $v = ORM::for_table('tbl_plans')->select('id')->select('name_plan')->find_many();
$plans = array();
$stocks = array("used" => 0, "unused" => 0);
$n = 0;
foreach ($tmp as $plan) {
$unused = ORM::for_table('tbl_voucher')
->where('id_plan', $plan['id'])
->where('status', 0)->count();
$used = ORM::for_table('tbl_voucher')
->where('id_plan', $plan['id'])
->where('status', 1)->count();
if ($unused > 0 || $used > 0) {
$plans[$n]['name_plan'] = $plan['name_plan'];
$plans[$n]['unused'] = $unused;
$plans[$n]['used'] = $used;
$stocks["unused"] += $unused;
$stocks["used"] += $used;
$n++;
}
}
file_put_contents($cacheStocksfile, json_encode($stocks));
file_put_contents($cachePlanfile, json_encode($plans));
}
}
$cacheMRfile = File::pathFixer('/monthlyRegistered.temp');
//Cache for 1 hour
if (file_exists($cacheMRfile) && time() - filemtime($cacheMRfile) < 3600) {
$monthlyRegistered = json_decode(file_get_contents($cacheMRfile), true);
} else {
//Monthly Registered Customers
$result = ORM::for_table('tbl_customers')
->select_expr('MONTH(created_at)', 'month')
->select_expr('COUNT(*)', 'count')
->where_raw('YEAR(created_at) = YEAR(NOW())')
->group_by_expr('MONTH(created_at)')
->find_many();
$monthlyRegistered = [];
foreach ($result as $row) {
$monthlyRegistered[] = [
'date' => $row->month,
'count' => $row->count
];
}
file_put_contents($cacheMRfile, json_encode($monthlyRegistered));
}
$cacheMSfile = $CACHE_PATH . File::pathFixer('/monthlySales.temp');
//Cache for 12 hours
if (file_exists($cacheMSfile) && time() - filemtime($cacheMSfile) < 43200) {
$monthlySales = json_decode(file_get_contents($cacheMSfile), true);
} else {
// Query to retrieve monthly data
$results = ORM::for_table('tbl_transactions')
->select_expr('MONTH(recharged_on)', 'month')
->select_expr('SUM(price)', 'total')
->where_raw("YEAR(recharged_on) = YEAR(CURRENT_DATE())") // Filter by the current year
->where_not_equal('method', 'Customer - Balance')
->where_not_equal('method', 'Recharge Balance - Administrator')
->group_by_expr('MONTH(recharged_on)')
->find_many();
// Create an array to hold the monthly sales data
$monthlySales = array();
// Iterate over the results and populate the array
foreach ($results as $result) {
$month = $result->month;
$totalSales = $result->total;
$monthlySales[$month] = array(
'month' => $month,
'totalSales' => $totalSales
);
}
// Fill in missing months with zero sales
for ($month = 1; $month <= 12; $month++) {
if (!isset($monthlySales[$month])) {
$monthlySales[$month] = array(
'month' => $month,
'totalSales' => 0
);
}
}
// Sort the array by month
ksort($monthlySales);
// Reindex the array
$monthlySales = array_values($monthlySales);
file_put_contents($cacheMSfile, json_encode($monthlySales));
}
if ($config['router_check']) {
$routeroffs = ORM::for_table('tbl_routers')->selects(['id', 'name', 'last_seen'])->where('status', 'Offline')->where('enabled', '1')->order_by_desc('name')->find_array();
$ui->assign('routeroffs', $routeroffs);
}
$timestampFile = "$UPLOAD_PATH/cron_last_run.txt";
if (file_exists($timestampFile)) {
$lastRunTime = file_get_contents($timestampFile);
$ui->assign('run_date', date('Y-m-d h:i:s A', $lastRunTime));
}
// Assign the monthly sales data to Smarty
$ui->assign('start_date', $start_date);
$ui->assign('current_date', $current_date);
$ui->assign('monthlySales', $monthlySales);
$ui->assign('xfooter', '');
$ui->assign('monthlyRegistered', $monthlyRegistered);
$ui->assign('stocks', $stocks);
$ui->assign('plans', $plans);
run_hook('view_dashboard'); #HOOK
$ui->display('dashboard.tpl');

View File

@ -5,13 +5,9 @@
**/
if(Admin::getID()){
//r2(getUrl('dashboard'));
$handler = 'dashboard';
}else if(User::getID()){
//r2(getUrl('home'));
$handler = 'home';
r2(U.'dashboard');
}if(User::getID()){
r2(U.'home');
}else{
//r2(getUrl('login'));
$handler = 'login';
r2(U.'login');
}
include($root_path . File::pathFixer('system/controllers/' . $handler . '.php'));

View File

@ -71,8 +71,8 @@ switch ($action) {
if (count($plns) > 0) {
$query->where_in('plan_name', $plns);
}
$x = $query->find_array();
$xy = $query->sum('price');
$x = $query->find_array();
$xy = $query->sum('price');
$ui->assign('sd', $sd);
$ui->assign('ed', $ed);
@ -83,7 +83,7 @@ switch ($action) {
$ui->assign('mdate', $mdate);
$ui->assign('recharged_on', $mdate);
run_hook('print_by_date'); #HOOK
$ui->display('admin/print/by-date.tpl');
$ui->display('print-by-date.tpl');
break;
case 'pdf-by-date':
@ -114,10 +114,7 @@ switch ($action) {
$query = ORM::for_table('tbl_transactions')
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) >= " . strtotime("$sd $ts"))
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) <= " . strtotime("$ed $te"))
->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
->select('tbl_transactions.*')
->select('tbl_customers.fullname', 'fullname')
->order_by_desc('tbl_transactions.id');
->order_by_desc('id');
if (count($tps) > 0) {
$query->where_in('type', $tps);
}
@ -134,13 +131,13 @@ switch ($action) {
if (count($plns) > 0) {
$query->where_in('plan_name', $plns);
}
$x = $query->find_array();
$xy = $query->sum('price');
$x = $query->find_array();
$xy = $query->sum('price');
$title = ' Reports [' . $mdate . ']';
$title = str_replace('-', ' ', $title);
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
if (file_exists($UPLOAD_PATH . '/logo.png')) {
$logo = $UPLOAD_URL_PATH . '/logo.png';
} else {
@ -157,11 +154,10 @@ switch ($action) {
</div>
<div id="logo"><img id="image" src="' . $logo . '" alt="logo" /></div>
</div>
<div id="header">' . Lang::T('All Transactions at Date') . ': ' . Lang::dateAndTimeFormat($sd, $ts) . ' - ' . Lang::dateAndTimeFormat($ed, $te) . '</div>
<div id="header">' . Lang::T('All Transactions at Date') . ': ' . Lang::dateAndTimeFormat($sd, $ts) .' - '. Lang::dateAndTimeFormat($ed, $te) . '</div>
<table id="customers">
<tr>
<th>' . Lang::T('Username') . '</th>
<th>' . Lang::T('Fullname') . '</th>
<th>' . Lang::T('Plan Name') . '</th>
<th>' . Lang::T('Type') . '</th>
<th>' . Lang::T('Plan Price') . '</th>
@ -174,7 +170,6 @@ switch ($action) {
foreach ($x as $value) {
$username = $value['username'];
$fullname = $value['fullname'];
$plan_name = $value['plan_name'];
$type = $value['type'];
$price = $config['currency_code'] . ' ' . number_format($value['price'], 0, $config['dec_point'], $config['thousands_sep']);
@ -186,7 +181,6 @@ switch ($action) {
$html .= "<tr" . (($c = !$c) ? ' class="alt"' : ' class=""') . ">" . "
<td>$username</td>
<td>$fullname</td>
<td>$plan_name</td>
<td>$type</td>
<td align='right'>$price</td>
@ -251,7 +245,7 @@ $style
$html
EOF;
$mpdf->WriteHTML($nhtml);
$mpdf->Output('phpnuxbill_reports_' . date('Ymd_His') . '.pdf', 'D');
$mpdf->Output('phpnuxbill_reports_'.date('Ymd_His') . '.pdf', 'D');
} else {
echo 'No Data';
}
@ -264,17 +258,13 @@ EOF;
$stype = _post('stype');
$d = ORM::for_table('tbl_transactions');
$d->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
->select('tbl_transactions.*')
->select('tbl_customers.fullname', 'fullname')
->order_by_desc('tbl_transactions.id');
if ($stype != '') {
$d->where('type', $stype);
}
$d->where_gte('recharged_on', $fdate);
$d->where_lte('recharged_on', $tdate);
$d->order_by_desc('id');
$x = $d->find_many();
$x = $d->find_many();
$dr = ORM::for_table('tbl_transactions');
if ($stype != '') {
@ -291,7 +281,7 @@ EOF;
$ui->assign('tdate', $tdate);
$ui->assign('stype', $stype);
run_hook('print_by_period'); #HOOK
$ui->display('admin/print/by-period.tpl');
$ui->display('print-by-period.tpl');
break;
@ -300,10 +290,6 @@ EOF;
$tdate = _post('tdate');
$stype = _post('stype');
$d = ORM::for_table('tbl_transactions');
$d->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
->select('tbl_transactions.*')
->select('tbl_customers.fullname', 'fullname')
->order_by_desc('tbl_transactions.id');
if ($stype != '') {
$d->where('type', $stype);
}
@ -311,7 +297,7 @@ EOF;
$d->where_gte('recharged_on', $fdate);
$d->where_lte('recharged_on', $tdate);
$d->order_by_desc('id');
$x = $d->find_many();
$x = $d->find_many();
$dr = ORM::for_table('tbl_transactions');
if ($stype != '') {
@ -325,7 +311,7 @@ EOF;
$title = ' Reports [' . $mdate . ']';
$title = str_replace('-', ' ', $title);
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
if (file_exists($UPLOAD_PATH . '/logo.png')) {
$logo = $UPLOAD_URL_PATH . '/logo.png';
} else {
@ -346,7 +332,6 @@ EOF;
<table id="customers">
<tr>
<th>' . Lang::T('Username') . '</th>
<th>' . Lang::T('Fullname') . '</th>
<th>' . Lang::T('Plan Name') . '</th>
<th>' . Lang::T('Type') . '</th>
<th>' . Lang::T('Plan Price') . '</th>
@ -359,7 +344,6 @@ EOF;
foreach ($x as $value) {
$username = $value['username'];
$fullname = $value['fullname'];
$plan_name = $value['plan_name'];
$type = $value['type'];
$price = $config['currency_code'] . ' ' . number_format($value['price'], 0, $config['dec_point'], $config['thousands_sep']);
@ -371,8 +355,7 @@ EOF;
$html .= "<tr" . (($c = !$c) ? ' class="alt"' : ' class=""') . ">" . "
<td>$username</td>
<td>$fullname</td>
<td>$plan_name</td>
<td>$plan_name</td>
<td>$type</td>
<td align='right'>$price</td>
<td>$recharged_on </td>
@ -444,5 +427,5 @@ EOF;
break;
default:
$ui->display('admin/404.tpl');
$ui->display('a404.tpl');
}

View File

@ -82,16 +82,16 @@ if ($step == 1) {
}
setcookie('forgot_username', '', time() - 3600, '/');
} else {
r2(getUrl('forgot&step=1'), 'e', Lang::T('Invalid Username or Verification Code'));
r2(U . 'forgot&step=1', 'e', Lang::T('Invalid Username or Verification Code'));
}
} else {
if (file_exists($otpPath)) {
unlink($otpPath);
}
r2(getUrl('forgot&step=1'), 'e', Lang::T('Invalid Username or Verification Code'));
r2(U . 'forgot&step=1', 'e', Lang::T('Invalid Username or Verification Code'));
}
} else {
r2(getUrl('forgot&step=1'), 'e', Lang::T('Invalid Username or Verification Code'));
r2(U . 'forgot&step=1', 'e', Lang::T('Invalid Username or Verification Code'));
}
} else if ($step == 7) {
$find = _post('find');

View File

@ -23,18 +23,18 @@ if (_post('send') == 'balance') {
}
$target = ORM::for_table('tbl_customers')->where('username', _post('username'))->find_one();
if (!$target) {
r2(getUrl('home'), 'd', Lang::T('Username not found'));
r2(U . 'home', 'd', Lang::T('Username not found'));
}
$username = _post('username');
$balance = _post('balance');
if ($user['balance'] < $balance) {
r2(getUrl('home'), 'd', Lang::T('insufficient balance'));
r2(U . 'home', 'd', Lang::T('insufficient balance'));
}
if (!empty($config['minimum_transfer']) && intval($balance) < intval($config['minimum_transfer'])) {
r2(getUrl('home'), 'd', Lang::T('Minimum Transfer') . ' ' . Lang::moneyFormat($config['minimum_transfer']));
r2(U . 'home', 'd', Lang::T('Minimum Transfer') . ' ' . Lang::moneyFormat($config['minimum_transfer']));
}
if ($user['username'] == $target['username']) {
r2(getUrl('home'), 'd', Lang::T('Cannot send to yourself'));
r2(U . 'home', 'd', Lang::T('Cannot send to yourself'));
}
if (Balance::transfer($user['id'], $username, $balance)) {
//sender
@ -75,10 +75,10 @@ if (_post('send') == 'balance') {
Message::sendBalanceNotification($user, $target, $balance, ($user['balance'] - $balance), Lang::getNotifText('balance_send'), $config['user_notification_payment']);
Message::sendBalanceNotification($target, $user, $balance, ($target['balance'] + $balance), Lang::getNotifText('balance_received'), $config['user_notification_payment']);
Message::sendTelegram("#u$user[username] send balance to #u$target[username] \n" . Lang::moneyFormat($balance));
r2(getUrl('home'), 's', Lang::T('Sending balance success'));
r2(U . 'home', 's', Lang::T('Sending balance success'));
}
} else {
r2(getUrl('home'), 'd', Lang::T('Failed, balance is not available'));
r2(U . 'home', 'd', Lang::T('Failed, balance is not available'));
}
} else if (_post('send') == 'plan') {
if ($user['status'] != 'Active') {
@ -90,12 +90,13 @@ if (_post('send') == 'balance') {
foreach ($actives as $active) {
$router = ORM::for_table('tbl_routers')->where('name', $active['routers'])->find_one();
if ($router) {
r2(getUrl('order/send/$router[id]/$active[plan_id]&u=') . trim(_post('username')), 's', Lang::T('Review package before recharge'));
r2(U . "order/send/$router[id]/$active[plan_id]&u=" . trim(_post('username')), 's', Lang::T('Review package before recharge'));
}
}
r2(getUrl('home'), 'w', Lang::T('Your friend do not have active package'));
r2(U . 'home', 'w', Lang::T('Your friend do not have active package'));
}
$_bill = User::_billing();
$ui->assign('_bills', $_bill);
// Sync plan to router
if (isset($_GET['sync']) && !empty($_GET['sync'])) {
@ -127,7 +128,7 @@ if (isset($_GET['sync']) && !empty($_GET['sync'])) {
}
}
}
r2(getUrl('home'), 's', $log);
r2(U . 'home', 's', $log);
}
if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
@ -135,7 +136,7 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
}
if (!empty(App::getTokenValue(_get('stoken')))) {
r2(getUrl('voucher/invoice/'));
r2(U . "voucher/invoice/");
die();
}
$bill = ORM::for_table('tbl_user_recharges')->where('id', $_GET['recharge'])->where('username', $user['username'])->findOne();
@ -146,17 +147,17 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
$routers = ORM::for_table('tbl_routers')->where('name', $bill['routers'])->find_one();
$router = $routers['id'];
}
r2(getUrl("order/gateway/$router/$bill[plan_id]"));
r2(U. "order/gateway/$router/$bill[plan_id]");
}
} else if (!empty(_get('extend'))) {
if ($user['status'] != 'Active') {
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
}
if (!$config['extend_expired']) {
r2(getUrl('home'), 'e', "cannot extend");
r2(U . 'home', 'e', "cannot extend");
}
if (!empty(App::getTokenValue(_get('stoken')))) {
r2(getUrl('home'), 'e', "You already extend");
r2(U . 'home', 'e', "You already extend");
}
$id = _get('extend');
$tur = ORM::for_table('tbl_user_recharges')->where('customer_id', $user['id'])->where('id', $id)->find_one();
@ -171,7 +172,7 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
// is already extend
$last = file_get_contents($path);
if ($last == $m) {
r2(getUrl('home'), 'e', "You already extend for this month");
r2(U . 'home', 'e', "You already extend for this month");
}
}
if ($tur['status'] != 'on') {
@ -196,17 +197,17 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
$tur->save();
App::setToken(_get('stoken'), $id);
file_put_contents($path, $m);
_log("Customer $tur[customer_id] $user[fullname] ($tur[username]) extend for $days days", "Customer", $user['id']);
Message::sendTelegram("#u$user[username] ($user[fullname]) #id$tur[customer_id] #extend #" . $p['type'] . " \n" . $p['name_plan'] .
_log("Customer $tur[customer_id] $tur[username] extend for $days days", "Customer", $user['id']);
Message::sendTelegram("#u$user[username] #extend #" . $p['type'] . " \n" . $p['name_plan'] .
"\nLocation: " . $p['routers'] .
"\nCustomer: " . $user['fullname'] .
"\nNew Expired: " . Lang::dateAndTimeFormat($expiration, $tur['time']));
r2(getUrl('home'), 's', "Extend until $expiration");
r2(U . 'home', 's', "Extend until $expiration");
} else {
r2(getUrl('home'), 'e', "Plan is not expired");
r2(U . 'home', 'e', "Plan is not expired");
}
} else {
r2(getUrl('home'), 'e', "Plan Not Found or Not Active");
r2(U . 'home', 'e', "Plan Not Found or Not Active");
}
} else if (isset($_GET['deactivate']) && !empty($_GET['deactivate'])) {
$bill = ORM::for_table('tbl_user_recharges')->where('id', $_GET['deactivate'])->where('username', $user['username'])->findOne();
@ -227,9 +228,9 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
$bill->save();
_log('User ' . $bill['username'] . ' Deactivate ' . $bill['namebp'], 'Customer', $bill['customer_id']);
Message::sendTelegram('User u' . $bill['username'] . ' Deactivate ' . $bill['namebp']);
r2(getUrl('home'), 's', 'Success deactivate ' . $bill['namebp']);
r2(U . 'home', 's', 'Success deactivate ' . $bill['namebp']);
} else {
r2(getUrl('home'), 'e', 'No Active Plan');
r2(U . 'home', 'e', 'No Active Plan');
}
}
@ -244,10 +245,10 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && $_c['hs_auth_m
require_once $dvc;
if ($_GET['mikrotik'] == 'login') {
(new $p['device'])->connect_customer($user, $_SESSION['nux-ip'], $_SESSION['nux-mac'], $bill['routers']);
r2(getUrl('home'), 's', Lang::T('Login Request successfully'));
r2(U . 'home', 's', Lang::T('Login Request successfully'));
} else if ($_GET['mikrotik'] == 'logout') {
(new $p['device'])->disconnect_customer($user, $bill['routers']);
r2(getUrl('home'), 's', Lang::T('Logout Request successfully'));
r2(U . 'home', 's', Lang::T('Logout Request successfully'));
}
} else {
new Exception(Lang::T("Devices Not Found"));
@ -268,16 +269,16 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && !empty($_SESSI
$ui->assign('logged', $_GET['logged']);
if ($_app_stage != 'demo') {
if ($_GET['mikrotik'] == 'login') {
r2(getUrl('home&hchap=true'), 's', Lang::T('Login Request successfully'));
r2(U . 'home&hchap=true', 's', Lang::T('Login Request successfully'));
}
$getmsg = $_GET['msg'];
///get auth notification from mikrotik
if ($getmsg == 'Connected') {
$msg .= Lang::T($getmsg);
r2(getUrl('home&logged=1'), 's', $msg);
r2(U . 'home&logged=1', 's', $msg);
} else if ($getmsg) {
$msg .= Lang::T($getmsg);
r2(getUrl('home'), 's', $msg);
r2(U . 'home', 's', $msg);
}
}
}
@ -295,39 +296,60 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && !empty($_SESSI
$ui->assign('logged', $_GET['logged']);
if ($_app_stage != 'demo') {
if ($_GET['mikrotik'] == 'login') {
r2(getUrl('home&hchap=true'), 's', Lang::T('Login Request successfully'));
r2(U . 'home&hchap=true', 's', Lang::T('Login Request successfully'));
}
$getmsg = $_GET['msg'];
///get auth notification from mikrotik
if ($getmsg == 'Connected') {
$msg .= Lang::T($getmsg);
r2(getUrl('home&logged=1'), 's', $msg);
r2(U . 'home&logged=1', 's', $msg);
} else if ($getmsg) {
$msg .= Lang::T($getmsg);
r2(getUrl('home'), 's', $msg);
r2(U . 'home', 's', $msg);
}
}
}
$tcf = ORM::for_table('tbl_customers_fields')
->where('customer_id', $user['id'])
->find_many();
$vpn = ORM::for_table('tbl_port_pool')
->find_one();
$ui->assign('cf', $tcf);
$ui->assign('vpn', $vpn);
$widgets = ORM::for_table('tbl_widgets')->where("enabled", 1)->where('user', 'Customer')->order_by_asc("orders")->findArray();
$count = count($widgets);
for ($i = 0; $i < $count; $i++) {
try{
if(file_exists($WIDGET_PATH . DIRECTORY_SEPARATOR . 'customer' . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php")){
require_once $WIDGET_PATH . DIRECTORY_SEPARATOR . 'customer' . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php";
$widgets[$i]['content'] = (new $widgets[$i]['widget'])->getWidget($widgets[$i]);
}else{
$widgets[$i]['content'] = "Widget not found";
$unpaid = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
// check expired payments
if ($unpaid) {
try {
if (strtotime($unpaid['expired_date']) < time()) {
$unpaid->status = 4;
$unpaid->save();
$unpaid = [];
}
} catch (Throwable $e) {
$widgets[$i]['content'] = $e->getMessage();
} catch (Exception $e) {
}
try {
if (strtotime($unpaid['created_date'], "+24 HOUR") < time()) {
$unpaid->status = 4;
$unpaid->save();
$unpaid = [];
}
} catch (Throwable $e) {
} catch (Exception $e) {
}
}
$ui->assign('widgets', $widgets);
$ui->assign('unpaid', $unpaid);
$ui->assign('code', alphanumeric(_get('code'), "-"));
$abills = User::getAttributes("Bill");
$ui->assign('abills', $abills);
run_hook('view_customer_dashboard'); #HOOK
$ui->display('customer/dashboard.tpl');

View File

@ -1,27 +0,0 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
*
**/
_admin();
$ui->assign('_title', Lang::T('Invoice Lists'));
$ui->assign('_system_menu', 'reports');
$action = $routes['1'];
$ui->assign('_admin', $admin);
if (empty($action)) {
$action = 'list';
}
switch ($action) {
case 'list':
$ui->assign('xheader', '<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.3/css/jquery.dataTables.min.css">');
$ui->assign('invoices', Invoice::getAll());
$ui->display('admin/invoices/list.tpl');
break;
default:
$ui->display('admin/404.tpl');
}

View File

@ -11,7 +11,7 @@ if ($maintenance_mode == true) {
}
if (User::getID()) {
r2(getUrl('home'));
r2(U . 'home');
}
if (isset($routes['1'])) {
@ -27,7 +27,7 @@ switch ($do) {
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
_msglog('e', Lang::T('Invalid or Expired CSRF Token'));
r2(getUrl('login'));
r2(U . 'login');
}
run_hook('customer_login'); #HOOK
if ($username != '' and $password != '') {
@ -54,15 +54,15 @@ switch ($do) {
} else {
_msglog('e', Lang::T('Invalid Username or Password'));
_log($username . ' ' . Lang::T('Failed Login'), 'User');
r2(getUrl('login'));
r2(U . 'login');
}
} else {
_msglog('e', Lang::T('Invalid Username or Password'));
r2(getUrl('login'));
r2(U . 'login');
}
} else {
_msglog('e', Lang::T('Invalid Username or Password'));
r2(getUrl('login'));
r2(U . 'login');
}
break;
@ -72,7 +72,7 @@ switch ($do) {
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
_msglog('e', Lang::T('Invalid or Expired CSRF Token'));
r2(getUrl('login'));
r2(U . 'login');
}
$voucher = Text::alphanumeric(_post('voucher_only'), "-_.,");
$tur = ORM::for_table('tbl_user_recharges')
@ -103,7 +103,7 @@ switch ($do) {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
} else {
new Exception(Lang::T("Devices Not Found"));
@ -112,7 +112,7 @@ switch ($do) {
if (!empty($config['voucher_redirect'])) {
_alert(Lang::T("Voucher activation success, now you can login"), 'danger', $config['voucher_redirect']);
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, you are connected to internet"));
r2(U . "login", 's', Lang::T("Voucher activation success, you are connected to internet"));
}
} else {
_alert(Lang::T('Internet Plan Expired'), 'danger', "login");
@ -148,7 +148,7 @@ switch ($do) {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
} else {
new Exception(Lang::T("Devices Not Found"));
@ -157,7 +157,7 @@ switch ($do) {
if (!empty($config['voucher_redirect'])) {
_alert(Lang::T("Voucher activation success, now you can login"), 'danger', $config['voucher_redirect']);
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, you are connected to internet"));
r2(U . "login", 's', Lang::T("Voucher activation success, you are connected to internet"));
}
} else {
_alert(Lang::T('Internet Plan Expired'), 'danger', "login");
@ -190,11 +190,11 @@ switch ($do) {
if ($d->save()) {
$user = ORM::for_table('tbl_customers')->where('username', $username)->find_one($d->id());
if (!$user) {
r2(getUrl('login'), 'e', Lang::T('Voucher activation failed'));
r2(U . 'login', 'e', Lang::T('Voucher activation failed'));
}
} else {
_alert(Lang::T('Login Successful'), 'success', "dashboard");
r2(getUrl('login'), 'e', Lang::T('Voucher activation failed') . '.');
r2(U . 'login', 'e', Lang::T('Voucher activation failed') . '.');
}
}
if ($v1['status'] == 0) {
@ -222,7 +222,7 @@ switch ($do) {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
} else {
new Exception(Lang::T("Devices Not Found"));
@ -231,26 +231,26 @@ switch ($do) {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, you are connected to internet"));
r2(U . "login", 's', Lang::T("Voucher activation success, you are connected to internet"));
}
} catch (Exception $e) {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
}
}
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
} else {
// if failed to recharge, restore old password
$user->password = $oldPass;
$user->save();
r2(getUrl('login'), 'e', Lang::T("Failed to activate voucher"));
r2(U . 'login', 'e', Lang::T("Failed to activate voucher"));
}
} else {
// used voucher
@ -269,7 +269,7 @@ switch ($do) {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
} else {
new Exception(Lang::T("Devices Not Found"));
@ -278,30 +278,30 @@ switch ($do) {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
} catch (Exception $e) {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
}
} else {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
} else {
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
}
} else {
// voucher used by other customer
r2(getUrl('login'), 'e', Lang::T('Voucher Not Valid'));
r2(U . 'login', 'e', Lang::T('Voucher Not Valid'));
}
}
} else {
_msglog('e', Lang::T('Invalid Username or Password'));
r2(getUrl('login'));
r2(U . 'login');
}
}
default:

View File

@ -80,45 +80,12 @@ switch ($action) {
}
break;
case 'message-csv':
$logs = ORM::for_table('tbl_message_logs')
->select('id')
->select('message_type')
->select('recipient')
->select('message_content')
->select('status')
->select('error_message')
->select('sent_at')
->order_by_asc('id')->find_array();
$h = false;
set_time_limit(-1);
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-type: text/csv");
header('Content-Disposition: attachment;filename="message-logs_' . date('Y-m-d_H_i') . '.csv"');
header('Content-Transfer-Encoding: binary');
foreach ($logs as $log) {
$ks = [];
$vs = [];
foreach ($log as $k => $v) {
$ks[] = $k;
$vs[] = $v;
}
if (!$h) {
echo '"' . implode('";"', $ks) . "\"\n";
$h = true;
}
echo '"' . implode('";"', $vs) . "\"\n";
}
break;
case 'list':
$q = (_post('q') ? _post('q') : _get('q'));
$keep = _post('keep');
if (!empty($keep)) {
ORM::raw_execute("DELETE FROM tbl_logs WHERE UNIX_TIMESTAMP(date) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))");
r2(getUrl('logs/list/'), 's', "Delete logs older than $keep days");
r2(U . "logs/list/", 's', "Delete logs older than $keep days");
}
if ($q != '') {
$query = ORM::for_table('tbl_logs')->where_like('description', '%' . $q . '%')->order_by_desc('id');
@ -130,14 +97,14 @@ switch ($action) {
$ui->assign('d', $d);
$ui->assign('q', $q);
$ui->display('admin/logs/system.tpl');
$ui->display('logs.tpl');
break;
case 'radius':
$q = (_post('q') ? _post('q') : _get('q'));
$keep = _post('keep');
if (!empty($keep)) {
ORM::raw_execute("DELETE FROM radpostauth WHERE UNIX_TIMESTAMP(authdate) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))", [], 'radius');
r2(getUrl('logs/radius/'), 's', "Delete logs older than $keep days");
r2(U . "logs/radius/", 's', "Delete logs older than $keep days");
}
if ($q != '') {
$query = ORM::for_table('radpostauth', 'radius')->where_like('username', '%' . $q . '%')->order_by_desc('id');
@ -149,37 +116,10 @@ switch ($action) {
$ui->assign('d', $d);
$ui->assign('q', $q);
$ui->display('admin/logs/radius.tpl');
$ui->display('logs-radius.tpl');
break;
case 'message':
$q = _post('q') ?: _get('q');
$keep = (int) _post('keep');
if (!empty($keep)) {
ORM::raw_execute("DELETE FROM tbl_message_logs WHERE UNIX_TIMESTAMP(sent_at) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))");
r2(getUrl('logs/message/'), 's', "Deleted logs older than $keep days");
}
if ($q !== null && $q !== '') {
$query = ORM::for_table('tbl_message_logs')
->whereRaw("message_type LIKE '%$q%' OR recipient LIKE '%$q%' OR message_content LIKE '%$q%' OR status LIKE '%$q%' OR error_message LIKE '%$q%'")
->order_by_desc('sent_at');
$d = Paginator::findMany($query, ['q' => $q]);
} else {
$query = ORM::for_table('tbl_message_logs')->order_by_desc('sent_at');
$d = Paginator::findMany($query);
}
if ($d) {
$ui->assign('d', $d);
} else {
$ui->assign('d', []);
}
$ui->assign('q', $q);
$ui->display('admin/logs/message.tpl');
break;
default:
r2(getUrl('logs/list/'), 's', '');
r2(U . 'logs/list/', 's', '');
}

View File

@ -14,7 +14,7 @@ switch ($action) {
case 'view':
$mail = ORM::for_table('tbl_customers_inbox')->where('customer_id', $user['id'])->find_one($routes['2']);
if(!$mail){
r2(getUrl('mail'), 'e', Lang::T('Message Not Found'));
r2(U. 'mail', 'e', Lang::T('Message Not Found'));
}
if($mail['date_read'] == null){
$mail->date_read = date('Y-m-d H:i:s');
@ -34,9 +34,9 @@ switch ($action) {
case 'delete':
if($routes['2']){
if(ORM::for_table('tbl_customers_inbox')->where('customer_id', $user['id'])->where('id', $routes['2'])->find_one()->delete()){
r2(getUrl('mail'), 's', Lang::T('Mail Deleted Successfully'));
r2(U. 'mail', 's', Lang::T('Mail Deleted Successfully'));
}else{
r2(getUrl('home'), 'e', Lang::T('Failed to Delete Message'));
r2(U. 'home', 'e', Lang::T('Failed to Delete Message'));
}
break;
}

View File

@ -15,9 +15,6 @@ if (empty($action)) {
$action = 'customer';
}
$ui->assign('xheader', '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">');
$ui->assign('xfooter', '<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>');
switch ($action) {
case 'customer':
if(!empty(_req('search'))){
@ -45,23 +42,13 @@ switch ($action) {
}
$ui->assign('search', $search);
$ui->assign('customers', $customerData);
$ui->assign('xheader', '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">');
$ui->assign('_title', Lang::T('Customer Geo Location Information'));
$ui->display('admin/maps/customers.tpl');
$ui->assign('xfooter', '<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>');
$ui->display('customers-map.tpl');
break;
case 'routers':
$name = _post('name');
$query = ORM::for_table('tbl_routers')->where_not_equal('coordinates', '')->order_by_desc('id');
$query->selects(['id', 'name', 'coordinates', 'description', 'coverage', 'enabled']);
if ($name != '') {
$query->where_like('name', '%' . $name . '%');
}
$d = Paginator::findMany($query, ['name' => $name], '20', '', true);
$ui->assign('name', $name);
$ui->assign('d', $d);
$ui->assign('_title', Lang::T('Routers Geo Location Information'));
$ui->display('admin/maps/routers.tpl');
break;
default:
r2(getUrl('map/customer'), 'e', 'action not defined');
r2(U . 'map/customer', 'e', 'action not defined');
break;
}

View File

@ -22,8 +22,6 @@ switch ($action) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$appUrl = APP_URL;
$select2_customer = <<<EOT
<script>
document.addEventListener("DOMContentLoaded", function(event) {
@ -32,9 +30,9 @@ document.addEventListener("DOMContentLoaded", function(event) {
ajax: {
url: function(params) {
if(params.term != undefined){
return '{$appUrl}/?_route=autoload/customer_select2&s='+params.term;
return './?_route=autoload/customer_select2&s='+params.term;
}else{
return '{$appUrl}/?_route=autoload/customer_select2';
return './?_route=autoload/customer_select2';
}
}
}
@ -48,7 +46,7 @@ EOT;
$id = $routes['2'];
$ui->assign('id', $id);
$ui->assign('xfooter', $select2_customer);
$ui->display('admin/message/single.tpl');
$ui->display('message.tpl');
break;
case 'send-post':
@ -57,79 +55,40 @@ EOT;
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$id_customer = $_POST['id_customer'] ?? '';
$message = $_POST['message'] ?? '';
$via = $_POST['via'] ?? '';
$subject = $_POST['subject'] ?? '';
// Get form data
$id_customer = $_POST['id_customer'];
$message = $_POST['message'];
$via = $_POST['via'];
// Validate subject based on the selected channel
if (($via === 'all' || $via === 'email' || $via === 'inbox') && empty($subject)) {
r2(getUrl('message/send'), 'e', LANG::T('Subject is required to send message using') . ' ' . $via . '.');
}
// Check if fields are empty
if ($id_customer == '' or $message == '' or $via == '') {
r2(U . 'message/send', 'e', Lang::T('All field is required'));
} else {
// Get customer details from the database
$c = ORM::for_table('tbl_customers')->find_one($id_customer);
if (empty($id_customer) || empty($message) || empty($via)) {
r2(getUrl('message/send'), 'e', Lang::T('Customer, Message, and Channel are required'));
}
// Replace placeholders in the message with actual values
$message = str_replace('[[name]]', $c['fullname'], $message);
$message = str_replace('[[user_name]]', $c['username'], $message);
$message = str_replace('[[phone]]', $c['phonenumber'], $message);
$message = str_replace('[[company_name]]', $config['CompanyName'], $message);
$customer = ORM::for_table('tbl_customers')->find_one($id_customer);
if (!$customer) {
r2(getUrl('message/send'), 'e', Lang::T('Customer not found'));
}
// Replace placeholders in message and subject
$currentMessage = str_replace(
['[[name]]', '[[user_name]]', '[[phone]]', '[[company_name]]'],
[$customer['fullname'], $customer['username'], $customer['phonenumber'], $config['CompanyName']],
$message
);
//Send the message
if ($via == 'sms' || $via == 'both') {
$smsSent = Message::sendSMS($c['phonenumber'], $message);
}
$currentSubject = str_replace(
['[[name]]', '[[user_name]]', '[[phone]]', '[[company_name]]'],
[$customer['fullname'], $customer['username'], $customer['phonenumber'], $config['CompanyName']],
$subject
);
if ($via == 'wa' || $via == 'both') {
$waSent = Message::sendWhatsapp($c['phonenumber'], $message);
}
if (strpos($message, '[[payment_link]]') !== false) {
$token = User::generateToken($customer['id'], 1);
if (!empty($token['token'])) {
$tur = ORM::for_table('tbl_user_recharges')
->where('customer_id', $customer['id'])
->find_one();
if ($tur) {
$url = '?_route=home&recharge=' . $tur['id'] . '&uid=' . urlencode($token['token']);
$currentMessage = str_replace('[[payment_link]]', $url, $currentMessage);
}
if (isset($smsSent) || isset($waSent)) {
r2(U . 'message/send', 's', Lang::T('Message Sent Successfully'));
} else {
$currentMessage = str_replace('[[payment_link]]', '', $currentMessage);
r2(U . 'message/send', 'e', Lang::T('Failed to send message'));
}
}
// Send the message through the selected channels
$smsSent = $waSent = $emailSent = $inboxSent = false;
if ($via === 'sms' || $via === 'both' || $via === 'all') {
$smsSent = Message::sendSMS($customer['phonenumber'], $currentSubject);
}
if ($via === 'wa' || $via === 'both' || $via === 'all') {
$waSent = Message::sendWhatsapp($customer['phonenumber'], $currentSubject);
}
if ($via === 'email' || $via === 'all') {
$emailSent = Message::sendEmail($customer['email'], $currentSubject, $currentMessage);
}
if ($via === 'inbox' || $via === 'all') {
$inboxSent = Message::addToInbox($customer['id'], $currentSubject, $currentMessage, 'Admin');
}
// Check if any message was sent successfully
if ($smsSent || $waSent || $emailSent || $inboxSent) {
r2(getUrl('message/send'), 's', Lang::T('Message Sent Successfully'));
} else {
r2(getUrl('message/send'), 'e', Lang::T('Failed to send message'));
}
break;
case 'send_bulk':
@ -137,362 +96,143 @@ EOT;
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$ui->assign('routers', ORM::forTable('tbl_routers')->where('enabled', '1')->find_many());
$ui->display('admin/message/bulk.tpl');
break;
// Get form data
$group = $_POST['group'];
$message = $_POST['message'];
$via = $_POST['via'];
$test = isset($_POST['test']) && $_POST['test'] === 'on' ? 'yes' : 'no';
$batch = $_POST['batch'];
$delay = $_POST['delay'];
case 'send_bulk_ajax':
// Check user permissions
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
die(json_encode(['status' => 'error', 'message' => 'Permission denied']));
}
set_time_limit(0);
// Get request parameters
$group = $_REQUEST['group'] ?? '';
$message = $_REQUEST['message'] ?? '';
$via = $_REQUEST['via'] ?? '';
$batch = $_REQUEST['batch'] ?? 100;
$page = $_REQUEST['page'] ?? 0;
$router = $_REQUEST['router'] ?? null;
$test = isset($_REQUEST['test']) && $_REQUEST['test'] === 'on';
$service = $_REQUEST['service'] ?? '';
$subject = $_REQUEST['subject'] ?? '';
if (empty($group) || empty($message) || empty($via) || empty($service)) {
die(json_encode(['status' => 'error', 'message' => LANG::T('All fields are required')]));
}
if (in_array($via, ['all', 'email', 'inbox']) && empty($subject)) {
die(json_encode(['status' => 'error', 'message' => LANG::T('Subject is required to send message using') . ' ' . $via . '.']));
}
// Get batch of customers based on group
$startpoint = $page * $batch;
$customers = [];
$totalCustomers = 0;
if (isset($router) && !empty($router)) {
switch ($router) {
case 'radius':
$routerName = 'Radius';
break;
default:
$router = ORM::for_table('tbl_routers')->find_one($router);
if (!$router) {
die(json_encode(['status' => 'error', 'message' => LANG::T('Invalid router')]));
}
$routerName = $router->name;
break;
}
}
if (isset($router) && !empty($router)) {
$query = ORM::for_table('tbl_user_recharges')
->left_outer_join('tbl_customers', 'tbl_user_recharges.customer_id = tbl_customers.id')
->where('tbl_user_recharges.routers', $routerName);
switch ($service) {
case 'all':
break;
default:
$validServices = ['PPPoE', 'Hotspot', 'VPN'];
if (in_array($service, $validServices)) {
$query->where('type', $service);
}
break;
}
$totalCustomers = $query->count();
$query->offset($startpoint)
->limit($batch);
switch ($group) {
case 'all':
break;
case 'new':
$query->where_raw("DATE(recharged_on) >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)");
break;
case 'expired':
$query->where('tbl_user_recharges.status', 'off');
break;
case 'active':
$query->where('tbl_user_recharges.status', 'on');
break;
}
// Fetch the customers
$query->selects([
['tbl_customers.phonenumber', 'phonenumber'],
['tbl_user_recharges.customer_id', 'customer_id'],
['tbl_customers.fullname', 'fullname'],
['tbl_customers.username', 'username'],
['tbl_customers.email', 'email'],
['tbl_customers.service_type', 'service_type'],
]);
$customers = $query->find_array();
} else {
switch ($group) {
case 'all':
$totalCustomersQuery = ORM::for_table('tbl_customers');
switch ($service) {
case 'all':
break;
default:
$validServices = ['PPPoE', 'Hotspot', 'VPN'];
if (in_array($service, $validServices)) {
$totalCustomersQuery->where('service_type', $service);
}
break;
}
$totalCustomers = $totalCustomersQuery->count();
$customers = $totalCustomersQuery->offset($startpoint)->limit($batch)->find_array();
break;
case 'new':
$totalCustomersQuery = ORM::for_table('tbl_customers')
->where_raw("DATE(created_at) >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)");
switch ($service) {
case 'all':
break;
default:
$validServices = ['PPPoE', 'Hotspot', 'VPN'];
if (in_array($service, $validServices)) {
$totalCustomersQuery->where('service_type', $service);
}
break;
}
$totalCustomers = $totalCustomersQuery->count();
$customers = $totalCustomersQuery->offset($startpoint)->limit($batch)->find_array();
break;
case 'expired':
$totalCustomersQuery = ORM::for_table('tbl_user_recharges')
->where('status', 'off');
switch ($service) {
case 'all':
break;
default:
$validServices = ['PPPoE', 'Hotspot', 'VPN'];
if (in_array($service, $validServices)) {
$totalCustomersQuery->where('type', $service);
}
break;
}
$totalCustomers = $totalCustomersQuery->count();
$customers = $totalCustomersQuery->select('customer_id')->offset($startpoint)->limit($batch)->find_array();
break;
case 'active':
$totalCustomersQuery = ORM::for_table('tbl_user_recharges')
->where('status', 'on');
switch ($service) {
case 'all':
break;
default:
$validServices = ['PPPoE', 'Hotspot', 'VPN'];
if (in_array($service, $validServices)) {
$totalCustomersQuery->where('type', $service);
}
break;
}
$totalCustomers = $totalCustomersQuery->count();
$customers = $totalCustomersQuery->select('customer_id')->offset($startpoint)->limit($batch)->find_array(); // Get customer data
break;
}
}
// Ensure $customers is always an array
if (!$customers) {
$customers = [];
}
// Send messages
// Initialize counters
$totalSMSSent = 0;
$totalSMSFailed = 0;
$totalWhatsappSent = 0;
$totalWhatsappFailed = 0;
$totalEmailSent = 0;
$totalEmailFailed = 0;
$totalInboxSent = 0;
$totalInboxFailed = 0;
$batchStatus = [];
//$subject = $config['CompanyName'] . ' ' . Lang::T('Notification Message');
$form = 'Admin';
foreach ($customers as $customer) {
$currentMessage = str_replace(
['[[name]]', '[[user_name]]', '[[phone]]', '[[company_name]]'],
[$customer['fullname'], $customer['username'], $customer['phonenumber'], $config['CompanyName']],
$message
);
$currentSubject = str_replace(
['[[name]]', '[[user_name]]', '[[phone]]', '[[company_name]]'],
[$customer['fullname'], $customer['username'], $customer['phonenumber'], $config['CompanyName']],
$subject
);
$phoneNumber = preg_replace('/\D/', '', $customer['phonenumber']);
if (empty($phoneNumber)) {
$batchStatus[] = [
'name' => $customer['fullname'],
'phone' => '',
'status' => 'No Phone Number'
];
continue;
}
if ($test) {
$batchStatus[] = [
'name' => $customer['fullname'],
'channel' => 'Test Channel',
'status' => 'Test Mode',
'message' => $currentMessage,
'service' => $service,
'router' => $routerName,
];
if (_req('send') == 'now') {
// Check if fields are empty
if ($group == '' || $message == '' || $via == '') {
r2(U . 'message/send_bulk', 'e', Lang::T('All fields are required'));
} else {
if ($via === 'sms' || $via === 'both' || $via === 'all') {
if (Message::sendSMS($customer['phonenumber'], $currentMessage)) {
$totalSMSSent++;
$batchStatus[] = ['name' => $customer['fullname'], 'phone' => $customer['phonenumber'], 'status' => 'SMS Sent', 'message' => $currentMessage];
} else {
$totalSMSFailed++;
$batchStatus[] = ['name' => $customer['fullname'], 'phone' => $customer['phonenumber'], 'status' => 'SMS Failed', 'message' => $currentMessage];
// Get customer details from the database based on the selected group
if ($group == 'all') {
$customers = ORM::for_table('tbl_customers')->find_many()->as_array();
} elseif ($group == 'new') {
// Get customers created just a month ago
$customers = ORM::for_table('tbl_customers')->where_raw("DATE(created_at) >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)")->find_many()->as_array();
} elseif ($group == 'expired') {
// Get expired user recharges where status is 'off'
$expired = ORM::for_table('tbl_user_recharges')->where('status', 'off')->find_many();
$customer_ids = [];
foreach ($expired as $recharge) {
$customer_ids[] = $recharge->customer_id;
}
$customers = ORM::for_table('tbl_customers')->where_in('id', $customer_ids)->find_many()->as_array();
} elseif ($group == 'active') {
// Get active user recharges where status is 'on'
$active = ORM::for_table('tbl_user_recharges')->where('status', 'on')->find_many();
$customer_ids = [];
foreach ($active as $recharge) {
$customer_ids[] = $recharge->customer_id;
}
$customers = ORM::for_table('tbl_customers')->where_in('id', $customer_ids)->find_many()->as_array();
}
if ($via === 'wa' || $via == 'both' || $via === 'all') {
if (Message::sendWhatsapp($customer['phonenumber'], $currentMessage)) {
$totalWhatsappSent++;
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => $customer['phonenumber'], 'status' => 'WhatsApp Sent', 'message' => $currentMessage];
} else {
$totalWhatsappFailed++;
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => $customer['phonenumber'], 'status' => 'WhatsApp Failed', 'message' => $currentMessage];
}
}
// Set the batch size
$batchSize = $batch;
if ($via === 'email' || $via === 'all') {
if (Message::sendEmail($customer['email'], $currentSubject, $currentMessage)) {
$totalEmailSent++;
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => $customer['email'], 'status' => 'Email Sent', 'message' => $currentMessage];
} else {
$totalEmailFailed++;
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => $customer['email'], 'status' => 'Email Failed', 'message' => $currentMessage];
}
}
// Calculate the number of batches
$totalCustomers = count($customers);
$totalBatches = ceil($totalCustomers / $batchSize);
if ($via === 'inbox' || $via === 'all') {
if (Message::addToInbox($customer['customer_id'], $currentSubject, $currentMessage, $form)) {
$totalInboxSent++;
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => 'Inbox', 'status' => 'Inbox Message Sent', 'message' => $currentMessage];
} else {
$totalInboxFailed++;
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => 'Inbox', 'status' => 'Inbox Message Failed', 'message' => $currentMessage];
// Loop through batches
for ($batchIndex = 0; $batchIndex < $totalBatches; $batchIndex++) {
// Get the starting and ending index for the current batch
$start = $batchIndex * $batchSize;
$end = min(($batchIndex + 1) * $batchSize, $totalCustomers);
$batchCustomers = array_slice($customers, $start, $end - $start);
// Loop through customers in the current batch and send messages
foreach ($batchCustomers as $customer) {
// Create a copy of the original message for each customer and save it as currentMessage
$currentMessage = $message;
$currentMessage = str_replace('[[name]]', $customer['fullname'], $currentMessage);
$currentMessage = str_replace('[[user_name]]', $customer['username'], $currentMessage);
$currentMessage = str_replace('[[phone]]', $customer['phonenumber'], $currentMessage);
$currentMessage = str_replace('[[company_name]]', $config['CompanyName'], $currentMessage);
// Send the message based on the selected method
if ($test === 'yes') {
// Only for testing, do not send messages to customers
$batchStatus[] = [
'name' => $customer['fullname'],
'phone' => $customer['phonenumber'],
'message' => $currentMessage,
'status' => 'Test Mode - Message not sent'
];
} else {
// Send the actual messages
if ($via == 'sms' || $via == 'both') {
$smsSent = Message::sendSMS($customer['phonenumber'], $currentMessage);
if ($smsSent) {
$totalSMSSent++;
$batchStatus[] = [
'name' => $customer['fullname'],
'phone' => $customer['phonenumber'],
'message' => $currentMessage,
'status' => 'SMS Message Sent'
];
} else {
$totalSMSFailed++;
$batchStatus[] = [
'name' => $customer['fullname'],
'phone' => $customer['phonenumber'],
'message' => $currentMessage,
'status' => 'SMS Message Failed'
];
}
}
if ($via == 'wa' || $via == 'both') {
$waSent = Message::sendWhatsapp($customer['phonenumber'], $currentMessage);
if ($waSent) {
$totalWhatsappSent++;
$batchStatus[] = [
'name' => $customer['fullname'],
'phone' => $customer['phonenumber'],
'message' => $currentMessage,
'status' => 'WhatsApp Message Sent'
];
} else {
$totalWhatsappFailed++;
$batchStatus[] = [
'name' => $customer['fullname'],
'phone' => $customer['phonenumber'],
'message' => $currentMessage,
'status' => 'WhatsApp Message Failed'
];
}
}
}
}
// Introduce a delay between each batch
if ($batchIndex < $totalBatches - 1) {
sleep($delay);
}
}
}
}
// Calculate if there are more customers to process
$hasMore = ($startpoint + $batch) < $totalCustomers;
// Return JSON response
echo json_encode([
'status' => 'success',
'page' => $page + 1,
'batchStatus' => $batchStatus,
'message' => $currentMessage,
'totalSent' => $totalSMSSent + $totalWhatsappSent + $totalEmailSent + $totalInboxSent,
'totalFailed' => $totalSMSFailed + $totalWhatsappFailed + $totalEmailFailed + $totalInboxFailed,
'hasMore' => $hasMore,
'service' => $service,
'router' => $routerName,
]);
$ui->assign('batchStatus', $batchStatus);
$ui->assign('totalSMSSent', $totalSMSSent);
$ui->assign('totalSMSFailed', $totalSMSFailed);
$ui->assign('totalWhatsappSent', $totalWhatsappSent);
$ui->assign('totalWhatsappFailed', $totalWhatsappFailed);
$ui->display('message-bulk.tpl');
break;
case 'send_bulk_selected':
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Set headers
header('Content-Type: application/json');
header('Cache-Control: no-cache, no-store, must-revalidate');
// Get the posted data
$customerIds = $_POST['customer_ids'] ?? [];
$via = $_POST['message_type'] ?? '';
$subject = $_POST['subject'] ?? '';
$message = isset($_POST['message']) ? trim($_POST['message']) : '';
if (empty($customerIds) || empty($message) || empty($via)) {
echo json_encode(['status' => 'error', 'message' => Lang::T('Invalid customer IDs, Message, or Message Type.')]);
exit;
}
if ($via === 'all' || $via === 'email' || $via === 'inbox' && empty($subject)) {
die(json_encode(['status' => 'error', 'message' => LANG::T('Subject is required to send message using') . ' ' . $via . '.']));
}
// Prepare to send messages
$sentCount = 0;
$failedCount = 0;
$form = 'Admin';
foreach ($customerIds as $customerId) {
$customer = ORM::for_table('tbl_customers')->where('id', $customerId)->find_one();
if ($customer) {
$messageSent = false;
// Check the message type and send accordingly
try {
if ($via === 'sms' || $via === 'all') {
$messageSent = Message::sendSMS($customer['phonenumber'], $message);
}
if (!$messageSent && ($via === 'wa' || $via === 'all')) {
$messageSent = Message::sendWhatsapp($customer['phonenumber'], $message);
}
if (!$messageSent && ($via === 'inbox' || $via === 'all')) {
Message::addToInbox($customer['id'], $subject, $message, $form);
$messageSent = true;
}
if (!$messageSent && ($via === 'email' || $via === 'all')) {
$messageSent = Message::sendEmail($customer['email'], $subject, $message);
}
} catch (Throwable $e) {
$messageSent = false;
$failedCount++;
sendTelegram('Failed to send message to ' . $e->getMessage());
_log('Failed to send message to ' . $customer['fullname'] . ': ' . $e->getMessage());
continue;
}
if ($messageSent) {
$sentCount++;
} else {
$failedCount++;
}
} else {
$failedCount++;
}
}
// Prepare the response
echo json_encode([
'status' => 'success',
'totalSent' => $sentCount,
'totalFailed' => $failedCount
]);
} else {
header('Content-Type: application/json');
echo json_encode(['status' => 'error', 'message' => Lang::T('Invalid request method.')]);
}
break;
default:
r2(getUrl('message/send_sms'), 'e', 'action not defined');
r2(U . 'message/send_sms', 'e', 'action not defined');
}

View File

@ -34,7 +34,7 @@ switch ($action) {
break;
case 'balance':
if (strpos($user['email'], '@') === false) {
r2(getUrl('accounts/profile'), 'e', Lang::T("Please enter your email address"));
r2(U . 'accounts/profile', 'e', Lang::T("Please enter your email address"));
}
$ui->assign('_title', 'Top Up');
$ui->assign('_system_menu', 'balance');
@ -44,7 +44,7 @@ switch ($action) {
break;
case 'package':
if (strpos($user['email'], '@') === false) {
r2(getUrl('accounts/profile'), 'e', Lang::T("Please enter your email address"));
r2(U . 'accounts/profile', 'e', Lang::T("Please enter your email address"));
}
$ui->assign('_title', 'Order Plan');
$ui->assign('_system_menu', 'package');
@ -144,12 +144,12 @@ switch ($action) {
r_find_unpaid'); #HOOK
if ($d) {
if (empty($d['pg_url_payment'])) {
r2(getUrl('order/buy/') . $trx['routers_id'] . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
r2(U . "order/buy/" . $trx['routers_id'] . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
} else {
r2(getUrl('order/view/') . $d['id'] . '/check/', 's', Lang::T("You have unpaid transaction"));
r2(U . "order/view/" . $d['id'] . '/check/', 's', Lang::T("You have unpaid transaction"));
}
} else {
r2(getUrl('order/package/'), 's', Lang::T("You have no unpaid transaction"));
r2(U . "order/package/", 's', Lang::T("You have no unpaid transaction"));
}
break;
case 'view':
@ -160,15 +160,15 @@ switch ($action) {
run_hook('customer_view_payment'); #HOOK
// jika tidak ditemukan, berarti punya orang lain
if (empty($trx)) {
r2(getUrl('order/package'), 'w', Lang::T("Payment not found"));
r2(U . "order/package", 'w', Lang::T("Payment not found"));
}
// jika url kosong, balikin ke buy, kecuali cancel
if ($trx['status'] == 1 && empty($trx['pg_url_payment']) && $routes['3'] != 'cancel') {
r2(getUrl('order/buy/') . (($trx['routers_id'] == 0) ? $trx['routers'] : $trx['routers_id']) . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
r2(U . "order/buy/" . (($trx['routers_id'] == 0) ? $trx['routers'] : $trx['routers_id']) . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
}
if ($routes['3'] == 'check') {
if (!file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $trx['gateway'] . '.php')) {
r2(getUrl('order/view/') . $trxid, 'e', Lang::T("No Payment Gateway Available"));
r2(U . 'order/view/' . $trxid, 'e', Lang::T("No Payment Gateway Available"));
}
run_hook('customer_check_payment_status'); #HOOK
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $trx['gateway'] . '.php';
@ -185,7 +185,7 @@ switch ($action) {
->find_one($trxid);
}
if (empty($trx)) {
r2(getUrl('order/package'), 'e', Lang::T("Transaction Not found"));
r2(U . "order/package", 'e', Lang::T("Transaction Not found"));
}
$router = ORM::for_table('tbl_routers')->where('name', $trx['routers'])->find_one();
@ -202,10 +202,10 @@ switch ($action) {
break;
case 'pay':
if ($config['enable_balance'] != 'yes') {
r2(getUrl('order/package'), 'e', Lang::T("Balance not enabled"));
r2(U . "order/package", 'e', Lang::T("Balance not enabled"));
}
if (!empty(App::getTokenValue($_GET['stoken']))) {
r2(getUrl('voucher/invoice/'));
r2(U . "voucher/invoice/");
die();
}
if ($user['status'] != 'Active') {
@ -213,7 +213,7 @@ switch ($action) {
}
$plan = ORM::for_table('tbl_plans')->find_one($routes[3]);
if (!$plan) {
r2(getUrl('order/package'), 'e', Lang::T("Plan Not found"));
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
}
if ($plan['is_radius'] == '1') {
$router_name = 'radius';
@ -247,21 +247,21 @@ switch ($action) {
// if success, then get the balance
Balance::min($user['id'], $total_cost);
App::setToken($_GET['stoken'], "success");
r2(getUrl('voucher/invoice/'), 's', Lang::T("Success to buy package"));
r2(U . "voucher/invoice/", 's', Lang::T("Success to buy package"));
} else {
r2(getUrl('order/package'), 'e', Lang::T("Failed to buy package"));
r2(U . "order/package", 'e', Lang::T("Failed to buy package"));
Message::sendTelegram("Buy Package with Balance Failed\n\n#u$c[username] #buy \n" . $plan['name_plan'] .
"\nRouter: " . $router_name .
"\nPrice: " . $total_cost);
}
} else {
r2(getUrl('order/gateway/$routes[2]/$routes[3]'), 'e', Lang::T("Insufficient balance"));
r2(U . "order/gateway/$routes[2]/$routes[3]", 'e', Lang::T("Insufficient balance"));
}
break;
case 'send':
if ($config['enable_balance'] != 'yes') {
r2(getUrl('order/package'), 'e', Lang::T("Balance not enabled"));
r2(U . "order/package", 'e', Lang::T("Balance not enabled"));
}
if ($user['status'] != 'Active') {
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
@ -270,10 +270,10 @@ switch ($action) {
$ui->assign('_system_menu', 'package');
$plan = ORM::for_table('tbl_plans')->find_one($routes['3']);
if (empty($plan)) {
r2(getUrl('order/package'), 'e', Lang::T("Plan Not found"));
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
}
if (!$plan['enabled']) {
r2(getUrl('home'), 'e', 'Plan is not exists');
r2(U . "home", 'e', 'Plan is not exists');
}
if ($plan['is_radius'] == '1') {
$routes['2'] = 0;
@ -312,13 +312,13 @@ switch ($action) {
}
if (!$target) {
r2(getUrl('home'), 'd', Lang::T('Username not found'));
r2(U . 'home', 'd', Lang::T('Username not found'));
}
if ($user['balance'] < $plan['price']) {
r2(getUrl('home'), 'd', Lang::T('insufficient balance'));
r2(U . 'home', 'd', Lang::T('insufficient balance'));
}
if ($user['username'] == $target['username']) {
r2(getUrl('order/pay/$routes[2]/$routes[3]'), 's', '^_^ v');
r2(U . "order/pay/$routes[2]/$routes[3]", 's', '^_^ v');
}
$active = ORM::for_table('tbl_user_recharges')
->where('username', _post('username'))
@ -326,7 +326,7 @@ switch ($action) {
->find_one();
if ($active && $active['plan_id'] != $plan['id']) {
r2(getUrl('order/package'), 'e', Lang::T("Target has active plan, different with current plant.") . " [ <b>$active[namebp]</b> ]");
r2(U . "order/package", 'e', Lang::T("Target has active plan, different with current plant.") . " [ <b>$active[namebp]</b> ]");
}
$result = Package::rechargeUser($target['id'], $router_name, $plan['id'], $user['username'], 'Balance');
if (!empty($result)) {
@ -371,7 +371,7 @@ switch ($action) {
$d->trx_invoice = $result;
$d->status = 2;
$d->save();
r2(getUrl("order/view/$trx_id"), 's', Lang::T("Success to send package"));
r2(U . "order/view/$trx_id", 's', Lang::T("Success to send package"));
} else {
$errorMessage = "Send Package with Balance Failed\n\n#u$user[username] #send \n" . $plan['name_plan'] .
"\nRouter: " . $router_name .
@ -381,7 +381,7 @@ switch ($action) {
$errorMessage .= "\nTax: " . $tax;
}
r2(getUrl('order/package'), 'e', Lang::T("Failed to Send package"));
r2(U . "order/package", 'e', Lang::T("Failed to Send package"));
Message::sendTelegram($errorMessage);
}
}
@ -395,7 +395,7 @@ switch ($action) {
$ui->assign('_title', Lang::T('Select Payment Gateway'));
$ui->assign('_system_menu', 'package');
if (strpos($user['email'], '@') === false) {
r2(getUrl('accounts/profile'), 'e', Lang::T("Please enter your email address"));
r2(U . 'accounts/profile', 'e', Lang::T("Please enter your email address"));
}
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
@ -410,10 +410,6 @@ switch ($action) {
if ($router['name'] != 'balance') {
list($bills, $add_cost) = User::getBills($id_customer);
}
$add_inv = User::getAttribute("Invoice", $id_customer);
if (!empty($add_inv)) {
$plan['price'] = $add_inv;
}
if($config['enable_coupons']){
if (!isset($_SESSION['coupon_attempts'])) {
@ -507,7 +503,7 @@ switch ($action) {
if (count($pgs) == 0) {
sendTelegram("Payment Gateway not set, please set it in Settings");
_log(Lang::T("Payment Gateway not set, please set it in Settings"));
r2(getUrl('home'), 'e', Lang::T("Failed to create Transaction.."));
r2(U . "home", 'e', Lang::T("Failed to create Transaction.."));
}
if (count($pgs) > 0) {
$ui->assign('pgs', $pgs);
@ -520,7 +516,7 @@ switch ($action) {
$ui->assign('custom', '1');
$ui->assign('amount', _post('amount'));
} else {
r2(getUrl('order/balance'), 'e', Lang::T("Please enter amount"));
r2(U . "order/balance", 'e', Lang::T("Please enter amount"));
}
}
@ -534,14 +530,14 @@ switch ($action) {
} else {
sendTelegram("Payment Gateway not set, please set it in Settings");
_log(Lang::T("Payment Gateway not set, please set it in Settings"));
r2(getUrl('home'), 'e', Lang::T("Failed to create Transaction.."));
r2(U . "home", 'e', Lang::T("Failed to create Transaction.."));
}
case 'buy':
$gateway = _post('gateway');
$discount = _post('discount') ?: 0;
if ($gateway == 'balance') {
unset($_SESSION['gateway']);
r2(getUrl('order/pay/') . $routes[2] . '/' . $routes[3]);
r2(U . 'order/pay/' . $routes[2] . '/' . $routes[3]);
}
if (empty($gateway) && !empty($_SESSION['gateway'])) {
$gateway = $_SESSION['gateway'];
@ -552,7 +548,7 @@ switch ($action) {
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
}
if (empty($gateway)) {
r2(getUrl('order/gateway/') . $routes[2] . '/' . $routes[3], 'w', Lang::T("Please select Payment Gateway"));
r2(U . 'order/gateway/' . $routes[2] . '/' . $routes[3], 'w', Lang::T("Please select Payment Gateway"));
}
run_hook('customer_buy_plan'); #HOOK
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $gateway . '.php';
@ -564,7 +560,7 @@ switch ($action) {
$amount = (float) $amount;
if ($amount <= 0) {
r2(getUrl('order/gateway/') . $routes[2] . '/' . $routes[3], 'w', Lang::T("Please enter amount"));
r2(U . "order/gateway/" . $routes[2] . '/' . $routes[3], 'w', Lang::T("Please enter amount"));
}
$d = ORM::for_table('tbl_payment_gateway')
@ -573,7 +569,7 @@ switch ($action) {
->find_one();
if ($d) {
if ($d['pg_url_payment']) {
r2(getUrl('order/view/') . $d['id'], 'w', Lang::T("You already have unpaid transaction, cancel it or pay it."));
r2(U . "order/view/" . $d['id'], 'w', Lang::T("You already have unpaid transaction, cancel it or pay it."));
} else {
if ($gateway == $d['gateway']) {
$id = $d['id'];
@ -610,7 +606,7 @@ switch ($action) {
$router['name'] = 'balance';
}
if (empty($router) || empty($plan)) {
r2(getUrl('order/package'), 'e', Lang::T("Plan Not found"));
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
}
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
@ -618,7 +614,7 @@ switch ($action) {
->find_one();
if ($d) {
if ($d['pg_url_payment']) {
r2(getUrl('order/view/') . $d['id'], 'w', Lang::T("You already have unpaid transaction, cancel it or pay it."));
r2(U . "order/view/" . $d['id'], 'w', Lang::T("You already have unpaid transaction, cancel it or pay it."));
} else {
if ($gateway == $d['gateway']) {
$id = $d['id'];
@ -697,11 +693,11 @@ switch ($action) {
break;
}
if (!$id) {
r2(getUrl('order/package/') . $d['id'], 'e', Lang::T("Failed to create Transaction.."));
r2(U . "order/package/" . $d['id'], 'e', Lang::T("Failed to create Transaction.."));
} else {
call_user_func($gateway . '_create_transaction', $d, $user);
}
break;
default:
r2(getUrl('order/package/'), 's', '');
r2(U . "order/package/", 's', '');
}

View File

@ -26,7 +26,7 @@ if (strpos($action, "-reset") !== false) {
} else {
file_put_contents($path, Http::getData('https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/pages_template/' . $action . '.html'));
}
r2(getUrl('pages/') . $action);
r2(U . 'pages/' . $action);
} else if (strpos($action, "-post") === false) {
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
@ -60,9 +60,9 @@ if (strpos($action, "-reset") !== false) {
$ui->assign("writeable", is_writable($path));
$ui->assign("pageHeader", str_replace('_', ' ', $action));
$ui->assign("PageFile", $action);
$ui->display('admin/settings/page.tpl');
$ui->display('page-edit.tpl');
} else
$ui->display('admin/404.tpl');
$ui->display('a404.tpl');
} else {
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
@ -78,10 +78,10 @@ if (strpos($action, "-reset") !== false) {
file_put_contents("$PAGES_PATH/vouchers/" . _post('template_name') . '.html', $html);
}
}
r2(getUrl('pages/') . $action, 's', Lang::T("Saving page success"));
r2(U . 'pages/' . $action, 's', Lang::T("Saving page success"));
} else {
r2(getUrl('pages/') . $action, 'e', Lang::T("Failed to save page, make sure i can write to folder pages, <i>chmod 664 pages/*.html<i>"));
r2(U . 'pages/' . $action, 'e', Lang::T("Failed to save page, make sure i can write to folder pages, <i>chmod 664 pages/*.html<i>"));
}
} else
$ui->display('admin/404.tpl');
$ui->display('a404.tpl');
}

View File

@ -16,7 +16,7 @@ switch ($action) {
if (file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $pg . '.php')) {
deleteFile($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR, $pg);
}
r2(getUrl('paymentgateway'), 's', Lang::T('Payment Gateway Deleted'));
r2(U . 'paymentgateway', 's', Lang::T('Payment Gateway Deleted'));
case 'audit':
$pg = alphanumeric($routes[2]);
@ -34,7 +34,7 @@ switch ($action) {
$ui->assign('pgs', $pgs);
$ui->assign('pg', $pg);
$ui->assign('q', $q);
$ui->display('admin/paymentgateway/audit.tpl');
$ui->display('paymentgateway-audit.tpl');
break;
case 'auditview':
$pg = alphanumeric($routes[2]);
@ -43,7 +43,7 @@ switch ($action) {
$d['pg_paid_response'] = (!empty($d['pg_paid_response']))? Text::jsonArray21Array(json_decode($d['pg_paid_response'], true)) : [];
$ui->assign('_title', 'Payment Gateway Audit View');
$ui->assign('pg', $d);
$ui->display('admin/paymentgateway/audit-view.tpl');
$ui->display('paymentgateway-audit-view.tpl');
break;
default:
if (_post('save') == 'actives') {
@ -61,7 +61,7 @@ switch ($action) {
$d->value = $pgs;
$d->save();
}
r2(getUrl('paymentgateway'), 's', Lang::T('Payment Gateway saved successfully'));
r2(U . 'paymentgateway', 's', Lang::T('Payment Gateway saved successfully'));
}
if (file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $action . '.php')) {
@ -70,18 +70,18 @@ switch ($action) {
if (function_exists($action . '_save_config')) {
call_user_func($action . '_save_config');
} else {
$ui->display('admin/404.tpl');
$ui->display('a404.tpl');
}
} else {
if (function_exists($action . '_show_config')) {
call_user_func($action . '_show_config');
} else {
$ui->display('admin/404.tpl');
$ui->display('a404.tpl');
}
}
} else {
if (!empty($action)) {
r2(getUrl('paymentgateway'), 'w', Lang::T('Payment Gateway Not Found'));
r2(U . 'paymentgateway', 'w', Lang::T('Payment Gateway Not Found'));
} else {
$files = scandir($PAYMENTGATEWAY_PATH);
foreach ($files as $file) {
@ -92,7 +92,7 @@ switch ($action) {
$ui->assign('_title', 'Payment Gateway Settings');
$ui->assign('pgs', $pgs);
$ui->assign('actives', explode(',', $config['payment_gateway']));
$ui->display('admin/paymentgateway/list.tpl');
$ui->display('paymentgateway.tpl');
}
}
}

View File

@ -12,8 +12,6 @@ $ui->assign('_system_menu', 'plan');
$action = $routes['1'];
$ui->assign('_admin', $admin);
$appUrl = APP_URL;
$select2_customer = <<<EOT
<script>
document.addEventListener("DOMContentLoaded", function(event) {
@ -22,9 +20,9 @@ document.addEventListener("DOMContentLoaded", function(event) {
ajax: {
url: function(params) {
if(params.term != undefined){
return '{$appUrl}/?_route=autoload/customer_select2&s='+params.term;
return './?_route=autoload/customer_select2&s='+params.term;
}else{
return '{$appUrl}/?_route=autoload/customer_select2';
return './?_route=autoload/customer_select2';
}
}
}
@ -32,7 +30,7 @@ document.addEventListener("DOMContentLoaded", function(event) {
});
</script>
EOT;
getUrl('docs');
switch ($action) {
case 'sync':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
@ -68,7 +66,7 @@ switch ($action) {
$log .= "PLAN NOT FOUND : $tur[username], $tur[namebp], $tur[type], $tur[routers]<br>";
}
}
r2(getUrl('plan/list'), 's', $log);
r2(U . 'plan/list', 's', $log);
case 'recharge':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
@ -84,7 +82,7 @@ switch ($action) {
}
$ui->assign('usings', $usings);
run_hook('view_recharge'); #HOOK
$ui->display('admin/plan/recharge.tpl');
$ui->display('recharge.tpl');
break;
case 'recharge-confirm':
@ -107,15 +105,11 @@ switch ($action) {
$cust = User::_info($id_customer);
$plan = ORM::for_table('tbl_plans')->find_one($planId);
list($bills, $add_cost) = User::getBills($id_customer);
$add_inv = User::getAttribute("Invoice", $id_customer);
if (!empty($add_inv)) {
$plan['price'] = $add_inv;
}
// Tax calculation start
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float) $config['custom_tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
if ($tax_rate_setting === 'custom') {
$tax_rate = $custom_tax_rate;
@ -133,13 +127,13 @@ switch ($action) {
if ($using == 'balance' && $config['enable_balance'] == 'yes') {
if (!$cust) {
r2(getUrl('plan/recharge'), 'e', Lang::T('Customer not found'));
r2(U . 'plan/recharge', 'e', Lang::T('Customer not found'));
}
if (!$plan) {
r2(getUrl('plan/recharge'), 'e', Lang::T('Plan not found'));
r2(U . 'plan/recharge', 'e', Lang::T('Plan not found'));
}
if ($cust['balance'] < $total_cost) {
r2(getUrl('plan/recharge'), 'e', Lang::T('insufficient balance'));
r2(U . 'plan/recharge', 'e', Lang::T('insufficient balance'));
}
$gateway = 'Recharge Balance';
}
@ -164,10 +158,9 @@ switch ($action) {
$ui->assign('server', $server);
$ui->assign('using', $using);
$ui->assign('plan', $plan);
$ui->assign('add_inv', $add_inv);
$ui->display('admin/plan/recharge-confirm.tpl');
$ui->display('recharge-confirm.tpl');
} else {
r2(getUrl('plan/recharge'), 'e', $msg);
r2(U . 'plan/recharge', 'e', $msg);
}
break;
@ -187,7 +180,7 @@ switch ($action) {
$username = App::getVoucherValue($svoucher);
$in = ORM::for_table('tbl_transactions')->where('username', $username)->order_by_desc('id')->find_one();
Package::createInvoice($in);
$ui->display('admin/plan/invoice.tpl');
$ui->display('invoice.tpl');
die();
}
@ -205,7 +198,7 @@ switch ($action) {
// Tax calculation start
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float) $config['custom_tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
if ($tax_rate_setting === 'custom') {
$tax_rate = $custom_tax_rate;
@ -224,13 +217,13 @@ switch ($action) {
if ($using == 'balance' && $config['enable_balance'] == 'yes') {
//$plan = ORM::for_table('tbl_plans')->find_one($planId);
if (!$cust) {
r2(getUrl('plan/recharge'), 'e', Lang::T('Customer not found'));
r2(U . 'plan/recharge', 'e', Lang::T('Customer not found'));
}
if (!$plan) {
r2(getUrl('plan/recharge'), 'e', Lang::T('Plan not found'));
r2(U . 'plan/recharge', 'e', Lang::T('Plan not found'));
}
if ($cust['balance'] < $total_cost) {
r2(getUrl('plan/recharge'), 'e', Lang::T('insufficient balance'));
r2(U . 'plan/recharge', 'e', Lang::T('insufficient balance'));
}
$gateway = 'Recharge Balance';
}
@ -246,13 +239,13 @@ switch ($action) {
$in = ORM::for_table('tbl_transactions')->where('username', $cust['username'])->order_by_desc('id')->find_one();
Package::createInvoice($in);
App::setVoucher($svoucher, $cust['username']);
$ui->display('admin/plan/invoice.tpl');
$ui->display('invoice.tpl');
_log('[' . $admin['username'] . ']: ' . 'Recharge ' . $cust['username'] . ' [' . $in['plan_name'] . '][' . Lang::moneyFormat($in['price']) . ']', $admin['user_type'], $admin['id']);
} else {
r2(getUrl('plan/recharge'), 'e', "Failed to recharge account");
r2(U . 'plan/recharge', 'e', "Failed to recharge account");
}
} else {
r2(getUrl('plan/recharge'), 'e', $msg);
r2(U . 'plan/recharge', 'e', $msg);
}
break;
@ -264,26 +257,13 @@ switch ($action) {
$c = ORM::for_table('tbl_customers')->where('username', $in['username'])->find_one();
if ($c) {
Message::sendInvoice($c, $in);
r2(getUrl('plan/view/') . $id, 's', "Success send to customer");
r2(U . 'plan/view/' . $id, 's', "Success send to customer");
}
r2(getUrl('plan/view/') . $id, 'd', "Customer not found");
r2(U . 'plan/view/' . $id, 'd', "Customer not found");
}
Package::createInvoice($in);
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
$logo = '';
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) {
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png';
$imgsize = getimagesize($logo);
$width = $imgsize[0];
$height = $imgsize[1];
$ui->assign('wlogo', $width);
$ui->assign('hlogo', $height);
}
$ui->assign('public_url', getUrl("voucher/invoice/$id/".md5($id. $db_pass)));
$ui->assign('logo', $logo);
$ui->assign('_title', 'View Invoice');
$ui->display('admin/plan/invoice.tpl');
$ui->display('invoice.tpl');
break;
@ -305,14 +285,14 @@ switch ($action) {
$ui->assign('date', Lang::dateAndTimeFormat($d['recharged_on'], $d['recharged_time']));
}
run_hook('print_invoice'); #HOOK
$ui->display('admin/plan/invoice-print.tpl');
$ui->display('invoice-print.tpl');
break;
case 'edit':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_user_recharges')->find_one($id);
if ($d) {
$ui->assign('d', $d);
@ -332,9 +312,9 @@ switch ($action) {
$ui->assign('p', $ps);
run_hook('view_edit_customer_plan'); #HOOK
$ui->assign('_title', 'Edit Plan');
$ui->display('admin/plan/edit.tpl');
$ui->display('plan-edit.tpl');
} else {
r2(getUrl('plan/list'), 'e', Lang::T('Account Not Found'));
r2(U . 'plan/list', 'e', Lang::T('Account Not Found'));
}
break;
@ -342,7 +322,7 @@ switch ($action) {
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_user_recharges')->find_one($id);
if ($d) {
run_hook('delete_customer_active_plan'); #HOOK
@ -359,7 +339,7 @@ switch ($action) {
}
$d->delete();
_log('[' . $admin['username'] . ']: ' . 'Delete Plan for Customer ' . $c['username'] . ' [' . $in['plan_name'] . '][' . Lang::moneyFormat($in['price']) . ']', $admin['user_type'], $admin['id']);
r2(getUrl('plan/list'), 's', Lang::T('Data Deleted Successfully'));
r2(U . 'plan/list', 's', Lang::T('Data Deleted Successfully'));
}
break;
@ -425,9 +405,9 @@ switch ($action) {
}
$d->save();
_log('[' . $admin['username'] . ']: ' . 'Edit Plan for Customer ' . $d['username'] . ' to [' . $d['namebp'] . '][' . Lang::moneyFormat($p['price']) . ']', $admin['user_type'], $admin['id']);
r2(getUrl('plan/list'), 's', Lang::T('Data Updated Successfully'));
r2(U . 'plan/list', 's', Lang::T('Data Updated Successfully'));
} else {
r2(getUrl('plan/edit/') . $id, 'e', $msg);
r2(U . 'plan/edit/' . $id, 'e', $msg);
}
break;
@ -466,7 +446,7 @@ switch ($action) {
$append_url = "&search=" . urlencode($search) . "&router=" . urlencode($router) . "&customer=" . urlencode($customer) . "&plan=" . urlencode($plan) . "&status=" . urlencode($status);
// option customers
$ui->assign('customers', ORM::for_table('tbl_voucher')->distinct()->select("user")->whereNotEqual("user", '0')->findArray());
$ui->assign('customers', ORM::for_table('tbl_voucher')->distinct()->select("user")->whereNotEqual("user", '0')->findArray());
// option plans
$plns = ORM::for_table('tbl_voucher')->distinct()->select("id_plan")->findArray();
if (count($plns) > 0) {
@ -530,7 +510,7 @@ switch ($action) {
$ui->assign('search', $search);
$ui->assign('page', $page);
run_hook('view_list_voucher'); #HOOK
$ui->display('admin/voucher/list.tpl');
$ui->display('voucher.tpl');
break;
case 'add-voucher':
@ -545,7 +525,7 @@ switch ($action) {
$r = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
$ui->assign('r', $r);
run_hook('view_add_voucher'); #HOOK
$ui->display('admin/voucher/add.tpl');
$ui->display('voucher-add.tpl');
break;
case 'remove-voucher':
@ -564,7 +544,7 @@ switch ($action) {
$jml++;
}
}
r2(getUrl('plan/voucher'), 's', "$jml " . Lang::T('Data Deleted Successfully'));
r2(U . 'plan/voucher', 's', "$jml " . Lang::T('Data Deleted Successfully'));
}
case 'print-voucher':
$from_id = _post('from_id');
@ -576,11 +556,9 @@ switch ($action) {
if (empty($vpl)) {
$vpl = 3;
}
if ($pagebreak < 1)
$pagebreak = 12;
if ($pagebreak < 1) $pagebreak = 12;
if ($limit < 1)
$limit = $pagebreak * 2;
if ($limit < 1) $limit = $pagebreak * 2;
if (empty($from_id)) {
$from_id = 0;
}
@ -641,7 +619,7 @@ switch ($action) {
$v = ORM::for_table('tbl_plans')
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
->where('tbl_voucher.status', '0')
->where('tbl_voucher.created_at', $selected_datetime)
->where('tbl_voucher.created_at', $selected_datetime)
->limit($limit);
$vc = ORM::for_table('tbl_plans')
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
@ -706,15 +684,12 @@ switch ($action) {
//for counting pagebreak
$ui->assign('jml', 0);
run_hook('view_print_voucher'); #HOOK
$ui->display('admin/print/voucher.tpl');
$ui->display('print-voucher.tpl');
break;
case 'voucher-post':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
if ($_app_stage == 'Demo') {
r2(getUrl('plan/add-voucher/'), 'e', 'You cannot perform this action in Demo mode');
}
$type = _post('type');
$plan = _post('plan');
@ -816,16 +791,16 @@ switch ($action) {
$ui->assign('from_id', 0);
$ui->assign('vpl', '3');
$ui->assign('pagebreak', $voucherPerPage);
$ui->display('admin/print/voucher.tpl');
$ui->display('print-voucher.tpl');
}
if ($numbervoucher == 1) {
r2(getUrl('plan/voucher-view/') . $d->id(), 's', Lang::T('Create Vouchers Successfully'));
r2(U . 'plan/voucher-view/' . $d->id(), 's', Lang::T('Create Vouchers Successfully'));
}
r2(getUrl('plan/voucher'), 's', Lang::T('Create Vouchers Successfully'));
r2(U . 'plan/voucher', 's', Lang::T('Create Vouchers Successfully'));
} else {
r2(getUrl('plan/add-voucher/') . $id, 'e', $msg);
r2(U . 'plan/add-voucher/' . $id, 'e', $msg);
}
break;
@ -880,11 +855,11 @@ switch ($action) {
$voucher = ORM::for_table('tbl_voucher')
->find_one($id);
if (!in_array($voucher['generated_by'], $sales)) {
r2(getUrl('plan/voucher/'), 'e', Lang::T('Voucher Not Found'));
r2(U . 'plan/voucher/', 'e', Lang::T('Voucher Not Found'));
}
}
if (!$voucher) {
r2(getUrl('plan/voucher/'), 'e', Lang::T('Voucher Not Found'));
r2(U . 'plan/voucher/', 'e', Lang::T('Voucher Not Found'));
}
$plan = ORM::for_table('tbl_plans')->find_one($voucher['id_plan']);
if ($voucher && $plan) {
@ -916,21 +891,21 @@ switch ($action) {
$content .= Lang::pad($config['note'], ' ', 2) . "\n";
$ui->assign('_title', Lang::T('View'));
$ui->assign('whatsapp', urlencode("```$content```"));
$ui->display('admin/voucher/view.tpl');
$ui->display('voucher-view.tpl');
} else {
r2(getUrl('plan/voucher/'), 'e', Lang::T('Voucher Not Found'));
r2(U . 'plan/voucher/', 'e', Lang::T('Voucher Not Found'));
}
break;
case 'voucher-delete':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$id = $routes['2'];
$id = $routes['2'];
run_hook('delete_voucher'); #HOOK
$d = ORM::for_table('tbl_voucher')->find_one($id);
if ($d) {
$d->delete();
r2(getUrl('plan/voucher'), 's', Lang::T('Data Deleted Successfully'));
r2(U . 'plan/voucher', 's', Lang::T('Data Deleted Successfully'));
}
break;
@ -941,7 +916,7 @@ switch ($action) {
$ui->assign('xfooter', $select2_customer);
$ui->assign('_title', Lang::T('Refill Account'));
run_hook('view_refill'); #HOOK
$ui->display('admin/plan/refill.tpl');
$ui->display('refill.tpl');
break;
@ -961,12 +936,12 @@ switch ($action) {
$v1->save();
$in = ORM::for_table('tbl_transactions')->where('username', $user['username'])->order_by_desc('id')->find_one();
Package::createInvoice($in);
$ui->display('admin/plan/invoice.tpl');
$ui->display('invoice.tpl');
} else {
r2(getUrl('plan/refill'), 'e', "Failed to refill account");
r2(U . 'plan/refill', 'e', "Failed to refill account");
}
} else {
r2(getUrl('plan/refill'), 'e', Lang::T('Voucher Not Valid'));
r2(U . 'plan/refill', 'e', Lang::T('Voucher Not Valid'));
}
break;
case 'deposit':
@ -981,7 +956,7 @@ switch ($action) {
$ui->assign('p', ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'Balance')->find_many());
}
run_hook('view_deposit'); #HOOK
$ui->display('admin/plan/deposit.tpl');
$ui->display('deposit.tpl');
break;
case 'deposit-post':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
@ -996,7 +971,7 @@ switch ($action) {
if (App::getVoucherValue($svoucher)) {
$in = ORM::for_table('tbl_transactions')->find_one(App::getVoucherValue($svoucher));
Package::createInvoice($in);
$ui->display('admin/plan/invoice.tpl');
$ui->display('invoice.tpl');
die();
}
@ -1012,9 +987,9 @@ switch ($action) {
if (!empty($svoucher)) {
App::setVoucher($svoucher, $trxId);
}
$ui->display('admin/plan/invoice.tpl');
$ui->display('invoice.tpl');
} else {
r2(getUrl('plan/refill'), 'e', "Failed to refill account");
r2(U . 'plan/refill', 'e', "Failed to refill account");
}
} else if (!empty($user) && !empty($plan)) {
$p = ORM::for_table('tbl_plans')->find_one($plan);
@ -1025,12 +1000,12 @@ switch ($action) {
if (!empty($svoucher)) {
App::setVoucher($svoucher, $trxId);
}
$ui->display('admin/plan/invoice.tpl');
$ui->display('invoice.tpl');
} else {
r2(getUrl('plan/refill'), 'e', "Failed to refill account");
r2(U . 'plan/refill', 'e', "Failed to refill account");
}
} else {
r2(getUrl('plan/refill'), 'e', "All field is required");
r2(U . 'plan/refill', 'e', "All field is required");
}
break;
case 'extend':
@ -1038,7 +1013,7 @@ switch ($action) {
$days = $routes[3];
$svoucher = $_GET['svoucher'];
if (App::getVoucherValue($svoucher)) {
r2(getUrl('plan'), 's', "Extend already done");
r2(U . 'plan', 's', "Extend already done");
}
$tur = ORM::for_table('tbl_user_recharges')->find_one($id);
$status = $tur['status'];
@ -1070,22 +1045,23 @@ switch ($action) {
$tur->status = "on";
$tur->save();
} else {
r2(getUrl('plan'), 's', "Plan not found");
r2(U . 'plan', 's', "Plan not found");
}
} else {
r2(getUrl('plan'), 's', "Customer not found");
r2(U . 'plan', 's', "Customer not found");
}
Message::sendTelegram("#u$tur[username] #id$tur[customer_id] #extend by $admin[fullname] #" . $p['type'] . " \n" . $p['name_plan'] .
Message::sendTelegram("#u$tur[username] #extend #" . $p['type'] . " \n" . $p['name_plan'] .
"\nLocation: " . $p['routers'] .
"\nCustomer: " . $c['fullname'] .
"\nNew Expired: " . Lang::dateAndTimeFormat($expiration, $tur['time']));
_log("$admin[fullname] extend Customer $tur[customer_id] $tur[username] #$tur[customer_id] for $days days", $admin['user_type'], $admin['id']);
r2(getUrl('plan'), 's', "Extend until $expiration");
_log("$admin[fullname] extend Customer $tur[customer_id] $tur[username] for $days days", $admin['user_type'], $admin['id']);
r2(U . 'plan', 's', "Extend until $expiration");
} else {
r2(getUrl('plan'), 's', "Customer is not expired yet");
r2(U . 'plan', 's', "Customer is not expired yet");
}
break;
default:
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/plan.js"></script>');
$ui->assign('_title', Lang::T('Customer'));
$search = _post('search');
$status = _req('status');
@ -1126,6 +1102,6 @@ switch ($action) {
$d = Paginator::findMany($query, ['search' => $search], 25, $append_url);
run_hook('view_list_billing'); #HOOK
$ui->assign('d', $d);
$ui->display('admin/plan/active.tpl');
$ui->display('plan.tpl');
break;
}

View File

@ -7,5 +7,5 @@
if(function_exists($routes[1])){
call_user_func($routes[1]);
}else{
r2(getUrl('dashboard'), 'e', 'Function not found');
r2(U.'dashboard', 'e', 'Function not found');
}

View File

@ -25,7 +25,7 @@ if (file_exists($cache) && time() - filemtime($cache) < (24 * 60 * 60)) {
$json = json_decode($txt, true);
if (empty($json['plugins']) && empty($json['payment_gateway'])) {
unlink($cache);
r2(getUrl('pluginmanager'));
r2(U . 'pluginmanager');
}
} else {
$data = Http::getData($plugin_repository);
@ -34,25 +34,24 @@ if (file_exists($cache) && time() - filemtime($cache) < (24 * 60 * 60)) {
}
switch ($action) {
case 'refresh':
if (file_exists($cache))
unlink($cache);
r2(getUrl('pluginmanager'), 's', 'Refresh success');
if (file_exists($cache)) unlink($cache);
r2(U . "pluginmanager", 's', 'Refresh success');
break;
case 'dlinstall':
if ($_app_stage == 'Demo') {
r2(getUrl('pluginmanager'), 'e', 'Demo Mode cannot install as it Security risk');
if ($_app_stage == 'demo') {
r2(U . "pluginmanager", 'e', 'Demo Mode cannot install as it Security risk');
}
if (!is_writeable($CACHE_PATH)) {
r2(getUrl('pluginmanager'), 'e', 'Folder cache/ is not writable');
r2(U . "pluginmanager", 'e', 'Folder cache/ is not writable');
}
if (!is_writeable($PLUGIN_PATH)) {
r2(getUrl('pluginmanager'), 'e', 'Folder plugin/ is not writable');
r2(U . "pluginmanager", 'e', 'Folder plugin/ is not writable');
}
if (!is_writeable($DEVICE_PATH)) {
r2(getUrl('pluginmanager'), 'e', 'Folder devices/ is not writable');
r2(U . "pluginmanager", 'e', 'Folder devices/ is not writable');
}
if (!is_writeable($UI_PATH . DIRECTORY_SEPARATOR . 'themes')) {
r2(getUrl('pluginmanager'), 'e', 'Folder themes/ is not writable');
r2(U . "pluginmanager", 'e', 'Folder themes/ is not writable');
}
$cache = $CACHE_PATH . DIRECTORY_SEPARATOR . 'installer' . DIRECTORY_SEPARATOR;
if (!file_exists($cache)) {
@ -98,7 +97,7 @@ switch ($action) {
}
//Cleaning
File::deleteFolder($cache);
r2(getUrl('pluginmanager'), 's', 'Installation success');
r2(U . "pluginmanager", 's', 'Installation success');
} else if (_post('gh_url', '') != '') {
$ghUrl = _post('gh_url', '');
if (!empty($config['github_token']) && !empty($config['github_username'])) {
@ -122,7 +121,7 @@ switch ($action) {
$zip->extractTo($cache);
$zip->close();
$folder = $cache . DIRECTORY_SEPARATOR . $plugin . '-main' . DIRECTORY_SEPARATOR;
if (!file_exists($folder)) {
if(!file_exists($folder)) {
$folder = $cache . DIRECTORY_SEPARATOR . $plugin . '-master' . DIRECTORY_SEPARATOR;
}
$success = 0;
@ -156,27 +155,23 @@ switch ($action) {
}
}
File::deleteFolder($cache);
r2(getUrl('pluginmanager'), 's', 'Installation success');
r2(U . "pluginmanager", 's', 'Installation success');
} else {
r2(getUrl('pluginmanager'), 'e', 'Nothing Installed');
r2(U . 'pluginmanager', 'e', 'Nothing Installed');
}
break;
case 'delete':
if ($_app_stage == 'Demo') {
r2(getUrl('pluginmanager'), 'e', 'You cannot perform this action in Demo mode');
}
if (!is_writeable($CACHE_PATH)) {
r2(getUrl('pluginmanager'), 'e', 'Folder cache/ is not writable');
r2(U . "pluginmanager", 'e', 'Folder cache/ is not writable');
}
if (!is_writeable($PLUGIN_PATH)) {
r2(getUrl('pluginmanager'), 'e', 'Folder plugin/ is not writable');
r2(U . "pluginmanager", 'e', 'Folder plugin/ is not writable');
}
set_time_limit(-1);
$tipe = $routes['2'];
$plugin = $routes['3'];
$file = $CACHE_PATH . DIRECTORY_SEPARATOR . $plugin . '.zip';
if (file_exists($file))
unlink($file);
if (file_exists($file)) unlink($file);
if ($tipe == 'plugin') {
foreach ($json['plugins'] as $plg) {
if ($plg['id'] == $plugin) {
@ -204,12 +199,12 @@ switch ($action) {
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
}
if (!file_exists($folder)) {
r2(getUrl('pluginmanager'), 'e', 'Extracted Folder is unknown');
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
}
scanAndRemovePath($folder, $PLUGIN_PATH . DIRECTORY_SEPARATOR);
File::deleteFolder($folder);
unlink($file);
r2(getUrl('pluginmanager'), 's', 'Plugin ' . $plugin . ' has been deleted');
r2(U . "pluginmanager", 's', 'Plugin ' . $plugin . ' has been deleted');
break;
}
}
@ -217,21 +212,17 @@ switch ($action) {
}
break;
case 'install':
if ($_app_stage == 'Demo') {
r2(getUrl('pluginmanager'), 'e', 'You cannot perform this action in Demo mode');
}
if (!is_writeable($CACHE_PATH)) {
r2(getUrl('pluginmanager'), 'e', 'Folder cache/ is not writable');
r2(U . "pluginmanager", 'e', 'Folder cache/ is not writable');
}
if (!is_writeable($PLUGIN_PATH)) {
r2(getUrl('pluginmanager'), 'e', 'Folder plugin/ is not writable');
r2(U . "pluginmanager", 'e', 'Folder plugin/ is not writable');
}
set_time_limit(-1);
$tipe = $routes['2'];
$plugin = $routes['3'];
$file = $CACHE_PATH . DIRECTORY_SEPARATOR . $plugin . '.zip';
if (file_exists($file))
unlink($file);
if (file_exists($file)) unlink($file);
if ($tipe == 'plugin') {
foreach ($json['plugins'] as $plg) {
if ($plg['id'] == $plugin) {
@ -259,12 +250,12 @@ switch ($action) {
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
}
if (!file_exists($folder)) {
r2(getUrl('pluginmanager'), 'e', 'Extracted Folder is unknown');
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
}
File::copyFolder($folder, $PLUGIN_PATH . DIRECTORY_SEPARATOR, ['README.md', 'LICENSE']);
File::deleteFolder($folder);
unlink($file);
r2(getUrl('pluginmanager'), 's', 'Plugin ' . $plugin . ' has been installed');
r2(U . "pluginmanager", 's', 'Plugin ' . $plugin . ' has been installed');
break;
}
}
@ -296,12 +287,12 @@ switch ($action) {
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
}
if (!file_exists($folder)) {
r2(getUrl('pluginmanager'), 'e', 'Extracted Folder is unknown');
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
}
File::copyFolder($folder, $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR, ['README.md', 'LICENSE']);
File::deleteFolder($folder);
unlink($file);
r2(getUrl('paymentgateway'), 's', 'Payment Gateway ' . $plugin . ' has been installed');
r2(U . "paymentgateway", 's', 'Payment Gateway ' . $plugin . ' has been installed');
break;
}
}
@ -333,12 +324,12 @@ switch ($action) {
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
}
if (!file_exists($folder)) {
r2(getUrl('pluginmanager'), 'e', 'Extracted Folder is unknown');
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
}
File::copyFolder($folder, $DEVICE_PATH . DIRECTORY_SEPARATOR, ['README.md', 'LICENSE']);
File::deleteFolder($folder);
unlink($file);
r2(getUrl('settings/devices'), 's', 'Device ' . $plugin . ' has been installed');
r2(U . "settings/devices", 's', 'Device ' . $plugin . ' has been installed');
break;
}
}
@ -354,7 +345,7 @@ switch ($action) {
$ui->assign('plugins', $json['plugins']);
$ui->assign('pgs', $json['payment_gateway']);
$ui->assign('dvcs', $json['devices']);
$ui->display('admin/settings/plugin-manager.tpl');
$ui->display('plugin-manager.tpl');
}

View File

@ -20,6 +20,7 @@ require_once $DEVICE_PATH . DIRECTORY_SEPARATOR . 'MikrotikPppoe' . '.php';
switch ($action) {
case 'list':
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/pool.js"></script>');
$name = _post('name');
if ($name != '') {
@ -32,14 +33,14 @@ switch ($action) {
$ui->assign('d', $d);
run_hook('view_pool'); #HOOK
$ui->display('admin/pool/list.tpl');
$ui->display('pool.tpl');
break;
case 'add':
$r = ORM::for_table('tbl_routers')->find_many();
$ui->assign('r', $r);
run_hook('view_add_pool'); #HOOK
$ui->display('admin/pool/add.tpl');
$ui->display('pool-add.tpl');
break;
case 'edit':
@ -48,9 +49,9 @@ switch ($action) {
if ($d) {
$ui->assign('d', $d);
run_hook('view_edit_pool'); #HOOK
$ui->display('admin/pool/edit.tpl');
$ui->display('pool-edit.tpl');
} else {
r2(getUrl('pool/list'), 'e', Lang::T('Account Not Found'));
r2(U . 'pool/list', 'e', Lang::T('Account Not Found'));
}
break;
@ -64,7 +65,7 @@ switch ($action) {
}
$d->delete();
r2(getUrl('pool/list'), 's', Lang::T('Data Deleted Successfully'));
r2(U . 'pool/list', 's', Lang::T('Data Deleted Successfully'));
}
break;
@ -77,7 +78,7 @@ switch ($action) {
$log .= 'DONE: ' . $pool['pool_name'] . ': ' . $pool['range_ip'] . '<br>';
}
}
r2(getUrl('pool/list'), 's', $log);
r2(U . 'pool/list', 's', $log);
break;
case 'add-post':
$name = _post('name');
@ -107,9 +108,9 @@ switch ($action) {
(new MikrotikPppoe())->add_pool($b);
}
$b->save();
r2(getUrl('pool/list'), 's', Lang::T('Data Created Successfully'));
r2(U . 'pool/list', 's', Lang::T('Data Created Successfully'));
} else {
r2(getUrl('pool/add'), 'e', $msg);
r2(U . 'pool/add', 'e', $msg);
}
break;
@ -142,12 +143,13 @@ switch ($action) {
(new MikrotikPppoe())->update_pool($old, $d);
}
r2(getUrl('pool/list'), 's', Lang::T('Data Updated Successfully'));
r2(U . 'pool/list', 's', Lang::T('Data Updated Successfully'));
} else {
r2(getUrl('pool/edit/') . $id, 'e', $msg);
r2(U . 'pool/edit/' . $id, 'e', $msg);
}
case 'port':
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/pool.js"></script>');
$name = _post('name');
if ($name != '') {
@ -160,14 +162,14 @@ switch ($action) {
$ui->assign('d', $d);
run_hook('view_port'); #HOOK
$ui->display('admin/port/list.tpl');
$ui->display('port.tpl');
break;
case 'add-port':
$r = ORM::for_table('tbl_routers')->find_many();
$ui->assign('r', $r);
run_hook('view_add_port'); #HOOK
$ui->display('admin/port/add.tpl');
$ui->display('port-add.tpl');
break;
case 'edit-port':
@ -176,9 +178,9 @@ switch ($action) {
if ($d) {
$ui->assign('d', $d);
run_hook('view_edit_port'); #HOOK
$ui->display('admin/port/edit.tpl');
$ui->display('port-edit.tpl');
} else {
r2(getUrl('pool/port'), 'e', Lang::T('Account Not Found'));
r2(U . 'pool/port', 'e', Lang::T('Account Not Found'));
}
break;
@ -189,7 +191,7 @@ switch ($action) {
if ($d) {
$d->delete();
r2(getUrl('pool/port'), 's', Lang::T('Data Deleted Successfully'));
r2(U . 'pool/port', 's', Lang::T('Data Deleted Successfully'));
}
break;
@ -202,7 +204,7 @@ switch ($action) {
$log .= 'DONE: ' . $pool['port_name'] . ': ' . $pool['range_port'] . '<br>';
}
}
r2(getUrl('pool/list'), 's', $log);
r2(U . 'pool/list', 's', $log);
break;
case 'add-port-post':
$name = _post('name');
@ -229,21 +231,21 @@ switch ($action) {
$b->range_port = $port_range;
$b->routers = $routers;
$b->save();
r2(getUrl('pool/port'), 's', Lang::T('Data Created Successfully'));
r2(U . 'pool/port', 's', Lang::T('Data Created Successfully'));
} else {
r2(getUrl('pool/add-port'), 'e', $msg);
r2(U . 'pool/add-port', 'e', $msg);
}
break;
case 'edit-port-post':
$name = _post('name');
$name = _post('name');
$public_ip = _post('public_ip');
$range_port = _post('range_port');
$routers = _post('routers');
run_hook('edit_port'); #HOOK
$msg = '';
$msg = '';
$msg = '';
if (Validator::Length($name, 30, 2) == false) {
$msg .= 'Name should be between 3 to 30 characters' . '<br>';
}
@ -259,18 +261,20 @@ switch ($action) {
}
if ($msg == '') {
$d->port_name = $name;
$d->port_name = $name;
$d->public_ip = $public_ip;
$d->range_port = $range_port;
$d->routers = $routers;
$d->save();
r2(getUrl('pool/port'), 's', Lang::T('Data Updated Successfully'));
r2(U . 'pool/port', 's', Lang::T('Data Updated Successfully'));
} else {
r2(getUrl('pool/edit-port/') . $id, 'e', $msg);
r2(U . 'pool/edit-port/' . $id, 'e', $msg);
}
break;
default:
r2(getUrl('pool/list/'), 's', '');
r2(U . 'pool/list/', 's', '');
}

View File

@ -22,7 +22,7 @@ switch ($action) {
$ui->assign('_system_menu', 'radius');
$ui->assign('_title', "Network Access Server");
$ui->assign('routers', ORM::for_table('tbl_routers')->find_many());
$ui->display('admin/radius/nas-add.tpl');
$ui->display('radius-nas-add.tpl');
break;
case 'nas-add-post':
$shortname = _post('shortname');
@ -58,12 +58,12 @@ switch ($action) {
if ($msg == '') {
require_once $DEVICE_PATH . DIRECTORY_SEPARATOR . "Radius.php";
if ((new Radius())->nasAdd($shortname, $nasname, $ports, $secret, $routers, $description, $type, $server, $community) > 0) {
r2(getUrl('radius/nas-list/'), 's', "NAS Added");
r2(U . 'radius/nas-list/', 's', "NAS Added");
} else {
r2(getUrl('radius/nas-add/'), 'e', "NAS Added Failed");
r2(U . 'radius/nas-add/', 'e', "NAS Added Failed");
}
} else {
r2(getUrl('radius/nas-add'), 'e', $msg);
r2(U . 'radius/nas-add', 'e', $msg);
}
break;
case 'nas-edit':
@ -78,9 +78,9 @@ switch ($action) {
if ($d) {
$ui->assign('routers', ORM::for_table('tbl_routers')->find_many());
$ui->assign('d', $d);
$ui->display('admin/radius/nas-edit.tpl');
$ui->display('radius-nas-edit.tpl');
} else {
r2(getUrl('radius/list'), 'e', Lang::T('Account Not Found'));
r2(U . 'radius/list', 'e', Lang::T('Account Not Found'));
}
break;
@ -115,12 +115,12 @@ switch ($action) {
if ($msg == '') {
require_once $DEVICE_PATH . DIRECTORY_SEPARATOR . "Radius.php";
if ((new Radius())->nasUpdate($id, $shortname, $nasname, $ports, $secret, $routers, $description, $type, $server, $community)) {
r2(getUrl('radius/list/'), 's', "NAS Saved");
r2(U . 'radius/list/', 's', "NAS Saved");
} else {
r2(getUrl('radius/nas-add'), 'e', 'NAS NOT Exists');
r2(U . 'radius/nas-add', 'e', 'NAS NOT Exists');
}
} else {
r2(getUrl('radius/nas-add'), 'e', $msg);
r2(U . 'radius/nas-add', 'e', $msg);
}
break;
case 'nas-delete':
@ -129,7 +129,7 @@ switch ($action) {
if ($d) {
$d->delete();
} else {
r2(getUrl('radius/nas-list'), 'e', 'NAS Not found');
r2(U . 'radius/nas-list', 'e', 'NAS Not found');
}
default:
$ui->assign('_system_menu', 'radius');
@ -147,5 +147,5 @@ switch ($action) {
}
$ui->assign('name', $name);
$ui->assign('nas', $nas);
$ui->display('admin/radius/nas.tpl');
$ui->display('radius-nas.tpl');
}

View File

@ -57,7 +57,7 @@ switch ($do) {
// Expire after 10 minutes
if (file_exists($otpPath) && time() - filemtime($otpPath) > 1200) {
unlink($otpPath);
r2(getUrl('register'), 's', 'Verification code expired');
r2(U . 'register', 's', 'Verification code expired');
} else if (file_exists($otpPath)) {
$code = file_get_contents($otpPath);
if ($code != $otp_code) {
@ -75,7 +75,7 @@ switch ($do) {
unlink($otpPath);
}
} else {
r2(getUrl('register'), 's', 'No Verification code');
r2(U . 'register', 's', 'No Verification code');
}
}
@ -113,15 +113,14 @@ switch ($do) {
$d->save();
}
}
if (file_exists($_FILES['photo']['tmp_name']))
unlink($_FILES['photo']['tmp_name']);
if (file_exists($_FILES['photo']['tmp_name'])) unlink($_FILES['photo']['tmp_name']);
User::setFormCustomField($user);
run_hook('register_user'); #HOOK
$msg .= Lang::T('Registration successful') . '<br>';
if ($config['reg_nofify_admin'] == 'yes') {
sendTelegram($config['CompanyName'] . ' - ' . Lang::T('New User Registration') . "\n\nFull Name: " . $fullname . "\nUsername: " . $username . "\nEmail: " . $email . "\nPhone Number: " . $phone_number . "\nAddress: " . $address);
}
r2(getUrl('login'), 's', Lang::T('Register Success! You can login now'));
r2(U . 'login', 's', Lang::T('Register Success! You can login now'));
} else {
$ui->assign('username', $username);
$ui->assign('fullname', $fullname);
@ -148,45 +147,8 @@ switch ($do) {
// Display register-otp.tpl if OTP is enabled
$ui->display('customer/register-otp.tpl');
} else {
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
if (!empty($config['login_page_logo']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'])) {
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'];
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png')) {
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png';
} else {
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.default.png';
}
if (!empty($config['login_page_wallpaper']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'])) {
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'];
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png')) {
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png';
} else {
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.default.png';
}
if (!empty($config['login_page_favicon']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'])) {
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'];
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png')) {
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png';
} else {
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.default.png';
}
$ui->assign('login_logo', $login_logo);
$ui->assign('wallpaper', $wallpaper);
$ui->assign('favicon', $favicon);
$ui->assign('csrf_token', $csrf_token);
$ui->assign('_title', Lang::T('Login'));
$ui->assign('customFields', User::getFormCustomField($ui, true));
switch ($config['login_page_type']) {
case 'custom':
$ui->display('customer/reg-login-custom-' . $config['login_Page_template'] . '.tpl');
break;
default:
$ui->display('customer/register.tpl');
break;
}
// Display register.tpl if OTP is not enabled
$ui->display('customer/register.tpl');
}
}
break;
@ -197,7 +159,7 @@ switch ($do) {
if (!empty($phone_number)) {
$d = ORM::for_table('tbl_customers')->where('username', $phone_number)->find_one();
if ($d) {
r2(getUrl('register'), 's', Lang::T('Account already exists'));
r2(U . 'register', 's', Lang::T('Account already exists'));
}
if (!file_exists($otpPath)) {
mkdir($otpPath);
@ -234,36 +196,6 @@ switch ($do) {
$ui->display('customer/register-rotp.tpl');
}
} else {
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
if (!empty($config['login_page_logo']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'])) {
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'];
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png')) {
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png';
} else {
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.default.png';
}
if (!empty($config['login_page_wallpaper']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'])) {
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'];
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png')) {
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png';
} else {
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.default.png';
}
if (!empty($config['login_page_favicon']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'])) {
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'];
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png')) {
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png';
} else {
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.default.png';
}
$ui->assign('login_logo', $login_logo);
$ui->assign('wallpaper', $wallpaper);
$ui->assign('favicon', $favicon);
$ui->assign('csrf_token', $csrf_token);
$ui->assign('_title', Lang::T('Login'));
$ui->assign('customFields', User::getFormCustomField($ui, true));
$ui->assign('username', "");
$ui->assign('fullname', "");
@ -272,15 +204,7 @@ switch ($do) {
$ui->assign('otp', false);
$ui->assign('_title', Lang::T('Register'));
run_hook('view_register'); #HOOK
switch ($config['login_page_type']) {
case 'custom':
$ui->display('customer/reg-login-custom-' . $config['login_Page_template'] . '.tpl');
break;
default:
$ui->display('customer/register.tpl');
break;
}
$ui->display('customer/register.tpl');
}
break;
}

View File

@ -55,13 +55,9 @@ switch ($action) {
->where('type', $tp);
if (count($mts) > 0) {
if (count($mts) != count($methods)) {
$w = [];
$v = [];
foreach ($mts as $mt) {
$w[] = 'method';
$v[] = "$mt - %";
$query->where_like('method', "$mt - %");
}
$query->where_likes($w, $v);
}
}
if (count($rts) > 0) {
@ -88,13 +84,9 @@ switch ($action) {
}
if (count($mts) > 0) {
if (count($mts) != count($methods)) {
$w = [];
$v = [];
foreach ($mts as $mt) {
$w[] = 'method';
$v[] = "$mt - %";
$query->where_like('method', "$mt - %");
}
$query->where_likes($w, $v);
}
}
if (count($rts) > 0) {
@ -122,6 +114,13 @@ switch ($action) {
if (count($plns) > 0) {
$query->where_in('plan_name', $plns);
}
if (count($mts) > 0) {
if (count($mts) != count($methods)) {
foreach ($mts as $mt) {
$query->where_like('method', "$mt - %");
}
}
}
$count = $query->count();
if ($count > 0) {
$result['datas'][] = $count;
@ -158,13 +157,9 @@ switch ($action) {
}
if (count($mts) > 0) {
if (count($mts) != count($methods)) {
$w = [];
$v = [];
foreach ($mts as $mt) {
$w[] = 'method';
$v[] = "$mt - %";
$query->where_like('method', "$mt - %");
}
$query->where_likes($w, $v);
}
}
if (count($rts) > 0) {
@ -246,7 +241,7 @@ switch ($action) {
$total += $v;
$array['data'][] = $v;
}
if ($total > 0) {
if($total>0){
$result['datas'][] = $array;
}
}
@ -258,34 +253,23 @@ switch ($action) {
die();
case 'by-date':
case 'activation':
$q = trim(_post('q') ?: _get('q'));
$q = (_post('q') ? _post('q') : _get('q'));
$keep = _post('keep');
if (!empty($keep)) {
ORM::raw_execute("DELETE FROM tbl_transactions WHERE date < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL ? DAY))", [$keep]);
r2(getUrl('reports/activation/'), 's', "Deleted logs older than $keep days");
ORM::raw_execute("DELETE FROM tbl_transactions WHERE date < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))");
r2(U . "logs/list/", 's', "Delete logs older than $keep days");
}
$query = ORM::for_table('tbl_transactions')
->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
->select('tbl_transactions.*')
->select('tbl_customers.fullname', 'fullname')
->order_by_desc('tbl_transactions.id');
if ($q !== '') {
$query->where_like('invoice', "%$q%");
}
try {
if ($q != '') {
$query = ORM::for_table('tbl_transactions')->where_like('invoice', '%' . $q . '%')->order_by_desc('id');
$d = Paginator::findMany($query, ['q' => $q]);
} catch (Exception $e) {
r2(getUrl('reports/activation/'), 'e', 'Database query failed: ' . $e->getMessage());
$d = [];
} else {
$query = ORM::for_table('tbl_transactions')->order_by_desc('id');
$d = Paginator::findMany($query);
}
$ui->assign('activation', $d);
$ui->assign('q', $q);
$ui->display('admin/reports/activation.tpl');
$ui->display('reports-activation.tpl');
break;
case 'by-period':
@ -293,7 +277,7 @@ switch ($action) {
$ui->assign('mtime', $mtime);
$ui->assign('tdate', $tdate);
run_hook('view_reports_by_period'); #HOOK
$ui->display('admin/reports/period.tpl');
$ui->display('reports-period.tpl');
break;
case 'period-view':
@ -302,10 +286,6 @@ switch ($action) {
$stype = _post('stype');
$d = ORM::for_table('tbl_transactions');
$d->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
->select('tbl_transactions.*')
->select('tbl_customers.fullname', 'fullname')
->order_by_desc('tbl_transactions.id');
if ($stype != '') {
$d->where('type', $stype);
}
@ -313,7 +293,7 @@ switch ($action) {
$d->where_gte('recharged_on', $fdate);
$d->where_lte('recharged_on', $tdate);
$d->order_by_desc('id');
$x = $d->find_many();
$x = $d->find_many();
$dr = ORM::for_table('tbl_transactions');
if ($stype != '') {
@ -330,7 +310,7 @@ switch ($action) {
$ui->assign('tdate', $tdate);
$ui->assign('stype', $stype);
run_hook('view_reports_period'); #HOOK
$ui->display('admin/reports/period-view.tpl');
$ui->display('reports-period-view.tpl');
break;
case 'daily-report':
@ -363,21 +343,16 @@ switch ($action) {
$query = ORM::for_table('tbl_transactions')
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) >= " . strtotime("$sd $ts"))
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) <= " . strtotime("$ed $te"))
->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
->select('tbl_transactions.*')
->select('tbl_customers.fullname', 'fullname')
->order_by_desc('tbl_transactions.id');
->order_by_desc('id');
if (count($tps) > 0) {
$query->where_in('type', $tps);
}
if (count($mts) > 0) {
$w = [];
$v = [];
foreach ($mts as $mt) {
$w[] = 'method';
$v[] = "$mt - %";
if (count($mts) != count($methods)) {
foreach ($mts as $mt) {
$query->where_like('method', "$mt - %");
}
}
$query->where_likes($w, $v);
}
if (count($rts) > 0) {
$query->where_in('routers', $rts);
@ -409,6 +384,6 @@ switch ($action) {
$ui->assign('dr', $dr);
$ui->assign('mdate', $mdate);
run_hook('view_daily_reports'); #HOOK
$ui->display('admin/reports/list.tpl');
$ui->display('reports.tpl');
break;
}

View File

@ -23,9 +23,24 @@ $leafletpickerHeader = <<<EOT
EOT;
switch ($action) {
case 'maps':
$name = _post('name');
$query = ORM::for_table('tbl_routers')->where_not_equal('coordinates', '')->order_by_desc('id');
$query->selects(['id', 'name', 'coordinates', 'description', 'coverage', 'enabled']);
if ($name != '') {
$query->where_like('name', '%' . $name . '%');
}
$d = Paginator::findMany($query, ['name' => $name], '20', '', true);
$ui->assign('name', $name);
$ui->assign('d', $d);
$ui->assign('_title', Lang::T('Routers Geo Location Information'));
$ui->assign('xheader', $leafletpickerHeader);
$ui->assign('xfooter', '<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>');
$ui->display('routers-maps.tpl');
break;
case 'add':
run_hook('view_add_routers'); #HOOK
$ui->display('admin/routers/add.tpl');
$ui->display('routers-add.tpl');
break;
case 'edit':
@ -38,9 +53,9 @@ switch ($action) {
if ($d) {
$ui->assign('d', $d);
run_hook('view_router_edit'); #HOOK
$ui->display('admin/routers/edit.tpl');
$ui->display('routers-edit.tpl');
} else {
r2(getUrl('routers/list'), 'e', Lang::T('Account Not Found'));
r2(U . 'routers/list', 'e', Lang::T('Account Not Found'));
}
break;
@ -50,7 +65,7 @@ switch ($action) {
$d = ORM::for_table('tbl_routers')->find_one($id);
if ($d) {
$d->delete();
r2(getUrl('routers/list'), 's', Lang::T('Data Deleted Successfully'));
r2(U . 'routers/list', 's', Lang::T('Data Deleted Successfully'));
}
break;
@ -94,9 +109,9 @@ switch ($action) {
$d->enabled = $enabled;
$d->save();
r2(getUrl('routers/edit/') . $d->id(), 's', Lang::T('Data Created Successfully'));
r2(U . 'routers/edit/' . $d->id(), 's', Lang::T('Data Created Successfully'));
} else {
r2(getUrl('routers/add'), 'e', $msg);
r2(U . 'routers/add', 'e', $msg);
}
break;
@ -182,13 +197,14 @@ switch ($action) {
$p->set('routers', $name);
$p->save();
}
r2(getUrl('routers/list'), 's', Lang::T('Data Updated Successfully'));
r2(U . 'routers/list', 's', Lang::T('Data Updated Successfully'));
} else {
r2(getUrl('routers/edit/') . $id, 'e', $msg);
r2(U . 'routers/edit/' . $id, 'e', $msg);
}
break;
default:
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/routers.js"></script>');
$name = _post('name');
$name = _post('name');
@ -199,6 +215,6 @@ switch ($action) {
$d = Paginator::findMany($query, ['name' => $name]);
$ui->assign('d', $d);
run_hook('view_list_routers'); #HOOK
$ui->display('admin/routers/list.tpl');
$ui->display('routers.tpl');
break;
}

View File

@ -2,7 +2,7 @@
$query = isset($_GET['query']) ? trim($_GET['query']) : '';
if (!empty($query)) {
if (!empty($query)) {
$results = ORM::for_table('tbl_customers')
->where_like('username', "%$query%")
->find_many();

View File

@ -33,7 +33,7 @@ switch ($action) {
}
}
}
r2(getUrl('services/hotspot'), 's', $log);
r2(U . 'services/hotspot', 's', $log);
} else if ($routes['2'] == 'pppoe') {
$plans = ORM::for_table('tbl_plans')->where('type', 'PPPOE')->find_many();
$log = '';
@ -49,10 +49,11 @@ switch ($action) {
}
}
}
r2(getUrl('services/pppoe'), 's', $log);
r2(U . 'services/pppoe', 's', $log);
}
r2(getUrl('services/hotspot'), 'w', 'Unknown command');
r2(U . 'services/hotspot', 'w', 'Unknown command');
case 'hotspot':
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/hotspot.js"></script>');
$name = _req('name');
$type1 = _req('type1');
$type2 = _req('type2');
@ -138,7 +139,7 @@ switch ($action) {
$d = Paginator::findMany($query, ['name' => $name], 20, $append_url);
$ui->assign('d', $d);
run_hook('view_list_plans'); #HOOK
$ui->display('admin/hotspot/list.tpl');
$ui->display('hotspot.tpl');
break;
case 'add':
$d = ORM::for_table('tbl_bandwidth')->find_many();
@ -155,7 +156,7 @@ switch ($action) {
}
$ui->assign('devices', $devices);
run_hook('view_add_plan'); #HOOK
$ui->display('admin/hotspot/add.tpl');
$ui->display('hotspot-add.tpl');
break;
case 'edit':
@ -190,9 +191,9 @@ switch ($action) {
}
$ui->assign('exps', $exps);
run_hook('view_edit_plan'); #HOOK
$ui->display('admin/hotspot/edit.tpl');
$ui->display('hotspot-edit.tpl');
} else {
r2(getUrl('services/hotspot'), 'e', Lang::T('Account Not Found'));
r2(U . 'services/hotspot', 'e', Lang::T('Account Not Found'));
}
break;
@ -213,7 +214,7 @@ switch ($action) {
}
$d->delete();
r2(getUrl('services/hotspot'), 's', Lang::T('Data Deleted Successfully'));
r2(U . 'services/hotspot', 's', Lang::T('Data Deleted Successfully'));
}
break;
@ -306,9 +307,9 @@ switch ($action) {
new Exception(Lang::T("Devices Not Found"));
}
}
r2(getUrl('services/edit/') . $d->id(), 's', Lang::T('Data Created Successfully'));
r2(U . 'services/edit/' . $d->id(), 's', Lang::T('Data Created Successfully'));
} else {
r2(getUrl('services/add'), 'e', $msg);
r2(U . 'services/add', 'e', $msg);
}
break;
@ -419,14 +420,15 @@ switch ($action) {
new Exception(Lang::T("Devices Not Found"));
}
}
r2(getUrl('services/hotspot'), 's', Lang::T('Data Updated Successfully'));
r2(U . 'services/hotspot', 's', Lang::T('Data Updated Successfully'));
} else {
r2(getUrl('services/edit/') . $id, 'e', $msg);
r2(U . 'services/edit/' . $id, 'e', $msg);
}
break;
case 'pppoe':
$ui->assign('_title', Lang::T('PPPOE Plans'));
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/pppoe.js"></script>');
$name = _post('name');
$name = _req('name');
@ -514,7 +516,7 @@ switch ($action) {
$ui->assign('d', $d);
run_hook('view_list_ppoe'); #HOOK
$ui->display('admin/pppoe/list.tpl');
$ui->display('pppoe.tpl');
break;
case 'pppoe-add':
@ -533,7 +535,7 @@ switch ($action) {
}
$ui->assign('devices', $devices);
run_hook('view_add_ppoe'); #HOOK
$ui->display('admin/pppoe/add.tpl');
$ui->display('pppoe-add.tpl');
break;
case 'pppoe-edit':
@ -576,9 +578,9 @@ switch ($action) {
}
$ui->assign('exps', $exps);
run_hook('view_edit_ppoe'); #HOOK
$ui->display('admin/pppoe/edit.tpl');
$ui->display('pppoe-edit.tpl');
} else {
r2(getUrl('services/pppoe'), 'e', Lang::T('Account Not Found'));
r2(U . 'services/pppoe', 'e', Lang::T('Account Not Found'));
}
break;
@ -600,7 +602,7 @@ switch ($action) {
}
$d->delete();
r2(getUrl('services/pppoe'), 's', Lang::T('Data Deleted Successfully'));
r2(U . 'services/pppoe', 's', Lang::T('Data Deleted Successfully'));
}
break;
@ -698,9 +700,9 @@ switch ($action) {
new Exception(Lang::T("Devices Not Found"));
}
}
r2(getUrl('services/pppoe'), 's', Lang::T('Data Created Successfully'));
r2(U . 'services/pppoe', 's', Lang::T('Data Created Successfully'));
} else {
r2(getUrl('services/pppoe-add'), 'e', $msg);
r2(U . 'services/pppoe-add', 'e', $msg);
}
break;
@ -799,9 +801,9 @@ switch ($action) {
new Exception(Lang::T("Devices Not Found"));
}
}
r2(getUrl('services/pppoe'), 's', Lang::T('Data Updated Successfully'));
r2(U . 'services/pppoe', 's', Lang::T('Data Updated Successfully'));
} else {
r2(getUrl('services/pppoe-edit/') . $id, 'e', $msg);
r2(U . 'services/pppoe-edit/' . $id, 'e', $msg);
}
break;
case 'balance':
@ -817,12 +819,12 @@ switch ($action) {
$ui->assign('d', $d);
run_hook('view_list_balance'); #HOOK
$ui->display('admin/balance/list.tpl');
$ui->display('balance.tpl');
break;
case 'balance-add':
$ui->assign('_title', Lang::T('Balance Plans'));
run_hook('view_add_balance'); #HOOK
$ui->display('admin/balance/add.tpl');
$ui->display('balance-add.tpl');
break;
case 'balance-edit':
$ui->assign('_title', Lang::T('Balance Plans'));
@ -830,7 +832,7 @@ switch ($action) {
$d = ORM::for_table('tbl_plans')->find_one($id);
$ui->assign('d', $d);
run_hook('view_edit_balance'); #HOOK
$ui->display('admin/balance/edit.tpl');
$ui->display('balance-edit.tpl');
break;
case 'balance-delete':
$id = $routes['2'];
@ -839,7 +841,7 @@ switch ($action) {
if ($d) {
run_hook('delete_balance'); #HOOK
$d->delete();
r2(getUrl('services/balance'), 's', Lang::T('Data Deleted Successfully'));
r2(U . 'services/balance', 's', Lang::T('Data Deleted Successfully'));
}
break;
case 'balance-edit-post':
@ -875,9 +877,9 @@ switch ($action) {
$d->prepaid = 'yes';
$d->save();
r2(getUrl('services/balance'), 's', Lang::T('Data Updated Successfully'));
r2(U . 'services/balance', 's', Lang::T('Data Updated Successfully'));
} else {
r2(getUrl('services/balance-edit/') . $id, 'e', $msg);
r2(U . 'services/balance-edit/' . $id, 'e', $msg);
}
break;
case 'balance-add-post':
@ -912,13 +914,14 @@ switch ($action) {
$d->prepaid = 'yes';
$d->save();
r2(getUrl('services/balance'), 's', Lang::T('Data Created Successfully'));
r2(U . 'services/balance', 's', Lang::T('Data Created Successfully'));
} else {
r2(getUrl('services/balance-add'), 'e', $msg);
r2(U . 'services/balance-add', 'e', $msg);
}
break;
case 'vpn':
$ui->assign('_title', Lang::T('VPN Plans'));
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/pppoe.js"></script>');
$name = _post('name');
$name = _req('name');
@ -1006,7 +1009,7 @@ switch ($action) {
$ui->assign('d', $d);
run_hook('view_list_vpn'); #HOOK
$ui->display('admin/vpn/list.tpl');
$ui->display('vpn.tpl');
break;
case 'vpn-add':
@ -1025,7 +1028,7 @@ switch ($action) {
}
$ui->assign('devices', $devices);
run_hook('view_add_vpn'); #HOOK
$ui->display('admin/vpn/add.tpl');
$ui->display('vpn-add.tpl');
break;
case 'vpn-edit':
@ -1068,9 +1071,9 @@ switch ($action) {
}
$ui->assign('exps', $exps);
run_hook('view_edit_vpn'); #HOOK
$ui->display('admin/vpn/edit.tpl');
$ui->display('vpn-edit.tpl');
} else {
r2(getUrl('services/vpn'), 'e', Lang::T('Account Not Found'));
r2(U . 'services/vpn', 'e', Lang::T('Account Not Found'));
}
break;
@ -1092,7 +1095,7 @@ switch ($action) {
}
$d->delete();
r2(getUrl('services/vpn'), 's', Lang::T('Data Deleted Successfully'));
r2(U . 'services/vpn', 's', Lang::T('Data Deleted Successfully'));
}
break;
@ -1190,9 +1193,9 @@ switch ($action) {
new Exception(Lang::T("Devices Not Found"));
}
}
r2(getUrl('services/vpn'), 's', Lang::T('Data Created Successfully'));
r2(U . 'services/vpn', 's', Lang::T('Data Created Successfully'));
} else {
r2(getUrl('services/vpn-add'), 'e', $msg);
r2(U . 'services/vpn-add', 'e', $msg);
}
break;
@ -1291,11 +1294,11 @@ switch ($action) {
new Exception(Lang::T("Devices Not Found"));
}
}
r2(getUrl('services/vpn'), 's', Lang::T('Data Updated Successfully'));
r2(U . 'services/vpn', 's', Lang::T('Data Updated Successfully'));
} else {
r2(getUrl('services/vpn-edit/') . $id, 'e', $msg);
r2(U . 'services/vpn-edit/' . $id, 'e', $msg);
}
break;
default:
$ui->display('admin/404.tpl');
$ui->display('a404.tpl');
}

View File

@ -23,7 +23,7 @@ switch ($action) {
$d->value = 'yes';
$d->save();
}
r2(APP_URL . '/docs');
r2('./docs');
break;
case 'devices':
$files = scandir($DEVICE_PATH);
@ -50,7 +50,7 @@ switch ($action) {
}
}
$ui->assign('devices', $devices);
$ui->display('admin/settings/devices.tpl');
$ui->display('app-devices.tpl');
break;
case 'app':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
@ -58,35 +58,23 @@ switch ($action) {
}
if (!empty(_get('testWa'))) {
if ($_app_stage == 'Demo') {
r2(getUrl('settings/app'), 'e', 'You cannot perform this action in Demo mode');
}
$result = Message::sendWhatsapp(_get('testWa'), 'PHPNuxBill Test Whatsapp');
r2(getUrl('settings/app'), 's', 'Test Whatsapp has been send<br>Result: ' . $result);
r2(U . "settings/app", 's', 'Test Whatsapp has been send<br>Result: ' . $result);
}
if (!empty(_get('testSms'))) {
if ($_app_stage == 'Demo') {
r2(getUrl('settings/app'), 'e', 'You cannot perform this action in Demo mode');
}
$result = Message::sendSMS(_get('testSms'), 'PHPNuxBill Test SMS');
r2(getUrl('settings/app'), 's', 'Test SMS has been send<br>Result: ' . $result);
r2(U . "settings/app", 's', 'Test SMS has been send<br>Result: ' . $result);
}
if (!empty(_get('testEmail'))) {
if ($_app_stage == 'Demo') {
r2(getUrl('settings/app'), 'e', 'You cannot perform this action in Demo mode');
}
Message::sendEmail(_get('testEmail'), 'PHPNuxBill Test Email', 'PHPNuxBill Test Email Body');
r2(getUrl('settings/app'), 's', 'Test Email has been send');
r2(U . "settings/app", 's', 'Test Email has been send');
}
if (!empty(_get('testTg'))) {
if ($_app_stage == 'Demo') {
r2(getUrl('settings/app'), 'e', 'You cannot perform this action in Demo mode');
}
$result = Message::sendTelegram('PHPNuxBill Test Telegram');
r2(getUrl('settings/app'), 's', 'Test Telegram has been send<br>Result: ' . $result);
r2(U . "settings/app", 's', 'Test Telegram has been send<br>Result: ' . $result);
}
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) {
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png?' . time();
} else {
@ -117,7 +105,7 @@ switch ($action) {
} else {
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.default.png';
}
$ui->assign('login_logo', $login_logo);
$ui->assign('wallpaper', $wallpaper);
$ui->assign('favicon', $favicon);
@ -146,8 +134,7 @@ switch ($action) {
$r = ORM::for_table('tbl_routers')->find_many();
$ui->assign('r', $r);
if (function_exists("shell_exec")) {
$which = stripos(php_uname('s'), "Win") === 0 ? 'where' : 'which';
$php = trim(shell_exec("$which php"));
$php = trim(shell_exec('which php'));
if (empty($php)) {
$php = 'php';
}
@ -178,43 +165,35 @@ switch ($action) {
run_hook('view_app_settings'); #HOOK
$csrf_token = Csrf::generateAndStoreToken();
$ui->assign('csrf_token', $csrf_token);
$ui->display('admin/settings/app.tpl');
$ui->display('app-settings.tpl');
break;
case 'app-post':
if ($_app_stage == 'Demo') {
r2(getUrl('settings/app'), 'e', 'You cannot perform this action in Demo mode');
}
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('settings/app'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'settings/app', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$company = _post('CompanyName');
$custom_tax_rate = filter_var(_post('custom_tax_rate'), FILTER_SANITIZE_SPECIAL_CHARS);
if (preg_match('/[^0-9.]/', $custom_tax_rate)) {
r2(getUrl('settings/app'), 'e', 'Special characters are not allowed in tax rate');
r2(U . 'settings/app', 'e', 'Special characters are not allowed in tax rate');
die();
}
run_hook('save_settings'); #HOOK
if (!empty($_FILES['logo']['name'])) {
if (function_exists('imagecreatetruecolor')) {
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png'))
unlink($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png');
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) unlink($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png');
File::resizeCropImage($_FILES['logo']['tmp_name'], $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png', 1078, 200, 100);
if (file_exists($_FILES['logo']['tmp_name']))
unlink($_FILES['logo']['tmp_name']);
if (file_exists($_FILES['logo']['tmp_name'])) unlink($_FILES['logo']['tmp_name']);
} else {
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
r2(U . 'settings/app', 'e', 'PHP GD is not installed');
}
}
if ($_POST['general'] && $company == '') {
r2(getUrl('settings/app'), 'e', Lang::T('All field is required'));
r2(U . 'settings/app', 'e', Lang::T('All field is required'));
} else {
if ($radius_enable) {
try {
@ -225,7 +204,7 @@ switch ($action) {
$ui->assign("error_message", "Radius table not found.<br><br>" .
$e->getMessage() .
"<br><br>Download <a href=\"https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/Development/install/radius.sql\">here</a> or <a href=\"https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/install/radius.sql\">here</a> and import it to database.<br><br>Check config.php for radius connection details");
$ui->display('admin/error.tpl');
$ui->display('error.tpl');
die();
}
}
@ -236,88 +215,6 @@ switch ($action) {
$_POST['man_fields_custom'] = isset($_POST['man_fields_custom']) ? 'yes' : 'no';
$enable_session_timeout = isset($_POST['enable_session_timeout']) ? 1 : 0;
$_POST['enable_session_timeout'] = $enable_session_timeout;
$_POST['notification_reminder_1day'] = isset($_POST['notification_reminder_1day']) ? 'yes' : 'no';
$_POST['notification_reminder_3days'] = isset($_POST['notification_reminder_3days']) ? 'yes' : 'no';
$_POST['notification_reminder_7days'] = isset($_POST['notification_reminder_7days']) ? 'yes' : 'no';
// hide dashboard
$_POST['hide_mrc'] = _post('hide_mrc', 'no');
$_POST['hide_tms'] = _post('hide_tms', 'no');
$_POST['hide_al'] = _post('hide_al', 'no');
$_POST['hide_uet'] = _post('hide_uet', 'no');
$_POST['hide_vs'] = _post('hide_vs', 'no');
$_POST['hide_pg'] = _post('hide_pg', 'no');
$_POST['hide_aui'] = _post('hide_aui', 'no');
// Login page post
$login_page_title = _post('login_page_head');
$login_page_description = _post('login_page_description');
$login_Page_template = _post('login_Page_template');
$login_page_type = _post('login_page_type');
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('settings/app'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
if ($login_page_type == 'custom' && (empty($login_Page_template) || empty($login_page_title) || empty($login_page_description))) {
r2(getUrl('settings/app'), 'e', 'Please fill all required fields');
return;
}
if (strlen($login_page_title) > 25) {
r2(getUrl('settings/app'), 'e', 'Login page title must not exceed 25 characters');
return;
}
if (strlen($login_page_description) > 100) {
r2(getUrl('settings/app'), 'e', 'Login page description must not exceed 50 characters');
return;
}
$image_paths = [];
$allowed_types = ['image/jpeg', 'image/png'];
if ($_FILES['login_page_favicon']['name'] != '') {
$favicon_type = $_FILES['login_page_favicon']['type'];
if (in_array($favicon_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_favicon']['name'])) {
$extension = pathinfo($_FILES['login_page_favicon']['name'], PATHINFO_EXTENSION);
$favicon_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('favicon_') . '.' . $extension;
File::resizeCropImage($_FILES['login_page_favicon']['tmp_name'], $favicon_path, 16, 16, 100);
$_POST['login_page_favicon'] = basename($favicon_path); // Save dynamic file name
if (file_exists($_FILES['login_page_favicon']['tmp_name']))
unlink($_FILES['login_page_favicon']['tmp_name']);
} else {
r2(getUrl('settings/app'), 'e', 'Favicon must be a JPG, JPEG, or PNG image.');
}
}
if ($_FILES['login_page_wallpaper']['name'] != '') {
$wallpaper_type = $_FILES['login_page_wallpaper']['type'];
if (in_array($wallpaper_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_wallpaper']['name'])) {
$extension = pathinfo($_FILES['login_page_wallpaper']['name'], PATHINFO_EXTENSION);
$wallpaper_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('wallpaper_') . '.' . $extension;
File::resizeCropImage($_FILES['login_page_wallpaper']['tmp_name'], $wallpaper_path, 1920, 1080, 100);
$_POST['login_page_wallpaper'] = basename($wallpaper_path); // Save dynamic file name
if (file_exists($_FILES['login_page_wallpaper']['tmp_name']))
unlink($_FILES['login_page_wallpaper']['tmp_name']);
} else {
r2(getUrl('settings/app'), 'e', 'Wallpaper must be a JPG, JPEG, or PNG image.');
}
}
if ($_FILES['login_page_logo']['name'] != '') {
$logo_type = $_FILES['login_page_logo']['type'];
if (in_array($logo_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_logo']['name'])) {
$extension = pathinfo($_FILES['login_page_logo']['name'], PATHINFO_EXTENSION);
$logo_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('logo_') . '.' . $extension;
File::resizeCropImage($_FILES['login_page_logo']['tmp_name'], $logo_path, 300, 60, 100);
$_POST['login_page_logo'] = basename($logo_path); // Save dynamic file name
if (file_exists($_FILES['login_page_logo']['tmp_name']))
unlink($_FILES['login_page_logo']['tmp_name']);
} else {
r2(getUrl('settings/app'), 'e', 'Logo must be a JPG, JPEG, or PNG image.');
}
}
foreach ($_POST as $key => $value) {
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
if ($d) {
@ -332,10 +229,102 @@ switch ($action) {
}
_log('[' . $admin['username'] . ']: ' . Lang::T('Settings Saved Successfully'), $admin['user_type'], $admin['id']);
r2(getUrl('settings/app'), 's', Lang::T('Settings Saved Successfully'));
r2(U . 'settings/app', 's', Lang::T('Settings Saved Successfully'));
}
break;
case 'login-page-post':
// Login page post
$login_page_title = _post('login_page_head');
$login_page_description = _post('login_page_description');
$login_Page_template = _post('login_Page_template');
$login_page_type = _post('login_page_type');
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(U . 'settings/app', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
if ($login_page_type == 'custom' && (empty($login_Page_template) || empty($login_page_title) || empty($login_page_description))) {
r2(U . 'settings/app', 'e', 'Please fill all required fields');
return;
}
if (strlen($login_page_title) > 25) {
r2(U . 'settings/app', 'e', 'Login page title must not exceed 25 characters');
return;
}
if (strlen($login_page_description) > 100) {
r2(U . 'settings/app', 'e', 'Login page description must not exceed 50 characters');
return;
}
$settings = [
'login_page_head' => $login_page_title,
'login_page_description' => $login_page_description,
'login_Page_template' => $login_Page_template,
'login_page_type' => $login_page_type,
];
$image_paths = [];
$allowed_types = ['image/jpeg', 'image/png'];
if ($_FILES['login_page_favicon']['name'] != '') {
$favicon_type = $_FILES['login_page_favicon']['type'];
if (in_array($favicon_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_favicon']['name'])) {
$extension = pathinfo($_FILES['login_page_favicon']['name'], PATHINFO_EXTENSION);
$favicon_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('favicon_') . '.' . $extension;
File::resizeCropImage($_FILES['login_page_favicon']['tmp_name'], $favicon_path, 16, 16, 100);
$settings['login_page_favicon'] = basename($favicon_path); // Save dynamic file name
if (file_exists($_FILES['login_page_favicon']['tmp_name'])) unlink($_FILES['login_page_favicon']['tmp_name']);
} else {
r2(U . 'settings/app', 'e', 'Favicon must be a JPG, JPEG, or PNG image.');
}
}
if ($_FILES['login_page_wallpaper']['name'] != '') {
$wallpaper_type = $_FILES['login_page_wallpaper']['type'];
if (in_array($wallpaper_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_wallpaper']['name'])) {
$extension = pathinfo($_FILES['login_page_wallpaper']['name'], PATHINFO_EXTENSION);
$wallpaper_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('wallpaper_') . '.' . $extension;
File::resizeCropImage($_FILES['login_page_wallpaper']['tmp_name'], $wallpaper_path, 1920, 1080, 100);
$settings['login_page_wallpaper'] = basename($wallpaper_path); // Save dynamic file name
if (file_exists($_FILES['login_page_wallpaper']['tmp_name'])) unlink($_FILES['login_page_wallpaper']['tmp_name']);
} else {
r2(U . 'settings/app', 'e', 'Wallpaper must be a JPG, JPEG, or PNG image.');
}
}
if ($_FILES['login_page_logo']['name'] != '') {
$logo_type = $_FILES['login_page_logo']['type'];
if (in_array($logo_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_logo']['name'])) {
$extension = pathinfo($_FILES['login_page_logo']['name'], PATHINFO_EXTENSION);
$logo_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('logo_') . '.' . $extension;
File::resizeCropImage($_FILES['login_page_logo']['tmp_name'], $logo_path, 300, 60, 100);
$settings['login_page_logo'] = basename($logo_path); // Save dynamic file name
if (file_exists($_FILES['login_page_logo']['tmp_name'])) unlink($_FILES['login_page_logo']['tmp_name']);
} else {
r2(U . 'settings/app', 'e', 'Logo must be a JPG, JPEG, or PNG image.');
}
}
foreach ($settings as $key => $value) {
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
if ($d) {
$d->value = $value;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = $key;
$d->value = $value;
$d->save();
}
}
_log('[' . $admin['username'] . ']: ' . Lang::T('Login Page Settings Saved Successfully'), $admin['user_type'], $admin['id']);
r2(U . 'settings/app', 's', Lang::T('Login Page Settings Saved Successfully'));
break;
case 'localisation':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
@ -362,19 +351,16 @@ switch ($action) {
run_hook('view_localisation'); #HOOK
$csrf_token = Csrf::generateAndStoreToken();
$ui->assign('csrf_token', $csrf_token);
$ui->display('admin/settings/localisation.tpl');
$ui->display('app-localisation.tpl');
break;
case 'localisation-post':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
if ($_app_stage == 'Demo') {
r2(getUrl('settings/localisation'), 'e', 'You cannot perform this action in Demo mode');
}
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('settings/localisation'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'settings/app', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$tzone = _post('tzone');
$date_format = _post('date_format');
@ -382,7 +368,7 @@ switch ($action) {
$lan = _post('lan');
run_hook('save_localisation'); #HOOK
if ($tzone == '' or $date_format == '' or $lan == '') {
r2(getUrl('settings/localisation'), 'e', Lang::T('All field is required'));
r2(U . 'settings/app', 'e', Lang::T('All field is required'));
} else {
$d = ORM::for_table('tbl_appconfig')->where('setting', 'timezone')->find_one();
$d->value = $tzone;
@ -467,7 +453,7 @@ switch ($action) {
$d->value = $lan;
$d->save();
_log('[' . $admin['username'] . ']: ' . 'Settings Saved Successfully', $admin['user_type'], $admin['id']);
r2(getUrl('settings/localisation'), 's', 'Settings Saved Successfully');
r2(U . 'settings/localisation', 's', 'Settings Saved Successfully');
}
break;
@ -485,11 +471,11 @@ switch ($action) {
} else if ($admin['user_type'] == 'Admin') {
$query = ORM::for_table('tbl_users')
->where_like('username', '%' . $search . '%')->where_any_is([
['user_type' => 'Report'],
['user_type' => 'Agent'],
['user_type' => 'Sales'],
['id' => $admin['id']]
])->order_by_asc('id');
['user_type' => 'Report'],
['user_type' => 'Agent'],
['user_type' => 'Sales'],
['id' => $admin['id']]
])->order_by_asc('id');
$d = Paginator::findMany($query, ['search' => $search]);
} else {
$query = ORM::for_table('tbl_users')
@ -540,7 +526,7 @@ switch ($action) {
run_hook('view_list_admin'); #HOOK
$csrf_token = Csrf::generateAndStoreToken();
$ui->assign('csrf_token', $csrf_token);
$ui->display('admin/admin/list.tpl');
$ui->display('admin.tpl');
break;
case 'users-add':
@ -551,17 +537,17 @@ switch ($action) {
$ui->assign('csrf_token', $csrf_token);
$ui->assign('_title', Lang::T('Add User'));
$ui->assign('agents', ORM::for_table('tbl_users')->where('user_type', 'Agent')->find_many());
$ui->display('admin/admin/add.tpl');
$ui->display('admin-add.tpl');
break;
case 'users-view':
$ui->assign('_title', Lang::T('Edit User'));
$id = $routes['2'];
$id = $routes['2'];
if (empty($id)) {
$id = $admin['id'];
}
//allow see himself
if ($admin['id'] == $id) {
$d = ORM::for_table('tbl_users')->where('id', $id)->find_array()[0];
$d = ORM::for_table('tbl_users')->where('id', $id)->find_array($id)[0];
} else {
if (in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
// Super Admin can see anyone
@ -580,9 +566,9 @@ switch ($action) {
$ui->assign('_title', $d['username']);
$csrf_token = Csrf::generateAndStoreToken();
$ui->assign('csrf_token', $csrf_token);
$ui->display('admin/admin/view.tpl');
$ui->display('admin-view.tpl');
} else {
r2(getUrl('settings/users'), 'e', Lang::T('Account Not Found'));
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
}
break;
case 'users-edit':
@ -590,7 +576,7 @@ switch ($action) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$ui->assign('_title', Lang::T('Edit User'));
$id = $routes['2'];
$id = $routes['2'];
if (empty($id)) {
$id = $admin['id'];
}
@ -636,9 +622,9 @@ switch ($action) {
run_hook('view_edit_admin'); #HOOK
$csrf_token = Csrf::generateAndStoreToken();
$ui->assign('csrf_token', $csrf_token);
$ui->display('admin/admin/edit.tpl');
$ui->display('admin-edit.tpl');
} else {
r2(getUrl('settings/users'), 'e', Lang::T('Account Not Found'));
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
}
break;
@ -646,20 +632,18 @@ switch ($action) {
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
if ($_app_stage == 'Demo') {
r2(getUrl('settings/users'), 'e', 'You cannot perform this action in Demo mode');
}
$id = $routes['2'];
$id = $routes['2'];
if (($admin['id']) == $id) {
r2(getUrl('settings/users'), 'e', 'Sorry You can\'t delete yourself');
r2(U . 'settings/users', 'e', 'Sorry You can\'t delete yourself');
}
$d = ORM::for_table('tbl_users')->find_one($id);
if ($d) {
run_hook('delete_admin'); #HOOK
$d->delete();
r2(getUrl('settings/users'), 's', Lang::T('User deleted Successfully'));
r2(U . 'settings/users', 's', Lang::T('User deleted Successfully'));
} else {
r2(getUrl('settings/users'), 'e', Lang::T('Account Not Found'));
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
}
break;
@ -667,12 +651,9 @@ switch ($action) {
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
if ($_app_stage == 'Demo') {
r2(getUrl('settings/users-add'), 'e', 'You cannot perform this action in Demo mode');
}
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('settings/users-add'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'settings/users-add', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$username = _post('username');
$fullname = _post('fullname');
@ -731,19 +712,16 @@ switch ($action) {
}
_log('[' . $admin['username'] . ']: ' . "Created $user_type <b>$username</b>", $admin['user_type'], $admin['id']);
r2(getUrl('settings/users'), 's', Lang::T('Account Created Successfully'));
r2(U . 'settings/users', 's', Lang::T('Account Created Successfully'));
} else {
r2(getUrl('settings/users-add'), 'e', $msg);
r2(U . 'settings/users-add', 'e', $msg);
}
break;
case 'users-edit-post':
if ($_app_stage == 'Demo') {
r2(getUrl('settings/users-edit/'), 'e', 'You cannot perform this action in Demo mode');
}
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('settings/users-edit/'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'settings/users-edit/', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$username = _post('username');
$fullname = _post('fullname');
@ -834,7 +812,7 @@ switch ($action) {
}
}
if (file_exists($imgPath)) {
if ($d['photo'] != '' && strpos($d['photo'], 'default') === false) {
if ($d['photo'] != '' && strpos($d['photo'], 'default') === false) {
if (file_exists($UPLOAD_PATH . $d['photo'])) {
unlink($UPLOAD_PATH . $d['photo']);
if (file_exists($UPLOAD_PATH . $d['photo'] . '.thumb.jpg')) {
@ -844,10 +822,9 @@ switch ($action) {
}
$d->photo = '/photos/' . $subfolder . '/' . $hash . '.jpg';
}
if (file_exists($_FILES['photo']['tmp_name']))
unlink($_FILES['photo']['tmp_name']);
if (file_exists($_FILES['photo']['tmp_name'])) unlink($_FILES['photo']['tmp_name']);
} else {
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
r2(U . 'settings/app', 'e', 'PHP GD is not installed');
}
}
@ -881,9 +858,9 @@ switch ($action) {
$d->save();
_log('[' . $admin['username'] . ']: $username ' . Lang::T('User Updated Successfully'), $admin['user_type'], $admin['id']);
r2(getUrl('settings/users-view/') . $id, 's', 'User Updated Successfully');
r2(U . 'settings/users-view/' . $id, 's', 'User Updated Successfully');
} else {
r2(getUrl('settings/users-edit/') . $id, 'e', $msg);
r2(U . 'settings/users-edit/' . $id, 'e', $msg);
}
break;
@ -891,17 +868,14 @@ switch ($action) {
run_hook('view_change_password'); #HOOK
$csrf_token = Csrf::generateAndStoreToken();
$ui->assign('csrf_token', $csrf_token);
$ui->display('admin/change-password.tpl');
$ui->display('change-password.tpl');
break;
case 'change-password-post':
if ($_app_stage == 'Demo') {
r2(getUrl('settings/change-password'), 'e', 'You cannot perform this action in Demo mode');
}
$password = _post('password');
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('settings/change-password'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'settings/change-password', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
if ($password != '') {
$d = ORM::for_table('tbl_users')->where('username', $admin['username'])->find_one();
@ -912,10 +886,10 @@ switch ($action) {
$npass = _post('npass');
$cnpass = _post('cnpass');
if (!Validator::Length($npass, 15, 5)) {
r2(getUrl('settings/change-password'), 'e', 'New Password must be 6 to 14 character');
r2(U . 'settings/change-password', 'e', 'New Password must be 6 to 14 character');
}
if ($npass != $cnpass) {
r2(getUrl('settings/change-password'), 'e', 'Both Password should be same');
r2(U . 'settings/change-password', 'e', 'Both Password should be same');
}
$npass = Password::_crypt($npass);
@ -925,15 +899,15 @@ switch ($action) {
_msglog('s', Lang::T('Password changed successfully, Please login again'));
_log('[' . $admin['username'] . ']: Password changed successfully', $admin['user_type'], $admin['id']);
r2(getUrl('admin'));
r2(U . 'admin');
} else {
r2(getUrl('settings/change-password'), 'e', Lang::T('Incorrect Current Password'));
r2(U . 'settings/change-password', 'e', Lang::T('Incorrect Current Password'));
}
} else {
r2(getUrl('settings/change-password'), 'e', Lang::T('Incorrect Current Password'));
r2(U . 'settings/change-password', 'e', Lang::T('Incorrect Current Password'));
}
} else {
r2(getUrl('settings/change-password'), 'e', Lang::T('Incorrect Current Password'));
r2(U . 'settings/change-password', 'e', Lang::T('Incorrect Current Password'));
}
break;
@ -951,21 +925,18 @@ switch ($action) {
$csrf_token = Csrf::generateAndStoreToken();
$ui->assign('csrf_token', $csrf_token);
$ui->assign('_default', json_decode(file_get_contents($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.default.json'), true));
$ui->display('admin/settings/notifications.tpl');
$ui->display('app-notifications.tpl');
break;
case 'notifications-post':
if ($_app_stage == 'Demo') {
r2(getUrl('settings/notifications'), 'e', 'You cannot perform this action in Demo mode');
}
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('settings/notifications'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'settings/notifications', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
file_put_contents($UPLOAD_PATH . "/notifications.json", json_encode($_POST));
r2(getUrl('settings/notifications'), 's', Lang::T('Settings Saved Successfully'));
r2(U . 'settings/notifications', 's', Lang::T('Settings Saved Successfully'));
break;
case 'dbstatus':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
@ -981,14 +952,11 @@ switch ($action) {
}
$ui->assign('tables', $tables);
run_hook('view_database'); #HOOK
$ui->display('admin/settings/dbstatus.tpl');
$ui->display('dbstatus.tpl');
}
break;
case 'dbbackup':
if ($_app_stage == 'Demo') {
r2(getUrl('settings/dbstatus'), 'e', 'You cannot perform this action in Demo mode');
}
if (!in_array($admin['user_type'], ['SuperAdmin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
@ -1009,9 +977,6 @@ switch ($action) {
echo json_encode($array);
break;
case 'dbrestore':
if ($_app_stage == 'Demo') {
r2(getUrl('settings/dbstatus'), 'e', 'You cannot perform this action in Demo mode');
}
if (!in_array($admin['user_type'], ['SuperAdmin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
@ -1059,11 +1024,10 @@ switch ($action) {
} catch (Throwable $e) {
} catch (Exception $e) {
}
if (file_exists($_FILES['json']['tmp_name']))
unlink($_FILES['json']['tmp_name']);
r2(getUrl('settings/dbstatus'), 's', "Restored $suc success $fal failed");
if (file_exists($_FILES['json']['tmp_name'])) unlink($_FILES['json']['tmp_name']);
r2(U . "settings/dbstatus", 's', "Restored $suc success $fal failed");
} else {
r2(getUrl('settings/dbstatus'), 'e', 'Upload failed');
r2(U . "settings/dbstatus", 'e', 'Upload failed');
}
break;
case 'language':
@ -1078,19 +1042,16 @@ switch ($action) {
}
$csrf_token = Csrf::generateAndStoreToken();
$ui->assign('csrf_token', $csrf_token);
$ui->display('admin/settings/language-add.tpl');
$ui->display('language-add.tpl');
break;
case 'lang-post':
if ($_app_stage == 'Demo') {
r2(getUrl('settings/dbstatus'), 'e', 'You cannot perform this action in Demo mode');
}
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('settings/language'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'settings/language', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
file_put_contents($lan_file, json_encode($_POST, JSON_PRETTY_PRINT));
r2(getUrl('settings/language'), 's', Lang::T('Translation saved Successfully'));
r2(U . 'settings/language', 's', Lang::T('Translation saved Successfully'));
break;
case 'maintenance':
@ -1100,12 +1061,9 @@ switch ($action) {
}
if (_post('save') == 'save') {
if ($_app_stage == 'Demo') {
r2(getUrl('settings/maintenance'), 'e', 'You cannot perform this action in Demo mode');
}
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('settings/maintenance'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'settings/maintenance', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
$status = isset($_POST['maintenance_mode']) ? 1 : 0; // Checkbox returns 1 if checked, otherwise 0
$force_logout = isset($_POST['maintenance_mode_logout']) ? 1 : 0; // Checkbox returns 1 if checked, otherwise 0
@ -1130,13 +1088,13 @@ switch ($action) {
}
}
r2(getUrl('settings/maintenance'), 's', Lang::T('Settings Saved Successfully'));
r2(U . "settings/maintenance", 's', Lang::T('Settings Saved Successfully'));
}
$csrf_token = Csrf::generateAndStoreToken();
$ui->assign('csrf_token', $csrf_token);
$ui->assign('_c', $config);
$ui->assign('_title', Lang::T('Maintenance Mode Settings'));
$ui->display('admin/settings/maintenance-mode.tpl');
$ui->display('maintenance-mode.tpl');
break;
case 'miscellaneous':
@ -1145,12 +1103,9 @@ switch ($action) {
exit;
}
if (_post('save') == 'save') {
if ($_app_stage == 'Demo') {
r2(getUrl('settings/miscellaneous'), 'e', 'You cannot perform this action in Demo mode');
}
$csrf_token = _post('csrf_token');
if (!Csrf::check($csrf_token)) {
r2(getUrl('settings/miscellaneous'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
r2(U . 'settings/miscellaneous', 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
}
foreach ($_POST as $key => $value) {
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
@ -1165,15 +1120,15 @@ switch ($action) {
}
}
r2(getUrl('settings/miscellaneous'), 's', Lang::T('Settings Saved Successfully'));
r2(U . "settings/miscellaneous", 's', Lang::T('Settings Saved Successfully'));
}
$csrf_token = Csrf::generateAndStoreToken();
$ui->assign('csrf_token', $csrf_token);
$ui->assign('_c', $config);
$ui->assign('_title', Lang::T('Miscellaneous Settings'));
$ui->display('admin/settings/miscellaneous.tpl');
$ui->display('app-miscellaneous.tpl');
break;
default:
$ui->display('admin/404.tpl');
$ui->display('a404.tpl');
}

View File

@ -4,47 +4,11 @@
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
**/
_auth();
$ui->assign('_title', Lang::T('Voucher'));
$ui->assign('_system_menu', 'voucher');
$action = $routes['1'];
if(!_auth(false)){
if($action== 'invoice'){
$id = $routes[2];
$sign = $routes[3];
if($sign != md5($id. $db_pass)) {
die("beda");
}
if (empty($id)) {
$in = ORM::for_table('tbl_transactions')->order_by_desc('id')->find_one();
} else {
$in = ORM::for_table('tbl_transactions')->where('id', $id)->find_one();
}
if ($in) {
Package::createInvoice($in);
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
$logo = '';
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) {
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png';
$imgsize = getimagesize($logo);
$width = $imgsize[0];
$height = $imgsize[1];
$ui->assign('wlogo', $width);
$ui->assign('hlogo', $height);
}
$ui->assign('public_url', getUrl("voucher/invoice/$id/".md5($id. $db_pass)));
$ui->assign('logo', $logo);
$ui->display('customer/invoice-customer.tpl');
die();
} else {
r2(getUrl('voucher/list-activated'), 'e', Lang::T('Not Found'));
}
}else{
r2(getUrl('login'));
}
}
$user = User::_info();
$ui->assign('_user', $user);
@ -66,12 +30,12 @@ switch ($action) {
$v1->used_date = date('Y-m-d H:i:s');
$v1->user = $user['username'];
$v1->save();
r2(getUrl('voucher/list-activated'), 's', Lang::T('Activation Vouchers Successfully'));
r2(U . "voucher/list-activated", 's', Lang::T('Activation Vouchers Successfully'));
} else {
r2(getUrl('voucher/activation'), 'e', "Failed to refill account");
r2(U . 'voucher/activation', 'e', "Failed to refill account");
}
} else {
r2(getUrl('voucher/activation'), 'e', Lang::T('Voucher Not Valid'));
r2(U . 'voucher/activation', 'e', Lang::T('Voucher Not Valid'));
}
break;
@ -100,23 +64,11 @@ switch ($action) {
}
if ($in) {
Package::createInvoice($in);
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
$logo = '';
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) {
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png';
$imgsize = getimagesize($logo);
$width = $imgsize[0];
$height = $imgsize[1];
$ui->assign('wlogo', $width);
$ui->assign('hlogo', $height);
}
$ui->assign('public_url', getUrl("voucher/invoice/$id/".md5($id. $db_pass)));
$ui->assign('logo', $logo);
$ui->display('customer/invoice-customer.tpl');
} else {
r2(getUrl('voucher/list-activated'), 'e', Lang::T('Not Found'));
r2(U . 'voucher/list-activated', 'e', Lang::T('Not Found'));
}
break;
default:
$ui->display('admin/404.tpl');
$ui->display('a404.tpl');
}

View File

@ -1,147 +0,0 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
**/
_admin();
$ui->assign('_title', Lang::T('Dashboard Widgets'));
$ui->assign('_system_menu', 'settings');
$action = alphanumeric($routes['1']);
$ui->assign('_admin', $admin);
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
r2(getUrl('dashboard'), 'e', Lang::T('You do not have permission to access this page'));
}
$tipeUser = _req("user");
if (empty($tipeUser)) {
$tipeUser = 'Admin';
}
if($tipeUser == 'Customer') {
$WIDGET_PATH .= DIRECTORY_SEPARATOR. 'customer';
}
$ui->assign('tipeUser', $tipeUser);
$max = ORM::for_table('tbl_widgets')->where("user", $tipeUser)->max('position');
$max2 = substr_count($config['dashboard_' . $tipeUser], '.') + substr_count($config['dashboard_' . $tipeUser], ',') + 1;
if ($max2 > $max) {
$max = $max2;
}
$ui->assign('max', $max);
if ($action == 'add') {
$pos = alphanumeric($routes['2']);
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$orders = alphanumeric($_POST['orders']);
$position = alphanumeric($_POST['position']);
$tipeUser = alphanumeric($_POST['tipeUser']);
$enabled = alphanumeric($_POST['enabled']);
$title = _post('title');
$widget = _post('widget');
$d = ORM::for_table('tbl_widgets')->create();
$d->orders = $orders;
$d->position = $position;
$d->user = $tipeUser;
$d->enabled = $enabled;
$d->title = $title;
$d->widget = $widget;
$d->content = _post('content');
$d->save();
if ($d->id() > 0) {
r2(getUrl('widgets&user=' . $tipeUser), 's', 'Widget Added Successfully');
}
}
$files = scandir($WIDGET_PATH);
$widgets = [];
foreach ($files as $file) {
if (strpos($file, '.php') !== false) {
$name = ucwords(str_replace('.php', '', str_replace('_', ' ', $file)));
$widgets[str_replace('.php', '', $file)] = $name;
}
}
$widget['position'] = $pos;
$widget['user'] = $tipeUser;
$ui->assign('users', ORM::for_table('tbl_widgets')->getEnum("user"));
$ui->assign('do', 'add');
$ui->assign('widgets', $widgets);
$ui->assign('widget', $widget);
$ui->display('admin/settings/widgets_add_edit.tpl');
} else if ($action == 'edit') {
// if request method post then save data
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$id = alphanumeric($_POST['id']);
$orders = alphanumeric($_POST['orders']);
$position = alphanumeric($_POST['position']);
$tipeUser = alphanumeric($_POST['tipeUser']);
$enabled = alphanumeric($_POST['enabled']);
$title = _post('title');
$widget = _post('widget');
$d = ORM::for_table('tbl_widgets')->find_one($id);
$d->orders = $orders;
$d->position = $position;
$d->user = $tipeUser;
$d->enabled = $enabled;
$d->title = $title;
$d->widget = $widget;
$d->content = _post('content');
$d->save();
r2(getUrl('widgets&user=' . $tipeUser), 's', 'Widget Saved Successfully');
}
$id = alphanumeric($routes['2']);
$widget = ORM::for_table('tbl_widgets')->find_one($id);
$files = scandir($WIDGET_PATH);
$widgets = [];
foreach ($files as $file) {
if (strpos($file, '.php') !== false) {
$name = ucwords(str_replace('.php', '', str_replace('_', ' ', $file)));
$widgets[str_replace('.php', '', $file)] = $name;
}
}
$ui->assign('users', ORM::for_table('tbl_widgets')->getEnum("user"));
$ui->assign('do', 'edit');
$ui->assign('widgets', $widgets);
$ui->assign('widget', $widget);
$ui->display('admin/settings/widgets_add_edit.tpl');
} else if ($action == 'delete') {
$id = alphanumeric($routes['2']);
$d = ORM::for_table('tbl_widgets')->find_one($id);
if ($d) {
$d->delete();
r2(getUrl('widgets&user=' . $tipeUser), 's', 'Widget Deleted Successfully');
}
r2(getUrl('widgets&user=' . $tipeUser), 'e', 'Widget Not Found');
} else if (!empty($action) && file_exists("system/widget/$action.php") && !empty($routes['2'])) {
require_once "system/widget/$action.php";
try {
(new $action)->run_command($routes['2']);
} catch (Throwable $e) {
//nothing to do
}
} else if ($action == 'pos') {
$jml = count($_POST['orders']);
for ($i = 0; $i < $jml; $i++) {
$d = ORM::for_table('tbl_widgets')->find_one($_POST['id'][$i]);
$d->orders = $_POST['orders'][$i];
$d->save();
}
r2(getUrl('widgets&user=' . $tipeUser), 's', 'Widget order Saved Successfully');
} else {
if (_post("save") == 'struct') {
$d = ORM::for_table('tbl_appconfig')->where('setting', 'dashboard_' . $tipeUser)->find_one();
if ($d) {
$d->value = _post('dashboard');
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'dashboard_' . $tipeUser;
$d->value = _post('dashboard');
$d->save();
}
_alert("Dashboard Structure Saved Successfully", "success", getUrl('widgets&user=' . $tipeUser));
}
$widgets = ORM::for_table('tbl_widgets')->where("user", $tipeUser)->order_by_asc("orders")->find_many();
$ui->assign('widgets', $widgets);
$ui->display('admin/settings/widgets.tpl');
}

View File

@ -30,7 +30,7 @@ if (php_sapi_name() !== 'cli') {
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 = [];
$rows = array();
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
echo "MYSQL Time\t" . $row['WAKTU'] . "\n";
}
@ -45,111 +45,80 @@ echo "Found " . count($d) . " user(s)\n";
run_hook('cronjob'); #HOOK
foreach ($d as $ds) {
try {
$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";
// Fetch user recharge details
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
if (!$u) {
throw new Exception("User recharge record not found for ID: " . $ds['id']);
$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";
$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();
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
if (empty($c)) {
$c = $u;
}
$dvc = Package::getDevice($p);
if ($_app_stage != 'demo') {
if (file_exists($dvc)) {
require_once $dvc;
(new $p['device'])->remove_customer($c, $p);
} else {
echo "Cron error Devices $p[device] not found, cannot disconnect $c[username]";
Message::sendTelegram("Cron error Devices $p[device] not found, cannot disconnect $c[username]");
}
}
echo Message::sendPackageNotification($c, $u['namebp'], $p['price'], $textExpired, $config['user_notification_expired']) . "\n";
//update database user dengan status off
$u->status = 'off';
$u->save();
// Fetch customer details
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
if (!$c) {
$c = $u;
}
// Fetch plan details
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
if (!$p) {
throw new Exception("Plan not found for ID: " . $u['plan_id']);
}
$dvc = Package::getDevice($p);
if ($_app_stage != 'demo') {
if (file_exists($dvc)) {
require_once $dvc;
(new $p['device'])->remove_customer($c, $p);
} else {
throw new Exception("Cron error: Devices " . $p['device'] . "not found, cannot disconnect ".$c['username']."\n");
}
}
// Send notification and update user status
try {
echo Message::sendPackageNotification(
$c,
$u['namebp'],
$p['price'],
Message::getMessageType($p['type'], $textExpired),
$config['user_notification_expired']
) . "\n";
$u->status = 'off';
$u->save();
} catch (Throwable $e) {
_log($e->getMessage());
sendTelegram($e->getMessage());
echo "Error: " . $e->getMessage() . "\n";
}
// Auto-renewal from deposit
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
[$bills, $add_cost] = User::getBills($ds['customer_id']);
if ($add_cost != 0) {
// autorenewal from deposit
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
list($bills, $add_cost) = User::getBills($ds['customer_id']);
if ($add_cost != 0) {
if (!empty($add_cost)) {
$p['price'] += $add_cost;
}
if ($p && $c['balance'] >= $p['price']) {
if (Package::rechargeUser($ds['customer_id'], $ds['routers'], $p['id'], 'Customer', 'Balance')) {
Balance::min($ds['customer_id'], $p['price']);
echo "plan enabled: " . (string) $p['enabled'] . " | User balance: " . (string) $c['balance'] . " | price " . (string) $p['price'] . "\n";
echo "auto renewal Success\n";
} else {
echo "plan enabled: " . $p['enabled'] . " | User balance: " . $c['balance'] . " | price " . $p['price'] . "\n";
echo "auto renewal Failed\n";
Message::sendTelegram("FAILED RENEWAL #cron\n\n#u." . $c['username'] . " #buy #Hotspot \n" . $p['name_plan'] .
"\nRouter: " . $p['routers'] .
"\nPrice: " . $p['price']);
}
}
if ($p && $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']);
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
echo "auto renewall Success\n";
} else {
echo "no renewal | plan enabled: " . (string) $p['enabled'] . " | User balance: " . (string) $c['balance'] . " | price " . (string) $p['price'] . "\n";
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 renewal | balance" . $config['enable_balance'] . " auto_renewal " . $c['auto_renewal'] . "\n";
echo "no renewall | plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
}
} else {
echo " : ACTIVE \r\n";
echo "no renewall | balance $config[enable_balance] auto_renewal $c[auto_renewal]\n";
}
} catch (Throwable $e) {
// Catch any unexpected errors
_log($e->getMessage());
sendTelegram($e->getMessage());
echo "Unexpected Error: " . $e->getMessage() . "\n";
} else {
echo " : ACTIVE \r\n";
}
}
//Cek interim-update radiusrest
if ($config['frrest_interim_update'] != 0) {
//Cek interim-update radiusrest
if ($config['frrest_interim_update'] != 0) {
$r_a = ORM::for_table('rad_acct')
->whereRaw("BINARY acctstatustype = 'Start' OR acctstatustype = 'Interim-Update'")
->where_lte('dateAdded', date("Y-m-d H:i:s"))->find_many();
->whereRaw("BINARY acctstatustype = 'Start' OR acctstatustype = 'Interim-Update'")
->where_lte('dateAdded', date("Y-m-d H:i:s"))->find_many();
foreach ($r_a as $ra) {
$interval = $_c['frrest_interim_update'] * 60;
$timeUpdate = strtotime($ra['dateAdded']) + $interval;
$timeNow = strtotime(date("Y-m-d H:i:s"));
if ($timeNow >= $timeUpdate) {
$ra->acctstatustype = 'Stop';
$ra->save();
}
}
foreach ($r_a as $ra) {
$interval = $_c['frrest_interim_update']*60;
$timeUpdate = strtotime($ra['dateAdded'])+$interval;
$timeNow = strtotime(date("Y-m-d H:i:s"));
if ($timeNow >= $timeUpdate) {
$ra->acctstatustype = 'Stop';
$ra->save();
}
}
}
if ($config['router_check']) {
@ -168,7 +137,7 @@ if ($config['router_check']) {
foreach ($routers as $router) {
// check if custom port
if (strpos($router->ip_address, ':') === false) {
if (strpos($router->ip_address, ':') === false){
$ip = $router->ip_address;
$port = 8728;
} else {
@ -238,7 +207,14 @@ if ($config['router_check']) {
Message::SendEmail($adminEmail, $subject, $message);
sendTelegram($message);
}
echo "Router monitoring finished checking.\n";
echo "Router monitoring finished\n";
}
if (defined('PHP_SAPI') && PHP_SAPI === 'cli') {
echo "Cronjob finished\n";
} else {
echo "</pre>";
}
flock($lock, LOCK_UN);
@ -248,5 +224,5 @@ unlink($lockFile);
$timestampFile = "$UPLOAD_PATH/cron_last_run.txt";
file_put_contents($timestampFile, time());
run_hook('cronjob_end'); #HOOK
echo "Cron job finished and completed successfully.\n";

View File

@ -23,7 +23,7 @@ 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 = [];
$rows = array();
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
echo "MYSQL Time\t" . $row['WAKTU'] . "\n";
}
@ -39,52 +39,22 @@ foreach ($d as $ds) {
$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;
}
// 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'];
$price = $p['price'];
}
if ($ds['expiration'] == $day7 && $config['notification_reminder_7days'] !== 'no') {
try {
echo Message::sendPackageNotification(
$c,
$p['name_plan'],
$price,
Message::getMessageType($p['type'], Lang::getNotifText('reminder_7_day')),
$config['user_notification_reminder']
) . "\n";
} catch (Exception $e) {
sendTelegram("Cron Reminder failed to send 7-day reminder to " . $ds['username'] . " Error: " . $e->getMessage());
}
} else if ($ds['expiration'] == $day3 && $config['notification_reminder_3days'] !== 'no') {
try {
echo Message::sendPackageNotification(
$c,
$p['name_plan'],
$price,
Message::getMessageType($p['type'], Lang::getNotifText('reminder_3_day')),
$config['user_notification_reminder']
) . "\n";
} catch (Exception $e) {
sendTelegram("Cron Reminder failed to send 3-day reminder to " . $ds['username'] . " Error: " . $e->getMessage());
}
} else if ($ds['expiration'] == $day1 && $config['notification_reminder_1day'] !== 'no') {
try {
echo Message::sendPackageNotification(
$c,
$p['name_plan'],
$price,
Message::getMessageType($p['type'], Lang::getNotifText('reminder_1_day')),
$config['user_notification_reminder']
) . "\n";
} catch (Exception $e) {
sendTelegram("Cron Reminder failed to send 1-day reminder to " . $ds['username'] . " Error: " . $e->getMessage());
}
if ($ds['expiration'] == $day7) {
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_7_day'), $config['user_notification_reminder']) . "\n";
} else if ($ds['expiration'] == $day3) {
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_3_day'), $config['user_notification_reminder']) . "\n";
} else if ($ds['expiration'] == $day1) {
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_1_day'), $config['user_notification_reminder']) . "\n";
}
}
}
}

View File

@ -122,9 +122,6 @@ class MikrotikHotspot
if (!empty(trim($bw['burst']))) {
$rate .= ' ' . $bw['burst'];
}
if ($bw['rate_up'] == '0' || $bw['rate_down'] == '0') {
$rate = '';
}
$addRequest = new RouterOS\Request('/ip/hotspot/user/profile/add');
$client->sendSync(
$addRequest
@ -205,9 +202,6 @@ class MikrotikHotspot
if (!empty(trim($bw['burst']))) {
$rate .= ' ' . $bw['burst'];
}
if ($bw['rate_up'] == '0' || $bw['rate_down'] == '0') {
$rate = '';
}
$setRequest = new RouterOS\Request('/ip/hotspot/user/profile/set');
$client->sendSync(
$setRequest

View File

@ -149,9 +149,6 @@ class MikrotikPppoe
if(!empty(trim($bw['burst']))){
$rate .= ' '.$bw['burst'];
}
if ($bw['rate_up'] == '0' || $bw['rate_down'] == '0') {
$rate = '';
}
$pool = ORM::for_table("tbl_pool")->where("pool_name", $plan['pool'])->find_one();
$addRequest = new RouterOS\Request('/ppp/profile/add');
$client->sendSync(
@ -208,9 +205,6 @@ class MikrotikPppoe
if(!empty(trim($bw['burst']))){
$rate .= ' '.$bw['burst'];
}
if ($bw['rate_up'] == '0' || $bw['rate_down'] == '0') {
$rate = '';
}
$pool = ORM::for_table("tbl_pool")->where("pool_name", $new_plan['pool'])->find_one();
$setRequest = new RouterOS\Request('/ppp/profile/set');
$client->sendSync(
@ -244,7 +238,7 @@ class MikrotikPppoe
function add_pool($pool){
global $_app_stage;
if ($_app_stage == 'Demo') {
if ($_app_stage == 'demo') {
return null;
}
$mikrotik = $this->info($pool['routers']);
@ -259,7 +253,7 @@ class MikrotikPppoe
function update_pool($old_pool, $new_pool){
global $_app_stage;
if ($_app_stage == 'Demo') {
if ($_app_stage == 'demo') {
return null;
}
$mikrotik = $this->info($new_pool['routers']);
@ -284,7 +278,7 @@ class MikrotikPppoe
function remove_pool($pool){
global $_app_stage;
if ($_app_stage == 'Demo') {
if ($_app_stage == 'demo') {
return null;
}
$mikrotik = $this->info($pool['routers']);
@ -329,7 +323,7 @@ class MikrotikPppoe
function getClient($ip, $user, $pass)
{
global $_app_stage;
if ($_app_stage == 'Demo') {
if ($_app_stage == 'demo') {
return null;
}
$iport = explode(":", $ip);
@ -339,7 +333,7 @@ class MikrotikPppoe
function removePpoeUser($client, $username)
{
global $_app_stage;
if ($_app_stage == 'Demo') {
if ($_app_stage == 'demo') {
return null;
}
$printRequest = new RouterOS\Request('/ppp/secret/print');
@ -376,7 +370,7 @@ class MikrotikPppoe
function removePpoeActive($client, $username)
{
global $_app_stage;
if ($_app_stage == 'Demo') {
if ($_app_stage == 'demo') {
return null;
}
$onlineRequest = new RouterOS\Request('/ppp/active/print');
@ -392,7 +386,7 @@ class MikrotikPppoe
function getIpHotspotUser($client, $username)
{
global $_app_stage;
if ($_app_stage == 'Demo') {
if ($_app_stage == 'demo') {
return null;
}
$printRequest = new RouterOS\Request(
@ -405,7 +399,7 @@ class MikrotikPppoe
function addIpToAddressList($client, $ip, $listName, $comment = '')
{
global $_app_stage;
if ($_app_stage == 'Demo') {
if ($_app_stage == 'demo') {
return null;
}
$addRequest = new RouterOS\Request('/ip/firewall/address-list/add');
@ -420,7 +414,7 @@ class MikrotikPppoe
function removeIpFromAddressList($client, $ip)
{
global $_app_stage;
if ($_app_stage == 'Demo') {
if ($_app_stage == 'demo') {
return null;
}
$printRequest = new RouterOS\Request(

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
"Announcement": "Pemberitahuan",
"Registration_Info": "Info Pendaftaran",
"Voucher_not_found__please_buy_voucher_befor_register": "Voucher tidak ditemukan, silakan beli voucher sebelum mendaftar",
"Register_Success__You_can_login_now": "Daftar berhadil! Anda dapat masuk sekarang",
"Register_Success__You_can_login_now": "Daftar Sukses! Anda dapat masuk sekarang",
"Log_in_to_Member_Panel": "Masuk ke Panel Anggota",
"Register_as_Member": "Daftar sebagai Anggota",
"Enter_Admin_Area": "Masuk ke Admin Panel",
@ -13,12 +13,11 @@
"Password": "Kata Sandi",
"Passwords_does_not_match": "Kata sandi tidak cocok",
"Account_already_axist": "Akun telah ada",
"Manage": "Kelola",
"Manage": "Mengelola",
"Submit": "Kirim",
"Save_Changes": "Simpan Perubahan",
"Cancel": "Batal",
"Edit": "Sunting",
"Order": "Urutan",
"Delete": "Hapus",
"Welcome": "Selamat Datang",
"Data_Created_Successfully": "Data Berhasil Dibuat",
@ -124,7 +123,7 @@
"Period_Reports": "Laporan Periode",
"All_Transactions": "Semua Transaksi",
"Total_Income": "Jumlah Pemasukan",
"All_Transactions_at_Date": "Semua transaksi pada tanggal",
"All_Transactions_at_Date": "Semua transaksi pada ganggal",
"Export_for_Print": "Ekspor untuk cetak",
"Print": "Cetak",
"Export_to_PDF": "Ekspor ke PDF",
@ -200,7 +199,7 @@
"Search_by_Username": "Cari berdasarkan nama pengguna",
"Search_by_Name": "Cari berdasarkan nama",
"Search_by_Code_Voucher": "Cari berdasarkan kode voucher",
"Search": "Cari",
"Search": "Mencari",
"Select_a_customer": "Pilih pelanggan",
"Select_Routers": "Pilih Router",
"Select_Plans": "Pilih Paket",
@ -332,7 +331,7 @@
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "Bayar ini dengan Saldo? Paket aktif Anda akan ditimpa",
"Success_to_buy_package": "Berhasil membeli paket",
"Auto_Renewal": "Perpanjangan otomatis",
"View": "Lihat",
"View": "Melihat",
"Back": "Kembali",
"Active": "Aktif",
"Transfer_Balance": "Kirim saldo",
@ -384,7 +383,6 @@
"Vouchers": "Voucher",
"Refill_Customer": "Isi Ulang Voucher",
"Recharge_Customer": "Isi Ulang Paket",
"Plan": "Paket",
"Plans": "Paket",
"PPPOE": "PPPOE",
"Bandwidth": "Bandwidth",
@ -413,7 +411,7 @@
"Paid": "Dibayar",
"Personal": "Pribadi",
"Coordinates": "Koordinat",
"Confirm": "Konfirmasi",
"Confirm": "Mengonfirmasi",
"Name": "Nama",
"Plan": "Paket",
"Using": "Menggunakan",
@ -421,7 +419,7 @@
"Additional_Cost": "Biaya tambahan",
"Resend": "Kirim ulang",
"Login": "Masuk",
"success": "Berhasil",
"success": "Sukses",
"Click_Here": "Klik disini",
"Your_friend_do_not_have_active_package": "Teman Anda tidak memiliki paket aktif",
"If_your_friend_have_Additional_Cost__you_will_pay_for_that_too": "Jika teman Anda memiliki biaya tambahan, Anda juga akan membayarnya",
@ -505,11 +503,11 @@
"Time": "Waktu",
"Data": "Data",
"1_Period___1_Month__Expires_the_20th_of_each_month": "1 Periode = 1 Bulan, Berakhir pada tanggal 20 setiap bulannya",
"Expired_Date": "Tanggal kadaluwarsa",
"Expired_Date": "Tanggal kadaluarsa",
"Expired_Action": "Tindakan Kedaluwarsa",
"Optional": "Opsional",
"Expired_Internet_Plan": "Paket Internet Kedaluwarsa",
"When_Expired__customer_will_be_move_to_selected_internet_plan": "Ketika kedaluwarsa, pelanggan akan dipindahkan ke paket internet yang dipilih",
"When_Expired__customer_will_be_move_to_selected_internet_plan": "Ketika Expired, pelanggan akan dipindahkan ke paket internet yang dipilih",
"Period": "Periode",
"Rate": "Kecepatan",
"Burst": "Burst",
@ -524,8 +522,7 @@
"Ascending": "Naik",
"Descending": "Menurun",
"Query": "Query",
"Add": "Tambah",
"Search": "Cari",
"Add": "Menambahkan",
"Logout_Successful": "Berhasil Keluar",
"warning": "peringatan",
"Created___Expired": "Dibuat \/ Kedaluwarsa",
@ -535,8 +532,8 @@
"Customer_can_login_but_cannot_buy_internet_plan__Admin_cannot_recharge_customer": "Pelanggan dapat login tetapi tidak dapat membeli paket internet, Admin tidak dapat mengisi ulang pelanggan",
"Don_t_forget_to_deactivate_all_active_plan_too": "Jangan lupa untuk menonaktifkan semua paket aktif juga",
"Attributes": "Atribut",
"Additional_Information": "Informasi tambahan",
"City_of_Resident": "Kota Tempat Tinggal",
"Additional_Information": "informasi tambahan",
"City_of_Resident": "Kota Residen",
"State_of_Resident": "Negara Bagian Tempat Tinggal",
"Zip_Code": "Kode Pos",
"Phone": "Telepon",
@ -557,7 +554,7 @@
"Input_your_phone_number": "Masukkan nomor telepon Anda",
"OTP": "OTP",
"Enter_OTP_that_was_sent_to_your_phone": "Masukkan OTP yang dikirimkan ke ponsel Anda",
"Update": "Perbarui",
"Update": "Memperbarui",
"Verification_code_has_been_sent_to_your_phone": "Kode verifikasi telah dikirimkan ke ponsel Anda",
"Please_wait_1039_seconds_before_sending_another_SMS": "Harap tunggu 1039 detik sebelum mengirim SMS lainnya",
"Please_wait_1015_seconds_before_sending_another_SMS": "Harap tunggu 1015 detik sebelum mengirim SMS lainnya",
@ -570,7 +567,7 @@
"Api": "Api",
"Http_Chap": "Http-Chap",
"Hotspot_Authentication_Method__Make_sure_you_have_changed_your_hotspot_login_page_": "Metode Otentikasi Hotspot. Pastikan Anda telah mengubah halaman login hotspot Anda.",
"Languge_set_to_indonesia": "Bahasa diatur ke Indonesia",
"Languge_set_to_indonesia": "Language set to indonesia",
"Enable": "Aktifkan",
"Diable": "Nonaktifkan",
"Verification_code": "Kod3 V3r1fik@s1",
@ -586,37 +583,37 @@
"_": "-",
"Search_Users": "Pencarian Pengguna",
"Routers_Maps": "Peta Router",
"Theme_Voucher": "Tema Voucher",
"Theme_Voucher": "Voucher Tema",
"Payment_Info": "Info Pembayaran",
"Documentation": "Dokumentasi",
"Customers": "Pelanggan",
"Package_Name": "Nama Paket",
"Routers_Offline": "Router Off",
"Routers_Offline": "Router Offline",
"Cron_appear_not_been_setup__please_check_your_cron_setup_": "Cron tampaknya belum disiapkan, silakan periksa pengaturan cron Anda.",
"Buy": "Beli",
"Buy": "Membeli",
"You_are_already_logged_in": "Anda sudah masuk",
"PPPOE_Package": "Paket PPPoE",
"Prepaid": "Prabayar",
"Postpaid": "Pascabayar",
"Enabled": "Aktifkan",
"Enabled": "Diaktifkan",
"Disable": "Nonaktifkan",
"Create_expired_Internet_Plan": "Buat Paket Internet yang Kedaluwarsa",
"When_customer_expired__you_can_move_it_to_Expired_Internet_Plan": "Ketika pelanggan kedaluwarsa, Anda dapat memindahkannya ke Paket Internet Kedaluwarsa",
"Price_Before_Discount": "Harga Sebelum Diskon",
"For_Discount_Rate__this_is_price_before_get_discount__must_be_more_expensive_with_real_price": "Untuk tarif diskon. Ini adalah harga sebelum mendapat diskon, pasti lebih mahal dari harga sebenarnya",
"on_login___on_up": "saat masuk \/ saat naik",
"For_Discount_Rate__this_is_price_before_get_discount__must_be_more_expensive_with_real_price": "Untuk Discount Rate, ini adalah harga sebelum mendapat diskon, pasti lebih mahal dari harga sebenarnya",
"on_login___on_up": "saat masuk \/ saat mendaftar",
"on_logout___on_down": "saat keluar \/ saat turun",
"Get_Directions": "Dapatkan Petunjuk Arah",
"Not_Working_with_Freeradius_Mysql": "Tidak Bekerja dengan Freeradius Mysql",
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_Customer_Credentials": "Pengguna tidak dapat mengubah ini, hanya admin. Jika Kosong, maka akan menggunakan Kredensial Pelanggan",
"Buy_this__your_active_package_will_be_overwritten": "Beli paket ini? Paket aktif Anda akan ditimpa",
"Buy_this__your_active_package_will_be_overwritten": "Beli ini? Paket aktif Anda akan ditimpa",
"Pay_this_with_Balance__your_active_package_will_be_overwritten": "Bayar ini dengan Saldo? Paket aktif Anda akan ditimpa",
"Error": "Kesalahan",
"Internal_Error": "Kesalahan Internal",
"Sorry__the_software_failed_to_process_the_request__if_it_still_happening__please_tell": "Maaf, perangkat lunak gagal memproses permintaan. Jika masih terjadi, mohon beri tahu",
"Sorry__the_software_failed_to_process_the_request__if_it_still_happening__please_tell": "Maaf, perangkat lunak gagal memproses permintaan, jika masih terjadi, mohon beri tahu",
"Try_Again": "Coba Lagi",
"Make_sure_you_use_API_Port__Default_8728": "Pastikan Anda menggunakan Port API, Default 8728",
"Make_sure_Username_and_Password_are_correct": "Pastikan nama pengguna dan kata sandi sudah benar",
"Make_sure_Username_and_Password_are_correct": "Pastikan Username dan Password sudah benar",
"Make_sure_your_hosting_not_blocking_port_to_external": "Pastikan hosting Anda tidak memblokir port ke eksternal",
"Make_sure_your_Mikrotik_accessible_from_PHPNuxBill": "Pastikan Mikrotik Anda dapat diakses dari PHPNuxBill",
"If_you_just_update_PHPNuxBill_from_upload_files__try_click_Update": "Jika Anda baru saja memperbarui PHPNuxBill dari mengunggah file, coba klik Perbarui",
@ -672,11 +669,11 @@
"Logout_Admin_if_not_Available_Online_a_period_of_time": "Logout Admin jika tidak tersedia\/Online dalam jangka waktu tertentu",
"Timeout_Duration": "Durasi Waktu Habis",
"Enter_the_session_timeout_duration__minutes_": "Masukkan durasi batas waktu sesi (menit)",
"Idle_Timeout__Logout_Admin_if_Idle_for_xx_minutes": "Batas waktu idle, Keluar dari Admin jika Idle selama xx menit",
"Idle_Timeout__Logout_Admin_if_Idle_for_xx_minutes": "Waktu Habis Idle, Keluar dari Admin jika Idle selama xx menit",
"New_Version_Notification": "Pemberitahuan Versi Baru",
"This_is_to_notify_you_when_new_updates_is_available": "Ini untuk memberi tahu Anda ketika pembaruan baru tersedia",
"Router_Check": "Pemeriksaan Router",
"If_enabled__the_system_will_notify_Admin_when_router_goes_Offline__If_admin_have_10_or_more_router_and_many_customers__it_will_get_overlapping__you_can_disabled": "Jika diaktifkan, sistem akan memberitahu Admin ketika router Off, Jika Admin memiliki 10 atau lebih router dan banyak pelanggan, maka akan terjadi tumpang tindih, Anda dapat menonaktifkannya",
"If_enabled__the_system_will_notify_Admin_when_router_goes_Offline__If_admin_have_10_or_more_router_and_many_customers__it_will_get_overlapping__you_can_disabled": "Jika diaktifkan, sistem akan memberitahu Admin ketika router Offline, Jika admin memiliki 10 atau lebih router dan banyak pelanggan, maka akan terjadi tumpang tindih, Anda dapat menonaktifkannya",
"Phone_OTP_Required": "Diperlukan OTP Telepon",
"OTP_is_required_when_user_want_to_change_phone_number_and_registration": "OTP diperlukan ketika pengguna ingin mengubah nomor telepon dan registrasi",
"by_WhatsApp": "melalui WhatsApp",
@ -704,7 +701,7 @@
"Used_Date": "Tanggal Penggunaan",
"Plugin_Installer": "Pemasang Plugin",
"Upload_Zip_Plugin_Theme_Device": "Unggah Plugin\/Tema\/Perangkat Zip",
"Install": "Pasang",
"Install": "Memasang",
"via_SMS": "melalui SMS",
"Via_WhatsApp": "Melalui WhatsApp",
"Via_WhatsApp_and_SMS": "Melalui WhatsApp dan SMS",
@ -743,9 +740,9 @@
"Status_": "Status:",
"Force_Logout_": "Paksa Keluar:",
"End_Date_": "Tanggal Berakhir:",
"Save": "Simpan",
"Save": "Menyimpan",
"Not_Active": "Tidak Aktif",
"Limit": "Batasi",
"Limit": "Membatasi",
"Create_expired_Internet_Package": "Buat Paket Internet yang Kedaluwarsa",
"When_customer_expired__you_can_move_it_to_Expired_Internet_Package": "Ketika pelanggan telah kedaluwarsa, Anda dapat memindahkannya ke Paket Internet Kedaluwarsa",
"Miscellaneous_Settings": "Pengaturan Lain-Lain",
@ -754,10 +751,10 @@
"Buy_Balance_Plans": "Beli Paket Saldo",
"New_Voucher_for_10mbps_Created": "Voucher Baru untuk 10mbps Dibuat",
"Previous": "Sebelumnya",
"Share": "Bagikan",
"Share": "Membagikan",
"Agent": "Agen",
"Sub_District": "Kecamatan",
"Ward": "Kelurahan",
"Ward": "Bangsal",
"Profile": "Profil",
"Credentials": "Kredensial",
"Cron_has_not_run_for_over_1_hour__Please_check_your_setup_": "Cron tidak berjalan selama lebih dari 1 jam. Harap periksa pengaturan Anda.",
@ -768,7 +765,7 @@
"Username_should_be_between_3_to_45_characters": "Nama pengguna harus terdiri dari 3 hingga 45 karakter",
"Single_session_Admin": "Sesi Tunggal Admin",
"Admin_can_only_have_single_session_login__it_will_logout_another_session": "Admin hanya dapat memiliki login satu sesi, maka akan keluar dari sesi berikutnya",
"For_Registration_and_Update_Phone_Number": "Untuk Registrasi dan Perbarui Nomor Telepon",
"For_Registration_and_Update_Phone_Number": "Untuk Registrasi dan Update Nomor Telepon",
"Login_as_Customer": "Masuk sebagai Pelanggan",
"Invalid_or_Expired_CSRF_Token": "Token CSRF Tidak Valid atau Kedaluwarsa",
"Edit_Service_Package": "Edit Paket Layanan",
@ -781,8 +778,8 @@
"Home_Address": "Alamat Rumah",
"Email_Address": "Alamat Email",
"Custom_Balance": "Saldo Kustom",
"Input_Desired_Amount": "Masukkan jumlah yang diinginkan",
"Advanced_Hotspot_System": "Sistem Hotspot Lanjutan",
"Input_Desired_Amount": "Masukkan Jumlah yang Diinginkan",
"Advanced_Hotspot_System": "Sistem Hotspot Canggih",
"Successful_Payments": "Pembayaran Berhasil",
"More_Info": "Info lebih lanjut",
"Failed_Payments": "Pembayaran Gagal",
@ -795,7 +792,7 @@
"_Click_this": "Klik ini",
"_to_visit_the_hotspot_login_page": "untuk mengunjungi halaman login hotspot",
"_Choose_your_desired_plan__enter_your_phone_number_and_click_Pay_Now__you_will_be_redirected_to_payment_portal_": "Pilih paket yang Anda inginkan, masukkan nomor telepon Anda dan klik Bayar Sekarang, Anda akan diarahkan ke portal pembayaran.",
"_Pay_with_Demo_Success_": "Bayar dengan Demo berhasil.",
"_Pay_with_Demo_Success_": "Bayar dengan Demo Sukses.",
"_After_Successful_Payment_you_will_be_awarded_the_package_and_you_will_received_your_Voucher_Code_for_login_": "Setelah Pembayaran Berhasil, Anda akan diberikan paket dan Anda akan menerima Kode Voucher untuk login.",
"_Come_back_here_to_see_your_hotspot_performance_at_a_glance_": "Kembali ke sini untuk melihat sekilas kinerja hotspot Anda.",
"Hotspot_Payment_History": "Riwayat Pembayaran Hotspot",
@ -828,7 +825,7 @@
"radius": "radius",
"Max_30_days": "Maksimal 30 hari",
"Information": "Informasi",
"Export_and_Print_will_show_all_data_without_pagination": "Ekspor dan Cetak akan menampilkan semua data tanpa paginasi",
"Export_and_Print_will_show_all_data_without_pagination": "Ekspor dan Cetak akan menampilkan semua data tanpa pagination",
"First_Name": "Nama Depan",
"Last_Name": "Nama Belakang",
"General": "Umum",
@ -888,7 +885,7 @@
"Select_Balance_Package_or_Custom_Amount": "Pilih Paket Saldo atau Jumlah Kustom",
"Or_custom_balance_amount_below": "Atau jumlah saldo khusus di bawah ini",
"Balance_Amount": "Jumlah Saldo",
"Input_custom_balance__will_ignore_plan_above": "Masukkan saldo khusus, akan mengabaikan paket di atas",
"Input_custom_balance__will_ignore_plan_above": "Masukkan saldo khusus, akan mengabaikan rencana di atas",
"Note": "Catatan",
"Customer_Login_Page_Settings": "Pengaturan Halaman Login Pelanggan",
"Choose_Template": "Pilih Template",
@ -912,7 +909,5 @@
"Mandatory_Fields": "Bidang yang wajib diisi",
"Single_Admin_Session": "Sesi Admin Tunggal",
"Mikrotik_SMS_Command": "Perintah SMS Mikrotik",
"Expired_Cronjob_Every_5_Minutes__Recommended_": "Cronjob Kedaluwarsa Setiap 5 Menit [Direkomendasikan]",
"Visit": "Kunjungi",
"sync": "Sinkron"
}
"Expired_Cronjob_Every_5_Minutes__Recommended_": "Cronjob Kedaluwarsa Setiap 5 Menit [Direkomendasikan]"
}

View File

@ -8,7 +8,7 @@
"Log_in_to_Member_Panel": "Iniciar sesi\u00f3n en el panel de miembros",
"Register_as_Member": "Reg\u00edstrese como miembro",
"Enter_Admin_Area": "Panel de administraci\u00f3n",
"PHPNuxBill": "Compañia",
"PHPNuxBill": "WENJEI",
"Username": "Usuario",
"Password": "Contrase\u00f1a",
"Passwords_does_not_match": "Las contrase\u00f1as no coinciden",
@ -541,7 +541,7 @@
"Agent": "Agente",
"Session_has_expired__Please_log_in_again_": "La sesi\u00f3n ha expirado. Por favor, inicie sesi\u00f3n nuevamente.",
"danger": "Peligro",
"City": "Pais",
"City": "Ciudad",
"District": "Distrito",
"State": "Estado",
"Zip": "C\u00f3digo Postal",
@ -565,278 +565,5 @@
"Max_30_days": "M\u00e1ximo 30 d\u00edas",
"Total": "Total",
"Information": "Informaci\u00f3n",
"Export_and_Print_will_show_all_data_without_pagination": "Exportar e imprimir mostrar\u00e1 todos los datos sin paginaci\u00f3n",
"Maps": "Mapas",
"Custom_Fields": "Campos personalizados",
"Cron_appear_not_been_setup__please_check_your_cron_setup_": "Aparece que no se ha configurado Cron, consulte su configuraci\u00f3n de Cron.",
"Check_if_Router_Online_": "\u00bfVerifique si Router Online?",
"To_check_whether_the_Router_is_online_or_not__please_visit_the_following_page": "Para verificar si el enrutador est\u00e1 en l\u00ednea o no, visite la p\u00e1gina siguiente",
"Cek_Now": "Cek ahora",
"Enable": "Permitir",
"Disable": "Desactivar",
"Router_Name___Location": "Nombre \/ ubicaci\u00f3n del enrutador",
"Coordinates": "Coordenadas",
"Coverage": "Cobertura",
"Continue_the_process_of_changing_Routers_": "\u00bfContinuar el proceso de cambiar los enrutadores?",
"First_Name": "Nombre",
"Last_Name": "Apellido",
"Plugin_Installer": "Instalador de plugin",
"Upload_Zip_Plugin_Theme_Device": "Subir el complemento\/tema\/dispositivo con zip",
"Install": "Instalar",
"CPU_Load": "Carga de la CPU",
"Temperature": "Temperatura",
"Voltage": "Voltaje",
"Wireless_Status": "Estado inal\u00e1mbrico",
"Interface_Status": "Estado de la interfaz",
"Hotspot_Online_Users": "Usuarios en l\u00ednea de hotspot",
"PPPoE_Online_Users": "Usuarios en l\u00ednea de PPPOE",
"Traffic_Monitor": "Monitor de tr\u00e1fico",
"Interface_Name": "Nombre de la interfaz",
"Tx__bytes_Out_": "Tx (bytes fuera)",
"Rx__bytes_In_": "Rx (bytes en)",
"Total_Usage": "Uso total",
"Uptime": "Tiempo de actividad",
"Server": "Servidor",
"Mac_Address": "Direcci\u00f3n MAC",
"Session_Time_Left": "Tiempo de sesi\u00f3n restante",
"Upload__RX_": "Cargue (RX)",
"Download__TX_": "Descargar (TX)",
"Service": "Servicio",
"Caller_ID": "Identificador de llamadas",
"Download": "Descargar",
"Upload": "Subir",
"Interface": "Interfaz",
"Last_Ip": "\u00daltima IP",
"Last_Activity": "\u00daltima actividad",
"Signal_Strength": "Resistencia a la se\u00f1al",
"Tx___Rx_CCQ": "TX \/ RX CCQ",
"Rx_Rate": "Tasa de rx",
"Tx_Rate": "Tasa de tx",
"Interace": "Interacci\u00f3n",
"TX": "Tx",
"RX": "Rx",
"Date_Time": "Fecha\/hora",
"Topic": "Tema",
"Send_Personal_Message": "Enviar mensaje personal",
"Send_Via": "Enviar",
"via_SMS": "a trav\u00e9s de SMS",
"Via_WhatsApp": "A trav\u00e9s de whatsapp",
"Via_WhatsApp_and_SMS": "A trav\u00e9s de whatsapp y sms",
"Compose_your_message___": "Componga tu mensaje ...",
"Use_placeholders_": "Use marcadores de posici\u00f3n:",
"Customer_Name": "Nombre del cliente",
"Customer_Username": "Nombre de usuario del cliente",
"Customer_Phone": "Tel\u00e9fono del cliente",
"Your_Company_Name": "Nombre de su empresa",
"Sign_in_into_your_account": "Inicie sesi\u00f3n en su cuenta",
"Usernames": "Nombre de usuario",
"Don_t_have_an_account_": "\u00bfNo tienes una cuenta?",
"General": "General",
"Pretty_URL": "Bonita url",
"rename__htaccess_firewall_to__htaccess": "renombrar .htaccess_firewall a .htaccess",
"Customer_Login_Page_Settings": "Configuraci\u00f3n de la p\u00e1gina de inicio de sesi\u00f3n del cliente",
"Choose_Template": "Elija plantilla",
"Custom": "Costumbre",
"Select_your_login_template_type": "Seleccione su tipo de plantilla de inicio de sesi\u00f3n",
"Select_Login_Page": "Seleccione la p\u00e1gina de inicio de sesi\u00f3n",
"Select_your_preferred_login_template": "Seleccione su plantilla de inicio de sesi\u00f3n preferida",
"Page_Heading___Company_Name": "Encabezado de p\u00e1gina \/ nombre de la empresa",
"This_Name_will_be_shown_on_the_login_wallpaper": "Este nombre se mostrar\u00e1 en el fondo de pantalla de inicio de sesi\u00f3n.",
"Page_Description": "Descripci\u00f3n de la p\u00e1gina",
"This_will_also_display_on_wallpaper__You_can_use_html_tag": "Esto tambi\u00e9n se mostrar\u00e1 en papel tapiz, puede usar la etiqueta HTML",
"Favicon": "Favic\u00f3n",
"Best_size_30_x_30___uploaded_image_will_be_autosize": "El mejor tama\u00f1o 30 x 30 | La imagen cargada se automatizar\u00e1",
"Login_Page_Logo": "Logotipo de la p\u00e1gina de inicio de sesi\u00f3n",
"Best_size_300_x_60___uploaded_image_will_be_autosize": "El mejor tama\u00f1o 300 x 60 | La imagen cargada se automatizar\u00e1",
"Login_Page_Wallpaper": "Fondo de pantalla de la p\u00e1gina de inicio de sesi\u00f3n",
"Best_size_1920_x_1080___uploaded_image_will_be_autosize": "El mejor tama\u00f1o 1920 x 1080 | La imagen cargada se automatizar\u00e1",
"Registration": "Registro",
"Allow_Registration": "Permitir el registro",
"No_Registration": "Sin registro",
"Registration_Username": "Nombre de usuario de registro",
"Photo_Required": "Foto requerida",
"Customer_Registration_need_to_upload_their_photo": "El registro del cliente necesita subir su foto",
"Customer_Registration_need_to_validate_using_OTP": "El registro del cliente debe validar con OTP",
"For_Registration_and_Update_Phone_Number": "Para el n\u00famero de tel\u00e9fono de registro y actualizaci\u00f3n",
"Notify_Admin": "Notificar a administrador",
"Notify_Admin_upon_self_registration": "Notificar al administrador sobre el registro autom\u00e1tico",
"Mandatory_Fields": "Campos obligatorios",
"Security": "Seguridad",
"Single_Admin_Session": "Sesi\u00f3n de administrador \u00fanica",
"Admin_can_only_have_single_session_login__it_will_logout_another_session": "El administrador solo puede tener inicio de sesi\u00f3n de una sola sesi\u00f3n, iniciar\u00e1 sesi\u00f3n en otra sesi\u00f3n",
"Enable_CSRF_Validation": "Habilitar la validaci\u00f3n de CSRF",
"Cross_site_request_forgery": "Falsificaci\u00f3n de solicitud de sitio cruzado",
"SMS_Notification": "Notificaci\u00f3n de SMS",
"Mikrotik_SMS_Command": "Comando de mikrotik sms",
"Tax_Rates_by_percentage": "Tasas impositivas por porcentaje",
"Settings_For_Mikrotik": "Configuraci\u00f3n para Mikrotik",
"Settings_For_Cron_Expired": "Configuraci\u00f3n para Cron expirado",
"Expired_Cronjob_Every_5_Minutes__Recommended_": "Cronjob vencido cada 5 minutos [recomendado]",
"Settings_For_Cron_Reminder": "Configuraci\u00f3n para el recordatorio de Cron",
"Login_Page_Settings_Saved_Successfully": "Configuraci\u00f3n de la p\u00e1gina de inicio de sesi\u00f3n guardada correctamente",
"Logout_Successful": "INCOMPTIR SEXITO",
"warning": "Advertencia",
"Go_Back": "Volver",
"Validate": "Validar",
"Forgot_Usernames": "Olvid\u00e9 nombres de usuario",
"You_are_already_logged_in": "Ya est\u00e1s iniciado",
"Hello": "Hola",
"your_internet_package": "Tu paquete de Internet",
"has_been_expired": "ha sido expirado",
"will_be_replaced_with_Customer_Name": "ser\u00e1 reemplazado por el nombre del cliente",
"will_be_replaced_with_Customer_username": "ser\u00e1 reemplazado por el nombre de usuario del cliente",
"will_be_replaced_with_Package_name": "ser\u00e1 reemplazado por el nombre del paquete",
"will_be_replaced_with_Package_price": "ser\u00e1 reemplazado por el precio del paquete",
"additional_bills_for_customers": "facturas adicionales para los clientes",
"will_be_replaced_with_Expiration_date": "ser\u00e1 reemplazado por la fecha de vencimiento",
"Your_Company_Name_at_Settings": "Nombre de su empresa en la configuraci\u00f3n",
"Your_Company_Address_at_Settings": "Direcci\u00f3n de su empresa en la configuraci\u00f3n",
"Your_Company_Phone_at_Settings": "Tel\u00e9fono de su empresa en la configuraci\u00f3n",
"Invoice_number": "N\u00famero de factura",
"Date_invoice_created": "Factura de fecha creada",
"Payment_gateway_user_paid_from": "El usuario de la pasarela de pago pagado por",
"Payment_channel_user_paid_from": "Usuario de canal de pago pagado desde",
"is_Hotspot_or_PPPOE": "es hotspot o pppoe",
"Internet_Package_Prices": "Precios de paquetes de Internet",
"Receiver_name": "Nombre del receptor",
"Username_internet": "Nombre de usuario Internet",
"User_password": "Contrase\u00f1a de usuario",
"Expired_datetime": "Expirado de fecha y hora",
"For_Notes_by_admin": "Para notas de admin",
"Transaction_datetime": "Transacci\u00f3n data de data",
"Balance_Before": "Equilibrar antes",
"Balance_After": "Equilibrar",
"Welcome_Message": "Mensaje de bienvenida",
"will_be_replaced_with_Customer_password": "ser\u00e1 reemplazado por la contrase\u00f1a del cliente",
"will_be_replaced_with_Customer_Portal_URL": "ser\u00e1 reemplazado por URL del portal del cliente",
"will_be_replaced_with_Company_Name": "ser\u00e1 reemplazado por el nombre de la empresa",
"Save": "Guardar",
"Save_as_template": "Guardar como plantilla",
"Template_Name": "Nombre de plantilla",
"Package_Price": "Precio del paquete",
"Voucher_Code": "C\u00f3digo de cup\u00f3n",
"Voucher_Package": "Paquete de cupones",
"Counter": "Contador",
"Sub_District": "Distrito",
"Ward": "Código Postal",
"Profile": "Perfil",
"Photo": "Foto",
"Phone": "Tel\u00e9fono",
"Credentials": "Cartas credenciales",
"RB5009_39": "RB5009-39",
"Admin": "Administraci\u00f3n",
"VPN_Plans": "Planes VPN",
"Using": "Usando",
"Postpaid_Recharge_for_the_first_time_use": "Recarga pospago por primera vez uso",
"Or": "O",
"Confirm": "Confirmar",
"Name": "Nombre",
"Plan": "Plan",
"Resend": "Revender",
"Home_Address": "Direcci\u00f3n de la casa",
"Other": "Otro",
"Business": "Negocio",
"Not_Working_for_freeradius": "No funciona para freeradius",
"Also_Working_for_freeradius": "Tambi\u00e9n trabajando para freeradius",
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_Customer_Credentials": "El usuario no puede cambiar esto, solo administrador. Si se vac\u00eda, usar\u00e1 las credenciales del cliente",
"Send_welcome_message": "Enviar mensaje de bienvenida",
"Notification_via": "Notificaci\u00f3n a trav\u00e9s de",
"SMS": "SMS",
"WA": "Whatsapp",
"Attributes": "Atributos",
"Additional_Information": "informaci\u00f3n adicional",
"City_of_Resident": "Ciudad del residente",
"State_of_Resident": "Estado de residente",
"Zip_Code": "C\u00f3digo postal",
"Continue_the_process_of_adding_Customer_Data_": "\u00bfContinuar el proceso de agregar datos de clientes?",
"Customer_cannot_buy_disabled_Package__but_admin_can_recharge_it__use_it_if_you_want_only_admin_recharge_it": "El cliente no puede comprar el paquete discapacitado, pero el administrador puede recargarlo, usarlo si solo desea recargarlo de administrador",
"Postpaid_will_have_fix_expired_date": "Postpaid tendr\u00e1 una fecha vencida",
"Prepaid": "Pagado",
"Postpaid": "Pospago",
"Personal_Package_will_only_show_to_personal_Customer__Business_Package_will_only_show_to_Business_Customer": "El paquete personal solo se mostrar\u00e1 al cliente personal, el paquete comercial solo se mostrar\u00e1 al cliente empresarial",
"Device": "Dispositivo",
"This_Device_are_the_logic_how_PHPNuxBill_Communicate_with_Mikrotik_or_other_Devices": "Este dispositivo es la l\u00f3gica de c\u00f3mo PhpNuxbill se comunica con Mikrotik u otros dispositivos",
"Price_Before_Discount": "Precio antes de descuento",
"For_Discount_Rate__this_is_price_before_get_discount__must_be_more_expensive_with_real_price": "Para una tasa de descuento, este es el precio antes de obtener descuento, debe ser m\u00e1s costoso con un precio real",
"1_Period___1_Month__Expires_the_20th_of_each_month": "1 per\u00edodo = 1 mes, expira el 20 de cada mes",
"Expired_Date": "Fecha vencida",
"Expired_will_be_this_date_every_month": "Caducado ser\u00e1 esta fecha cada mes",
"Expired_Action": "Acci\u00f3n vencida",
"Optional": "Opcional",
"Expired_Internet_Plan": "Plan de Internet vencido",
"When_Expired__customer_will_be_move_to_selected_internet_plan": "Cuando expire, el cliente se trasladar\u00e1 al plan de Internet seleccionado",
"on_login___on_up": "en el login \/ encendido",
"on_logout___on_down": "On-Logout \/ On-Down",
"Continue_the_PPPoE_Package_change_process_": "\u00bfContinuar el proceso de cambio de paquete PPPOE?",
"Period": "Per\u00edodo",
"Login_as_Customer": "Iniciar sesi\u00f3n como cliente",
"Rate": "Tasa",
"Create_Bandwidth_Package_for_expired_Internet_Package": "Crear paquete de ancho de banda para paquete de Internet vencido",
"When_customer_expired__you_can_move_it_to_Expired_Internet_Package": "Cuando el cliente caduque, podr\u00e1 moverlo a Paquete de Internet Caducado",
"Category": "Categor\u00eda",
"Create_expired_Internet_Plan": "Crear plan de Internet vencido",
"When_customer_expired__you_can_move_it_to_Expired_Internet_Plan": "Cuando el cliente caduque, podr\u00e1 moverlo a Plan de Internet Caducado",
"Personal_Package_will_only_show_to_personal_Customer__Business_package_will_only_show_to_Business_Customer": "El paquete personal solo se mostrar\u00e1 a los clientes personales, el paquete comercial solo se mostrar\u00e1 a los clientes comerciales",
"Continue_the_process_of_adding_the_PPPoE_Package_": "\u00bfContinuar con el proceso de agregar el paquete PPPoE?",
"Face_Detection": "Detecci\u00f3n de rostros",
"Customer_cannot_login_again": "El cliente no puede iniciar sesi\u00f3n nuevamente",
"Customer_can_login_but_cannot_buy_internet_package__Admin_cannot_recharge_customer": "El cliente puede iniciar sesi\u00f3n pero no puede comprar un paquete de Internet. El administrador no puede recargar al cliente.",
"Don_t_forget_to_deactivate_all_active_package_too": "No olvides desactivar tambi\u00e9n todos los paquetes activos.",
"Not_Working_with_Freeradius_Mysql": "No funciona con Freeradius Mysql",
"Continue_the_Customer_Data_change_process_": "\u00bfContinuar con el proceso de cambio de datos del cliente?",
"Port_Pool": "Grupo de puerto",
"New_port": "Nuevo puerto",
"Port_Name": "Nombre del puerto",
"Public_IP": "IP p\u00fablica",
"Range_Port": "Rango de Puertos",
"Add_Port_Pool": "Agregar grupo de puertos",
"Continue_the_process_of_adding_Ports_": "\u00bfContinuar con el proceso de agregar puertos?",
"Continue_the_VPN_creation_process_": "\u00bfContinuar con el proceso de creaci\u00f3n de VPN?",
"": "",
"Local_IP": "IP local",
"Test_Connection": "Conexi\u00f3n de prueba",
"Continue_the_process_of_adding_Routers_": "\u00bfContinuar con el proceso de agregar enrutadores?",
"Continue_the_Pool_addition_process_": "\u00bfContinuar con el proceso de adici\u00f3n de la piscina?",
"Private_IP": "IP privada",
"Sync_account_if_you_failed_login_to_internet": "Sincronizar cuenta si no se pudo iniciar sesi\u00f3n en Internet",
"Data_Change": "Cambio de datos",
"Face_Detect": "Detecci\u00f3n de rostro",
"Email_Address": "Direcci\u00f3n de correo electr\u00f3nico",
"Transaction_History_List": "Lista de historial de transacciones",
"Contabo": "Contabo",
"Not_Active": "No activo",
"New_Service_Package": "Nuevo paquete de servicios",
"Limit": "L\u00edmite",
"Time": "Tiempo",
"Data": "Datos",
"ID": "IDENTIFICACI\u00d3N",
"Create_expired_Internet_Package": "Crear paquete de Internet vencido",
"Oops__The_page_you_are_looking_for_was_not_found": "\u00a1Ups! La p\u00e1gina que est\u00e1 buscando no fue encontrada",
"Back_to_Dashboard": "Volver al panel de control",
"Add_User": "Agregar usuario",
"Report_Viewer": "Visor de informes",
"Super_Administrator": "Super administrador",
"Send_Notification": "Enviar notificaci\u00f3n",
"Don_t_Send": "No env\u00ede",
"Registration_successful": "Registro exitoso",
"New_User_Registration": "Registro de nuevo usuario",
"New_Field": "Nuevo campo",
"Installed_Devices": "Dispositivos instalados",
"Miscellaneous_Settings": "Configuraciones varias",
"Display_bandwidth_plan_for_customer": "Mostrar plan de ancho de banda para el cliente",
"Radius_Rest_Interim_Update": "Actualizaci\u00f3n provisional de Radius Rest",
"in_minutes__leave_0_to_disable_this_feature_": "en minutos, deje 0 para deshabilitar esta funci\u00f3n.",
"Check_if_Customer_Online": "Verificar si el cliente est\u00e1 en l\u00ednea",
"This_will_show_is_Customer_currently_is_online_or_not": "Esto mostrar\u00e1 si el cliente est\u00e1 actualmente en l\u00ednea o no.",
"Allow_Balance_Custom_Amount": "Permitir saldo Importe personalizado",
"Allow_Customer_buy_balance_with_any_amount": "Permitir al Cliente comprar saldo con cualquier monto",
"Make_sure_you_use_API_Port__Default_8728": "Aseg\u00farese de utilizar el puerto API, predeterminado 8728",
"Make_sure_Username_and_Password_are_correct": "Aseg\u00farese de que el nombre de usuario y la contrase\u00f1a sean correctos",
"Make_sure_your_hosting_not_blocking_port_to_external": "Aseg\u00farese de que su hosting no bloquee el puerto al externo",
"Make_sure_your_Mikrotik_accessible_from_PHPNuxBill": "Aseg\u00farese de que su Mikrotik sea accesible desde PHPNuxBill",
"If_you_just_update_PHPNuxBill_from_upload_files__try_click_Update": "Si simplemente actualiza PHPNuxBill desde la carga de archivos, intente hacer clic en Actualizar",
"Update": "Actualizar",
"Update_PHPNuxBill": "Actualizar PHPNuxBill",
"Ask_Github_Community": "Pregunta a la comunidad de Github",
"Ask_Telegram_Community": "Pregunta a la comunidad de Telegram"
"Export_and_Print_will_show_all_data_without_pagination": "Exportar e imprimir mostrar\u00e1 todos los datos sin paginaci\u00f3n"
}

View File

@ -1483,14 +1483,6 @@ class ORM implements ArrayAccess
return $this->_add_simple_where($column_name, 'LIKE', $value);
}
/**
* Add any WHERE ... LIKE clause to your query.
*/
public function where_likes($column = null, $values = null)
{
return $this->_addWhere('(' . implode(' LIKE ? OR ', $column) . ' LIKE ? )', $values);
}
/**
* Add where WHERE ... NOT LIKE clause to your query.
*/

View File

@ -1,211 +1,188 @@
{
"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`;"
],
"2024.6.5": [
"ALTER TABLE `tbl_plans` ADD `price_old` VARCHAR(40) NOT NULL DEFAULT '' AFTER `price`;",
"ALTER TABLE `tbl_plans` ADD `device` VARCHAR(32) NOT NULL DEFAULT '' AFTER `plan_type`;"
],
"2024.6.10": [
"ALTER TABLE `tbl_pool` ADD `local_ip` VARCHAR(40) NOT NULL DEFAULT '' AFTER `pool_name`;"
],
"2024.6.11": [
"ALTER TABLE `tbl_plans` ADD `plan_expired` INT NOT NULL DEFAULT '0' AFTER `pool`;",
"ALTER TABLE `tbl_plans` DROP `pool_expired`, DROP `list_expired`;"
],
"2024.6.19": [
"ALTER TABLE `tbl_plans` ADD `expired_date` TINYINT(1) NOT NULL DEFAULT '20' AFTER `plan_expired`;"
],
"2024.6.21": [
"ALTER TABLE `tbl_plans` ADD `on_login` TEXT NULL DEFAULT NULL AFTER `device`;",
"ALTER TABLE `tbl_plans` ADD `on_logout` TEXT NULL DEFAULT NULL AFTER `on_login`;"
],
"2024.7.6": [
"CREATE TABLE IF NOT EXISTS `rad_acct` ( `id` bigint NOT NULL, `acctsessionid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `realm` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasid` varchar(32) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasportid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `nasporttype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `framedipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',`acctstatustype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `macaddr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `dateAdded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;",
"ALTER TABLE `rad_acct` ADD PRIMARY KEY (`id`), ADD KEY `username` (`username`), ADD KEY `framedipaddress` (`framedipaddress`), ADD KEY `acctsessionid` (`acctsessionid`), ADD KEY `nasipaddress` (`nasipaddress`);",
"ALTER TABLE `rad_acct` MODIFY `id` bigint NOT NULL AUTO_INCREMENT;"
],
"2024.7.24": [
"ALTER TABLE `tbl_voucher` ADD `used_date` DATETIME NULL DEFAULT NULL AFTER `status`;",
"UPDATE `tbl_voucher` SET `used_date`=now() WHERE `status`=1;"
],
"2024.8.1": [
"ALTER TABLE `tbl_payment_gateway` CHANGE `gateway_trx_id` `gateway_trx_id` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';",
"ALTER TABLE `tbl_payment_gateway` CHANGE `pg_url_payment` `pg_url_payment` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';"
],
"2024.8.2": [
"CREATE TABLE IF NOT EXISTS `tbl_customers_inbox` (`id` int UNSIGNED NOT NULL AUTO_INCREMENT, `customer_id` int NOT NULL, `date_created` datetime NOT NULL, `date_read` datetime DEFAULT NULL, `subject` varchar(64) COLLATE utf8mb4_general_ci NOT NULL, `body` TEXT NULL DEFAULT NULL, `from` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'System' COMMENT 'System or Admin or Else',`admin_id` int NOT NULL DEFAULT '0' COMMENT 'other than admin is 0', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
],
"2024.8.5": [
"ALTER TABLE `tbl_customers` ADD `pppoe_username` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `password`;",
"ALTER TABLE `tbl_customers` ADD `pppoe_ip` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `pppoe_password`;"
],
"2024.8.5.1": [
"ALTER TABLE `tbl_routers` ADD `coordinates` VARCHAR(50) NOT NULL DEFAULT '' AFTER `description`;",
"ALTER TABLE `tbl_routers` ADD `coverage` VARCHAR(8) NOT NULL DEFAULT '0' AFTER `coordinates`;"
],
"2024.8.6": [
"ALTER TABLE `rad_acct` ADD `acctinputoctets` BIGINT NOT NULL DEFAULT '0' AFTER `framedipaddress`;",
"ALTER TABLE `rad_acct` ADD `acctoutputoctets` BIGINT NOT NULL DEFAULT '0' AFTER `acctinputoctets`;"
],
"2024.8.7": [
"ALTER TABLE `tbl_customers` CHANGE `coordinates` `coordinates` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates';"
],
"2024.8.28": [
"ALTER TABLE `tbl_routers` ADD `status` ENUM('Online', 'Offline') DEFAULT 'Online' AFTER `coordinates`;",
"ALTER TABLE `tbl_routers` ADD `last_seen` DATETIME AFTER `status`;"
],
"2024.9.13": [
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','VPN','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
"ALTER TABLE `tbl_customers` CHANGE `service_type` `service_type` ENUM('Hotspot','PPPoE','VPN','Others') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'Others' COMMENT 'For selecting user type';",
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','VPN','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
"CREATE TABLE IF NOT EXISTS `tbl_port_pool` ( `id` int(10) NOT NULL AUTO_INCREMENT , `public_ip` varchar(40) NOT NULL, `port_name` varchar(40) NOT NULL, `range_port` varchar(40) NOT NULL, `routers` varchar(40) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
],
"2024.10.10": [
"ALTER TABLE `tbl_users` ADD `login_token` VARCHAR(40) AFTER `last_login`;"
],
"2024.10.17": [
"CREATE TABLE IF NOT EXISTS `tbl_meta` ( `id` int UNSIGNED NOT NULL AUTO_INCREMENT, `tbl` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Table name', `tbl_id` int NOT NULL COMMENT 'table value id', `name` varchar(32) COLLATE utf8mb4_general_ci NOT NULL, `value` mediumtext COLLATE utf8mb4_general_ci, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='This Table to add additional data for any table';"
],
"2024.10.30": [
"ALTER TABLE `tbl_users` ADD `photo` VARCHAR(128) NOT NULL DEFAULT '/admin.default.png' AFTER `root`;",
"ALTER TABLE `tbl_users` ADD `data` TEXT NULL DEFAULT NULL COMMENT 'to put additional data' AFTER `status`;"
],
"2024.10.31": [
"ALTER TABLE `tbl_customers` ADD `photo` VARCHAR(128) NOT NULL DEFAULT '/user.default.jpg' AFTER `password`;"
],
"2024.12.5.1": [
"ALTER TABLE `tbl_transactions` ADD `user_id` INT(11) NOT NULL DEFAULT 0 AFTER `username`;",
"ALTER TABLE `tbl_payment_gateway` ADD `user_id` INT(11) NOT NULL DEFAULT 0 AFTER `username`;"
],
"2024.12.16": [
"CREATE TABLE `tbl_coupons` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `code` VARCHAR(50) NOT NULL UNIQUE, `type` ENUM('fixed', 'percent') NOT NULL, `value` DECIMAL(10,2) NOT NULL, `description` TEXT NOT NULL, `max_usage` INT NOT NULL DEFAULT 1,`usage_count` INT NOT NULL DEFAULT 0,`status` ENUM('active', 'inactive') NOT NULL, `min_order_amount` DECIMAL(10,2) NOT NULL, `max_discount_amount` DECIMAL(10,2) NOT NULL, `start_date` DATE NOT NULL,`end_date` DATE NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);"
],
"2024.12.20": [
"ALTER TABLE `tbl_voucher` ADD `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `status`;"
],
"2025.1.23": [
"ALTER TABLE `rad_acct` ADD `acctsessiontime` BIGINT(12) NOT NULL DEFAULT '0' AFTER `framedipaddress`;"
],
"2025.2.14": [
"CREATE TABLE IF NOT EXISTS `tbl_widgets` ( `id` int NOT NULL AUTO_INCREMENT, `orders` int NOT NULL DEFAULT '99', `position` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1. top 2. left 3. right 4. bottom',`enabled` tinyint(1) NOT NULL DEFAULT '1', `title` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `widget` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `content` text COLLATE utf8mb4_general_ci NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
],
"2025.2.17": [
"INSERT INTO `tbl_widgets` (`id`, `orders`, `position`, `enabled`, `title`, `widget`, `content`) VALUES (1, 1, 1, 1, 'Top Widget', 'top_widget', ''),(2, 2, 1, 1, 'Default Info', 'default_info_row', ''),(3, 1, 2, 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''),(4, 2, 2, 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''),(5, 3, 2, 1, 'Voucher Stocks', 'voucher_stocks', ''),(6, 4, 2, 1, 'Customer Expired', 'customer_expired', ''),(7, 1, 3, 1, 'Cron Monitor', 'cron_monitor', ''),(8, 2, 3, 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''),(9, 3, 3, 1, 'Info Payment Gateway', 'info_payment_gateway', ''),(10, 4, 3, 1, 'Graph Customers Insight', 'graph_customers_insight', ''),(11, 5, 3, 1, 'Activity Log', 'activity_log', '');"
],
"2025.2.19": [
"ALTER TABLE `tbl_widgets` ADD `user` ENUM('Admin','Agent','Sales','Customer') NOT NULL DEFAULT 'Admin' AFTER `position`;"
],
"2025.2.21": [
"INSERT INTO `tbl_widgets` (`id`, `orders`, `position`, `user`, `enabled`, `title`, `widget`, `content`) VALUES (60, 1, 2, 'Customer', 1, 'Account Info', 'account_info', ''),(61, 3, 1, 'Customer', 1, 'Active Internet Plan', 'active_internet_plan', ''),(62, 4, 1, 'Customer', 1, 'Balance Transfer', 'balance_transfer', ''),(63, 1, 1, 'Customer', 1, 'Unpaid Order', 'unpaid_order', ''),(64, 2, 1, 'Customer', 1, 'Announcement', 'announcement', ''),(65, 5, 1, 'Customer', 1, 'Recharge A Friend', 'recharge_a_friend', ''),(66, 2, 2, 'Customer', 1, 'Voucher Activation', 'voucher_activation', '');"
],
"2025.2.25": [
"INSERT INTO `tbl_widgets` (`id`, `orders`, `position`, `user`, `enabled`, `title`, `widget`, `content`) VALUES (30, 1, 1, 'Agent', 1, 'Top Widget', 'top_widget', ''), (31, 2, 1, 'Agent', 1, 'Default Info', 'default_info_row', ''), (32, 1, 2, 'Agent', 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''), (33, 2, 2, 'Agent', 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''), (34, 3, 2, 'Agent', 1, 'Voucher Stocks', 'voucher_stocks', ''), (35, 4, 2, 'Agent', 1, 'Customer Expired', 'customer_expired', ''), (36, 1, 3, 'Agent', 1, 'Cron Monitor', 'cron_monitor', ''), (37, 2, 3, 'Agent', 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''), (38, 3, 3, 'Agent', 1, 'Info Payment Gateway', 'info_payment_gateway', ''), (39, 4, 3, 'Agent', 1, 'Graph Customers Insight', 'graph_customers_insight', ''),(40, 5, 3, 'Agent', 1, 'Activity Log', 'activity_log', '');",
"INSERT INTO `tbl_widgets` (`id`, `orders`, `position`, `user`, `enabled`, `title`, `widget`, `content`) VALUES (41, 1, 1, 'Sales', 1, 'Top Widget', 'top_widget', ''), (42, 2, 1, 'Sales', 1, 'Default Info', 'default_info_row', ''), (43, 1, 2, 'Sales', 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''), (44, 2, 2, 'Sales', 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''), (45, 3, 2, 'Sales', 1, 'Voucher Stocks', 'voucher_stocks', ''), (46, 4, 2, 'Sales', 1, 'Customer Expired', 'customer_expired', ''), (47, 1, 3, 'Sales', 1, 'Cron Monitor', 'cron_monitor', ''), (48, 2, 3, 'Sales', 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''), (49, 3, 3, 'Sales', 1, 'Info Payment Gateway', 'info_payment_gateway', ''), (50, 4, 3, 'Sales', 1, 'Graph Customers Insight', 'graph_customers_insight', ''), (51, 5, 3, 'Sales', 1, 'Activity Log', 'activity_log', '');"
],
"2025.3.5": [
"CREATE TABLE IF NOT EXISTS `tbl_message_logs` ( `id` SERIAL PRIMARY KEY, `message_type` VARCHAR(50), `recipient` VARCHAR(255), `message_content` TEXT, `status` VARCHAR(50), `error_message` TEXT, `sent_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
],
"2025.3.10": [
"CREATE TABLE IF NOT EXISTS `tbl_invoices` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `number` VARCHAR(50) NOT NULL, `customer_id` INT NOT NULL, `fullname` VARCHAR(100) NOT NULL, `email` VARCHAR(100) NOT NULL, `address` TEXT, `status` ENUM('Unpaid', 'Paid', 'Cancelled') NOT NULL DEFAULT 'Unpaid', `due_date` DATETIME NOT NULL, `filename` VARCHAR(255), `amount` DECIMAL(10, 2) NOT NULL, `data` JSON NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP);"
]
}
"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`;"
],
"2024.6.5": [
"ALTER TABLE `tbl_plans` ADD `price_old` VARCHAR(40) NOT NULL DEFAULT '' AFTER `price`;",
"ALTER TABLE `tbl_plans` ADD `device` VARCHAR(32) NOT NULL DEFAULT '' AFTER `plan_type`;"
],
"2024.6.10": [
"ALTER TABLE `tbl_pool` ADD `local_ip` VARCHAR(40) NOT NULL DEFAULT '' AFTER `pool_name`;"
],
"2024.6.11": [
"ALTER TABLE `tbl_plans` ADD `plan_expired` INT NOT NULL DEFAULT '0' AFTER `pool`;",
"ALTER TABLE `tbl_plans` DROP `pool_expired`, DROP `list_expired`;"
],
"2024.6.19": [
"ALTER TABLE `tbl_plans` ADD `expired_date` TINYINT(1) NOT NULL DEFAULT '20' AFTER `plan_expired`;"
],
"2024.6.21": [
"ALTER TABLE `tbl_plans` ADD `on_login` TEXT NULL DEFAULT NULL AFTER `device`;",
"ALTER TABLE `tbl_plans` ADD `on_logout` TEXT NULL DEFAULT NULL AFTER `on_login`;"
],
"2024.7.6": [
"CREATE TABLE IF NOT EXISTS `rad_acct` ( `id` bigint NOT NULL, `acctsessionid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `realm` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasid` varchar(32) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasportid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `nasporttype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `framedipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',`acctstatustype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `macaddr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `dateAdded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;",
"ALTER TABLE `rad_acct` ADD PRIMARY KEY (`id`), ADD KEY `username` (`username`), ADD KEY `framedipaddress` (`framedipaddress`), ADD KEY `acctsessionid` (`acctsessionid`), ADD KEY `nasipaddress` (`nasipaddress`);",
"ALTER TABLE `rad_acct` MODIFY `id` bigint NOT NULL AUTO_INCREMENT;"
],
"2024.7.24": [
"ALTER TABLE `tbl_voucher` ADD `used_date` DATETIME NULL DEFAULT NULL AFTER `status`;",
"UPDATE `tbl_voucher` SET `used_date`=now() WHERE `status`=1;"
],
"2024.8.1": [
"ALTER TABLE `tbl_payment_gateway` CHANGE `gateway_trx_id` `gateway_trx_id` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';",
"ALTER TABLE `tbl_payment_gateway` CHANGE `pg_url_payment` `pg_url_payment` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';"
],
"2024.8.2": [
"CREATE TABLE IF NOT EXISTS `tbl_customers_inbox` (`id` int UNSIGNED NOT NULL AUTO_INCREMENT, `customer_id` int NOT NULL, `date_created` datetime NOT NULL, `date_read` datetime DEFAULT NULL, `subject` varchar(64) COLLATE utf8mb4_general_ci NOT NULL, `body` TEXT NULL DEFAULT NULL, `from` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'System' COMMENT 'System or Admin or Else',`admin_id` int NOT NULL DEFAULT '0' COMMENT 'other than admin is 0', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
],
"2024.8.5": [
"ALTER TABLE `tbl_customers` ADD `pppoe_username` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `password`;",
"ALTER TABLE `tbl_customers` ADD `pppoe_ip` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `pppoe_password`;"
],
"2024.8.5.1": [
"ALTER TABLE `tbl_routers` ADD `coordinates` VARCHAR(50) NOT NULL DEFAULT '' AFTER `description`;",
"ALTER TABLE `tbl_routers` ADD `coverage` VARCHAR(8) NOT NULL DEFAULT '0' AFTER `coordinates`;"
],
"2024.8.6": [
"ALTER TABLE `rad_acct` ADD `acctinputoctets` BIGINT NOT NULL DEFAULT '0' AFTER `framedipaddress`;",
"ALTER TABLE `rad_acct` ADD `acctoutputoctets` BIGINT NOT NULL DEFAULT '0' AFTER `acctinputoctets`;"
],
"2024.8.7": [
"ALTER TABLE `tbl_customers` CHANGE `coordinates` `coordinates` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates';"
],
"2024.8.28": [
"ALTER TABLE `tbl_routers` ADD `status` ENUM('Online', 'Offline') DEFAULT 'Online' AFTER `coordinates`;",
"ALTER TABLE `tbl_routers` ADD `last_seen` DATETIME AFTER `status`;"
],
"2024.9.13": [
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','VPN','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
"ALTER TABLE `tbl_customers` CHANGE `service_type` `service_type` ENUM('Hotspot','PPPoE','VPN','Others') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'Others' COMMENT 'For selecting user type';",
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','VPN','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
"CREATE TABLE IF NOT EXISTS `tbl_port_pool` ( `id` int(10) NOT NULL AUTO_INCREMENT , `public_ip` varchar(40) NOT NULL, `port_name` varchar(40) NOT NULL, `range_port` varchar(40) NOT NULL, `routers` varchar(40) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
],
"2024.10.10": [
"ALTER TABLE `tbl_users` ADD `login_token` VARCHAR(40) AFTER `last_login`;"
],
"2024.10.17": [
"CREATE TABLE IF NOT EXISTS `tbl_meta` ( `id` int UNSIGNED NOT NULL AUTO_INCREMENT, `tbl` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Table name', `tbl_id` int NOT NULL COMMENT 'table value id', `name` varchar(32) COLLATE utf8mb4_general_ci NOT NULL, `value` mediumtext COLLATE utf8mb4_general_ci, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='This Table to add additional data for any table';"
],
"2024.10.30": [
"ALTER TABLE `tbl_users` ADD `photo` VARCHAR(128) NOT NULL DEFAULT '/admin.default.png' AFTER `root`;",
"ALTER TABLE `tbl_users` ADD `data` TEXT NULL DEFAULT NULL COMMENT 'to put additional data' AFTER `status`;"
],
"2024.10.31": [
"ALTER TABLE `tbl_customers` ADD `photo` VARCHAR(128) NOT NULL DEFAULT '/user.default.jpg' AFTER `password`;"
],
"2024.12.5.1": [
"ALTER TABLE `tbl_transactions` ADD `user_id` INT(11) NOT NULL DEFAULT 0 AFTER `username`;",
"ALTER TABLE `tbl_payment_gateway` ADD `user_id` INT(11) NOT NULL DEFAULT 0 AFTER `username`;"
],
"2024.12.16": [
"CREATE TABLE `tbl_coupons` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `code` VARCHAR(50) NOT NULL UNIQUE, `type` ENUM('fixed', 'percent') NOT NULL, `value` DECIMAL(10,2) NOT NULL, `description` TEXT NOT NULL, `max_usage` INT NOT NULL DEFAULT 1,`usage_count` INT NOT NULL DEFAULT 0,`status` ENUM('active', 'inactive') NOT NULL, `min_order_amount` DECIMAL(10,2) NOT NULL, `max_discount_amount` DECIMAL(10,2) NOT NULL, `start_date` DATE NOT NULL,`end_date` DATE NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);"
],
"2024.12.20": [
"ALTER TABLE `tbl_voucher` ADD `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `status`;"
]
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,15 +0,0 @@
<?php
class activity_log
{
public function getWidget()
{
global $config, $ui, $current_date, $start_date;
$dlog = ORM::for_table('tbl_logs')->limit(5)->order_by_desc('id')->findArray();
$ui->assign('dlog', $dlog);
// $log = ORM::for_table('tbl_logs')->count();
// $ui->assign('log', $log);
return $ui->fetch('widget/activity_log.tpl');
}
}

View File

@ -1,17 +0,0 @@
<?php
class cron_monitor
{
public function getWidget()
{
global $UPLOAD_PATH,$ui;
$timestampFile = "$UPLOAD_PATH/cron_last_run.txt";
if (file_exists($timestampFile)) {
$lastRunTime = file_get_contents($timestampFile);
$ui->assign('run_date', date('Y-m-d h:i:s A', $lastRunTime));
}
return $ui->fetch('widget/cron_monitor.tpl');
}
}

View File

@ -1,14 +0,0 @@
<?php
class account_info
{
public function getWidget()
{
global $ui;
$abills = User::getAttributes("Bill");
$ui->assign('abills', $abills);
return $ui->fetch('widget/customers/account_info.tpl');
}
}

View File

@ -1,20 +0,0 @@
<?php
class active_internet_plan
{
public function getWidget()
{
global $ui, $user;
$_bill = User::_billing();
$ui->assign('_bills', $_bill);
$tcf = ORM::for_table('tbl_customers_fields')
->where('customer_id', $user['id'])
->find_many();
$vpn = ORM::for_table('tbl_port_pool')
->find_one();
$ui->assign('cf', $tcf);
$ui->assign('vpn', $vpn);
return $ui->fetch('widget/customers/active_internet_plan.tpl');
}
}

View File

@ -1,11 +0,0 @@
<?php
class announcement
{
public function getWidget()
{
global $ui;
return $ui->fetch('widget/customers/announcement.tpl');
}
}

View File

@ -1,11 +0,0 @@
<?php
class balance_transfer
{
public function getWidget()
{
global $ui;
return $ui->fetch('widget/customers/balance_transfer.tpl');
}
}

View File

@ -1,11 +0,0 @@
<?php
class button_order_internet_plan
{
public function getWidget()
{
global $ui;
return $ui->fetch('widget/customers/button_order_internet_plan.tpl');
}
}

View File

@ -1,11 +0,0 @@
<?php
class html_only
{
public function getWidget($data = null)
{
global $ui;
return $data['content'];
}
}

View File

@ -1,22 +0,0 @@
<?php
class html_php
{
public function getWidget($data = null)
{
global $ui;
$ui->assign('card_header', $data['title']);
ob_start();
try{
eval('?>'. $data['content']);
}catch(Exception $e){
echo $e->getMessage();
echo "<br>";
echo $e->getTraceAsString();
}
$content = ob_get_clean();
$ui->assign('card_body', $content);
return $ui->fetch('widget/card_html.tpl');
}
}

View File

@ -1,11 +0,0 @@
<?php
class recharge_a_friend
{
public function getWidget()
{
global $ui;
return $ui->fetch('widget/customers/recharge_a_friend.tpl');
}
}

View File

@ -1,39 +0,0 @@
<?php
class unpaid_order
{
public function getWidget()
{
global $ui, $user;
$unpaid = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
// check expired payments
if ($unpaid) {
try {
if (strtotime($unpaid['expired_date']) < time()) {
$unpaid->status = 4;
$unpaid->save();
$unpaid = [];
}
} catch (Throwable $e) {
} catch (Exception $e) {
}
try {
if (strtotime($unpaid['created_date'], "+24 HOUR") < time()) {
$unpaid->status = 4;
$unpaid->save();
$unpaid = [];
}
} catch (Throwable $e) {
} catch (Exception $e) {
}
}
$ui->assign('unpaid', $unpaid);
return $ui->fetch('widget/customers/unpaid_order.tpl');
}
}

View File

@ -1,11 +0,0 @@
<?php
class voucher_activation
{
public function getWidget()
{
global $ui;
return $ui->fetch('widget/customers/voucher_activation.tpl');
}
}

View File

@ -1,63 +0,0 @@
<?php
class customer_expired
{
public function getWidget()
{
global $ui, $current_date, $config;
//user expire
$query = ORM::for_table('tbl_user_recharges')
->table_alias('tur')
->selects([
'c.id',
'tur.username',
'c.fullname',
'c.phonenumber',
'c.email',
'tur.expiration',
'tur.time',
'tur.recharged_on',
'tur.recharged_time',
'tur.namebp',
'tur.routers'
])
->innerJoin('tbl_customers', ['tur.customer_id', '=', 'c.id'], 'c')
->where_lte('expiration', $current_date)
->order_by_desc('expiration');
$expire = Paginator::findMany($query);
// Get the total count of expired records for pagination
$totalCount = ORM::for_table('tbl_user_recharges')
->where_lte('expiration', $current_date)
->count();
// Pass the total count and current page to the paginator
$paginator['total_count'] = $totalCount;
if(!empty($_COOKIE['expdef']) && $_COOKIE['expdef'] != $config['customer_expired_expdef']) {
$d = ORM::for_table('tbl_appconfig')->where('setting', 'customer_expired_expdef')->find_one();
if ($d) {
$d->value = $_COOKIE['expdef'];
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'customer_expired_expdef';
$d->value = $_COOKIE['expdef'];
$d->save();
}
}
if(!empty($config['customer_expired_expdef']) && empty($_COOKIE['expdef'])){
$_COOKIE['expdef'] = $config['customer_expired_expdef'];
setcookie('expdef', $config['customer_expired_expdef'], time() + (86400 * 30), "/");
}
// Assign the pagination HTML to the template variable
$ui->assign('expire', $expire);
$ui->assign('cookie', $_COOKIE);
return $ui->fetch('widget/customer_expired.tpl');
}
}

View File

@ -1,17 +0,0 @@
<?php
class default_info_row
{
public function getWidget()
{
global $config,$ui;
if ($config['enable_balance'] == 'yes'){
$cb = ORM::for_table('tbl_customers')->whereGte('balance', 0)->sum('balance');
$ui->assign('cb', $cb);
}
return $ui->fetch('widget/default_info_row.tpl');
}
}

View File

@ -1,28 +0,0 @@
<?php
class graph_customers_insight
{
public function getWidget()
{
global $CACHE_PATH,$ui;
$u_act = ORM::for_table('tbl_user_recharges')->where('status', 'on')->count();
if (empty($u_act)) {
$u_act = '0';
}
$ui->assign('u_act', $u_act);
$u_all = ORM::for_table('tbl_user_recharges')->count();
if (empty($u_all)) {
$u_all = '0';
}
$ui->assign('u_all', $u_all);
$c_all = ORM::for_table('tbl_customers')->count();
if (empty($c_all)) {
$c_all = '0';
}
$ui->assign('c_all', $c_all);
return $ui->fetch('widget/graph_customers_insight.tpl');
}
}

View File

@ -1,38 +0,0 @@
<?php
class graph_monthly_registered_customers
{
public function getWidget()
{
global $CACHE_PATH,$ui;
$cacheMRfile = $CACHE_PATH . File::pathFixer('/monthlyRegistered.temp');
//Compatibility for old path
if (file_exists($oldCacheMRfile = str_replace($CACHE_PATH, '', $cacheMRfile))) {
rename($oldCacheMRfile, $cacheMRfile);
}
//Cache for 1 hour
if (file_exists($cacheMRfile) && time() - filemtime($cacheMRfile) < 3600) {
$monthlyRegistered = json_decode(file_get_contents($cacheMRfile), true);
} else {
//Monthly Registered Customers
$result = ORM::for_table('tbl_customers')
->select_expr('MONTH(created_at)', 'month')
->select_expr('COUNT(*)', 'count')
->where_raw('YEAR(created_at) = YEAR(NOW())')
->group_by_expr('MONTH(created_at)')
->find_many();
$monthlyRegistered = [];
foreach ($result as $row) {
$monthlyRegistered[] = [
'date' => $row->month,
'count' => $row->count
];
}
file_put_contents($cacheMRfile, json_encode($monthlyRegistered));
}
$ui->assign('monthlyRegistered', $monthlyRegistered);
return $ui->fetch('widget/graph_monthly_registered_customers.tpl');
}
}

View File

@ -1,60 +0,0 @@
<?php
class graph_monthly_sales
{
public function getWidget()
{
global $CACHE_PATH, $ui;
$cacheMSfile = $CACHE_PATH . File::pathFixer('/monthlySales.temp');
//Cache for 12 hours
if (file_exists($cacheMSfile) && time() - filemtime($cacheMSfile) < 43200) {
$monthlySales = json_decode(file_get_contents($cacheMSfile), true);
} else {
// Query to retrieve monthly data
$results = ORM::for_table('tbl_transactions')
->select_expr('MONTH(recharged_on)', 'month')
->select_expr('SUM(price)', 'total')
->where_raw("YEAR(recharged_on) = YEAR(CURRENT_DATE())") // Filter by the current year
->where_not_equal('method', 'Customer - Balance')
->where_not_equal('method', 'Recharge Balance - Administrator')
->group_by_expr('MONTH(recharged_on)')
->find_many();
// Create an array to hold the monthly sales data
$monthlySales = array();
// Iterate over the results and populate the array
foreach ($results as $result) {
$month = $result->month;
$totalSales = $result->total;
$monthlySales[$month] = array(
'month' => $month,
'totalSales' => $totalSales
);
}
// Fill in missing months with zero sales
for ($month = 1; $month <= 12; $month++) {
if (!isset($monthlySales[$month])) {
$monthlySales[$month] = array(
'month' => $month,
'totalSales' => 0
);
}
}
// Sort the array by month
ksort($monthlySales);
// Reindex the array
$monthlySales = array_values($monthlySales);
file_put_contents($cacheMSfile, json_encode($monthlySales));
}
$ui->assign('monthlySales', $monthlySales);
return $ui->fetch('widget/graph_monthly_sales.tpl');
}
}

View File

@ -1,21 +0,0 @@
<?php
class html_php
{
public function getWidget($data = null)
{
global $ui;
$ui->assign('card_header', $data['title']);
ob_start();
try{
eval('?>'. $data['content']);
}catch(Exception $e){
echo $e->getMessage();
echo "<br>";
echo $e->getTraceAsString();
}
$content = ob_get_clean();
return $content;
}
}

View File

@ -1,22 +0,0 @@
<?php
class html_php
{
public function getWidget($data = null)
{
global $ui;
$ui->assign('card_header', $data['title']);
ob_start();
try{
eval('?>'. $data['content']);
}catch(Exception $e){
echo $e->getMessage();
echo "<br>";
echo $e->getTraceAsString();
}
$content = ob_get_clean();
$ui->assign('card_body', $content);
return $ui->fetch('widget/card_html.tpl');
}
}

View File

@ -1,11 +0,0 @@
<?php
class info_payment_gateway
{
public function getWidget($data = null)
{
global $ui;
return $ui->fetch('widget/info_payment_gateway.tpl');
}
}

View File

@ -1,16 +0,0 @@
<?php
class mikrotik_cron_monitor
{
public function getWidget()
{
global $config,$ui;
if ($config['router_check']) {
$routeroffs = ORM::for_table('tbl_routers')->selects(['id', 'name', 'last_seen'])->where('status', 'Offline')->where('enabled', '1')->order_by_desc('name')->find_array();
$ui->assign('routeroffs', $routeroffs);
}
return $ui->fetch('widget/mikrotik_cron_monitor.tpl');
}
}

View File

@ -1,18 +0,0 @@
<?php
```php
class widget_name
{
public static getWidget($data)
{
global $config, $ui;
return $ui->fetch('widget/template');
}
}
```

View File

@ -1,51 +0,0 @@
<?php
class top_widget
{
public function getWidget()
{
global $ui, $current_date, $start_date;
$iday = ORM::for_table('tbl_transactions')
->where('recharged_on', $current_date)
->where_not_equal('method', 'Customer - Balance')
->where_not_equal('method', 'Recharge Balance - Administrator')
->sum('price');
if ($iday == '') {
$iday = '0.00';
}
$ui->assign('iday', $iday);
$imonth = ORM::for_table('tbl_transactions')
->where_not_equal('method', 'Customer - Balance')
->where_not_equal('method', 'Recharge Balance - Administrator')
->where_gte('recharged_on', $start_date)
->where_lte('recharged_on', $current_date)->sum('price');
if ($imonth == '') {
$imonth = '0.00';
}
$ui->assign('imonth', $imonth);
$u_act = ORM::for_table('tbl_user_recharges')->where('status', 'on')->count();
if (empty($u_act)) {
$u_act = '0';
}
$ui->assign('u_act', $u_act);
$u_all = ORM::for_table('tbl_user_recharges')->count();
if (empty($u_all)) {
$u_all = '0';
}
$ui->assign('u_all', $u_all);
$c_all = ORM::for_table('tbl_customers')->count();
if (empty($c_all)) {
$c_all = '0';
}
$ui->assign('c_all', $c_all);
return $ui->fetch('widget/top_widget.tpl');
}
}

View File

@ -1,43 +0,0 @@
<?php
class voucher_stocks
{
public function getWidget()
{
global $CACHE_PATH,$ui;
$cacheStocksfile = $CACHE_PATH . File::pathFixer('/VoucherStocks.temp');
$cachePlanfile = $CACHE_PATH . File::pathFixer('/VoucherPlans.temp');
//Cache for 5 minutes
if (file_exists($cacheStocksfile) && time() - filemtime($cacheStocksfile) < 600) {
$stocks = json_decode(file_get_contents($cacheStocksfile), true);
$plans = json_decode(file_get_contents($cachePlanfile), true);
} else {
// Count stock
$tmp = $v = ORM::for_table('tbl_plans')->select('id')->select('name_plan')->find_many();
$plans = array();
$stocks = array("used" => 0, "unused" => 0);
$n = 0;
foreach ($tmp as $plan) {
$unused = ORM::for_table('tbl_voucher')
->where('id_plan', $plan['id'])
->where('status', 0)->count();
$used = ORM::for_table('tbl_voucher')
->where('id_plan', $plan['id'])
->where('status', 1)->count();
if ($unused > 0 || $used > 0) {
$plans[$n]['name_plan'] = $plan['name_plan'];
$plans[$n]['unused'] = $unused;
$plans[$n]['used'] = $used;
$stocks["unused"] += $unused;
$stocks["used"] += $used;
$n++;
}
}
file_put_contents($cacheStocksfile, json_encode($stocks));
file_put_contents($cachePlanfile, json_encode($plans));
}
$ui->assign('stocks', $stocks);
$ui->assign('plans', $plans);
return $ui->fetch('widget/voucher_stocks.tpl');
}
}

9
ui/lib/c/bandwidth.js Normal file
View File

@ -0,0 +1,9 @@
$(document).on("click", ".cdelete", function(e) {
e.preventDefault();
var id = this.id;
bootbox.confirm("Are you sure?", function(result) {
if(result){
window.location.href = "index.php?_route=bandwidth/delete/" + id;
}
});
});

9
ui/lib/c/customers.js Normal file
View File

@ -0,0 +1,9 @@
$(document).on("click", ".cdelete", function(e) {
e.preventDefault();
var id = this.id;
bootbox.confirm("Are you sure?", function(result) {
if(result){
window.location.href = "index.php?_route=customers/delete/" + id;
}
});
});

9
ui/lib/c/hotspot.js Normal file
View File

@ -0,0 +1,9 @@
$(document).on("click", ".cdelete", function(e) {
e.preventDefault();
var id = this.id;
bootbox.confirm("Are you sure?", function(result) {
if(result){
window.location.href = "index.php?_route=services/delete/" + id;
}
});
});

8
ui/lib/c/index.html Normal file
View File

@ -0,0 +1,8 @@
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More