diff --git a/system/autoload/Validator.php b/system/autoload/Validator.php index 65dd2f59..c200a2bf 100644 --- a/system/autoload/Validator.php +++ b/system/autoload/Validator.php @@ -20,7 +20,7 @@ class Validator * @param array $hits * @return void */ - private static function textHit($string, $exclude = "") + public static function textHit($string, $exclude = "") { if (empty($exclude)) return false; if (is_array($exclude)) { diff --git a/system/controllers/codecanyon.php b/system/controllers/codecanyon.php new file mode 100644 index 00000000..5406c98d --- /dev/null +++ b/system/controllers/codecanyon.php @@ -0,0 +1,118 @@ +<?php +/** + * PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/) + * by https://t.me/ibnux + **/ + +_admin(); +$ui->assign('_title', $_L['Code Canyon']); +$ui->assign('_system_menu', 'settings'); + +$plugin_repository = 'https://hotspotbilling.github.io/Plugin-Repository/repository.json'; + +$action = $routes['1']; +$admin = Admin::_info(); +$ui->assign('_admin', $admin); +$cache = File::pathFixer('system/cache/codecanyon.json'); + +if ($admin['user_type'] != 'Admin') { + r2(U . "dashboard", 'e', $_L['Do_Not_Access']); +} +if (empty($config['envato_token'])) { + r2(U . 'settings/app', 'w', '<a href="' . U . 'settings/app#envato' . '">Envato Personal Access Token</a> is not set'); +} + +switch ($action) { + + case 'install': + if (!is_writeable(File::pathFixer('system/cache/'))) { + r2(U . "codecanyon", 'e', 'Folder system/cache/ is not writable'); + } + if (!is_writeable(File::pathFixer('system/plugin/'))) { + r2(U . "codecanyon", 'e', 'Folder system/plugin/ is not writable'); + } + if (!is_writeable(File::pathFixer('system/paymentgateway/'))) { + r2(U . "codecanyon", 'e', 'Folder system/paymentgateway/ is not writable'); + } + set_time_limit(-1); + $item_id = $routes['2']; + $tipe = $routes['3']; + $result = Http::getData('https://api.envato.com/v3/market/buyer/download?item_id=' . $item_id, ['Authorization: Bearer ' . $config['envato_token']]); + $json = json_decode($result, true); + if (!isset($json['download_url'])) { + r2(U . 'codecanyon', 'e', 'Failed to get download url. ' . $json['description']); + } + $file = File::pathFixer('system/cache/codecanyon/'); + if(!file_exists($file)){ + mkdir($file); + } + $file .= $item_id . '.zip'; + if (file_exists($file)) + unlink($file); + $fp = fopen($file, 'w+'); + $ch = curl_init($json['download_url']); + curl_setopt($ch, CURLOPT_POST, 0); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 120); + curl_setopt($ch, CURLOPT_TIMEOUT, 120); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_FILE, $fp); + curl_exec($ch); + curl_close($ch); + fclose($fp); + $zip = new ZipArchive(); + $zip->open($file); + $zip->extractTo(File::pathFixer('system/cache/codecanyon/')); + $zip->close(); + die($json['download_url']); + case 'reload': + if (file_exists($cache)) unlink($cache); + default: + if (class_exists('ZipArchive')) { + $zipExt = true; + } else { + $zipExt = false; + } + $ui->assign('zipExt', $zipExt); + + if (file_exists($cache) && time() - filemtime($cache) < (24 * 60 * 60)) { + $txt = file_get_contents($cache); + $plugins = json_decode($txt, true); + $ui->assign('chached_until', date($config['date_format'] . ' H:i', filemtime($cache)+(24 * 60 * 60))); + if (count($plugins) == 0) { + unlink($cache); + r2(U . 'codecanyon'); + } + } else { + $plugins = []; + $page = _get('page', 1); + back: + $result = Http::getData('https://api.envato.com/v3/market/buyer/list-purchases?&page=' . $page, ['Authorization: Bearer ' . $config['envato_token']]); + $items = json_decode($result, true); + if ($items && count($items['results']) > 0) { + foreach ($items['results'] as $item) { + $name = strtolower($item['item']['name']); + //if(strpos($name,'phpnuxbill') !== false){ + if (strpos($name, 'wordpress') !== false) { + //if(strpos($name,'plugin') !== false){ + if (strpos($name, 'theme') !== false) { + $item['type'] = '1'; + } else if (strpos($name, 'payment gateway') !== false) { + $item['type'] = '2'; + } + if (in_array($item['type'], [1, 2])) { + $plugins[] = $item; + } + } + } + $page++; + goto back; + } + file_put_contents($cache, json_encode($plugins)); + if (file_exists($cache)){ + $ui->assign('chached_until', date($config['date_format'] . ' H:i', filemtime($cache)+(24 * 60 * 60))); + } + } + $ui->assign('plugins', $plugins); + $ui->display('codecanyon.tpl'); +} diff --git a/system/lan/english/common.lan.php b/system/lan/english/common.lan.php index 5345f97f..646d2c07 100644 --- a/system/lan/english/common.lan.php +++ b/system/lan/english/common.lan.php @@ -418,3 +418,9 @@ $_L['Voucher_activation_success_now_you_can_login'] = 'Voucher activation succes $_L['Client_Can_Purchase'] = 'Client Can Purchase'; $_L['Buy_this_your_active_package_will_be_overwritten'] = 'Buy this? your active package will be overwritten'; $_L['Pay_this_with_Balance_your_active_package_will_be_overwritten'] = 'Pay this with Balance? your active package will be overwritten'; +$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite'; +$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite'; +$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite'; +$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite'; +$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite'; +$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite'; diff --git a/ui/ui/app-settings.tpl b/ui/ui/app-settings.tpl index 12854e41..94d2708f 100644 --- a/ui/ui/app-settings.tpl +++ b/ui/ui/app-settings.tpl @@ -413,6 +413,31 @@ </div> </div> </div> + <div class="panel-heading" id="envato"> + <div class="btn-group pull-right"> + <button class="btn btn-primary btn-xs" title="save" type="submit"><span + class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span></button> + </div> + Envato / Codecanyon + </div> + <div class="panel-body"> + <div class="form-group"> + <label class="col-md-2 control-label">Envato Personal Token</label> + <div class="col-md-6"> + <input type="text" class="form-control" id="envato_token" name="envato_token" + value="{$_c['envato_token']}" placeholder="BldWuBsxxxxxxxxxxxPDzPozHAPui"> + </div> + <span class="help-block col-md-4"><a href="https://build.envato.com/create-token/" target="_blank">Create Token</a></span> + </div> + <div class="form-group"> + <label class="control-label col-md-offset-2 col-md-8" style="text-align: left;">Envato Permission<br> + - View and search Envato sites<br> + - Download the user's purchased items<br> + - List purchases the user has made<br><br> + <a href="https://codecanyon.net/category/php-scripts?term=phpnuxbill" target="_blank" class="btn btn-xs btn-primary">View MarketPlace</a> + </label> + </div> + </div> </div> <div class="panel-body"> diff --git a/ui/ui/codecanyon.tpl b/ui/ui/codecanyon.tpl new file mode 100644 index 00000000..5427bd44 --- /dev/null +++ b/ui/ui/codecanyon.tpl @@ -0,0 +1,50 @@ +{include file="sections/header.tpl"} +<div class="row"> + <div class="col-sm-12"> + <div class="panel panel-primary panel-hovered"> + <div class="panel-heading"> + <div class="btn-group pull-right"> + <a class="btn btn-danger btn-xs" href="https://codecanyon.net/category/php-scripts?term=phpnuxbill" target="_blank">Buy Plugin</a> + </div> + Plugin Purcashed + </div> + <div class="panel-body row"> + {if Lang::arrayCount($plugins) > 0} + {foreach $plugins as $plugin} + <div class="col-md-4"> + <div class="box box-hovered mb20 box-primary"> + <div class="box-header"> + <h3 class="box-title text1line">{$plugin['item']['name']}</h3> + </div> + <div class="box-body"><small><i>@{$plugin['item']['author_username']} • Last update: + {Lang::dateFormat($plugin['item']['updated_at'])}</i></small></div> + <div class="box-footer "> + <div class="btn-group btn-group-justified" role="group" aria-label="..."> + <a href="{$plugin['item']['author_url']}" target="_blank" class="btn btn-primary"><i + class="ion ion-chatboxes"></i> Author</a> + <a href="{$plugin['item']['url']}" target="_blank" class="btn btn-success"><i + class="ion ion-chatboxes"></i> Product</a> + <a {if $zipExt } href="{$_url}codecanyon/install/{$plugin['item']['id']}/{$plugin['type']}" + onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')" + {else} href="#" onclick="alert('PHP ZIP extension is not available')" + {/if} + class="btn btn-danger"><i class="ion ion-chatboxes"></i> Install</a> + </div> + </div> + </div> + </div> + {/foreach} + {else} + <div class="col-md-12"> + <div class="alert alert-info"> + <i class="fa fa-info-circle"></i> No plugins purcashed yet. + </div> + </div> + {/if} + </div> + <div class="panel-footer"> + Cached Until {$chached_until} <a href="{$_url}codecanyon/reload">Force reload</a> + </div> + </div> + </div> +{include file="sections/footer.tpl"} \ No newline at end of file diff --git a/ui/ui/plugin-manager.tpl b/ui/ui/plugin-manager.tpl index cf6f630a..364d7881 100644 --- a/ui/ui/plugin-manager.tpl +++ b/ui/ui/plugin-manager.tpl @@ -8,19 +8,21 @@ <div class="col-md-4"> <div class="box box-hovered mb20 box-primary"> <div class="box-header"> - <h3 class="box-title">{$plugin['name']}</h3> + <h3 class="box-title text1line">{$plugin['name']}</h3> + </div> + <div class="box-body" style="overflow-y: scroll;"> + <div style="max-height: 50px; min-height: 50px;">{$plugin['description']}</div> </div> - <div class="box-body">{$plugin['description']}<br><small><i>@{$plugin['author']} Last update: {$plugin['last_update']}</i></small></div> <div class="box-footer "> + <center><small><i>@{$plugin['author']} Last update: {$plugin['last_update']}</i></small></center> <div class="btn-group btn-group-justified" role="group" aria-label="..."> - <a href="{$plugin['url']}" target="_blank" - class="btn btn-primary"><i class="ion ion-chatboxes"></i> Website</a> - <a href="{$plugin['github']}" target="_blank" - class="btn btn-success"><i class="ion ion-chatboxes"></i> Github</a> - <a {if $zipExt } - href="{$_url}pluginmanager/install/plugin/{$plugin['id']}" onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')" - {else} - href="#" onclick="alert('PHP ZIP extension is not available')" + <a href="{$plugin['url']}" target="_blank" class="btn btn-primary"><i + class="ion ion-chatboxes"></i> Website</a> + <a href="{$plugin['github']}" target="_blank" class="btn btn-success"><i + class="ion ion-chatboxes"></i> Github</a> + <a {if $zipExt } href="{$_url}pluginmanager/install/plugin/{$plugin['id']}" + onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')" + {else} href="#" onclick="alert('PHP ZIP extension is not available')" {/if} class="btn btn-warning"><i class="ion ion-chatboxes"></i> Install</a> </div> @@ -37,19 +39,21 @@ <div class="col-md-4"> <div class="box box-hovered mb20 box-primary"> <div class="box-header"> - <h3 class="box-title">{$pg['name']}</h3> + <h3 class="box-title text1line">{$pg['name']}</h3> + </div> + <div class="box-body" style="overflow-y: scroll;"> + <div style="max-height: 50px; min-height: 50px;">{$pg['description']}</div> </div> - <div class="box-body">{$pg['description']}<br><small><i>@{$pg['author']} Last update: {$pg['last_update']}</i></small></div> <div class="box-footer "> + <center><small><i>@{$pg['author']} Last update: {$pg['last_update']}</i></small></center> <div class="btn-group btn-group-justified" role="group" aria-label="..."> - <a href="{$pg['url']}" target="_blank" - class="btn btn-primary"><i class="ion ion-chatboxes"></i> Website</a> - <a href="{$pg['github']}" target="_blank" - class="btn btn-success"><i class="ion ion-chatboxes"></i> Github</a> - <a {if $zipExt } - href="{$_url}pluginmanager/install/payment/{$pg['id']}" onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')" - {else} - href="#" onclick="alert('PHP ZIP extension is not available')" + <a href="{$pg['url']}" target="_blank" class="btn btn-primary"><i + class="ion ion-chatboxes"></i> Website</a> + <a href="{$pg['github']}" target="_blank" class="btn btn-success"><i + class="ion ion-chatboxes"></i> Github</a> + <a {if $zipExt } href="{$_url}pluginmanager/install/payment/{$pg['id']}" + onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')" + {else} href="#" onclick="alert('PHP ZIP extension is not available')" {/if} class="btn btn-warning"><i class="ion ion-chatboxes"></i> Install</a> </div> diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index 629d96ed..8ae45f9e 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -30,6 +30,23 @@ .select2-container .select2-selection--single .select2-selection__rendered { margin-top: 0px !important; } + + @media (min-width: 768px) { + .outer { + height: 200px + /* Or whatever */ + } + } + + .text1line { + display: block; + /* or inline-block */ + text-overflow: ellipsis; + word-wrap: break-word; + overflow: hidden; + max-height: 1em; + line-height: 1em; + } </style> {if isset($xheader)} @@ -182,7 +199,7 @@ <li {if $_routes[1] eq 'by-period'}class="active" {/if}><a href="{$_url}reports/by-period">{$_L['Period_Reports']}</a></li> <li {if $_routes[1] eq 'activation'}class="active" {/if}><a - href="{$_url}reports/activation">{Lang::T('Activation History')}</a></li> + href="{$_url}reports/activation">{Lang::T('Activation History')}</a></li> {$_MENU_REPORTS} </ul> </li> @@ -252,15 +269,20 @@ href="{$_url}settings/users">{$_L['Administrator_Users']}</a></li> <li {if $_routes[1] eq 'dbstatus'}class="active" {/if}><a href="{$_url}settings/dbstatus">{$_L['Backup_Restore']}</a></li> - <li {if $_routes[0] eq 'pluginmanager'}class="active" {/if}> - <a href="{$_url}pluginmanager">{Lang::T('Plugin Manager')}</a> - </li> <li {if $_system_menu eq 'paymentgateway'}class="active" {/if}> <a href="{$_url}paymentgateway"> <span class="text">{Lang::T('Payment Gateway')}</span> </a> </li> {$_MENU_SETTINGS} + <li {if $_routes[0] eq 'pluginmanager'}class="active" {/if}> + <a href="{$_url}pluginmanager"><i class="glyphicon glyphicon-tasks"></i> + {Lang::T('Plugin Manager')} <small class="label pull-right">Free</small></a> + </li> + <li {if $_routes[0] eq 'codecanyon'}class="active" {/if}> + <a href="{$_url}codecanyon"><i class="glyphicon glyphicon-shopping-cart"></i> + Codecanyon.net <small class="label pull-right">Paid</small></a> + </li> </ul> </li> {$_MENU_AFTER_SETTINGS} @@ -274,10 +296,10 @@ <ul class="treeview-menu"> <li {if $_routes[1] eq 'list'}class="active" {/if}><a href="{$_url}logs/phpnuxbill">PhpNuxBill</a></li> - {if $_c['radius_enable']} + {if $_c['radius_enable']} <li {if $_routes[1] eq 'radius'}class="active" {/if}><a href="{$_url}logs/radius">Radius</a> </li> - {/if} + {/if} </ul> {$_MENU_LOGS} </li> @@ -301,11 +323,11 @@ </section> <section class="content"> -{if isset($notify)} - <div class="alert alert-{if $notify_t == 's'}success{else}danger{/if}"> - <button type="button" class="close" data-dismiss="alert"> - <span aria-hidden="true">×</span> - </button> - <div>{$notify}</div> - </div> + {if isset($notify)} + <div class="alert alert-{if $notify_t == 's'}success{else}danger{/if}"> + <button type="button" class="close" data-dismiss="alert"> + <span aria-hidden="true">×</span> + </button> + <div>{$notify}</div> + </div> {/if} \ No newline at end of file