From 40f452cff8a7a8d19cb4e429a08231a83be2c943 Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:46:07 +0100 Subject: [PATCH 01/28] just little bold --- ui/ui/user-ui/header.tpl | 401 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 400 insertions(+), 1 deletion(-) diff --git a/ui/ui/user-ui/header.tpl b/ui/ui/user-ui/header.tpl index f57da6bc..e52c1b69 100644 --- a/ui/ui/user-ui/header.tpl +++ b/ui/ui/user-ui/header.tpl @@ -178,7 +178,7 @@ } .content .row [class*=col-] .box { - -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); box-shadow: 4px 4px 30px rgba(221, 224, 255, .54); -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, .1); -ms-box-shadow: 0 1px 1px rgba(0, 0, 0, .1); @@ -215,16 +215,19 @@ background: transparent; background-color: transparent; } + .box.box-solid.box-primary>.box-header { color: inherit; background-color: transparent; border-color: transparent; } + .box.box-solid.box-info>.box-header { color: inherit; background-color: transparent; border-color: transparent; } + .box.box-solid.box-danger>.box-header { color: inherit; background-color: transparent; @@ -246,6 +249,21 @@ box-shadow: 0px 4px 30px rgba(221, 224, 255, .54); } + .modern-skin-dark .main-sidebar .sidebar .sidebar-menu li>a { + font-weight: bold; + } + + .content-header>h1 { + font-weight: bold; + } + + .box-header>.fa, + .box-header>.glyphicon, + .box-header>.ion, + .box-header .box-title { + font-weight: bold; + } + /* New Customize Interface End Here */ ::-moz-selection { @@ -306,6 +324,387 @@ margin: 0; padding: 10px; } + + + + + .toggle-container { + position: absolute; + top: 17px; + right: 15px; + cursor: pointer; + } + + .toggle-container .toggle-icon { + font-size: 25px; + color: rgb(100 116 139); + transition: color 0.5s ease; + } + + @media (max-width: 600px) { + .toggle-container { + top: 15px; + right: 200px; + } + + .toggle-container .toggle-icon { + font-size: 20px; + color: rgb(100 116 139); + transition: color 0.5s ease; + } + } + + + /* dark mode styles start here */ + .dark-mode { + background-color: #1a202c; + color: #cbd5e0; + } + + .dark-mode .main-header .logo, + .dark-mode .main-header .navbar, + .dark-mode .main-sidebar, + .dark-mode .main-sidebar .sidebar, + .dark-mode .sidebar-menu li>a { + background-color: #0e1219; + color: #cbd5e0; + } + + .dark-mode .sidebar-menu li:hover, + .dark-mode .sidebar-menu li:focus { + color: #10d435; + } + + .dark-mode .main-sidebar .sidebar .sidebar-menu li.active a { + background-color: #2e298e; + } + + .dark-mode .content, + .dark-mode .content-header, + .dark-mode .content-wrapper, + .dark-mode .right-side { + background-color: #0e1219; + } + + .dark-mode .main-footer { + background-color: #1a202c; + color: #cbd5e0; + } + + .dark-mode .panel, + .dark-mode .box { + background-color: #2d3748; + border-color: #4a5568; + box-shadow: none; + } + + .dark-mode .panel-heading, + .dark-mode .box-header { + background-color: transparent; + color: #cbd5e0; + } + + .dark-mode .box-footer, + .dark-mode .panel-footer { + background-color: #2d3748; + } + + .dark-mode .search-container { + background-color: #2d3748; + color: #cbd5e0; + } + + .dark-mode .searchTerm { + background-color: #4a5568; + color: #cbd5e0; + } + + .dark-mode .cancelButton { + background-color: #e53e3e; + } + + .dark-mode .notification-top-bar { + background-color: #742a2a; + } + + .dark-mode .bs-callout { + background-color: #2d3748; + border-color: #4a5568; + color: #cbd5e0; + } + + .dark-mode .bs-callout h4 { + color: #cbd5e0; + } + + .dark-mode .bg-gray { + background-color: inherit !important; + } + + .dark-mode .breadcrumb { + padding: 8px 15px; + margin-bottom: 20px; + list-style: none; + background-color: rgba(221, 224, 255, .54); + border-radius: 4px; + } + + .dark-mode .pagination>.disabled>span, + .dark-mode .pagination>.disabled>span:hover, + .dark-mode .pagination>.disabled>span:focus, + .dark-mode .pagination>.disabled>a, + .dark-mode .pagination>.disabled>a:hover, + .dark-mode .pagination>.disabled>a:focus { + color: inherit; + background-color: rgba(221, 224, 255, .54); + border-color: rgba(221, 224, 255, .54); + cursor: not-allowed; + } + + .dark-mode .pagination>.active>a, + .dark-mode .pagination>.active>a:hover, + .dark-mode .pagination>.active>a:focus, + .dark-mode .pagination>.active>span, + .dark-mode .pagination>.active>span:hover, + .dark-mode .pagination>.active>span:focus { + z-index: 2; + color: #fff; + background-color: #435ebe; + border-color: rgba(221, 224, 255, .54); + box-shadow: 0 2px 5px rgba(67, 94, 190, .3); + cursor: default; + } + + .dark-mode .pagination>li>a { + background: inherit; + color: inherit; + border: 1px solid; + border-color: rgba(221, 224, 255, .54); + } + + .dark-mode .table { + background-color: inherit; + color: #ddd; + border-color: #444; + } + + .dark-mode .table th, + .dark-mode .table td { + background-color: inherit; + border-color: inherit; + color: #ddd; + } + + .dark-mode .table th { + background-color: inherit; + font-weight: bold; + } + + .dark-mode .table-striped tbody tr:nth-of-type(odd) { + background-color: inherit; + } + + .dark-mode .table-bordered { + border: 1px solid #444; + } + + .dark-mode .table-hover tbody tr:hover { + background-color: #555; + color: #fff; + } + + .dark-mode .table-condensed th, + .dark-mode .table-condensed td { + padding: 8px; + } + + .dark-mode .panel>.table:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child { + border-bottom-right-radius: 21px; + border-bottom-left-radius: 21px; + } + + .dark-mode .panel>.table:last-child>tbody:last-child>tr:last-child, + .dark-mode .panel>.table:last-child>tfoot:last-child>tr:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child { + border-bottom-right-radius: 21px; + border-bottom-left-radius: 21px; + } + + .dark-mode .panel>.table:last-child>tbody:last-child>tr:last-child td:last-child, + .dark-mode .panel>.table:last-child>tbody:last-child>tr:last-child th:last-child, + .dark-mode .panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child, + .dark-mode .panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child { + border-bottom-right-radius: 21px; + } + + .dark-mode .help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: inherit; + } + + .dark-mode .text-muted { + color: rgba(221, 224, 255, .54); + } + + .dark-mode .form-control { + display: block; + width: 100%; + padding: 6px 12px; + font-size: 14px; + line-height: 1.428571429; + color: inherit; + background-color: transparent; + background-image: none; + border: 1px solid; + border-color: rgba(221, 224, 255, .54); + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + } + + .dark-mode .main-footer { + border-top: 1px solid transparent; + } + + .dark-mode .box.box-solid.box-primary>.box-header { + color: #fff; + background-color: inherit; + border-color: rgba(221, 224, 255, .54); + border-top-left-radius: 45px; + border-top-right-radius: 45px; + } + + .dark-mode .box-body { + border-radius: 0px; + padding: 10px; + } + + .dark-mode .box-header { + display: block; + padding: 10px; + position: relative; + border-color: transparent; + border-radius: 0px; + } + + .dark-mode .nav-stacked>li>a { + color: inherit; + } + + .dark-mode .list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: transparent; + border: 1px solid rgba(221, 224, 255, .54); + } + + .dark-mode .panel-footer { + padding: 10px 15px; + border-top: 1px rgba(221, 224, 255, .54); + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; + } + + + .dark-mode .content .row [class*=col-] .box { + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: 4px 4px 30px rgba(221, 224, 255, .54); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, .1); + -ms-box-shadow: 0 1px 1px rgba(0, 0, 0, .1); + -webkit-border-radius: 1px !important; + -moz-border-radius: 1px !important; + -ms-border-radius: 1px !important; + border-radius: 15px !important; + border-color: inherit; + background-color: inherit; + } + + /* Dark Mode - Input Fields */ + .dark-mode input:not(#filterNavigateMenu), + .dark-mode textarea:not(#filterNavigateMenu), + .dark-mode select:not(#filterNavigateMenu), + .dark-mode .select2-selection:not(#filterNavigateMenu) { + color: inherit; + transition: all .5s ease-in-out; + } + + .dark-mode input:focus:not(#filterNavigateMenu), + .dark-mode textarea:focus:not(#filterNavigateMenu), + .dark-mode select:focus:not(#filterNavigateMenu), + .dark-mode .select2-selection:focus:not(#filterNavigateMenu) { + color: #1f201f; + outline: none; + } + + .dark-mode .input-group .form-control { + position: relative; + z-index: 2; + float: left; + width: 100%; + margin-bottom: 0; + color: inherit; + border-color: rgba(221, 224, 255, .54); + background-color: inherit; + } + + .dark-mode .input-group .input-group-addon { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + color: inherit; + border-bottom-left-radius: 0; + border-color: rgba(221, 224, 255, .54); + background-color: transparent; + } + + .dark-mode .input-group .form-control:last-child, + .dark-mode .input-group-addon:last-child, + .dark-mode .input-group-btn:last-child>.btn, + .dark-mode .input-group-btn:last-child>.btn-group>.btn, + .dark-mode .input-group-btn:last-child>.dropdown-toggle, + .dark-mode .input-group-btn:first-child>.btn:not(:first-child), + .dark-mode .input-group-btn:first-child>.btn-group:not(:first-child)>.btn { + color: inherit; + } + + .dark-mode input:not(#filterNavigateMenu), + textarea:not(#filterNavigateMenu), + optgroup:not(#filterNavigateMenu), + select:not(#filterNavigateMenu), + .dark-mode .select2-selection:not(#filterNavigateMenu) { + -moz-transition: all .5s ease-in-out; + -o-transition: all .5s ease-in-out; + -webkit-transition: all .5s ease-in-out; + transition: all .5s ease-in-out; + } + + .dark-mode .modern-skin-dark .main-sidebar .sidebar .sidebar-menu li>a { + font-weight: bold; + } + + .dark-mode .content-header>h1 { + font-weight: bold; + } + + .dark-mode .box-header>.fa, + .dark-mode .box-header>.glyphicon, + .dark-mode .box-header>.ion, + .dark-mode .box-header .box-title { + font-weight: bold; + } {if isset($xheader)} From 93d53cc6d832e20201f23cddb374bf19f1f6d24d Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:59:19 +0100 Subject: [PATCH 02/28] We added bold to sidebar, we want your opinion if it looks good or we should remove it --- ui/ui/sections/header.tpl | 476 +++++++++++++++++++++++++++++++++++++- 1 file changed, 474 insertions(+), 2 deletions(-) diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index 26270036..843109d9 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -171,7 +171,7 @@ -webkit-border-radius: 1px !important; -moz-border-radius: 1px !important; -ms-border-radius: 1px !important; - border-radius: 25px !important; + border-radius: 15px !important; border-color: rgba(221, 224, 255, .54); } @@ -180,11 +180,13 @@ background-color: transparent; border-color: transparent; } + .box.box-solid.box-info>.box-header { color: inherit; background-color: transparent; border-color: transparent; } + .box.box-solid.box-danger>.box-header { color: inherit; background-color: transparent; @@ -211,6 +213,7 @@ border-top: 1px solid transparent; padding: 10px; background-color: inherit; + border-radius: 15px; } .panel-footer { @@ -232,6 +235,26 @@ box-shadow: 0px 4px 30px rgba(221, 224, 255, .54); } + .panel-success>.panel-heading { + color: #3c763d; + background-color: transparent; + border-color: #d6e9c6; + } + + .content-header>h1 { + font-weight: bold; + } + + .box-header>.fa, + .box-header>.glyphicon, + .box-header>.ion, + .box-header .box-title { + font-weight: bold; + } + + .modern-skin-dark .main-sidebar .sidebar .sidebar-menu li>a { + font-weight: bold; + } /* Search Bar Start Here */ .wrap { @@ -303,6 +326,13 @@ overflow-y: auto; } + .panel-heading { + padding: 10px 15px; + border-bottom: 0px solid transparent; + border-top-right-radius: 21px; + border-top-left-radius: 21px; + } + /* Search Bar End Here */ /* New Customize Interface End Here */ @@ -332,7 +362,6 @@ th:first-child, td:first-child { position: sticky; - left: 0px; background-color: #f9f9f9; } @@ -534,6 +563,449 @@ -ms-transform: translateX(26px); transform: translateX(26px); } + + /* dark mode styles start here */ + + .dark-mode { + background-color: #1a202c; + color: #cbd5e0; + } + + .dark-mode .main-header .logo, + .dark-mode .main-header .navbar, + .dark-mode .main-sidebar, + .dark-mode .main-sidebar .sidebar, + .dark-mode .sidebar-menu li>a { + background-color: #1a202c; + color: #cbd5e0; + } + + .dark-mode .sidebar-menu li:hover, + .dark-mode .sidebar-menu li:focus { + color: #10d435; + } + + .dark-mode .main-sidebar .sidebar .sidebar-menu li.active a { + background-color: #2e298e; + } + + .dark-mode .content, + .dark-mode .content-header, + .dark-mode .content-wrapper, + .dark-mode .right-side { + background-color: #2d3748; + } + + .dark-mode .main-footer { + background-color: #1a202c; + color: #cbd5e0; + } + + .dark-mode .panel, + .dark-mode .box { + background-color: #2d3748; + border-color: #4a5568; + box-shadow: none; + } + + .dark-mode .panel-heading, + .dark-mode .box-header { + background-color: transparent; + color: #cbd5e0; + } + + .dark-mode .box-footer, + .dark-mode .panel-footer { + background-color: #2d3748; + } + + .dark-mode .search-container { + background-color: #2d3748; + color: #cbd5e0; + } + + .dark-mode .searchTerm { + background-color: #4a5568; + color: #cbd5e0; + } + + .dark-mode .cancelButton { + background-color: #e53e3e; + } + + .dark-mode .notification-top-bar { + background-color: #742a2a; + } + + .dark-mode .bs-callout { + background-color: #2d3748; + border-color: #4a5568; + color: #cbd5e0; + } + + .dark-mode .bs-callout h4 { + color: #cbd5e0; + } + + .dark-mode .bg-gray { + background-color: inherit !important; + } + + .toggle-container { + position: absolute; + top: 17px; + right: 15px; + cursor: pointer; + } + + .toggle-container .toggle-icon { + font-size: 25px; + color: rgb(100 116 139); + transition: color 0.5s ease; + } + + @media (max-width: 600px) { + .toggle-container { + top: 15px; + right: 60px; + } + + .toggle-container .toggle-icon { + font-size: 20px; + color: rgb(100 116 139); + transition: color 0.5s ease; + } + } + + .dark-mode .toggle-container .toggle-icon { + color: #ffdd57; + } + + .dark-mode th:first-child, + .dark-mode td:first-child { + background-color: #4a4949; + } + + .dark-mode .panel>.table:last-child>tbody:last-child>tr:last-child td:first-child, + .dark-mode .panel>.table:last-child>tbody:last-child>tr:last-child th:first-child, + .dark-mode .panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child, + .dark-mode .panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child { + background-color: #4a4949; + border-bottom-left-radius: 21px; + } + + .dark-mode .table>thead>tr>td.danger, + .dark-mode .table>thead>tr>th.danger, + .dark-mode .table>thead>tr.danger>td, + .dark-mode .table>thead>tr.danger>th, + .dark-mode .table>tbody>tr>td.danger, + .dark-mode .table>tbody>tr>th.danger, + .dark-mode .table>tbody>tr.danger>td, + .dark-mode .table>tbody>tr.danger>th, + .dark-mode .table>tfoot>tr>td.danger, + .dark-mode .table>tfoot>tr>th.danger, + .dark-mode .table>tfoot>tr.danger>td, + .dark-mode .table>tfoot>tr.danger>th { + background-color: #694760; + } + + .dark-mode .panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: 21px; + border-top-left-radius: 21px; + } + + .dark-mode .table-bordered>thead>tr>th, + .dark-mode .table-bordered>thead>tr>td, + .dark-mode .table-bordered>tbody>tr>th, + .dark-mode .table-bordered>tbody>tr>td, + .dark-mode .table-bordered>tfoot>tr>th, + .dark-mode .table-bordered>tfoot>tr>td { + border: 1px solid; + border-color: rgba(221, 224, 255, .54); + } + + /* Dark Mode - Input Fields */ + .dark-mode input:not(#filterNavigateMenu), + .dark-mode textarea:not(#filterNavigateMenu), + .dark-mode select:not(#filterNavigateMenu), + .dark-mode .select2-selection:not(#filterNavigateMenu) { + color: inherit; + transition: all .5s ease-in-out; + } + + .dark-mode input:focus:not(#filterNavigateMenu), + .dark-mode textarea:focus:not(#filterNavigateMenu), + .dark-mode select:focus:not(#filterNavigateMenu), + .dark-mode .select2-selection:focus:not(#filterNavigateMenu) { + color: #1f201f; + outline: none; + } + + .dark-mode .nav-stacked>li>a { + color: inherit; + } + + .dark-mode .input-group .form-control { + position: relative; + z-index: 2; + float: left; + width: 100%; + margin-bottom: 0; + color: inherit; + border-color: rgba(221, 224, 255, .54); + background-color: inherit; + } + + .dark-mode .input-group .input-group-addon { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + color: inherit; + border-bottom-left-radius: 0; + border-color: rgba(221, 224, 255, .54); + background-color: transparent; + } + + .dark-mode .input-group .form-control:last-child, + .dark-mode .input-group-addon:last-child, + .dark-mode .input-group-btn:last-child>.btn, + .dark-mode .input-group-btn:last-child>.btn-group>.btn, + .dark-mode .input-group-btn:last-child>.dropdown-toggle, + .dark-mode .input-group-btn:first-child>.btn:not(:first-child), + .dark-mode .input-group-btn:first-child>.btn-group:not(:first-child)>.btn { + color: inherit; + } + + .dark-mode input:not(#filterNavigateMenu), + textarea:not(#filterNavigateMenu), + optgroup:not(#filterNavigateMenu), + select:not(#filterNavigateMenu), + .dark-mode .select2-selection:not(#filterNavigateMenu) { + -moz-transition: all .5s ease-in-out; + -o-transition: all .5s ease-in-out; + -webkit-transition: all .5s ease-in-out; + transition: all .5s ease-in-out; + } + + .dark-mode .form-control { + display: block; + width: 100%; + padding: 6px 12px; + font-size: 14px; + line-height: 1.428571429; + color: inherit; + background-color: transparent; + background-image: none; + border: 1px solid; + border-color: rgba(221, 224, 255, .54); + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + } + + .dark-mode .help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: inherit; + } + + .dark-mode .text-muted { + color: rgba(221, 224, 255, .54); + } + + .dark-mode .breadcrumb { + padding: 8px 15px; + margin-bottom: 20px; + list-style: none; + background-color: rgba(221, 224, 255, .54); + border-radius: 4px; + } + + .dark-mode .pagination>.disabled>span, + .dark-mode .pagination>.disabled>span:hover, + .dark-mode .pagination>.disabled>span:focus, + .dark-mode .pagination>.disabled>a, + .dark-mode .pagination>.disabled>a:hover, + .dark-mode .pagination>.disabled>a:focus { + color: inherit; + background-color: rgba(221, 224, 255, .54); + border-color: rgba(221, 224, 255, .54); + cursor: not-allowed; + } + + .dark-mode .pagination>.active>a, + .dark-mode .pagination>.active>a:hover, + .dark-mode .pagination>.active>a:focus, + .dark-mode .pagination>.active>span, + .dark-mode .pagination>.active>span:hover, + .dark-mode .pagination>.active>span:focus { + z-index: 2; + color: #fff; + background-color: #435ebe; + border-color: rgba(221, 224, 255, .54); + box-shadow: 0 2px 5px rgba(67, 94, 190, .3); + cursor: default; + } + + .dark-mode .pagination>li>a { + background: inherit; + color: inherit; + border: 1px solid; + border-color: rgba(221, 224, 255, .54); + } + + .dark-mode .table { + background-color: #2a2a2a; + color: #ddd; + border-color: #444; + } + + .dark-mode .table th, + .dark-mode .table td { + background-color: #333; + border-color: #444; + color: #ddd; + } + + .dark-mode .table th { + background-color: #444; + font-weight: bold; + } + + .dark-mode .table-striped tbody tr:nth-of-type(odd) { + background-color: #3a3a3a; + } + + .dark-mode .table-bordered { + border: 1px solid #444; + } + + .dark-mode .table-hover tbody tr:hover { + background-color: #555; + color: #fff; + } + + .dark-mode .table-condensed th, + .dark-mode .table-condensed td { + padding: 8px; + } + + .dark-mode .panel>.table:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child { + border-bottom-right-radius: 21px; + border-bottom-left-radius: 21px; + } + + .dark-mode .panel>.table:last-child>tbody:last-child>tr:last-child, + .dark-mode .panel>.table:last-child>tfoot:last-child>tr:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child { + border-bottom-right-radius: 21px; + border-bottom-left-radius: 21px; + } + + .dark-mode .panel>.table:last-child>tbody:last-child>tr:last-child td:last-child, + .dark-mode .panel>.table:last-child>tbody:last-child>tr:last-child th:last-child, + .dark-mode .panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child, + .dark-mode .panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child, + .dark-mode .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child { + border-bottom-right-radius: 21px; + } + + /* Dark Mode - Select2 Dropdown start here */ + .dark-mode .select2-container--bootstrap .select2-results__option--highlighted[aria-selected] { + background-color: rgb(96, 89, 89); + color: #ffffff; + } + + .dark-mode .select2-container--bootstrap .select2-results__option { + padding: 6px 12px; + background-color: rgb(96, 89, 89); + color: #f8f9fa; + } + + .dark-mode .select2-results__option[aria-selected] { + cursor: pointer; + background-color: inherit; + color: #ffffff; + } + + .dark-mode .select2-results__option { + padding: 6px 12px; + user-select: none; + -webkit-user-select: none; + background-color: #343a40; + color: #f8f9fa; + } + + .dark-mode .select2-dropdown { + background-color: #343a40; + border-color: #454d55; + } + + .dark-mode .select2-selection--single { + background-color: #495057; + color: #ffffff; + border-color: #454d55; + } + + .dark-mode .select2-selection__rendered { + color: #ffffff; + } + + .dark-mode .select2-selection__arrow b { + border-color: #ffffff transparent transparent transparent; + } + + .dark-mode .select2-container--bootstrap .select2-selection--single .select2-selection__rendered { + color: inherit; + padding: 0; + } + + .dark-mode .main-footer { + border-top: 1px solid transparent; + } + + .dark-mode .list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: transparent; + border: 1px solid rgba(221, 224, 255, .54); + } + + .dark-mode .modern-skin-dark .main-sidebar .sidebar .sidebar-menu li>a { + font-weight: bold; + } + + .dark-mode .content-header>h1 { + font-weight: bold; + } + + .dark-mode .box-header>.fa, + .dark-mode .box-header>.glyphicon, + .dark-mode .box-header>.ion, + .dark-mode .box-header .box-title { + font-weight: bold; + } + + /* Dark Mode - Select2 Dropdown ends here */ + + /* dark mode styles start ends here */ {if isset($xheader)} {$xheader} From 4f74aa0bff1908eac7303e73bd9314724a76b08c Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:14:50 +0100 Subject: [PATCH 03/28] Please if you dont like the bold feature kindly report it --- ui/ui/sections/header.tpl | 12 ++++++++++++ ui/ui/user-ui/header.tpl | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index 843109d9..d056aabc 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -256,6 +256,10 @@ font-weight: bold; } + .main-header .logo .logo-lg { + font-weight: bold; + } + /* Search Bar Start Here */ .wrap { width: 30%; @@ -1003,6 +1007,14 @@ font-weight: bold; } + .dark-mode .content-header>h2 { + font-weight: bold; + } + + .dark-mode .main-header .logo .logo-lg { + font-weight: bold; + } + /* Dark Mode - Select2 Dropdown ends here */ /* dark mode styles start ends here */ diff --git a/ui/ui/user-ui/header.tpl b/ui/ui/user-ui/header.tpl index e52c1b69..09841709 100644 --- a/ui/ui/user-ui/header.tpl +++ b/ui/ui/user-ui/header.tpl @@ -264,6 +264,10 @@ font-weight: bold; } + .main-header .logo .logo-lg { + font-weight: bold; + } + /* New Customize Interface End Here */ ::-moz-selection { @@ -705,6 +709,14 @@ .dark-mode .box-header .box-title { font-weight: bold; } + + .dark-mode .content-header>h2 { + font-weight: bold; + } + + .dark-mode .main-header .logo .logo-lg { + font-weight: bold; + } {if isset($xheader)} From c255a7be4972fcd47a30cee9593093bdf90dfd61 Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:47:28 +0100 Subject: [PATCH 04/28] fix modal in dark mode --- ui/ui/sections/header.tpl | 19 +++++++++++++++++++ ui/ui/user-ui/header.tpl | 20 ++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index d056aabc..0ea33f58 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -1015,6 +1015,25 @@ font-weight: bold; } + .dark-mode .modal-content { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 15px; + border-bottom-left-radius: 15px; + -webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, .125); + box-shadow: 0 2px 3px rgba(0, 0, 0, .125); + border: 0; + background: #1a202c; + } + + .dark-mode .modal-header { + padding: 15px; + border-bottom: 1px solid rgba(221, 224, 255, .54); + min-height: 16.428571429px; + background-color: #1a202c; + color: inherit; + } + /* Dark Mode - Select2 Dropdown ends here */ /* dark mode styles start ends here */ diff --git a/ui/ui/user-ui/header.tpl b/ui/ui/user-ui/header.tpl index 09841709..f88820aa 100644 --- a/ui/ui/user-ui/header.tpl +++ b/ui/ui/user-ui/header.tpl @@ -717,6 +717,26 @@ .dark-mode .main-header .logo .logo-lg { font-weight: bold; } + + + .dark-mode .modal-content { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 15px; + border-bottom-left-radius: 15px; + -webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, .125); + box-shadow: 0 2px 3px rgba(0, 0, 0, .125); + border: 0; + background: #1a202c; + } + + .dark-mode .modal-header { + padding: 15px; + border-bottom: 1px solid rgba(221, 224, 255, .54); + min-height: 16.428571429px; + background-color: #1a202c; + color: inherit; + } {if isset($xheader)} From 299fd90949450257a8632a868f6c939f658963a0 Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:13:14 +0100 Subject: [PATCH 05/28] fix dark mode drop-down menu --- ui/ui/sections/header.tpl | 11 +++++++++++ ui/ui/user-ui/header.tpl | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index 0ea33f58..2588a37f 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -1034,6 +1034,17 @@ color: inherit; } + .dark-mode .navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a, + .dark-mode .navbar-nav>.messages-menu>.dropdown-menu>li.footer>a, + .dark-mode .navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a { + background: #1a202c !important; + color: inherit !important; + } + + .dark-mode .navbar-nav>.user-menu>.dropdown-menu>.user-footer { + background-color: #1a202c; + } + /* Dark Mode - Select2 Dropdown ends here */ /* dark mode styles start ends here */ diff --git a/ui/ui/user-ui/header.tpl b/ui/ui/user-ui/header.tpl index f88820aa..37b9e1ee 100644 --- a/ui/ui/user-ui/header.tpl +++ b/ui/ui/user-ui/header.tpl @@ -737,6 +737,28 @@ background-color: #1a202c; color: inherit; } + + + .dark-mode .navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a, + .dark-mode .navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a, + .dark-mode .navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a { + display: block; + white-space: nowrap; + border-bottom: 1px solid rgba(221, 224, 255, .54); + background: #1a202c; + color: inherit; + } + + .dark-mode .navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a, + .dark-mode .navbar-nav>.messages-menu>.dropdown-menu>li.footer>a, + .dark-mode .navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a { + background: #1a202c !important; + color: inherit !important; + } + + .dark-mode .navbar-nav>.user-menu>.dropdown-menu>.user-footer { + background-color: #1a202c; + } {if isset($xheader)} From 9e63d7ce20e9da98c7a957f8092347204e78572f Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:36:30 +0100 Subject: [PATCH 06/28] add margin to the table list --- ui/ui/reports.tpl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ui/ui/reports.tpl b/ui/ui/reports.tpl index 21a39b9f..7303afb1 100644 --- a/ui/ui/reports.tpl +++ b/ui/ui/reports.tpl @@ -80,8 +80,9 @@ -
-
+
+
+
@@ -126,6 +127,7 @@
+
-
-
-
+
+
@@ -127,7 +126,6 @@
-
+ {Lang::T("Back")} {Lang::T("Delete")} - {Lang::T("Share")} + {Lang::T("Share")}
From 3aead7a98ab7a53fd8f93d99215e0dea58152ea1 Mon Sep 17 00:00:00 2001 From: Ibnu Maksum Date: Mon, 9 Sep 2024 13:23:26 +0700 Subject: [PATCH 11/28] Fix toggle dark mode --- ui/ui/user-ui/header.tpl | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/ui/ui/user-ui/header.tpl b/ui/ui/user-ui/header.tpl index a2be9f04..4298c03a 100644 --- a/ui/ui/user-ui/header.tpl +++ b/ui/ui/user-ui/header.tpl @@ -333,9 +333,6 @@ .toggle-container { - position: absolute; - top: 17px; - right: 15px; cursor: pointer; } @@ -346,10 +343,6 @@ } @media (max-width: 600px) { - .toggle-container { - top: 15px; - right: 200px; - } .toggle-container .toggle-icon { font-size: 20px; @@ -781,13 +774,13 @@
  • - +
  • - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {foreach $d as $ds} +
    +
    {Lang::T('Internet Package')}{Lang::T('Limit')} - {Lang::T('Expired')}
    {Lang::T('Name')}{Lang::T('Type')}Bandwidth{Lang::T('Category')}{Lang::T('Price')}{Lang::T('Validity')}{Lang::T('Time')}{Lang::T('Data')}{Lang::T('Location')}{Lang::T('Device')}{Lang::T('Internet Package')}{Lang::T('Date')}{Lang::T('ID')}{Lang::T('Manage')}
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + {foreach $d as $ds} + }class="warning" title="Postpaid" {/if}> @@ -146,11 +148,11 @@ @@ -163,13 +165,14 @@ {Lang::T('Edit')} + onclick="return confirm('{Lang::T('Delete')}?')" + class="btn btn-danger btn-xs"> - {/foreach} - -
    {Lang::T('Internet Package')} + {Lang::T('Limit')} + {Lang::T('Expired')}
    {Lang::T('Name')}{Lang::T('Type')}Bandwidth{Lang::T('Category')}{Lang::T('Price')}{Lang::T('Validity')}{Lang::T('Time')}{Lang::T('Data')}{Lang::T('Location')}{Lang::T('Device')}{Lang::T('Internet Package')}{Lang::T('Date')}{Lang::T('ID')}{Lang::T('Manage')}
    {$ds['name_plan']} {if $ds['prepaid'] == no}Postpaid{else}Prepaid{/if} {$ds['plan_type']} {$ds['name_bw']}{$ds['data_limit']} {$ds['data_unit']} {if $ds['is_radius']} - RADIUS + RADIUS {else} - {if $ds['routers']!=''} - {$ds['routers']} - {/if} + {if $ds['routers']!=''} + {$ds['routers']} + {/if} {/if} {$ds['device']}
    + {/foreach} + + +
    -{include file="sections/footer.tpl"} +{include file="sections/footer.tpl"} \ No newline at end of file diff --git a/ui/ui/plan.tpl b/ui/ui/plan.tpl index 4cf71280..3cca5861 100644 --- a/ui/ui/plan.tpl +++ b/ui/ui/plan.tpl @@ -5,19 +5,19 @@
    {if in_array($_admin['user_type'],['SuperAdmin','Admin'])} -
    - sync -
    - {*
    - CSV -
    *} +
    + sync +
    + {*
    + CSV +
    *} {/if}   -{Lang::T('Active Customers')} + {Lang::T('Active Customers')}
    @@ -70,33 +70,34 @@
    - - - - - - - - - - - - - - - {foreach $d as $ds} - +
      +
    {Lang::T('Username')}{Lang::T('Plan Name')}{Lang::T('Type')}{Lang::T('Created On')}{Lang::T('Expires On')}{Lang::T('Method')}{Lang::T('Location')}{Lang::T('Manage')}
    + + + + + + + + + + + + + + {foreach $d as $ds} + {if $ds['type'] == 'Hotspot'} - + {else} - + {/if} @@ -107,19 +108,20 @@ {Lang::T('Edit')} {if in_array($_admin['user_type'],['SuperAdmin','Admin'])} - + {/if} {if $ds['status']=='off' && $_c['extend_expired']} - {Lang::T('Extend')} + {Lang::T('Extend')} {/if} - {/foreach} - -
    {Lang::T('Username')}{Lang::T('Plan Name')}{Lang::T('Type')}{Lang::T('Created On')}{Lang::T('Expires On')}{Lang::T('Method')}{Lang::T('Location')}{Lang::T('Manage')}
    {if $ds['customer_id'] == '0'} - {$ds['username']} + {$ds['username']} {else} - {$ds['username']} + {$ds['username']} {/if} {$ds['namebp']}{$ds['namebp']}{$ds['namebp']}{$ds['namebp']}{$ds['type']} {Lang::dateAndTimeFormat($ds['recharged_on'],$ds['recharged_time'])}
    + {/foreach} + + +
    {include file="pagination.tpl"} @@ -131,10 +133,10 @@ var res = prompt("Extend for many days?", "3"); if (res) { if (confirm("Extend for " + res + " days?")) { - window.location.href = "{$_url}plan/extend/"+idP+"/"+res+"&stoken={App::getToken()}"; + window.location.href = "{$_url}plan/extend/" + idP + "/" + res + "&stoken={App::getToken()}"; } } } -{include file="sections/footer.tpl"} +{include file="sections/footer.tpl"} \ No newline at end of file diff --git a/ui/ui/pppoe.tpl b/ui/ui/pppoe.tpl index 3c17d6b1..9dfc8711 100644 --- a/ui/ui/pppoe.tpl +++ b/ui/ui/pppoe.tpl @@ -35,8 +35,8 @@ @@ -44,9 +44,9 @@ @@ -54,8 +54,8 @@ @@ -63,8 +63,8 @@ @@ -72,7 +72,7 @@ @@ -81,7 +81,7 @@ @@ -104,36 +104,38 @@
    - - - - - - - - - - - - - - - - - - - - - - - - - - {foreach $d as $ds} - +
    +
    {Lang::T('Internet Plan')} - {Lang::T('Expired')}
    {Lang::T('Name')}{Lang::T('Type')}{Lang::T('Bandwidth')}{Lang::T('Price')}{Lang::T('Validity')}{Lang::T('IP Pool')}{Lang::T('Internet Plan')}{Lang::T('Date')}{Lang::T('Location')}{Lang::T('Device')}{Lang::T('Manage')}ID
    + + + + + + + + + + + + + + + + + + + + + + + + + {foreach $d as $ds} + - + @@ -144,11 +146,11 @@ @@ -161,9 +163,10 @@ - {/foreach} - -
    {Lang::T('Internet Plan')} + {Lang::T('Expired')}
    {Lang::T('Name')}{Lang::T('Type')}{Lang::T('Bandwidth')}{Lang::T('Price')}{Lang::T('Validity')}{Lang::T('IP Pool')}{Lang::T('Internet Plan')}{Lang::T('Date')}{Lang::T('Location')}{Lang::T('Device')}{Lang::T('Manage')}ID
    {$ds['name_plan']}{$ds['plan_type']} {if $ds['prepaid'] != 'yes'}{Lang::T('Postpaid')}{else}{Lang::T('Prepaid')}{/if}{$ds['plan_type']} {if $ds['prepaid'] != + 'yes'}{Lang::T('Postpaid')}{else}{Lang::T('Prepaid')}{/if} {$ds['name_bw']} {Lang::moneyFormat($ds['price'])} {$ds['validity']} {$ds['validity_unit']}{if $ds['prepaid'] == no}{$ds['expired_date']}{/if} {if $ds['is_radius']} - RADIUS + RADIUS {else} - {if $ds['routers']!=''} - {$ds['routers']} - {/if} + {if $ds['routers']!=''} + {$ds['routers']} + {/if} {/if} {$ds['device']} {$ds['id']}
    + {/foreach} + + +
    -{include file="sections/footer.tpl"} +{include file="sections/footer.tpl"} \ No newline at end of file diff --git a/ui/ui/voucher.tpl b/ui/ui/voucher.tpl index 6f357b48..abf652f0 100644 --- a/ui/ui/voucher.tpl +++ b/ui/ui/voucher.tpl @@ -17,11 +17,12 @@
    {if in_array($_admin['user_type'],['SuperAdmin','Admin'])} - + {/if}  
    @@ -41,8 +42,8 @@
    @@ -50,7 +51,7 @@ @@ -65,7 +66,7 @@ @@ -76,8 +77,8 @@ class="fa fa-search">
    - +
    @@ -85,24 +86,25 @@
    - - - - - - - - - - - - - - - - - {foreach $d as $ds} - +
      +
    ID{Lang::T('Type')}{Lang::T('Routers')}{Lang::T('Plan Name')}{Lang::T('Code Voucher')}{Lang::T('Status Voucher')}{Lang::T('Customer')}{Lang::T('Used Date')}{Lang::T('Generated By')}{Lang::T('Manage')}
    + + + + + + + + + + + + + + + + {foreach $d as $ds} + @@ -112,33 +114,35 @@ onmouseenter="this.style.backgroundColor = 'white';"> {$ds['code']} - {/foreach} - -
    ID{Lang::T('Type')}{Lang::T('Routers')}{Lang::T('Plan Name')}{Lang::T('Code Voucher')}{Lang::T('Status Voucher')}{Lang::T('Customer')}{Lang::T('Used Date')}{Lang::T('Generated By')}{Lang::T('Manage')}
    {$ds['id']} {$ds['type']} {$ds['routers']} {if $ds['status'] eq '0'} {else} + {else} {/if} {if $ds['user'] eq '0'} - {else}{$ds['user']} {/if} {if $ds['used_date']}{Lang::dateTimeFormat($ds['used_date'])}{/if} {if $ds['generated_by']} - {$admins[$ds['generated_by']]} + {$admins[$ds['generated_by']]} {else} - {/if} {if $ds['status'] neq '1'} -   {Lang::T('View')}   +   {Lang::T('View')}   {/if} {if in_array($_admin['user_type'],['SuperAdmin','Admin'])} - + {/if}
    + {/foreach} + + +
    {include file="pagination.tpl"} -{include file="sections/footer.tpl"} +{include file="sections/footer.tpl"} \ No newline at end of file From 723e99ebedc231e502707621ec169cd1da57aa57 Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Wed, 11 Sep 2024 14:19:13 +0100 Subject: [PATCH 16/28] fix panel headers in css, add cron job monitor to check if cron is running, has run, or not setup --- system/controllers/dashboard.php | 6 +++ system/cron.php | 69 ++++++++++++++++++-------------- ui/ui/dashboard.tpl | 17 ++++++++ ui/ui/sections/header.tpl | 30 ++++++++++++-- 4 files changed, 87 insertions(+), 35 deletions(-) diff --git a/system/controllers/dashboard.php b/system/controllers/dashboard.php index 4d1c9849..9f1185b0 100644 --- a/system/controllers/dashboard.php +++ b/system/controllers/dashboard.php @@ -214,6 +214,12 @@ if ($config['router_check']) { $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); diff --git a/system/cron.php b/system/cron.php index e4e6719c..81d9f423 100644 --- a/system/cron.php +++ b/system/cron.php @@ -1,6 +1,27 @@ where('enabled', '1')->find_many(); if (!$routers) { echo "No active routers found in the database.\n"; @@ -186,14 +187,20 @@ if ($config['router_check']) { Message::SendEmail($adminEmail, $subject, $message); sendTelegram($message); } - - if (defined('PHP_SAPI') && PHP_SAPI === 'cli') { - echo "Cronjob finished\n"; - } else { - echo ""; - } - - flock($lock, LOCK_UN); - fclose($lock); - unlink($lockFile); + echo "Router monitoring finished\n"; } + + +if (defined('PHP_SAPI') && PHP_SAPI === 'cli') { + echo "Cronjob finished\n"; +} else { + echo ""; +} + +flock($lock, LOCK_UN); +fclose($lock); +unlink($lockFile); + +$timestampFile = "$UPLOAD_PATH/cron_last_run.txt"; +file_put_contents($timestampFile, time()); + diff --git a/ui/ui/dashboard.tpl b/ui/ui/dashboard.tpl index eb6788da..7a998ba8 100644 --- a/ui/ui/dashboard.tpl +++ b/ui/ui/dashboard.tpl @@ -194,6 +194,23 @@ {/if} + {if $run_date} + {if $current_time - $run_time > 3600} +
    +
      {Lang::T('Cron has not run for over 1 hour. Please + check your setup.')}
    +
    + {else} +
    +
    {Lang::T('Cron Job last ran on')}: {$run_date}
    +
    + {/if} + {else} +
    +
      {Lang::T('Cron appear not been setup, please check + your cron setup.')}
    +
    + {/if} {if $_c['hide_pg'] != 'yes'}
    {Lang::T('Payment Gateway')}: {str_replace(',',', ',$_c['payment_gateway'])} diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index bba3dbce..34b7f1e9 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -148,12 +148,26 @@ color: inherit; background-color: transparent; border-color: transparent; + border-bottom-right-radius: 21px; + border-bottom-left-radius: 21px; } - .panel-primary>.panel-heading { - color: inherit; - background-color: transparent; - border-color: transparent; + .panel-success>.panel-heading { + border-bottom-right-radius: 21px; + border-bottom-left-radius: 21px; + } + + .panel-warning>.panel-heading { + border-bottom-right-radius: 21px; + border-bottom-left-radius: 21px; + } + + .panel-danger>.panel-heading { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; + border-bottom-right-radius: 21px; + border-bottom-left-radius: 21px; } .panel-heading { @@ -656,6 +670,9 @@ } .toggle-container { + position: absolute; + top: 17px; + right: 15px; cursor: pointer; } @@ -666,6 +683,11 @@ } @media (max-width: 600px) { + .toggle-container { + top: 15px; + right: 60px; + } + .toggle-container .toggle-icon { font-size: 20px; color: rgb(100 116 139); From 05b681df47fb12f84725091f3831b0199a96a545 Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Wed, 11 Sep 2024 14:38:54 +0100 Subject: [PATCH 17/28] change current_time to current_date --- ui/ui/dashboard.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/ui/dashboard.tpl b/ui/ui/dashboard.tpl index 7a998ba8..78955672 100644 --- a/ui/ui/dashboard.tpl +++ b/ui/ui/dashboard.tpl @@ -195,7 +195,7 @@
    {/if} {if $run_date} - {if $current_time - $run_time > 3600} + {if $current_date - $run_time > 3600}
      {Lang::T('Cron has not run for over 1 hour. Please check your setup.')}
    From fe532a62386a5b588d65cb8fdd1b5d9097153fac Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:52:34 +0100 Subject: [PATCH 18/28] change the time calculation logic --- ui/ui/dashboard.tpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/ui/dashboard.tpl b/ui/ui/dashboard.tpl index 78955672..f0432982 100644 --- a/ui/ui/dashboard.tpl +++ b/ui/ui/dashboard.tpl @@ -195,7 +195,9 @@
    {/if} {if $run_date} - {if $current_date - $run_time > 3600} + {assign var="current_time" value=$smarty.now} + {assign var="run_time" value=strtotime($run_date)} + {if $current_time - $run_time > 3600}
      {Lang::T('Cron has not run for over 1 hour. Please check your setup.')}
    From 68de3a71b930f55c0713197c745263e088601b0b Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:39:45 +0100 Subject: [PATCH 19/28] if admin session time error, it logout admin out whether admin are online or not, once time reach it logout you out --- system/autoload/Admin.php | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/system/autoload/Admin.php b/system/autoload/Admin.php index 66052cda..18d016c6 100644 --- a/system/autoload/Admin.php +++ b/system/autoload/Admin.php @@ -13,25 +13,27 @@ class Admin { global $db_pass, $config; $enable_session_timeout = $config['enable_session_timeout']; - if ($enable_session_timeout) { - $timeout = 60; - if ($config['session_timeout_duration']) { - $timeout = intval($config['session_timeout_duration']); + $session_timeout_duration = $config['session_timeout_duration'] ? intval($config['session_timeout_duration'] * 60) : intval(60 * 60); // Convert minutes to seconds + + // Check if the session is active and valid + if (isset($_SESSION['aid']) && isset($_SESSION['aid_expiration'])) { + if ($_SESSION['aid_expiration'] > time()) { + if ($enable_session_timeout) { + $_SESSION['aid_expiration'] = time() + $session_timeout_duration; + } + return $_SESSION['aid']; + } + // Session expired, log out the user + elseif ($enable_session_timeout && $_SESSION['aid_expiration'] <= time()) { + self::removeCookie(); + session_destroy(); + _alert(Lang::T('Session has expired. Please log in again.'), 'danger', "admin"); + return 0; } - $session_timeout_duration = $timeout * 60; // Convert minutes to seconds } - if (isset($_SESSION['aid']) && isset($_SESSION['aid_expiration']) && $_SESSION['aid_expiration'] > time()) { - return $_SESSION['aid']; - } elseif ($enable_session_timeout && isset($_SESSION['aid']) && isset($_SESSION['aid_expiration']) && $_SESSION['aid_expiration'] <= time()) { - self::removeCookie(); - session_destroy(); - _alert(Lang::T('Session has expired. Please log in again.'), 'danger', "admin"); - return 0; - } - // Check if cookie is set and valid + // Check if the cookie is set and valid elseif (isset($_COOKIE['aid'])) { - // id.time.sha1 $tmp = explode('.', $_COOKIE['aid']); if (sha1($tmp[0] . '.' . $tmp[1] . '.' . $db_pass) == $tmp[2]) { if (time() - $tmp[1] < 86400 * 7) { From 095e8937a29c6279b86e6ea5fcf5c0b94c0e1943 Mon Sep 17 00:00:00 2001 From: agamsatria Date: Fri, 13 Sep 2024 00:43:46 +0700 Subject: [PATCH 20/28] Paket vpn tunnel remot --- system/controllers/home.php | 10 +- system/controllers/order.php | 7 + system/controllers/pool.php | 126 +++++++++++ system/controllers/services.php | 374 ++++++++++++++++++++++++++++++++ system/controllers/settings.php | 10 + system/updates.json | 6 + ui/ui/app-localisation.tpl | 8 + ui/ui/customers-add.tpl | 1 + ui/ui/customers-edit.tpl | 1 + ui/ui/plan.tpl | 10 +- ui/ui/port-add.tpl | 51 +++++ ui/ui/port-edit.tpl | 49 +++++ ui/ui/port.tpl | 76 +++++++ ui/ui/recharge.tpl | 1 + ui/ui/scripts/custom.js | 23 +- ui/ui/sections/header.tpl | 4 + ui/ui/user-ui/dashboard.tpl | 25 ++- ui/ui/user-ui/orderPlan.tpl | 104 +++++++++ ui/ui/vpn-add.tpl | 188 ++++++++++++++++ ui/ui/vpn-edit.tpl | 255 ++++++++++++++++++++++ ui/ui/vpn.tpl | 179 +++++++++++++++ 21 files changed, 1502 insertions(+), 6 deletions(-) create mode 100644 ui/ui/port-add.tpl create mode 100644 ui/ui/port-edit.tpl create mode 100644 ui/ui/port.tpl create mode 100644 ui/ui/vpn-add.tpl create mode 100644 ui/ui/vpn-edit.tpl create mode 100644 ui/ui/vpn.tpl diff --git a/system/controllers/home.php b/system/controllers/home.php index a71d340e..20e1d1b6 100644 --- a/system/controllers/home.php +++ b/system/controllers/home.php @@ -317,7 +317,15 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && !empty($_SESSI } } } - + +$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); + $ui->assign('unpaid', ORM::for_table('tbl_payment_gateway') ->where('username', $user['username']) ->where('status', 1) diff --git a/system/controllers/order.php b/system/controllers/order.php index 0d4b2a3c..988db104 100644 --- a/system/controllers/order.php +++ b/system/controllers/order.php @@ -113,12 +113,19 @@ switch ($action) { ->where('type', 'Hotspot') ->where('prepaid', 'yes') ->find_many(); + $plans_vpn = ORM::for_table('tbl_plans') + ->where('plan_type', $account_type) + ->where('enabled', '1')->where('is_radius', 0) + ->where('type', 'VPN') + ->where('prepaid', 'yes') + ->find_many(); } $ui->assign('routers', $routers); $ui->assign('radius_pppoe', $radius_pppoe); $ui->assign('radius_hotspot', $radius_hotspot); $ui->assign('plans_pppoe', $plans_pppoe); $ui->assign('plans_hotspot', $plans_hotspot); + $ui->assign('plans_vpn', $plans_vpn); run_hook('customer_view_order_plan'); #HOOK $ui->display('user-ui/orderPlan.tpl'); break; diff --git a/system/controllers/pool.php b/system/controllers/pool.php index 5528e751..ba599f22 100644 --- a/system/controllers/pool.php +++ b/system/controllers/pool.php @@ -147,6 +147,132 @@ switch ($action) { } else { r2(U . 'pool/edit/' . $id, 'e', $msg); } + + case 'port': + $ui->assign('xfooter', ''); + + $name = _post('name'); + if ($name != '') { + $query = ORM::for_table('tbl_port_pool')->where_like('pool_name', '%' . $name . '%')->order_by_desc('id'); + $d = Paginator::findMany($query, ['name' => $name]); + } else { + $query = ORM::for_table('tbl_port_pool')->order_by_desc('id'); + $d = Paginator::findMany($query); + } + + $ui->assign('d', $d); + run_hook('view_port'); #HOOK + $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('port-add.tpl'); + break; + + case 'edit-port': + $id = $routes['2']; + $d = ORM::for_table('tbl_port_pool')->find_one($id); + if ($d) { + $ui->assign('d', $d); + run_hook('view_edit_port'); #HOOK + $ui->display('port-edit.tpl'); + } else { + r2(U . 'pool/port', 'e', Lang::T('Account Not Found')); + } + break; + + case 'delete-port': + $id = $routes['2']; + run_hook('delete_port'); #HOOK + $d = ORM::for_table('tbl_port_pool')->find_one($id); + if ($d) { + $d->delete(); + + r2(U . 'pool/port', 's', Lang::T('Data Deleted Successfully')); + } + break; + + case 'sync': + $pools = ORM::for_table('tbl_port_pool')->find_many(); + $log = ''; + foreach ($pools as $pool) { + if ($pool['routers'] != 'radius') { + (new MikrotikPppoe())->update_pool($pool, $pool); + $log .= 'DONE: ' . $pool['port_name'] . ': ' . $pool['range_port'] . '
    '; + } + } + r2(U . 'pool/list', 's', $log); + break; + case 'add-port-post': + $name = _post('name'); + $port_range = _post('port_range'); + $public_ip = _post('public_ip'); + $routers = _post('routers'); + run_hook('add_pool'); #HOOK + $msg = ''; + if (Validator::Length($name, 30, 2) == false) { + $msg .= 'Name should be between 3 to 30 characters' . '
    '; + } + if ($port_range == '' or $routers == '') { + $msg .= Lang::T('All field is required') . '
    '; + } + + $d = ORM::for_table('tbl_port_pool')->where('routers', $routers)->find_one(); + if ($d) { + $msg .= Lang::T('Routers already have ports, each router can only have 1 port range!') . '
    '; + } + if ($msg == '') { + $b = ORM::for_table('tbl_port_pool')->create(); + $b->public_ip = $public_ip; + $b->port_name = $name; + $b->range_port = $port_range; + $b->routers = $routers; + $b->save(); + r2(U . 'pool/port', 's', Lang::T('Data Created Successfully')); + } else { + r2(U . 'pool/add-port', 'e', $msg); + } + break; + + + case 'edit-port-post': + $name = _post('name'); + $public_ip = _post('public_ip'); + $range_port = _post('range_port'); + $routers = _post('routers'); + run_hook('edit_port'); #HOOK + $msg = ''; + $msg = ''; + if (Validator::Length($name, 30, 2) == false) { + $msg .= 'Name should be between 3 to 30 characters' . '
    '; + } + if ($range_port == '' or $routers == '') { + $msg .= Lang::T('All field is required') . '
    '; + } + + $id = _post('id'); + $d = ORM::for_table('tbl_port_pool')->find_one($id); + $old = ORM::for_table('tbl_port_pool')->find_one($id); + if (!$d) { + $msg .= Lang::T('Data Not Found') . '
    '; + } + + if ($msg == '') { + $d->port_name = $name; + $d->public_ip = $public_ip; + $d->range_port = $range_port; + $d->routers = $routers; + $d->save(); + + + + r2(U . 'pool/port', 's', Lang::T('Data Updated Successfully')); + } else { + r2(U . 'pool/edit-port/' . $id, 'e', $msg); + } break; default: diff --git a/system/controllers/services.php b/system/controllers/services.php index aaa69635..9bc32e5e 100644 --- a/system/controllers/services.php +++ b/system/controllers/services.php @@ -901,6 +901,380 @@ switch ($action) { r2(U . 'services/balance-add', 'e', $msg); } break; + case 'vpn': + $ui->assign('_title', Lang::T('VPN Plans')); + $ui->assign('xfooter', ''); + + $name = _post('name'); + $name = _req('name'); + $type1 = _req('type1'); + $type2 = _req('type2'); + $type3 = _req('type3'); + $bandwidth = _req('bandwidth'); + $valid = _req('valid'); + $device = _req('device'); + $status = _req('status'); + $router = _req('router'); + $ui->assign('type1', $type1); + $ui->assign('type2', $type2); + $ui->assign('type3', $type3); + $ui->assign('bandwidth', $bandwidth); + $ui->assign('valid', $valid); + $ui->assign('device', $device); + $ui->assign('status', $status); + $ui->assign('router', $router); + + $append_url = "&type1=" . urlencode($type1) + . "&type2=" . urlencode($type2) + . "&type3=" . urlencode($type3) + . "&bandwidth=" . urlencode($bandwidth) + . "&valid=" . urlencode($valid) + . "&device=" . urlencode($device) + . "&status=" . urlencode($status) + . "&router=" . urlencode($router); + + $bws = ORM::for_table('tbl_plans')->distinct()->select("id_bw")->where('tbl_plans.type', 'VPN')->findArray(); + $ids = array_column($bws, 'id_bw'); + if(count($ids)){ + $ui->assign('bws', ORM::for_table('tbl_bandwidth')->select("id")->select('name_bw')->where_id_in($ids)->findArray()); + }else{ + $ui->assign('bws', []); + } + $ui->assign('type2s', ORM::for_table('tbl_plans')->getEnum("plan_type")); + $ui->assign('type3s', ORM::for_table('tbl_plans')->getEnum("typebp")); + $ui->assign('valids', ORM::for_table('tbl_plans')->getEnum("validity_unit")); + $ui->assign('routers', array_column(ORM::for_table('tbl_plans')->distinct()->select("routers")->whereNotEqual('routers', '')->findArray(), 'routers')); + $devices = []; + $files = scandir($DEVICE_PATH); + foreach ($files as $file) { + $ext = pathinfo($file, PATHINFO_EXTENSION); + if ($ext == 'php') { + $devices[] = pathinfo($file, PATHINFO_FILENAME); + } + } + $ui->assign('devices', $devices); + $query = ORM::for_table('tbl_bandwidth') + ->left_outer_join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw')) + ->where('tbl_plans.type', 'VPN'); + if (!empty($type1)) { + $query->where('tbl_plans.prepaid', $type1); + } + if (!empty($type2)) { + $query->where('tbl_plans.plan_type', $type2); + } + if (!empty($type3)) { + $query->where('tbl_plans.typebp', $type3); + } + if (!empty($bandwidth)) { + $query->where('tbl_plans.id_bw', $bandwidth); + } + if (!empty($valid)) { + $query->where('tbl_plans.validity_unit', $valid); + } + if (!empty($router)) { + if ($router == 'radius') { + $query->where('tbl_plans.is_radius', '1'); + } else { + $query->where('tbl_plans.routers', $router); + } + } + if (!empty($device)) { + $query->where('tbl_plans.device', $device); + } + if (in_array($status, ['0', '1'])) { + $query->where('tbl_plans.enabled', $status); + } + if ($name != '') { + $query->where_like('tbl_plans.name_plan', '%' . $name . '%'); + } + $d = Paginator::findMany($query, ['name' => $name], 20, $append_url); + + $ui->assign('d', $d); + run_hook('view_list_vpn'); #HOOK + $ui->display('vpn.tpl'); + break; + + case 'vpn-add': + $ui->assign('_title', Lang::T('VPN Plans')); + $d = ORM::for_table('tbl_bandwidth')->find_many(); + $ui->assign('d', $d); + $r = ORM::for_table('tbl_routers')->find_many(); + $ui->assign('r', $r); + $devices = []; + $files = scandir($DEVICE_PATH); + foreach ($files as $file) { + $ext = pathinfo($file, PATHINFO_EXTENSION); + if ($ext == 'php') { + $devices[] = pathinfo($file, PATHINFO_FILENAME); + } + } + $ui->assign('devices', $devices); + run_hook('view_add_vpn'); #HOOK + $ui->display('vpn-add.tpl'); + break; + + case 'vpn-edit': + $ui->assign('_title', Lang::T('VPN Plans')); + $id = $routes['2']; + $d = ORM::for_table('tbl_plans')->find_one($id); + if ($d) { + if (empty($d['device'])) { + if ($d['is_radius']) { + $d->device = 'Radius'; + } else { + $d->device = 'MikrotikVpn'; + } + $d->save(); + } + $ui->assign('d', $d); + $p = ORM::for_table('tbl_pool')->where('routers', ($d['is_radius']) ? 'radius' : $d['routers'])->find_many(); + $ui->assign('p', $p); + $b = ORM::for_table('tbl_bandwidth')->find_many(); + $ui->assign('b', $b); + $r = []; + if ($d['is_radius']) { + $r = ORM::for_table('tbl_routers')->find_many(); + } + $ui->assign('r', $r); + $devices = []; + $files = scandir($DEVICE_PATH); + foreach ($files as $file) { + $ext = pathinfo($file, PATHINFO_EXTENSION); + if ($ext == 'php') { + $devices[] = pathinfo($file, PATHINFO_FILENAME); + } + } + $ui->assign('devices', $devices); + //select expired plan + if ($d['is_radius']) { + $exps = ORM::for_table('tbl_plans')->selects('id', 'name_plan')->where('type', 'VPN')->where("is_radius", 1)->findArray(); + } else { + $exps = ORM::for_table('tbl_plans')->selects('id', 'name_plan')->where('type', 'VPN')->where("routers", $d['routers'])->findArray(); + } + $ui->assign('exps', $exps); + run_hook('view_edit_vpn'); #HOOK + $ui->display('vpn-edit.tpl'); + } else { + r2(U . 'services/vpn', 'e', Lang::T('Account Not Found')); + } + break; + + case 'vpn-delete': + $id = $routes['2']; + + $d = ORM::for_table('tbl_plans')->find_one($id); + if ($d) { + run_hook('delete_vpn'); #HOOK + + $dvc = Package::getDevice($d); + if ($_app_stage != 'demo') { + if (file_exists($dvc)) { + require_once $dvc; + (new $d['device'])->remove_plan($d); + } else { + new Exception(Lang::T("Devices Not Found")); + } + } + $d->delete(); + + r2(U . 'services/vpn', 's', Lang::T('Data Deleted Successfully')); + } + break; + + case 'vpn-add-post': + $name = _post('name_plan'); + $plan_type = _post('plan_type'); + $radius = _post('radius'); + $id_bw = _post('id_bw'); + $price = _post('price'); + $validity = _post('validity'); + $validity_unit = _post('validity_unit'); + $routers = _post('routers'); + $device = _post('device'); + $pool = _post('pool_name'); + $enabled = _post('enabled'); + $prepaid = _post('prepaid'); + $expired_date = _post('expired_date'); + + + $msg = ''; + if (Validator::UnsignedNumber($validity) == false) { + $msg .= 'The validity must be a number' . '
    '; + } + if (Validator::UnsignedNumber($price) == false) { + $msg .= 'The price must be a number' . '
    '; + } + if ($name == '' or $id_bw == '' or $price == '' or $validity == '' or $pool == '') { + $msg .= Lang::T('All field is required') . '
    '; + } + if (empty($radius)) { + if ($routers == '') { + $msg .= Lang::T('All field is required') . '
    '; + } + } + + $d = ORM::for_table('tbl_plans')->where('name_plan', $name)->find_one(); + if ($d) { + $msg .= Lang::T('Name Plan Already Exist') . '
    '; + } + run_hook('add_vpn'); #HOOK + if ($msg == '') { + $b = ORM::for_table('tbl_bandwidth')->where('id', $id_bw)->find_one(); + if ($b['rate_down_unit'] == 'Kbps') { + $unitdown = 'K'; + $raddown = '000'; + } else { + $unitdown = 'M'; + $raddown = '000000'; + } + if ($b['rate_up_unit'] == 'Kbps') { + $unitup = 'K'; + $radup = '000'; + } else { + $unitup = 'M'; + $radup = '000000'; + } + $rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown; + $radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown . '/' . $b['burst']; + $rate = trim($rate . " " . $b['burst']); + $d = ORM::for_table('tbl_plans')->create(); + $d->type = 'VPN'; + $d->name_plan = $name; + $d->id_bw = $id_bw; + $d->price = $price; + $d->plan_type = $plan_type; + $d->validity = $validity; + $d->validity_unit = $validity_unit; + $d->pool = $pool; + if (!empty($radius)) { + $d->is_radius = 1; + $d->routers = ''; + } else { + $d->is_radius = 0; + $d->routers = $routers; + } + if ($prepaid == 'no') { + if ($expired_date > 28 && $expired_date < 1) { + $expired_date = 20; + } + $d->expired_date = $expired_date; + } else { + $d->expired_date = 0; + } + $d->enabled = $enabled; + $d->prepaid = $prepaid; + $d->device = $device; + $d->save(); + + $dvc = Package::getDevice($d); + if ($_app_stage != 'demo') { + if (file_exists($dvc)) { + require_once $dvc; + (new $d['device'])->add_plan($d); + } else { + new Exception(Lang::T("Devices Not Found")); + } + } + r2(U . 'services/vpn', 's', Lang::T('Data Created Successfully')); + } else { + r2(U . 'services/vpn-add', 'e', $msg); + } + break; + + case 'edit-vpn-post': + $id = _post('id'); + $plan_type = _post('plan_type'); + $name = _post('name_plan'); + $id_bw = _post('id_bw'); + $price = _post('price'); + $validity = _post('validity'); + $validity_unit = _post('validity_unit'); + $routers = _post('routers'); + $device = _post('device'); + $pool = _post('pool_name'); + $plan_expired = _post('plan_expired'); + $enabled = _post('enabled'); + $prepaid = _post('prepaid'); + $expired_date = _post('expired_date'); + $on_login = _post('on_login'); + $on_logout = _post('on_logout'); + + $msg = ''; + if (Validator::UnsignedNumber($validity) == false) { + $msg .= 'The validity must be a number' . '
    '; + } + if (Validator::UnsignedNumber($price) == false) { + $msg .= 'The price must be a number' . '
    '; + } + if ($name == '' or $id_bw == '' or $price == '' or $validity == '' or $pool == '') { + $msg .= Lang::T('All field is required') . '
    '; + } + + $d = ORM::for_table('tbl_plans')->where('id', $id)->find_one(); + $old = ORM::for_table('tbl_plans')->where('id', $id)->find_one(); + if ($d) { + } else { + $msg .= Lang::T('Data Not Found') . '
    '; + } + run_hook('edit_vpn'); #HOOK + if ($msg == '') { + $b = ORM::for_table('tbl_bandwidth')->where('id', $id_bw)->find_one(); + if ($b['rate_down_unit'] == 'Kbps') { + $unitdown = 'K'; + $raddown = '000'; + } else { + $unitdown = 'M'; + $raddown = '000000'; + } + if ($b['rate_up_unit'] == 'Kbps') { + $unitup = 'K'; + $radup = '000'; + } else { + $unitup = 'M'; + $radup = '000000'; + } + $rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown; + $radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown . '/' . $b['burst']; + $rate = trim($rate . " " . $b['burst']); + + $d->name_plan = $name; + $d->id_bw = $id_bw; + $d->price = $price; + $d->plan_type = $plan_type; + $d->validity = $validity; + $d->validity_unit = $validity_unit; + $d->routers = $routers; + $d->pool = $pool; + $d->plan_expired = $plan_expired; + $d->enabled = $enabled; + $d->prepaid = $prepaid; + $d->device = $device; + $d->on_login = $on_login; + $d->on_logout = $on_logout; + if ($prepaid == 'no') { + if ($expired_date > 28 && $expired_date < 1) { + $expired_date = 20; + } + $d->expired_date = $expired_date; + } else { + $d->expired_date = 0; + } + $d->save(); + + $dvc = Package::getDevice($d); + if ($_app_stage != 'demo') { + if (file_exists($dvc)) { + require_once $dvc; + (new $d['device'])->update_plan($old, $d); + } else { + new Exception(Lang::T("Devices Not Found")); + } + } + r2(U . 'services/vpn', 's', Lang::T('Data Updated Successfully')); + } else { + r2(U . 'services/vpn-edit/' . $id, 'e', $msg); + } + break; default: $ui->display('a404.tpl'); } diff --git a/system/controllers/settings.php b/system/controllers/settings.php index 33e4abe9..96cb497b 100644 --- a/system/controllers/settings.php +++ b/system/controllers/settings.php @@ -295,6 +295,16 @@ switch ($action) { $d->value = _post('pppoe_plan'); $d->save(); } + $d = ORM::for_table('tbl_appconfig')->where('setting', 'vpn_plan')->find_one(); + if ($d) { + $d->value = _post('vpn_plan'); + $d->save(); + } else { + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'vpn_plan'; + $d->value = _post('vpn_plan'); + $d->save(); + } $currency_code = $_POST['currency_code']; $d = ORM::for_table('tbl_appconfig')->where('setting', 'currency_code')->find_one(); diff --git a/system/updates.json b/system/updates.json index bce2f4ef..8d66fc0c 100644 --- a/system/updates.json +++ b/system/updates.json @@ -155,5 +155,11 @@ "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;" ] } \ No newline at end of file diff --git a/ui/ui/app-localisation.tpl b/ui/ui/app-localisation.tpl index 936c3abb..571d5588 100644 --- a/ui/ui/app-localisation.tpl +++ b/ui/ui/app-localisation.tpl @@ -128,6 +128,14 @@
    {Lang::T('Change title in user Plan order')}
    +
    + +
    + +
    + {Lang::T('Change title in user Plan order')} +
    diff --git a/ui/ui/customers-edit.tpl b/ui/ui/customers-edit.tpl index e1ce53f8..0ed074b4 100644 --- a/ui/ui/customers-edit.tpl +++ b/ui/ui/customers-edit.tpl @@ -75,6 +75,7 @@ +
    diff --git a/ui/ui/plan.tpl b/ui/ui/plan.tpl index 3cca5861..32111f4a 100644 --- a/ui/ui/plan.tpl +++ b/ui/ui/plan.tpl @@ -95,9 +95,13 @@ {/if} {if $ds['type'] == 'Hotspot'} - {$ds['namebp']} - {else} - {$ds['namebp']} + {$ds['namebp']} + {/if} + {if $ds['type'] == 'PPPOE'} + {$ds['namebp']} + {/if} + {if $ds['type'] == 'VPN'} + {$ds['namebp']} {/if} {$ds['type']} {Lang::dateAndTimeFormat($ds['recharged_on'],$ds['recharged_time'])} diff --git a/ui/ui/port-add.tpl b/ui/ui/port-add.tpl new file mode 100644 index 00000000..b689a896 --- /dev/null +++ b/ui/ui/port-add.tpl @@ -0,0 +1,51 @@ +{include file="sections/header.tpl"} + +
    +
    +
    +
    {Lang::T('Add Port Pool')}
    +
    + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + Or {Lang::T('Cancel')} +
    +
    +
    + +
    +
    +
    +
    + +{include file="sections/footer.tpl"} diff --git a/ui/ui/port-edit.tpl b/ui/ui/port-edit.tpl new file mode 100644 index 00000000..46413314 --- /dev/null +++ b/ui/ui/port-edit.tpl @@ -0,0 +1,49 @@ +{include file="sections/header.tpl"} + +
    +
    +
    +
    {Lang::T('Edit Port')}
    +
    + +
    + +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    + +
    +
    + + Or {Lang::T('Cancel')} +
    +
    +
    + +
    +
    +
    +
    + +{include file="sections/footer.tpl"} diff --git a/ui/ui/port.tpl b/ui/ui/port.tpl new file mode 100644 index 00000000..77fd2661 --- /dev/null +++ b/ui/ui/port.tpl @@ -0,0 +1,76 @@ +{include file="sections/header.tpl"} + +
    +
    +
    +
    +
    + sync +
    + {Lang::T('Port Pool')} - VPN Tunnels +
    +
    +
    +
    + +
    +   +
    +
    + + + + + + + + + + + + + {foreach $d as $ds} + + + + + + + + + {/foreach} + +
    {Lang::T('Port Name')}{Lang::T('Public IP')}{Lang::T('Range Port')}{Lang::T('Routers')}{Lang::T('Manage')}ID
    {$ds['port_name']}{$ds['public_ip']}{$ds['range_port']}{$ds['routers']} + {Lang::T('Edit')} + + {$ds['id']}
    +
    + {include file="pagination.tpl"} +
    +

    {Lang::T('Create expired Internet Plan')}

    +

    {Lang::T('When customer expired, you can move it to Expired Internet Plan')}

    +
    +
    +
    +
    +
    + +{include file="sections/footer.tpl"} diff --git a/ui/ui/recharge.tpl b/ui/ui/recharge.tpl index b896ab50..96370d58 100644 --- a/ui/ui/recharge.tpl +++ b/ui/ui/recharge.tpl @@ -22,6 +22,7 @@
    +
    diff --git a/ui/ui/scripts/custom.js b/ui/ui/scripts/custom.js index 844f5ffc..87734583 100644 --- a/ui/ui/scripts/custom.js +++ b/ui/ui/scripts/custom.js @@ -96,7 +96,7 @@ $(function() { }); }; - }else{ + } else if ($('#POE').is(':checked')) { $.ajax({ type: "POST", dataType: "html", @@ -117,6 +117,27 @@ $(function() { } }); }); + } else { + $.ajax({ + type: "POST", + dataType: "html", + url: "index.php?_route=autoload/server", + success: function(msg){ + $("#server").html(msg); + } + }); + $("#server").change(function(){ + var server = $("#server").val(); + $.ajax({ + type: "POST", + dataType: "html", + url: "index.php?_route=autoload/plan", + data: "jenis=VPN&server="+server, + success: function(msg){ + $("#plan").html(msg); + } + }); + }); } }); }); diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index 34b7f1e9..bb5f8525 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -1283,6 +1283,8 @@ href="{$_url}services/hotspot">Hotspot
  • PPPOE
  • +
  • VPN
  • Bandwidth
  • {if $_c['enable_balance'] == 'yes'} @@ -1341,6 +1343,8 @@ href="{$_url}routers">Routers
  • IP Pool
  • +
  • Port Pool
  • {Lang::T('Routers Maps')}
  • {$_MENU_NETWORK} diff --git a/ui/ui/user-ui/dashboard.tpl b/ui/ui/user-ui/dashboard.tpl index 361e6487..65e24c39 100644 --- a/ui/ui/user-ui/dashboard.tpl +++ b/ui/ui/user-ui/dashboard.tpl @@ -88,6 +88,8 @@ Hotspot {elseif $_user.service_type == 'PPPoE'} PPPoE + {elseif $_user.service_type == 'VPN'} + VPN {elseif $_user.service_type == 'Others' || $_user.service_type == null} Others {/if} @@ -165,8 +167,10 @@
    {if $_bill['type'] == 'Hotspot'} {if $_c['hotspot_plan']==''}Hotspot Plan{else}{$_c['hotspot_plan']}{/if} - {else} + {else if $_bill['type'] == 'PPPOE'} {if $_c['pppoe_plan']==''}PPPOE Plan{else}{$_c['pppoe_plan']}{/if} + {else if $_bill['type'] == 'VPN'} + {if $_c['pppoe_plan']==''}VPN Plan{else}{$_c['vpn_plan']}{/if} {/if}
    @@ -215,6 +219,25 @@ {$_bill['plan_type']} + {if $_bill['type'] == 'VPN' && $_bill['routers'] == $vpn['routers']} + + {Lang::T('Public IP')} + {$vpn['public_ip']} / {$vpn['port_name']} + + + {Lang::T('Private IP')} + {$_user['pppoe_ip']} + + {foreach $cf as $tcf} + + {if $tcf['field_name'] == 'Winbox' or $tcf['field_name'] == 'Api' or $tcf['field_name'] == 'Web'} + {$tcf['field_name']} - Port + {$tcf['field_value']} + + {/if} + {/foreach} + {/if} + {if $nux_ip neq ''} {Lang::T('Current IP')} diff --git a/ui/ui/user-ui/orderPlan.tpl b/ui/ui/user-ui/orderPlan.tpl index f79ed4dd..9db514ff 100644 --- a/ui/ui/user-ui/orderPlan.tpl +++ b/ui/ui/user-ui/orderPlan.tpl @@ -226,6 +226,7 @@ {/if} {foreach $routers as $router} {if Validator::isRouterHasPlan($plans_hotspot, $router['name']) || Validator::isRouterHasPlan($plans_pppoe, + $router['name']) || Validator::isRouterHasPlan($plans_vpn, $router['name'])}
    {$router['name']}
    @@ -338,9 +339,62 @@ {/if} {/foreach}
    + {/if} + {if $_user['service_type'] == 'VPN' && Validator::countRouterPlan($plans_vpn,$router['name'])>0} +
    {if $_c['vpn_plan']==''}VPN Plan{else}{$_c['vpn_plan']}{/if}
    +
    + {foreach $plans_vpn as $plan} + {if $router['name'] eq $plan['routers']} +
    +
    +
    {$plan['name_plan']}
    +
    +
    + + + + + + + + + + + + + + + +
    {Lang::T('Type')}{$plan['type']}
    {Lang::T('Price')}{Lang::moneyFormat($plan['price'])}
    {Lang::T('Validity')}{$plan['validity']} {$plan['validity_unit']}
    +
    +
    +
    +
    + {Lang::T('Buy')} + {if $_c['enable_balance'] == 'yes' && $_user['balance']>=$plan['price']} + {Lang::T('Pay With Balance')} + {/if} +
    + {if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && + $_user['balance']>=$plan['price']} + {Lang::T('Buy for friend')} + {/if} +
    +
    +
    + {/if} + {/foreach} +
    {/if} {if $_user['service_type'] == 'Others' || $_user['service_type'] == '' && (Validator::countRouterPlan($plans_hotspot, $router['name'])>0 || Validator::countRouterPlan($plans_pppoe, + $router['name'])>0 || Validator::countRouterPlan($plans_vpn, $router['name'])>0)}
    {if $_c['hotspot_plan']==''}Hotspot Plan{else}{$_c['hotspot_plan']}{/if}
    @@ -443,6 +497,56 @@ {/if} {/foreach} +
    {if $_c['vpn_plan']==''}VPN Plan{else}{$_c['vpn_plan']}{/if}
    +
    + {foreach $plans_vpn as $plan} + {if $router['name'] eq $plan['routers']} +
    +
    +
    {$plan['name_plan']}
    +
    +
    + + + + + + + + + + + + + + + +
    {Lang::T('Type')}{$plan['type']}
    {Lang::T('Price')}{Lang::moneyFormat($plan['price'])}
    {Lang::T('Validity')}{$plan['validity']} {$plan['validity_unit']}
    +
    +
    +
    +
    + {Lang::T('Buy')} + {if $_c['enable_balance'] == 'yes' && $_user['balance']>=$plan['price']} + {Lang::T('Pay With Balance')} + {/if} +
    + {if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && + $_user['balance']>=$plan['price']} + {Lang::T('Buy for friend')} + {/if} +
    +
    +
    + {/if} + {/foreach} +
    {/if} {/if} diff --git a/ui/ui/vpn-add.tpl b/ui/ui/vpn-add.tpl new file mode 100644 index 00000000..ae26a8ac --- /dev/null +++ b/ui/ui/vpn-add.tpl @@ -0,0 +1,188 @@ +{include file="sections/header.tpl"} + +
    +
    +
    +
    {Lang::T('Add Service Plan')}
    +
    +
    +
    + +
    + {Lang::T('Enable')} + {Lang::T('Disable')} +
    +
    +
    + +
    + {Lang::T('Prepaid')} + {Lang::T('Postpaid')} +
    +
    +
    + +
    + {Lang::T('Personal')} + {Lang::T('Business')} +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + {$_c['currency_code']} + +
    +
    + {if $_c['enable_tax'] == 'yes'} + {if $_c['tax_rate'] == 'custom'} +

    {number_format($_c['custom_tax_rate'], 2)} % {Lang::T('Tax Rates + will be added')}

    + {else} +

    {number_format($_c['tax_rate'] * 100, 2)} % {Lang::T('Tax Rates + will be added')}

    + {/if} + {/if} +
    +
    + +
    + +
    +
    + +
    +

    {Lang::T('1 Period = 1 Month, Expires the 20th of each month')} +

    +
    + +
    + +
    + +

    {Lang::T('Cannot be change after saved')}

    +
    +
    +
    + +
    + +
    +
    +
    +
    + + Or {Lang::T('Cancel')} +
    +
    +
    +
    +
    +
    +
    + +{if $_c['radius_enable']} + {literal} + + {/literal} +{/if} +{include file="sections/footer.tpl"} diff --git a/ui/ui/vpn-edit.tpl b/ui/ui/vpn-edit.tpl new file mode 100644 index 00000000..53428605 --- /dev/null +++ b/ui/ui/vpn-edit.tpl @@ -0,0 +1,255 @@ +{include file="sections/header.tpl"} + +
    +
    +
    +
    +
    {Lang::T('Edit Service Plan')} || {$d['name_plan']}
    +
    + +
    + +
    + {Lang::T('Enable')} + {Lang::T('Disable')} +
    +
    +
    + +
    + + {Lang::T('Prepaid')} + {Lang::T('Postpaid')} +
    +
    +
    + +
    + + {Lang::T('Personal')} + {Lang::T('Business')} +
    +
    + {if $_c['radius_enable'] and $d['is_radius']} +
    + +
    + +
    +
    + {/if} +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + {$_c['currency_code']} + +
    +
    + {if $_c['enable_tax'] == 'yes'} + {if $_c['tax_rate'] == 'custom'} +

    {number_format($_c['custom_tax_rate'], 2)} % {Lang::T('Tax Rates + will be added')}

    + {else} +

    {number_format($_c['tax_rate'] * 100, 2)} % {Lang::T('Tax Rates + will be added')}

    + {/if} + {/if} + +
    +
    + +
    + +
    +
    + +

    {Lang::T('1 Period = 1 Month, Expires the 20th of each month')}

    +
    + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    + {Lang::T('Expired Action')} {Lang::T('Optional')} +
    + +
    + +

    + {Lang::T('When Expired, customer will be move to selected internet plan')}

    +
    +
    +
    +
    +
    + {if !$d['is_radius']} +
    +
    +
    {Lang::T('on-login / on-up')}
    +
    + +
    +
    +
    +
    {Lang::T('on-logout / on-down')}
    +
    + +
    +
    +
    + {/if} +
    +
    +
    + + Or {Lang::T('Cancel')} +
    +
    +
    + + + + + + + + + + + + + + +{include file="sections/footer.tpl"} diff --git a/ui/ui/vpn.tpl b/ui/ui/vpn.tpl new file mode 100644 index 00000000..6047e446 --- /dev/null +++ b/ui/ui/vpn.tpl @@ -0,0 +1,179 @@ +{include file="sections/header.tpl"} + +
    +
    +
    +
    +
    + sync +
    {Lang::T('VPN Package')} +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + {foreach $d as $ds} + + + + + + + + + + + + + + + {/foreach} + +
    {Lang::T('Internet Plan')} + {Lang::T('Expired')}
    {Lang::T('Name')}{Lang::T('Type')}{Lang::T('Bandwidth')}{Lang::T('Price')}{Lang::T('Validity')}{Lang::T('IP Pool')}{Lang::T('Internet Plan')}{Lang::T('Date')}{Lang::T('Location')}{Lang::T('Device')}{Lang::T('Manage')}ID
    {$ds['name_plan']}{$ds['plan_type']} {if $ds['prepaid'] != 'yes'}{Lang::T('Postpaid')}{else}{Lang::T('Prepaid')}{/if}{$ds['name_bw']}{Lang::moneyFormat($ds['price'])}{$ds['validity']} {$ds['validity_unit']}{$ds['pool']}{if $ds['plan_expired']}{Lang::T('Yes')}{else}{Lang::T('No')} + {/if}{if $ds['prepaid'] == no}{$ds['expired_date']}{/if} + {if $ds['is_radius']} + RADIUS + {else} + {if $ds['routers']!=''} + {$ds['routers']} + {/if} + {/if} + {$ds['device']} + {Lang::T('Edit')} + + {$ds['id']}
    +
    + +
    +
    +
    + +{include file="sections/footer.tpl"} From f5d9649f97e512751dbcb1eec8c1c40925c31fde Mon Sep 17 00:00:00 2001 From: AGSTR <144728914+agstrxyz@users.noreply.github.com> Date: Fri, 13 Sep 2024 00:46:40 +0700 Subject: [PATCH 21/28] Add files via upload --- system/devices/MikrotikVpn.php | 504 +++++++++++++++++++++++++++++++++ 1 file changed, 504 insertions(+) create mode 100644 system/devices/MikrotikVpn.php diff --git a/system/devices/MikrotikVpn.php b/system/devices/MikrotikVpn.php new file mode 100644 index 00000000..6edeed2c --- /dev/null +++ b/system/devices/MikrotikVpn.php @@ -0,0 +1,504 @@ + 'Mikrotik Vpn', + 'description' => 'To handle connection between PHPNuxBill with Mikrotik VPN', + 'author' => 'agstr', + 'url' => [ + 'Github' => 'https://github.com/agstrxyz', + 'Telegram' => 'https://t.me/agstrxyz', + 'Youtube' => 'https://www.youtube.com/@agstrxyz', + 'Donate' => 'https://paypal.me/ibnux' + ] + ]; + } + + function add_customer($customer, $plan) + { + global $isChangePlan; + $mikrotik = $this->info($plan['routers']); + $client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + $cid = self::getIdByCustomer($customer, $client); + if (empty($cid)) { + $this->addVpnUser($client, $plan, $customer); + }else{ + $setRequest = new RouterOS\Request('/ppp/secret/set'); + $setRequest->setArgument('numbers', $cid); + if (!empty($customer['pppoe_password'])) { + $setRequest->setArgument('password', $customer['pppoe_password']); + } else { + $setRequest->setArgument('password', $customer['password']); + } + if (!empty($customer['pppoe_username'])) { + $setRequest->setArgument('name', $customer['pppoe_username']); + } else { + $setRequest->setArgument('name', $customer['username']); + } + if (!empty($customer['pppoe_ip'])) { + $setRequest->setArgument('remote-address', $customer['pppoe_ip']); + }else{ + $setRequest->setArgument('remote-address', '0.0.0.0'); + } + $setRequest->setArgument('profile', $plan['name_plan']); + $setRequest->setArgument('comment', $customer['fullname'] . ' | ' . $customer['email'] . ' | ' . implode(', ', User::getBillNames($customer['id']))); + $client->sendSync($setRequest); + if(isset($isChangePlan) && $isChangePlan){ + $this->removeVpnActive($client, $customer['username']); + if (!empty($customer['pppoe_username'])) { + $this->removeVpnActive($client, $customer['pppoe_username']); + } + } + } + } + + function remove_customer($customer, $plan) + { + $mikrotik = $this->info($plan['routers']); + $client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + if (!empty($plan['plan_expired'])) { + $p = ORM::for_table("tbl_plans")->find_one($plan['plan_expired']); + if($p){ + $this->add_customer($customer, $p); + $this->removeVpnActive($client, $customer['username']); + if (!empty($customer['pppoe_username'])) { + $this->removeVpnActive($client, $customer['pppoe_username']); + } + return; + } + } + $this->removeVpnUser($client, $customer['username'], $customer['id']); + if (!empty($customer['pppoe_username'])) { + $this->removeVpnUser($client, $customer['pppoe_username'], $customer['id']); + } + $this->removeVpnActive($client, $customer['username']); + if (!empty($customer['pppoe_username'])) { + $this->removeVpnActive($client, $customer['pppoe_username']); + } + } + + public function change_username($plan, $from, $to) + { + $mikrotik = $this->info($plan['routers']); + $client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + $printRequest = new RouterOS\Request('/ppp/secret/print'); + $printRequest->setQuery(RouterOS\Query::where('name', $from)); + $cid = $client->sendSync($printRequest)->getProperty('.id'); + if (!empty($cid)) { + $setRequest = new RouterOS\Request('/ppp/secret/set'); + $setRequest->setArgument('numbers', $cid); + $setRequest->setArgument('name', $to); + $client->sendSync($setRequest); + $this->removeVpnActive($client, $from); + } + } + + function add_plan($plan) + { + $mikrotik = $this->info($plan['routers']); + $client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + + + $bw = ORM::for_table("tbl_bandwidth")->find_one($plan['id_bw']); + if ($bw['rate_down_unit'] == 'Kbps') { + $unitdown = 'K'; + } else { + $unitdown = 'M'; + } + if ($bw['rate_up_unit'] == 'Kbps') { + $unitup = 'K'; + } else { + $unitup = 'M'; + } + $rate = $bw['rate_up'] . $unitup . "/" . $bw['rate_down'] . $unitdown; + if(!empty(trim($bw['burst']))){ + $rate .= ' '.$bw['burst']; + } + $pool = ORM::for_table("tbl_pool")->where("pool_name", $plan['pool'])->find_one(); + $addRequest = new RouterOS\Request('/ppp/profile/add'); + $client->sendSync( + $addRequest + ->setArgument('name', $plan['name_plan']) + ->setArgument('local-address', (!empty($pool['local_ip'])) ? $pool['local_ip']: $pool['pool_name']) + ->setArgument('remote-address', $pool['pool_name']) + ->setArgument('rate-limit', $rate) + ); + } + + + function getIdByCustomer($customer, $client){ + $printRequest = new RouterOS\Request('/ppp/secret/print'); + $printRequest->setQuery(RouterOS\Query::where('name', $customer['username'])); + $id = $client->sendSync($printRequest)->getProperty('.id'); + if(empty($id)){ + if (!empty($customer['pppoe_username'])) { + $printRequest = new RouterOS\Request('/ppp/secret/print'); + $printRequest->setQuery(RouterOS\Query::where('name', $customer['pppoe_username'])); + $id = $client->sendSync($printRequest)->getProperty('.id'); + } + } + return $id; + } + + function update_plan($old_name, $new_plan) + { + $mikrotik = $this->info($new_plan['routers']); + $client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + + $printRequest = new RouterOS\Request( + '/ppp profile print .proplist=.id', + RouterOS\Query::where('name', $old_name['name_plan']) + ); + $profileID = $client->sendSync($printRequest)->getProperty('.id'); + if (empty($profileID)) { + $this->add_plan($new_plan); + } else { + $bw = ORM::for_table("tbl_bandwidth")->find_one($new_plan['id_bw']); + if ($bw['rate_down_unit'] == 'Kbps') { + $unitdown = 'K'; + } else { + $unitdown = 'M'; + } + if ($bw['rate_up_unit'] == 'Kbps') { + $unitup = 'K'; + } else { + $unitup = 'M'; + } + $rate = $bw['rate_up'] . $unitup . "/" . $bw['rate_down'] . $unitdown; + if(!empty(trim($bw['burst']))){ + $rate .= ' '.$bw['burst']; + } + $pool = ORM::for_table("tbl_pool")->where("pool_name", $new_plan['pool'])->find_one(); + $setRequest = new RouterOS\Request('/ppp/profile/set'); + $client->sendSync( + $setRequest + ->setArgument('numbers', $profileID) + ->setArgument('local-address', (!empty($pool['local_ip'])) ? $pool['local_ip']: $pool['pool_name']) + ->setArgument('remote-address', $pool['pool_name']) + ->setArgument('rate-limit', $rate) + ->setArgument('on-up', $new_plan['on_login']) + ->setArgument('on-down', $new_plan['on_logout']) + ); + } + } + + function remove_plan($plan) + { + $mikrotik = $this->info($plan['routers']); + $client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + $printRequest = new RouterOS\Request( + '/ppp profile print .proplist=.id', + RouterOS\Query::where('name', $plan['name_plan']) + ); + $profileID = $client->sendSync($printRequest)->getProperty('.id'); + + $removeRequest = new RouterOS\Request('/ppp/profile/remove'); + $client->sendSync( + $removeRequest + ->setArgument('numbers', $profileID) + ); + } + + function add_pool($pool){ + global $_app_stage; + if ($_app_stage == 'demo') { + return null; + } + $mikrotik = $this->info($pool['routers']); + $client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + $addRequest = new RouterOS\Request('/ip/pool/add'); + $client->sendSync( + $addRequest + ->setArgument('name', $pool['pool_name']) + ->setArgument('ranges', $pool['range_ip']) + ); + } + + function update_pool($old_pool, $new_pool){ + global $_app_stage; + if ($_app_stage == 'demo') { + return null; + } + $mikrotik = $this->info($new_pool['routers']); + $client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + $printRequest = new RouterOS\Request( + '/ip pool print .proplist=.id', + RouterOS\Query::where('name', $old_pool['pool_name']) + ); + $poolID = $client->sendSync($printRequest)->getProperty('.id'); + if (empty($poolID)) { + $this->add_pool($new_pool); + } else { + $setRequest = new RouterOS\Request('/ip/pool/set'); + $client->sendSync( + $setRequest + ->setArgument('numbers', $poolID) + ->setArgument('name', $new_pool['pool_name']) + ->setArgument('ranges', $new_pool['range_ip']) + ); + } + } + + function remove_pool($pool){ + global $_app_stage; + if ($_app_stage == 'demo') { + return null; + } + $mikrotik = $this->info($pool['routers']); + $client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + $printRequest = new RouterOS\Request( + '/ip pool print .proplist=.id', + RouterOS\Query::where('name', $pool['pool_name']) + ); + $poolID = $client->sendSync($printRequest)->getProperty('.id'); + $removeRequest = new RouterOS\Request('/ip/pool/remove'); + $client->sendSync( + $removeRequest + ->setArgument('numbers', $poolID) + ); + } + + + function online_customer($customer, $router_name) + { + $mikrotik = $this->info($router_name); + $client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + $printRequest = new RouterOS\Request( + '/ppp active print', + RouterOS\Query::where('user', $customer['username']) + ); + return $client->sendSync($printRequest)->getProperty('.id'); + } + + function info($name) + { + return ORM::for_table('tbl_routers')->where('name', $name)->find_one(); + } + + function getClient($ip, $user, $pass) + { + global $_app_stage; + if ($_app_stage == 'demo') { + return null; + } + $iport = explode(":", $ip); + return new RouterOS\Client($iport[0], $user, $pass, ($iport[1]) ? $iport[1] : null); + } + + function removeVpnUser($client, $username, $cstid) + { + global $_app_stage; + if ($_app_stage == 'demo') { + return null; + } + $printRequest = new RouterOS\Request('/ppp/secret/print'); + //$printRequest->setArgument('.proplist', '.id'); + $printRequest->setQuery(RouterOS\Query::where('name', $username)); + $id = $client->sendSync($printRequest)->getProperty('.id'); + $removeRequest = new RouterOS\Request('/ppp/secret/remove'); + $removeRequest->setArgument('numbers', $id); + $client->sendSync($removeRequest); + $this->rmNat($client, $cstid); + } + + function addVpnUser($client, $plan, $customer) + { + $setRequest = new RouterOS\Request('/ppp/secret/add'); + $setRequest->setArgument('service', 'any'); + $setRequest->setArgument('profile', $plan['name_plan']); + $setRequest->setArgument('comment', $customer['fullname'] . ' | ' . $customer['email'] . ' | ' . implode(', ', User::getBillNames($customer['id']))); + if (!empty($customer['pppoe_password'])) { + $setRequest->setArgument('password', $customer['pppoe_password']); + } else { + $setRequest->setArgument('password', $customer['password']); + } + if (!empty($customer['pppoe_username'])) { + $setRequest->setArgument('name', $customer['pppoe_username']); + } else { + $setRequest->setArgument('name', $customer['username']); + } + if (!empty($customer['pppoe_ip'])) { + $ips = $customer['pppoe_ip']; + $setRequest->setArgument('remote-address', $customer['pppoe_ip']); + } else { + $ips = $this->checkIpAddr($plan['pool'], $customer['id']); + $setRequest->setArgument('remote-address', $ips); + + } + $this->addNat($client, $plan, $customer, $ips); + $client->sendSync($setRequest); + $customer->service_type = 'VPN'; + $customer->pppoe_ip = $ips; + $customer->save(); + } + + function removeVpnActive($client, $username) + { + global $_app_stage; + if ($_app_stage == 'demo') { + return null; + } + $onlineRequest = new RouterOS\Request('/ppp/active/print'); + $onlineRequest->setArgument('.proplist', '.id'); + $onlineRequest->setQuery(RouterOS\Query::where('name', $username)); + $id = $client->sendSync($onlineRequest)->getProperty('.id'); + + $removeRequest = new RouterOS\Request('/ppp/active/remove'); + $removeRequest->setArgument('numbers', $id); + $client->sendSync($removeRequest); + } + + + function addIpToAddressList($client, $ip, $listName, $comment = '') + { + global $_app_stage; + if ($_app_stage == 'demo') { + return null; + } + $addRequest = new RouterOS\Request('/ip/firewall/address-list/add'); + $client->sendSync( + $addRequest + ->setArgument('address', $ip) + ->setArgument('comment', $comment) + ->setArgument('list', $listName) + ); + + } + + function removeIpFromAddressList($client, $ip) + { + global $_app_stage; + if ($_app_stage == 'demo') { + return null; + } + $printRequest = new RouterOS\Request( + '/ip firewall address-list print .proplist=.id', + RouterOS\Query::where('address', $ip) + ); + $id = $client->sendSync($printRequest)->getProperty('.id'); + $removeRequest = new RouterOS\Request('/ip/firewall/address-list/remove'); + $client->sendSync( + $removeRequest + ->setArgument('numbers', $id) + ); + } + + function addNat($client, $plan, $cust, $ips) + { + global $_app_stage; + if ($_app_stage == 'demo') { + return null; + } + $this->checkPort($cust['id'], 'Winbox', $plan['routers']); + $this->checkPort($cust['id'], 'Api', $plan['routers']); + $this->checkPort($cust['id'], 'Web', $plan['routers']); + $tcf = ORM::for_table('tbl_customers_fields') + ->where('customer_id', $cust['id']) + ->find_many(); + + foreach ($tcf as $cf) { + $dst = $cf['field_value']; + $cmnt = $cf['field_name']; + if ($cmnt == 'Winbox') { + $tp = '8291'; } + if ($cmnt == 'Web') { + $tp = '80'; } + if ($cmnt == 'Api') { + $tp = '8728'; } + if ($cmnt == 'Winbox' || $cmnt == 'Web' || $cmnt == 'Api') { + $addRequest = new RouterOS\Request('/ip/firewall/nat/add'); + $client->sendSync( + $addRequest + ->setArgument('chain', 'dstnat') + ->setArgument('protocol', 'tcp') + ->setArgument('dst-port', $dst) + ->setArgument('action', 'dst-nat') + ->setArgument('to-addresses', $ips) + ->setArgument('to-ports', $tp) + ->setArgument('address', $ip) + ->setArgument('comment', $cmnt.' || '.$cust['username']) + ); + } + } + } + + function rmNat($client, $cstid) + { + global $_app_stage; + if ($_app_stage == 'demo') { + return null; + } + $tcf = ORM::for_table('tbl_customers_fields') + ->where('customer_id', $cstid) + ->find_many(); + $cst = ORM::for_table('tbl_customers')->find_one($cstid); + $printRequest = new RouterOS\Request('/ip/firewall/nat/print'); + $printRequest->setQuery(RouterOS\Query::where('to-addresses', $cst['pppoe_ip'])); + $nats = $client->sendSync($printRequest); + foreach ($nats as $nat) { + $id = $client->sendSync($printRequest)->getProperty('.id'); + $removeRequest = new RouterOS\Request('/ip/firewall/nat/remove'); + $removeRequest->setArgument('numbers', $id); + $client->sendSync($removeRequest); + } + } + + + function checkPort($id, $portn, $router) + { + $tcf = ORM::for_table('tbl_customers_fields') + ->where('customer_id', $id) + ->where('field_name', $portn) + ->find_one(); + $ports = ORM::for_table('tbl_port_pool') + ->where('routers', $router) + ->find_one(); + $port = explode('-',$ports['range_port']); + if (empty($tcf) && !empty($ports)) { + repeat: + $portr = rand($port['0'], $port['1']); + if (ORM::for_table('tbl_customers_fields')->where('field_value', $portr)->find_one()) { + if($portr == $port['1']) + { + return; + } + goto repeat; + } + $cf = ORM::for_table('tbl_customers_fields')->create(); + $cf->customer_id = $id; + $cf->field_name = $portn; + $cf->field_value = $portr; + $cf->save(); + } + } + + function checkIpAddr($pname, $id) { + $c = ORM::for_table('tbl_customers')->find_one($id); + $ipp = ORM::for_table('tbl_pool') + ->where('pool_name', $pname) + ->find_one(); + $ip_r = explode('-',$ipp['range_ip']); + $ip_1 = explode('.',$ip_r['0']); + $ip_2 = explode('.',$ip_r['1']); + repeat: + $ipt = rand($ip_1['3'], $ip_2['3']); + $ips = $ip_1['0'].'.'.$ip_1['1'].'.'.$ip_1['2'].'.'.$ipt; + if (empty($c['pppoe_ip'])) { + if (ORM::for_table('tbl_customers')->where('pppoe_ip' ,$ips)->find_one()) { + if ($ip_2['3'] == $ipt) + { + return; + } + goto repeat; + } + return $ips; + } + } + +} From 82569239e2a1d43e355d06ed7f01a5eb8838554a Mon Sep 17 00:00:00 2001 From: Ibnu Maksum Date: Fri, 13 Sep 2024 14:46:14 +0700 Subject: [PATCH 22/28] update changelog --- CHANGELOG.md | 7 +++++++ version.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21df89e6..8f9e0862 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ # CHANGELOG +## 2024.9.13 + +- Add Selling Mikrotik VPN By @agstrxyz +- Theme Redesign by @Focuslinkstech +- Fix That and this + + ## 2024.8.28 - add Router Status Offline/Online by @Focuslinkstech diff --git a/version.json b/version.json index 1bd146b2..13f748ef 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "2024.9.6" + "version": "2024.9.13" } \ No newline at end of file From c2916da21541812a277b24c1772c95a9cf6d4f35 Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Fri, 13 Sep 2024 09:33:59 +0100 Subject: [PATCH 23/28] fix dark button --- ui/ui/sections/header.tpl | 3 --- 1 file changed, 3 deletions(-) diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index bb5f8525..a86d1409 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -670,9 +670,6 @@ } .toggle-container { - position: absolute; - top: 17px; - right: 15px; cursor: pointer; } From a31286d7812f34fa12a99e21899476f3065be8d1 Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Fri, 13 Sep 2024 09:47:43 +0100 Subject: [PATCH 24/28] fix toggle switch button mobile view --- ui/ui/sections/header.tpl | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index a86d1409..862dbe4d 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -679,19 +679,6 @@ transition: color 0.5s ease; } - @media (max-width: 600px) { - .toggle-container { - top: 15px; - right: 60px; - } - - .toggle-container .toggle-icon { - font-size: 20px; - color: rgb(100 116 139); - transition: color 0.5s ease; - } - } - .dark-mode .toggle-container .toggle-icon { color: #ffdd57; } From 985ddda41f9c5cc07cd6e18d9563be475634da70 Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Fri, 13 Sep 2024 09:55:58 +0100 Subject: [PATCH 25/28] fix panel warning bottom radius --- ui/ui/dashboard.tpl | 2 +- ui/ui/sections/header.tpl | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/ui/ui/dashboard.tpl b/ui/ui/dashboard.tpl index f0432982..b47f0796 100644 --- a/ui/ui/dashboard.tpl +++ b/ui/ui/dashboard.tpl @@ -198,7 +198,7 @@ {assign var="current_time" value=$smarty.now} {assign var="run_time" value=strtotime($run_date)} {if $current_time - $run_time > 3600} -
    +
      {Lang::T('Cron has not run for over 1 hour. Please check your setup.')}
    diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index 862dbe4d..a075a25a 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -157,11 +157,6 @@ border-bottom-left-radius: 21px; } - .panel-warning>.panel-heading { - border-bottom-right-radius: 21px; - border-bottom-left-radius: 21px; - } - .panel-danger>.panel-heading { color: #a94442; background-color: #f2dede; From 3c6ef3bcf34fac4a861036cdb55e8f9b5606057b Mon Sep 17 00:00:00 2001 From: AGSTR <144728914+agstrxyz@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:31:03 +0700 Subject: [PATCH 26/28] Update MikrotikVpn.php --- system/devices/MikrotikVpn.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/system/devices/MikrotikVpn.php b/system/devices/MikrotikVpn.php index 6edeed2c..a8f41fec 100644 --- a/system/devices/MikrotikVpn.php +++ b/system/devices/MikrotikVpn.php @@ -400,8 +400,10 @@ class MikrotikVpn $this->checkPort($cust['id'], 'Web', $plan['routers']); $tcf = ORM::for_table('tbl_customers_fields') ->where('customer_id', $cust['id']) - ->find_many(); - + ->find_many(); + $ip = ORM::for_table('tbl_port_pool') + ->where('routers', $plan['routers']) + ->find_one(); foreach ($tcf as $cf) { $dst = $cf['field_value']; $cmnt = $cf['field_name']; @@ -421,7 +423,7 @@ class MikrotikVpn ->setArgument('action', 'dst-nat') ->setArgument('to-addresses', $ips) ->setArgument('to-ports', $tp) - ->setArgument('address', $ip) + ->setArgument('dst-address', $ip['public_ip']) ->setArgument('comment', $cmnt.' || '.$cust['username']) ); } @@ -434,9 +436,7 @@ class MikrotikVpn if ($_app_stage == 'demo') { return null; } - $tcf = ORM::for_table('tbl_customers_fields') - ->where('customer_id', $cstid) - ->find_many(); + $cst = ORM::for_table('tbl_customers')->find_one($cstid); $printRequest = new RouterOS\Request('/ip/firewall/nat/print'); $printRequest->setQuery(RouterOS\Query::where('to-addresses', $cst['pppoe_ip'])); From f81f3df700196ea2b022dd7f9c7bb578cb5a26ec Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Fri, 13 Sep 2024 10:43:42 +0100 Subject: [PATCH 27/28] add mailer error reporting --- system/autoload/Message.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/system/autoload/Message.php b/system/autoload/Message.php index 988c98e0..cdc04525 100644 --- a/system/autoload/Message.php +++ b/system/autoload/Message.php @@ -154,6 +154,9 @@ class Message $mail->Body = $body; } $mail->send(); + if (!$mail->send()) { + _log(Lang::T("Email not sent, Mailer Error: ") . $mail->ErrorInfo); + } //

    } From f738c9b120b324c447f5fa4bf0db30481577c58a Mon Sep 17 00:00:00 2001 From: Focuslinkstech <45756999+Focuslinkstech@users.noreply.github.com> Date: Fri, 13 Sep 2024 12:03:18 +0100 Subject: [PATCH 28/28] add seperate css for cron monitor --- ui/ui/dashboard.tpl | 6 +++--- ui/ui/sections/header.tpl | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ui/ui/dashboard.tpl b/ui/ui/dashboard.tpl index b47f0796..79db90d3 100644 --- a/ui/ui/dashboard.tpl +++ b/ui/ui/dashboard.tpl @@ -198,17 +198,17 @@ {assign var="current_time" value=$smarty.now} {assign var="run_time" value=strtotime($run_date)} {if $current_time - $run_time > 3600} -

    +
      {Lang::T('Cron has not run for over 1 hour. Please check your setup.')}
    {else} -
    +
    {Lang::T('Cron Job last ran on')}: {$run_date}
    {/if} {else} -
    +
      {Lang::T('Cron appear not been setup, please check your cron setup.')}
    diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index a075a25a..89c354d6 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -157,6 +157,30 @@ border-bottom-left-radius: 21px; } + .panel-cron-success>.panel-heading { + border-bottom-right-radius: 21px; + border-bottom-left-radius: 21px; + color: #fff; + background-color: #169210; + border-color: #25e01c; + + } + + .panel-cron-warning>.panel-heading { + border-bottom-right-radius: 21px; + border-bottom-left-radius: 21px; + color: #350808; + background-color: #efeb0a; + border-color: #efeb0a; + } + .panel-cron-danger>.panel-heading { + border-bottom-right-radius: 21px; + border-bottom-left-radius: 21px; + color: #fff; + background-color: #e61212; + border-color: #df1335; + } + .panel-danger>.panel-heading { color: #a94442; background-color: #f2dede;