diff --git a/classes/Core.class.php b/classes/Core.class.php index 40f19c7..071b5f3 100644 --- a/classes/Core.class.php +++ b/classes/Core.class.php @@ -6,7 +6,7 @@ private $hooks = null; private $router = null; private $template = null; - + private $admin = null; public function __construct() { spl_autoload_register([ $this, 'load' ]); @@ -85,6 +85,7 @@ $this->modules = new Modules($this); $this->template = new Template($this); $this->router = new Router($this); + $this->admin = new CoreAdmin($this); $this->router->addRoute('/', function() { if(Auth::isLoggedIn()) { @@ -213,164 +214,6 @@ ]); }); - - $this->router->addRoute('/admin', function() { - if(!Auth::isLoggedIn()) { - Response::redirect('/'); - } - - $this->template->display('admin'); - }); - - $this->router->addRoute('^/admin(?:/([a-zA-Z0-9\-_]+))(?:/([a-zA-Z0-9\-_]+))?$', function($destination = null, $tab = NULL) { - $data = [ - 'tab' => $tab - ]; - - if(!Auth::isLoggedIn()) { - Response::redirect('/'); - } - - switch($destination) { - case 'server': - $uname = explode(' ', shell_exec('uname -a')); - - $uptime_array = explode(" ", exec("cat /proc/uptime")); - $seconds = round($uptime_array[0], 0); - $minutes = $seconds / 60; - $hours = $minutes / 60; - $days = floor($hours / 24); - $hours = sprintf('%02d', floor($hours - ($days * 24))); - $minutes = sprintf('%02d', floor($minutes - ($days * 24 * 60) - ($hours * 60))); - - if ($days == 0) { - $uptime = $hours . ":" . $minutes . " (hh:mm)"; - } elseif($days == 1) { - $uptime = $days . " day, " . $hours . ":" . $minutes . " (hh:mm)"; - } else { - $uptime = $days . " days, " . $hours . ":" . $minutes . " (hh:mm)"; - } - - $memory = []; - $meminfo = file('/proc/meminfo', \FILE_SKIP_EMPTY_LINES); - - foreach($meminfo AS $line) { - preg_match('/(?[a-zA-Z]+):([\s]+)(?[0-9]+)\s(?[a-zA-Z]+)$/Uis', $line, $matches); - - if(!empty($matches['name'])) { - switch(trim($matches['name'])) { - case 'MemTotal': $memory['total'] = $matches['value']; break; - case 'MemFree': $memory['free'] = $matches['value']; break; - case 'SwapTotal': $memory['total_swap'] = $matches['value']; break; - case 'SwapFree': $memory['free_swap'] = $matches['value']; break; - case 'Buffers': $memory['buffer'] = $matches['value']; break; - case 'Cached': $memory['cache'] = $matches['value']; break; - default: break; - } - } - } - - $disks = []; - $output = shell_exec('df -T -h'); - $search = [ 'G', 'M' ]; - $replace = [ ' GB', ' MB' ]; - - foreach(explode(PHP_EOL, $output) AS $index => $line) { - if($index === 0 || empty(trim($line))) { - continue; - } - - preg_match('/^(?P[\da-zA-Z\/]+)\s+(?P[\da-zA-Z\/]+)\s+(?P[0-9A-Z\.]+)\s+(?P[0-9A-Z\.]+)\s+(?P[0-9A-Z\.]+)\s+(?P\d+%)\s+(?P[\da-zA-Z\/]+)$/', $line, $matches); - - $disks[] = [ - 'filesystem' => (isset($matches['filesystem']) ? $matches['filesystem'] : NULL), - 'type' => (isset($matches['type']) ? $matches['type'] : NULL), - 'size' => (isset($matches['size']) ? str_replace($search, $replace, $matches['size']) : NULL), - 'used' => (isset($matches['used']) ? str_replace($search, $replace, $matches['used']) : NULL), - 'avail' => (isset($matches['avail']) ? str_replace($search, $replace, $matches['avail']) : NULL), - 'percent' => (isset($matches['percent']) ? $matches['percent'] : NULL), - 'mount' => (isset($matches['mount']) ? $matches['mount'] : NULL) - ]; - } - - $data['hostname'] = exec('hostname -f'); - $data['time_system'] = exec('date +\'%d %b %Y %T %Z\''); - $data['time_php'] = date('d M Y H:i:s T'); - $data['os'] = $uname[0]; - $data['kernel'] = $uname[2]; - $data['uptime'] = $uptime; - $data['memory'] = $memory; - $data['disks'] = $disks; - break; - case 'logs': - $logfiles = []; - $position = 0; - $size = 0; - $logfile = NULL; - $directories = [ - '/var/fruithost/logs/', - '/var/log/' - ]; - - if(isset($_GET['file']) && !empty($_GET['file'])) { - $logfile = Encryption::decrypt($_GET['file'], sprintf('LOGFILE::%s', Auth::getID())); - - if(!file_exists($logfile)) { - $logfile = NULL; - } - - if(!is_readable($logfile)) { - $logfile = NULL; - } - - if(!empty($logfile)) { - $logfile = explode(PHP_EOL, shell_exec(sprintf('cat %s 2>&1', $logfile))); - } - } - - do { - $size = count($directories); - $directory = $directories[$position++]; - - foreach(new \DirectoryIterator($directory) AS $info) { - if($info->isDot()) { - continue; - } - - if($info->isDir()) { - if($info->isReadable()) { - $directories[] = $info->getPathName(); - $size = count($directories); - } - continue; - } - - if(preg_match('/(\.(gz|\d)$|\-bin\.)/', $info->getPathName())) { - continue; - } - - $path = str_replace($info->getFileName(), '', $info->getPathName()); - - if(empty($logfiles[$path])) { - $logfiles[$path] = []; - } - - $logfiles[$path][] = $info->getFileName(); - } - } while($size > $position); - - $data['logfile'] = $logfile; - $data['logfiles'] = $logfiles; - break; - case 'modules': - $data['repositorys'] = Database::fetch('SELECT * FROM `' . DATABASE_PREFIX . 'repositorys`'); - $data['modules'] = $this->modules; - break; - } - - $this->template->display('admin' . (!empty($destination) ? sprintf('/%s', $destination) : ''), $data); - }); - $this->router->addRoute('/login', function() { if(Auth::isLoggedIn()) { Response::redirect('/'); diff --git a/classes/CoreAdmin.class.php b/classes/CoreAdmin.class.php new file mode 100644 index 0000000..00c3c6d --- /dev/null +++ b/classes/CoreAdmin.class.php @@ -0,0 +1,207 @@ +addModal((new Modal('add_repository', 'Add Repository', dirname(__DIR__) . '/views/admin/repository_create.php'))->addButton([ + (new Button())->setName('cancel')->setLabel('Cancel')->addClass('btn-outline-danger')->setDismissable(), + (new Button())->setName('create')->setLabel('Create')->addClass('btn-outline-success') + ])->onSave([ $this, 'onCreateRepository' ])); + + $this->getRouter()->addRoute('/admin', function() { + if(!Auth::isLoggedIn()) { + Response::redirect('/'); + } + + $this->template->display('admin'); + }); + + $this->getRouter()->addRoute('^/admin(?:/([a-zA-Z0-9\-_]+))(?:/([a-zA-Z0-9\-_]+))?$', function($destination = null, $tab = NULL) { + $data = [ + 'tab' => $tab + ]; + + if(!Auth::isLoggedIn()) { + Response::redirect('/'); + } + + switch($destination) { + case 'server': + $uname = explode(' ', shell_exec('uname -a')); + + $uptime_array = explode(" ", exec("cat /proc/uptime")); + $seconds = round($uptime_array[0], 0); + $minutes = $seconds / 60; + $hours = $minutes / 60; + $days = floor($hours / 24); + $hours = sprintf('%02d', floor($hours - ($days * 24))); + $minutes = sprintf('%02d', floor($minutes - ($days * 24 * 60) - ($hours * 60))); + + if($days == 0) { + $uptime = $hours . ":" . $minutes . " (hh:mm)"; + } elseif($days == 1) { + $uptime = $days . " day, " . $hours . ":" . $minutes . " (hh:mm)"; + } else { + $uptime = $days . " days, " . $hours . ":" . $minutes . " (hh:mm)"; + } + + $memory = []; + $meminfo = file('/proc/meminfo', \FILE_SKIP_EMPTY_LINES); + + foreach($meminfo AS $line) { + preg_match('/(?[a-zA-Z]+):([\s]+)(?[0-9]+)\s(?[a-zA-Z]+)$/Uis', $line, $matches); + + if(!empty($matches['name'])) { + switch(trim($matches['name'])) { + case 'MemTotal': $memory['total'] = $matches['value']; break; + case 'MemFree': $memory['free'] = $matches['value']; break; + case 'SwapTotal': $memory['total_swap'] = $matches['value']; break; + case 'SwapFree': $memory['free_swap'] = $matches['value']; break; + case 'Buffers': $memory['buffer'] = $matches['value']; break; + case 'Cached': $memory['cache'] = $matches['value']; break; + default: break; + } + } + } + + $disks = []; + $output = shell_exec('df -T -h'); + $search = [ 'G', 'M' ]; + $replace = [ ' GB', ' MB' ]; + + foreach(explode(PHP_EOL, $output) AS $index => $line) { + if($index === 0 || empty(trim($line))) { + continue; + } + + preg_match('/^(?P[\da-zA-Z\/]+)\s+(?P[\da-zA-Z\/]+)\s+(?P[0-9A-Z\.]+)\s+(?P[0-9A-Z\.]+)\s+(?P[0-9A-Z\.]+)\s+(?P\d+%)\s+(?P[\da-zA-Z\/]+)$/', $line, $matches); + + $disks[] = [ + 'filesystem' => (isset($matches['filesystem']) ? $matches['filesystem'] : NULL), + 'type' => (isset($matches['type']) ? $matches['type'] : NULL), + 'size' => (isset($matches['size']) ? str_replace($search, $replace, $matches['size']) : NULL), + 'used' => (isset($matches['used']) ? str_replace($search, $replace, $matches['used']) : NULL), + 'avail' => (isset($matches['avail']) ? str_replace($search, $replace, $matches['avail']) : NULL), + 'percent' => (isset($matches['percent']) ? $matches['percent'] : NULL), + 'mount' => (isset($matches['mount']) ? $matches['mount'] : NULL) + ]; + } + + $data['hostname'] = exec('hostname -f'); + $data['time_system'] = exec('date +\'%d %b %Y %T %Z\''); + $data['time_php'] = date('d M Y H:i:s T'); + $data['os'] = $uname[0]; + $data['kernel'] = $uname[2]; + $data['uptime'] = $uptime; + $data['memory'] = $memory; + $data['disks'] = $disks; + break; + case 'logs': + $logfiles = []; + $position = 0; + $size = 0; + $logfile = NULL; + $directories = [ + '/var/fruithost/logs/', + '/var/log/' + ]; + + if(isset($_GET['file']) && !empty($_GET['file'])) { + $logfile = Encryption::decrypt($_GET['file'], sprintf('LOGFILE::%s', Auth::getID())); + + if(!file_exists($logfile)) { + $logfile = NULL; + } + + if(!is_readable($logfile)) { + $logfile = NULL; + } + + if(!empty($logfile)) { + $logfile = explode(PHP_EOL, shell_exec(sprintf('cat %s 2>&1', $logfile))); + } + } + + do { + $size = count($directories); + $directory = $directories[$position++]; + + foreach(new \DirectoryIterator($directory) AS $info) { + if($info->isDot()) { + continue; + } + + if($info->isDir()) { + if($info->isReadable()) { + $directories[] = $info->getPathName(); + $size = count($directories); + } + continue; + } + + if(preg_match('/(\.(gz|\d)$|\-bin\.)/', $info->getPathName())) { + continue; + } + + $path = str_replace($info->getFileName(), '', $info->getPathName()); + + if(empty($logfiles[$path])) { + $logfiles[$path] = []; + } + + $logfiles[$path][] = $info->getFileName(); + } + } while($size > $position); + + $data['logfile'] = $logfile; + $data['logfiles'] = $logfiles; + break; + case 'modules': + $upgradeable = []; + $list = sprintf('%s%s%s%s%s', dirname(PATH), DS, 'temp', DS, 'update.list'); + + if(file_exists($list)) { + $upgradeable = json_decode(file_get_contents($list)); + } + + $data['upgradeable'] = $upgradeable; + $data['repositorys'] = Database::fetch('SELECT * FROM `' . DATABASE_PREFIX . 'repositorys`'); + $data['modules'] = $this->getModules(); + break; + } + + $this->getTemplate()->display('admin' . (!empty($destination) ? sprintf('/%s', $destination) : ''), $data); + }); + } + + public function onCreateRepository($data = []) { + if(empty($data['repository_url']) || !filter_var($data['repository_url'], FILTER_VALIDATE_URL)) { + return 'Please enter an valid repository URL!'; + } + + $repositorys = Database::fetch('SELECT * FROM `' . DATABASE_PREFIX . 'repositorys` WHERE `url`=:url', [ + 'url' => $data['repository_url'] + ]); + + if(count($repositorys) > 0) { + return 'Repository already exists!'; + } else { + Database::insert(DATABASE_PREFIX . 'repositorys', [ + 'id' => null, + 'url' =>$data['repository_url'], + 'time_updated' => NULL + ]); + } + + return true; + } + } +?> \ No newline at end of file diff --git a/classes/Module.class.php b/classes/Module.class.php index 63f9d0c..032835c 100644 --- a/classes/Module.class.php +++ b/classes/Module.class.php @@ -24,6 +24,14 @@ return $this->instance; } + public function getPath() { + return $this->path; + } + + public function getDirectory() { + return basename($this->path); + } + public function isEnabled() { return $this->enabled; } diff --git a/classes/ModuleInterface.class.php b/classes/ModuleInterface.class.php index 45e9656..bf881cf 100644 --- a/classes/ModuleInterface.class.php +++ b/classes/ModuleInterface.class.php @@ -18,6 +18,18 @@ /* Override Me */ } + public function getRouter() { + return $this->core->getRouter(); + } + + public function getModules() { + return $this->core->getModules(); + } + + public function getTemplate() { + return $this->core->getTemplate(); + } + public function getCore() { return $this->core; } diff --git a/classes/Modules.class.php b/classes/Modules.class.php index fc11ee4..a66e715 100644 --- a/classes/Modules.class.php +++ b/classes/Modules.class.php @@ -38,9 +38,9 @@ $name = basename($path); if($this->hasModule($name)) { - $modules[] = $this->getModule($name); + $modules[$name] = $this->getModule($name); } else { - $modules[] = $module; + $modules[$name] = $module; } } diff --git a/default/admin/modules.php b/default/admin/modules.php index 3c17d4b..607d0f8 100644 --- a/default/admin/modules.php +++ b/default/admin/modules.php @@ -25,7 +25,7 @@ case 'repositorys': ?>
- +
@@ -43,9 +43,14 @@ ?> - - - - - - - + + if(count($repositorys) === 0) { + ?> +
+ sentiment_very_dissatisfied +

No Repositorys available!

+

Please adding some Repositorys to keep updates.

+ +
+ } else { + ?> +
RepositoryStatusActions
- - - - + + + -
- url; ?> - - time_updated)); ?> - RepositoryStatusActions
- + + + + url; ?> + + + time_updated)) { + print 'Never updated'; + } else { + print date(Auth::getSettings('TIME_FORMAT', NULL, 'd.m.Y - H:i'), strtotime($repository->time_updated)); + } + ?> + + + + + + + + + @@ -116,12 +142,27 @@ $links['enable'] = 'Enable'; } + if(isset($upgradeable->{$module->getDirectory()})) { + $links['upgrade'] = 'Upgrade'; + } + $links['deinstall'] = 'Deinstall'; print implode(' | ', $links); ?>

+ {$module->getDirectory()})) { + $upgrade = $upgradeable->{$module->getDirectory()}; + ?> + +

getDescription(); ?>

Version getVersion(); ?> | by getAuthor()->getName(); ?> @@ -138,6 +179,19 @@ + footer(); ?> \ No newline at end of file diff --git a/handler/admin/modules.php b/handler/admin/modules.php new file mode 100644 index 0000000..ceac9e2 --- /dev/null +++ b/handler/admin/modules.php @@ -0,0 +1,113 @@ + $repository + ]); + } + } else { + $repositorys = Database::fetch('SELECT * FROM `' . DATABASE_PREFIX . 'repositorys`'); + } + + if(count($repositorys) === 0) { + #print "EMPTY"; + } else { + $count = 0; + $updateable = []; + $packages = []; + $conflicts = []; + $installed = $this->getCore()->getModules()->getList(); + + foreach($repositorys AS $entry) { + // Load GitHub by RAW + if(preg_match('/github\.com\/([^\/]+)\/(.*)(?:\/)?$/Uis', $entry->url, $matches)) { + $entry->url = sprintf('https://raw.githubusercontent.com/%s/%s/master', $matches[1], rtrim($matches[2], '/')); + } + + $list = @file_get_contents(sprintf('%s/modules.list', $entry->url)); + + if(empty($list)) { + continue; + } + + $modules = explode(PHP_EOL, $list); + $loaded = 0; + + foreach($modules AS $name) { + $info = file_get_contents(sprintf('%s/%s/module.package', $entry->url, $name)); + + if(!isset($conflicts[$name])) { + $conflicts[$name] = []; + } + + $conflicts[$name][] = $entry; + + ++$loaded; + + if(isset($packages[$name])) { + continue; + } + + $packages[$name] = $info; + + if(empty($info)) { + continue; + } + + if(!isset($installed[$name])) { + continue; + } + + $check = $installed[$name]; + $remote = json_decode($info); + + if(!empty($check) && !empty($remote) && isset($remote->version) && version_compare($remote->version, $check->getInfo()->getVersion(), '>')) { + $updateable[$name] = $remote; + } + } + + Database::update(DATABASE_PREFIX . 'repositorys', 'id', [ + 'id' => $entry->id, + 'time_updated' => date('Y-m-d H:i:s', time()) + ]); + + ++$count; + } + } + + file_put_contents(sprintf('%s%s%s%s%s', dirname(PATH), DS, 'temp', DS, 'update.list'), json_encode($updateable)); + + $this->assign('success', sprintf('%d Repository%s was updated. Found %d related Update%s!', $count, ($count === 1 ? '' : 's'), count($updateable), (count($updateable) === 1 ? '' : 's'))); + $this->assign('repositorys', Database::fetch('SELECT * FROM `' . DATABASE_PREFIX . 'repositorys`')); + break; + case 'delete': + $messages = []; + + if(isset($_POST['repository'])) { + foreach($_POST['repository'] AS $repository) { + Database::delete(DATABASE_PREFIX . 'repositorys', [ + 'id' => $repository + ]); + } + + $messages[] = sprintf('%d Repositorys was successfully removed', count($_POST['repository'])); + + $this->assign('repositorys', Database::fetch('SELECT * FROM `' . DATABASE_PREFIX . 'repositorys`')); + } + + if(count($messages) > 0) { + $this->assign('success', implode(' and ', $messages)); + } else { + $this->assign('error', 'Please select some entries you want to delete.'); + } + break; + } + } +?> \ No newline at end of file diff --git a/views/admin/repository_create.php b/views/admin/repository_create.php new file mode 100644 index 0000000..9cd4cb5 --- /dev/null +++ b/views/admin/repository_create.php @@ -0,0 +1,11 @@ + +
+
+ +
+ +
+
+
\ No newline at end of file