diff options
Diffstat (limited to 'ncp-web')
-rw-r--r-- | ncp-web/L10N.php | 9 | ||||
-rw-r--r-- | ncp-web/css/ncp.css (renamed from ncp-web/ncp.css) | 72 | ||||
-rw-r--r-- | ncp-web/elements.php | 154 | ||||
-rw-r--r-- | ncp-web/img/files.svg | 1 | ||||
-rw-r--r-- | ncp-web/index.php | 91 | ||||
-rw-r--r-- | ncp-web/js/minified.js (renamed from ncp-web/minified.js) | 0 | ||||
-rw-r--r-- | ncp-web/js/ncp.js (renamed from ncp-web/ncp.js) | 123 | ||||
-rw-r--r-- | ncp-web/ncp-launcher.php | 289 | ||||
-rw-r--r-- | ncp-web/ncp-output.php | 7 | ||||
-rw-r--r-- | ncp-web/sidebar.php | 64 |
10 files changed, 425 insertions, 385 deletions
diff --git a/ncp-web/L10N.php b/ncp-web/L10N.php index 2fdf5434..d786413b 100644 --- a/ncp-web/L10N.php +++ b/ncp-web/L10N.php @@ -69,7 +69,6 @@ class L10N function save($lang) { $cfg = 'ncp-web.cfg'; - $line = file_get_contents( $cfg ); $str = "LANGUAGE_=$lang"; return file_put_contents( $cfg , $str ); } @@ -141,12 +140,14 @@ class L10N function load_language_setting() { - $webui_config_file = 'ncp-web.cfg'; - $fh = fopen($webui_config_file, 'r'); + $cfg = 'ncp-web.cfg'; + if (!file_exists($cfg)) + return "auto"; + $fh = fopen($cfg, 'r'); if ($fh === false) return "auto"; - $lang=file_get_contents($webui_config_file); + $lang=file_get_contents($cfg); fclose($fh); return ltrim($lang, 'LANGUAGE_='); } diff --git a/ncp-web/ncp.css b/ncp-web/css/ncp.css index e379824f..bfd2a1cb 100644 --- a/ncp-web/ncp.css +++ b/ncp-web/css/ncp.css @@ -233,7 +233,7 @@ select { -webkit-appearance:none; -moz-appearance:none; appearance:none; - background:url('../../../core/css/../img/actions/triangle-s.svg') no-repeat right 4px center; + #background:url('../../../core/css/../img/actions/triangle-s.svg') no-repeat right 4px center; background-color:inherit; outline:0; padding-right:24px !important @@ -410,7 +410,7 @@ input[type='checkbox'].checkbox--white:indeterminate:disabled + label:after,inpu } #header .logo { - background-image:url("logo.svg"); + background-image:url("../img/logo.svg"); background-repeat:no-repeat; background-size:175px; background-position:center; @@ -425,7 +425,7 @@ input[type='checkbox'].checkbox--white:indeterminate:disabled + label:after,inpu } #header .logo-icon { display:inline-block; - background-image:url('img/ncp-logo.svg'); + background-image:url('../img/ncp-logo.svg'); background-repeat:no-repeat; background-position:center center; background-size:contain; @@ -599,7 +599,7 @@ kbd { overflow:auto; box-sizing:border-box } -#app-navigation > ul > li:focus,#app-navigation > ul > li:hover,#app-navigation > ul > li.active,#app-navigation > ul > li a.selected,#app-navigation > ul > li:focus > a,#app-navigation > ul > li:hover > a,#app-navigation > ul > li.active > a,#app-navigation > ul > li a.selected > a { +#app-navigation > ul > li:focus,#app-navigation ul:hover,#app-navigation ul.active,#app-navigation > ul > li a.selected,#app-navigation > ul > li:focus > a,#app-navigation > ul > li:hover > a,#app-navigation > ul > li.active > a,#app-navigation > ul > li a.selected > a { opacity:1; box-shadow:inset 2px 0 #0082c9 } @@ -626,7 +626,7 @@ kbd { background-position:14px center; background-repeat:no-repeat } -#app-navigation li > a { +#app-navigation li > span, #app-navigation ul { display:block; width:90%; line-height:44px; @@ -637,7 +637,19 @@ kbd { white-space:nowrap; text-overflow:ellipsis; color:#000; - opacity:0.57 + opacity:0.57; + font-weight: normal; +} +#app-navigation li > span { + font-weight: bold; + background-image:url('../img/files.svg'); + background-size: 16px 16px; + background-position: 10px center; + background-repeat: no-repeat; + padding: 0px 12px 0px 36px; +} +#app-navigation ul { + padding-left: 2em; } #app-navigation li > a:first-child img { margin-bottom:-3px; @@ -655,7 +667,7 @@ kbd { margin:0; padding:0; background:none; - background-image:url('../../../core/css/../img/actions/triangle-s.svg?v=1'); +#background-image:url('../../../core/css/../img/actions/triangle-s.svg?v=1'); background-size:16px; background-repeat:no-repeat; background-position:center; @@ -685,10 +697,11 @@ kbd { -ms-transform:rotate(0); transform:rotate(0) } -#app-navigation > { +#app-navigation { + overflow-y: scroll } #app-navigation > ul ul { - display:none + /* display:none */ } #app-navigation > ul ul li > a { padding-left:32px @@ -832,6 +845,7 @@ kbd { border-left:0; margin-right:0 } + #app-content { position:relative; height:100%; @@ -1058,7 +1072,7 @@ select { width: 100%; } -#loading-gif { +.loading-gif { display: none; } @@ -1073,23 +1087,23 @@ select { text-align: center; } -#config-box-info-txt { +.config-box-info-txt { white-space: pre-wrap; text-align: center; } -#config-button-wrapper { +.config-button-wrapper { display: flex; align-items: center; justify-content: center; } .icon-close { - background-image:url('img/close.svg') + background-image:url('../img/close.svg') } .icon-menu { - background-image: url('img/menu.svg'); + background-image: url('../img/menu.svg'); } #power { @@ -1117,43 +1131,43 @@ select { } .icon-power-white { - background-image: url('img/poweroff.svg'); + background-image: url('../img/poweroff.svg'); } .icon-nc-white { - background-image: url('img/nc-button.svg'); + background-image: url('../img/nc-button.svg'); } .icon-nc-info { - background-image: url('img/info-white.svg'); + background-image: url('../img/info-white.svg'); } .icon-config { - background-image: url('img/settings-white.svg'); + background-image: url('../img/settings-white.svg'); } .icon-reboot-white { - background-image: url('img/reboot.svg'); + background-image: url('../img/reboot.svg'); } .icon-dashboard { - background-image: url('img/dashboard.svg'); + background-image: url('../img/dashboard.svg'); } .icon-wizard-white { - background-image: url('img/wizard.svg'); + background-image: url('../img/wizard.svg'); } .icon-red-circle { - background-image: url('img/red-circle.svg'); + background-image: url('../img/red-circle.svg'); padding: 8px; display: none; } .icon-green-circle { - background-image: url('img/green-circle.svg'); + background-image: url('../img/green-circle.svg'); padding: 8px; } .icon-info { - background-image: url('img/info.svg'); - padding: 8px; - float: right; - display: none; + background-image: url('../img/info.svg'); + position: absolute; + top: 5px; + right: 1em; } #expand #expandDisplayName { @@ -1230,7 +1244,7 @@ a#versionlink:hover { right: 5px; display: block; background: none; - background-image:url('img/view-close.svg'); + background-image:url('../img/view-close.svg'); width: 38px; height: 19px; text-indent: -9999px; @@ -1311,7 +1325,7 @@ a#versionlink:hover { overflow:hidden } -#details-box { +.details-box { background-color: #fbfbfb; border: solid 1px lightgray; color: #565656; diff --git a/ncp-web/elements.php b/ncp-web/elements.php new file mode 100644 index 00000000..dafb3aad --- /dev/null +++ b/ncp-web/elements.php @@ -0,0 +1,154 @@ +<?php +/// +// NextCloudPi Web Panel Side bar +// +// Copyleft 2018 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com> +// GPL licensed (see end of file) * Use at your own risk! +// +// More at https://ownyourbits.com/2017/02/13/nextcloud-ready-raspberry-pi-image/ +/// + +// fill options with contents from directory + +function print_config_form( $ncp_app, $cfg, $l ) +{ + $ret = <<<HTML + <div id="config-box"> + <table> +HTML; + + foreach ($cfg['params'] as $param) + { + $ret .= "<tr>"; + $ret .= "<td><label for=\"$ncp_app-$param[id]\">$param[name]</label></td>"; + + // default to text input + if (!array_key_exists('type', $param)) + { + $ret .= "<td><input type=\"text\" name=\"$param[name]\" id=\"$ncp_app-$param[id]\" value=\"$param[value]\" size=\"40\"></td>"; + } + + // checkbox + else if ($param['type'] == 'bool') + { + $checked = ""; + if ($param['value'] == 'yes') + $checked = 'checked'; + $ret .= "<td><input type=\"checkbox\" id=\"$ncp_app-$param[id]\" name=\"$param[name]\" value=\"$param[value]\" $checked></td>"; + } + $ret .= "</tr>"; + } + + $ret .= <<<HTML + </table> + </div> + <div class="config-button-wrapper"> + <button id="$ncp_app-config-button" class="config-button">Run</button> + <img class="loading-gif" src="img/loading-small.gif"> + <div class="circle-retstatus" class="icon-red-circle"></div> + </div> + </form> +HTML; + return $ret; +} + +function print_config_forms( $l /* translations l10n object */ ) +{ + $bin_dir = '/usr/local/bin/ncp/'; + $cfg_dir = '/usr/local/etc/ncp-config.d/'; + $d_iterator = new RecursiveDirectoryIterator($bin_dir); + $iterator = new RecursiveIteratorIterator($d_iterator); + $objects = new RegexIterator($iterator, '/^.+\.sh$/i', RecursiveRegexIterator::GET_MATCH); + + $ret = ""; + $sections = array_diff(scandir($bin_dir), array('.', '..', 'l10n')); + foreach ($sections as $section) + { + $scripts = array_diff(scandir($bin_dir . $section), array('.', '..', 'nc-wifi.sh', 'nc-info.sh')); + foreach ($scripts as $script) + { + $ncp_app = pathinfo($script, PATHINFO_FILENAME); + $cfg_file = $cfg_dir . $ncp_app . ".cfg"; + $cfg = json_decode(file_get_contents($cfg_file), true); + + $hidden = 'hidden'; + if (array_key_exists('app',$_GET) && $_GET['app'] == $ncp_app) + $hidden = ''; + $ret .= <<<HTML + <div id="$cfg[id]-config-box" class="$hidden"> + <h2 class="text-title">$cfg[description]</h2> + <div class="config-box-info-txt">$cfg[info]</div> + <a href="#" target="_blank"> + <div class="icon-info"></div> + </a> + <br/> + <div class="table-wrapper"> +HTML; + + $ret .= print_config_form($ncp_app, $cfg, $l); + $ret .= <<<HTML + <div id="$ncp_app-details-box" class="details-box outputbox hidden"></div> + </div> + </div> +HTML; + } + } + return $ret; +} + +function print_sidebar( $l /* translations l10n object */, $ticks /* wether to calculate ticks(slow) */ ) +{ + $bin_dir = '/usr/local/bin/ncp/'; + $cfg_dir = '/usr/local/etc/ncp-config.d/'; + $d_iterator = new RecursiveDirectoryIterator($bin_dir); + $iterator = new RecursiveIteratorIterator($d_iterator); + $objects = new RegexIterator($iterator, '/^.+\.sh$/i', RecursiveRegexIterator::GET_MATCH); + + $ret = ""; + $sections = array_diff(scandir($bin_dir), array('.', '..', 'l10n')); + foreach ($sections as $section) + { + $ret .= "<li id=\"$section\" class=\"nav-recent\"><span>{$l->__($section, $section)}</span>"; + + $scripts = array_diff(scandir($bin_dir . $section), array('.', '..', 'nc-wifi.sh', 'nc-info.sh')); + foreach ($scripts as $script) + { + $ncp_app = pathinfo($script, PATHINFO_FILENAME); + $cfg_file = $cfg_dir . $ncp_app . ".cfg"; + $cfg = json_decode(file_get_contents($cfg_file), true); + + $active = ""; + if ( $ticks ) { + exec("bash -c \"source /usr/local/etc/library.sh && is_active_app $ncp_app\"", $output, $retval); + if ($retval == 0) + $active = " ✓"; + } else if (sizeof($cfg['params']) > 0 && $cfg['params'][0]['id'] == 'ACTIVE' && $cfg['params'][0]['value'] == 'yes') + $active = " ✓"; + + $ret .= "<ul id=\"$ncp_app\" class=\"nav-recent\">"; + $ret .= "<a href=\"#\"> {$l->__($ncp_app, $ncp_app)}$active </a>"; + $ret .= "</ul>"; + } + $ret .= "</li>"; + } + + return $ret; +} + +// License +// +// This script is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This script is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this script; if not, write to the +// Free Software Foundation, Inc., 59 Temple Place, Suite 330, +// Boston, MA 02111-1307 USA +?> diff --git a/ncp-web/img/files.svg b/ncp-web/img/files.svg new file mode 100644 index 00000000..15365027 --- /dev/null +++ b/ncp-web/img/files.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" version="1.1" height="16"><path d="m1.5 2c-0.25 0-0.5 0.25-0.5 0.5v11c0 0.26 0.24 0.5 0.5 0.5h13c0.26 0 0.5-0.241 0.5-0.5v-9c0-0.25-0.25-0.5-0.5-0.5h-6.5l-2-2z"/></svg> diff --git a/ncp-web/index.php b/ncp-web/index.php index d12b6c0f..fdd30260 100644 --- a/ncp-web/index.php +++ b/ncp-web/index.php @@ -17,15 +17,19 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"> <meta name="mobile-web-app-capable" content="yes"> <?php + // redirect to activation first time exec("a2query -s ncp-activation", $output, $ret); if ($ret == 0) { header("Location: activate"); exit(); } + ini_set('session.cookie_httponly', 1); + if (isset($_SERVER['HTTPS'])) + ini_set('session.cookie_secure', 1); session_start(); - include('sidebar.php'); + include('elements.php'); $modules_path = '/usr/local/etc/ncp-config.d/'; $l10nDir = "l10n"; @@ -38,16 +42,14 @@ header("X-Frame-Options: DENY"); header("Cache-Control: no-cache"); header('Pragma: no-cache'); - ini_set('session.cookie_httponly', 1); - if (isset($_SERVER['HTTPS'])) - ini_set('session.cookie_secure', 1); + header('Expires: -1'); // HTTP2 push headers - header("Link: </minified.js>; rel=preload; as=script;,</ncp.js>; rel=preload; as=script;,</ncp.css>; rel=preload; as=style;,</img/ncp-logo.svg>; rel=preload; as=image;, </img/loading-small.gif>; rel=preload; as=image;, rel=preconnect href=ncp-launcher.php;"); + header("Link: </js/minified.js>; rel=preload; as=script;,</js/ncp.js>; rel=preload; as=script;,</css/ncp.css>; rel=preload; as=style;,</img/ncp-logo.svg>; rel=preload; as=image;, </img/loading-small.gif>; rel=preload; as=image;, rel=preconnect href=ncp-launcher.php;"); ?> <link rel="icon" type="image/png" href="img/favicon.png"/> - <link rel="stylesheet" href="ncp.css"> + <link rel="stylesheet" href="css/ncp.css"> </head> <body id="body-user"> <?php @@ -70,9 +72,13 @@ <?php exec("ncp-test-updates", $output, $ret); if ($ret == 0) { + $version = "v0.0"; + $ver_file = '/var/run/.ncp-latest-version'; + if (file_exists($ver_file)) + $version = file_get_contents($ver_file); echo '<div id="notification">'; echo '<div id="update-notification" class="row type-error closeable">'; - echo "version " . file_get_contents( '/var/run/.ncp-latest-version' ) . " is available"; + echo "version " . $version . " is available"; echo '<a class="action close icon-close" href="#" alt="Dismiss"></a>'; echo '</div>'; echo '</div>'; @@ -110,25 +116,30 @@ HTML; </div> </a> <a id=versionlink target="_blank" href="https://github.com/nextcloud/nextcloudpi/blob/master/changelog.md"> - <?php echo file_get_contents( "/usr/local/etc/ncp-version" ) ?> + <?php + $version = "v0.0"; + $ver_file = "/usr/local/etc/ncp-version"; + if (file_exists($ver_file)) + $version = file_get_contents($ver_file); + echo $version; + ?> </a> -<?php - // language selection drop - $selected_lang=$l->load_language_setting(); + <?php + // language selection drop + $selected_lang=$l->load_language_setting(); - $fh = fopen('langs.cfg', 'r'); - echo "<select id=\"language-selection\" name=\"language-selection\">"; - while ($line = fgets($fh)) { - echo "<option value='" . $line . "' "; - error_log("NACHO $line - $selected_lang"); - if( $line == $selected_lang ) - echo "selected='selected'"; - echo ">". $line ."</option>"; - } - echo "<option value=\"[new]\">new..</option>"; - echo "</select>"; - fclose($fh); -?> + $fh = fopen('langs.cfg', 'r'); + echo "<select id=\"language-selection\" name=\"language-selection\">"; + while ($line = fgets($fh)) { + echo "<option value='" . $line . "' "; + if( $line == $selected_lang ) + echo "selected='selected'"; + echo ">". $line ."</option>"; + } + echo "<option value=\"[new]\">new..</option>"; + echo "</select>"; + fclose($fh); + ?> </div> <div id="header-right"> <a href="https://ownyourbits.com" id="nextcloud-btn" target="_blank" tabindex="1" title="<?php echo $l->__("Launch Nextcloud"); ?>"> @@ -174,42 +185,26 @@ HTML; <div id="content" class="app-files" role="main"> <div id='overlay' class="hidden"></div> <div id="app-navigation"> - <ul id="ncp-options"> + <div id="ncp-options"> <?php echo print_sidebar($l, false); ?> - </ul> + </div> </div> <div id="app-content"> <div id="app-navigation-toggle" class="icon-menu hidden"></div> - <div id="config-wrapper" class="hidden"> - <h2 id="config-box-title" class="text-title"><?php echo $l->__("System Info"); ?></h2> - <div id="config-box-info-txt"></div> - <a href="#" target="_blank"> - <div id="config-extra-info" class="icon-info"></div> - </a> - <br/> - <div id="config-box-wrapper" class="table-wrapper"> - <form> - <div id="config-box"></div> - <div id="config-button-wrapper"> - <button id="config-button"><?php echo $l->__("Run"); ?></button> - <img id="loading-gif" src="img/loading-small.gif"> - <div id="circle-retstatus" class="icon-red-circle"></div> - </div> - </form> - <div id="details-box" class="outputbox"></div> - </div> + <div id="config-wrapper"> + <?php echo print_config_forms($l); ?> </div> - <div id="dashboard-wrapper"> + <div id="dashboard-wrapper" <?php if(array_key_exists('app',$_GET) && ($_GET['app'] != 'dashboard')) echo 'class="hidden"'; ?>> <h2 class="text-title"><?php echo $l->__("System Info"); ?></h2> <div id="dashboard-suggestions" class="table-wrapper"></div> <div id="dashboard-table" class="outputbox table-wrapper"></div> <div id="loading-info-gif"> <img src="img/loading-small.gif"> </div> </div> - <div id="nc-config-wrapper" class="hidden"> + <div id="nc-config-wrapper" <?php if($_GET['app'] != 'config') echo 'class="hidden"';?>> <h2 class="text-title"><?php echo $l->__("Nextcloud configuration"); ?></h2> <div id="nc-config-box" class="table-wrapper"> <?php @@ -253,8 +248,8 @@ HTML; echo '<input type="hidden" id="csrf-token-ui" name="csrf-token-ui" value="' . getCSRFToken() . '"/>'; echo '<input type="hidden" id="csrf-token-cfg" name="csrf-token-cfg" value="' . getCSRFToken() . '"/>'; ?> - <script src="minified.js"></script> - <script src="ncp.js"></script> + <script src="js/minified.js"></script> + <script src="js/ncp.js"></script> </body> </html> diff --git a/ncp-web/minified.js b/ncp-web/js/minified.js index 251866b7..251866b7 100644 --- a/ncp-web/minified.js +++ b/ncp-web/js/minified.js diff --git a/ncp-web/ncp.js b/ncp-web/js/ncp.js index fa53b714..3f4e6d38 100644 --- a/ncp-web/ncp.js +++ b/ncp-web/js/ncp.js @@ -12,17 +12,28 @@ var $ = MINI.$, $$ = MINI.$$, EE = MINI.EE; var selectedID = null; var lock = false; +// URL based navigation +window.onpopstate = function(event) { + var ncp_app = location.search.split('=')[1]; + if (ncp_app == 'config') + switch_to_section('nc-config'); + else if (ncp_app == 'dashboard') + switch_to_section('dashboard'); + else + app_clicked($('#' + ncp_app)); +}; + function errorMsg() { $('#config-box').fill( "Something went wrong. Try refreshing the page" ); } -function switch_to_section( name ) +function switch_to_section(section) { - $( '#config-wrapper' ).hide(); - $( '#dashboard-wrapper' ).hide(); - $( '#nc-config-wrapper' ).hide(); - $( '#' + name + '-wrapper' ).show(); + $( '#config-wrapper > div' ).hide(); + $( '#dashboard-wrapper' ).hide(); + $( '#nc-config-wrapper' ).hide(); + $( '#' + section + '-wrapper' ).show(); $( '#' + selectedID ).set('-active'); selectedID = null; } @@ -81,27 +92,19 @@ function disable_slide_menu() function set_sidebar_click_handlers() { // Show selected option configuration box - $( 'li' , '#app-navigation' ).on('click', function(e) + $( 'ul' , '#app-navigation' ).on('click', function(e) { if ( selectedID == this.get( '.id' ) ) // already selected return; if ( lock ) return; - lock = true; if ( window.innerWidth <= 768 ) close_menu(); $( '#' + selectedID ).set('-active'); - var that = this; - $.request('post', 'ncp-launcher.php', { action:'cfgreq', - ref:this.get('.id') , - csrf_token: $( '#csrf-token' ).get( '.value' ) }).then( - function success( result ) - { - cfgreqReceive( result, that ); - lock = false; - }).error( errorMsg ); + app_clicked(this); + history.pushState(null, selectedID, "?app=" + selectedID); }); } @@ -139,24 +142,17 @@ function reload_sidebar() }).error( errorMsg ); } -function cfgreqReceive( result, item ) +function app_clicked(item) { - var ret = $.parseJSON( result ); - if ( ret.token ) - $('#csrf-token').set( { value: ret.token } ); - - switch_to_section( 'config' ); + $('.details-box').hide(); + $('.circle-retstatus').hide(); + $('#' + selectedID + '-config-box').hide(); + switch_to_section('config'); selectedID = item.get('.id'); - item.set( '+active' ); - - $('#details-box' ).hide(); - $('#circle-retstatus').hide(); - $('#config-box').ht( ret.output ); - $('#config-box-title' ).fill( $( '#' + selectedID + '-desc' ).get( '.value' ) ); - $('#config-box-info-txt' ).fill( $( '#' + selectedID + '-info' ).get( '.value' ) ); - $('#config-box-wrapper').show(); - $('#config-extra-info').set( { $display: 'inline-block' } ); - $('#config-extra-info').up().set( '@href', 'https://github.com/nextcloud/nextcloudpi/wiki/Configuration-Reference#' + selectedID ); + item.set('+active'); + $('#' + selectedID + '-config-box').show(); + var baseURL = 'https://github.com/nextcloud/nextcloudpi/wiki/Configuration-Reference#'; + $('#' + selectedID + '-config-box .icon-info').up().set( '@href', baseURL + selectedID ); } $(function() @@ -174,28 +170,28 @@ $(function() { if ( e.origin != 'https://' + window.location.hostname + ':4443') { - $('#details-box').fill( "Invalid origin" ); + $('.details-box').fill( "Invalid origin" ); return; } - var box = $$('#details-box'); - $('#details-box').ht( box.innerHTML + e.data + '<br>' ); + var box = $$('.details-box'); + $('.details-box').ht( box.innerHTML + e.data + '<br>' ); box.scrollTop = box.scrollHeight; }, false); set_sidebar_click_handlers(); // Launch selected script - $( '#config-button' ).on('click', function(e) + $( '.config-button' ).on('click', function(e) { lock = true; - $('#details-box').hide( '' ); - $('#config-button').set('@disabled',true); - $('#loading-gif').set( { $display: 'inline' } ); + $('.details-box').hide( '' ); + $('.config-button').set('@disabled',true); + $('.loading-gif').set( { $display: 'inline' } ); // create configuration object var cfg = {}; - $( 'input' , '#config-box' ).each( function(item){ + $( 'input' , '#' + selectedID + '-config-box' ).each( function(item){ if( item.getAttribute('type') == 'checkbox' ) item.value = item.checked ? 'yes' : 'no'; @@ -215,11 +211,11 @@ $(function() // reset box - $('#details-box').fill(); - $('#details-box').show(); - $('#details-box').set( {$height: '0vh'} ); - $('#details-box').animate( {$height: '50vh'}, 150 ); - $('#circle-retstatus').hide(); + $('.details-box').fill(); + $('.details-box').show(); + $('.details-box').set( {$height: '0vh'} ); + $('.details-box').animate( {$height: '50vh'}, 150 ); + $('.circle-retstatus').hide(); $( 'input' , '#config-box-wrapper' ).set('@disabled',true); @@ -227,7 +223,7 @@ $(function() $.request('post', 'ncp-launcher.php', { action:'launch', ref : selectedID, config: $.toJSON(cfg), - csrf_token: $( '#csrf-token' ).get( '.value' ) }).then( + csrf_token: $( '#csrf-token' ).get( '.value' ) }).then( function success( result ) { var ret = $.parseJSON( result ); @@ -240,17 +236,17 @@ $(function() if( ret.ref && ret.ref == 'nc-update' ) window.location.reload( true ); reload_sidebar(); - $('#circle-retstatus').set( '+icon-green-circle' ); + $('.circle-retstatus').set( '+icon-green-circle' ); } else - $('#circle-retstatus').set( '-icon-green-circle' ); - $('#circle-retstatus').show(); + $('.circle-retstatus').set( '-icon-green-circle' ); + $('.circle-retstatus').show(); } else // print error from server instead - $('#details-box').fill(ret.output); + $('.details-box').fill(ret.output); $( 'input' , '#config-box-wrapper' ).set('@disabled', null); - $('#config-button').set('@disabled',null); - $('#loading-gif').hide(); + $('.config-button').set('@disabled',null); + $('.loading-gif').hide(); lock = false; }).error( errorMsg ); }); @@ -263,19 +259,10 @@ $(function() $( '#' + selectedID ).set('-active'); - // request - $.request('post', 'ncp-launcher.php', { action:'cfgreq', - ref:'nc-update' , - csrf_token: $( '#csrf-token' ).get( '.value' ) }).then( - function success( result ) - { - cfgreqReceive( result, $( '#nc-update' ) ); - lock = false; - } - ).error( errorMsg ); + app_clicked( $('#nc-update') ); //clear details box - $('#details-box').hide( '' ); + $('.details-box').hide( '' ); } ); // slide menu @@ -314,9 +301,9 @@ $(function() csrf_token: $( '#csrf-token' ).get( '.value' ) }).then( function success( result ) { - $('#config-box-wrapper').hide(); + switch_to_section( 'nc-config' ); $.off( poweroff_event_handler ); - $('#config-box-title').fill( "Shutting down..." ); + $('#nc-config-wrapper').ht('<h2 class="text-title">Shutting down...<h2>'); }).error( errorMsg ); } ); @@ -329,9 +316,9 @@ $(function() csrf_token: $( '#csrf-token' ).get( '.value' ) }).then( function success( result ) { - $('#config-box-wrapper').hide(); + switch_to_section( 'nc-config' ); $.off( poweroff_event_handler ); - $('#config-box-title').fill( "Rebooting..." ); + $('#nc-config-wrapper').ht('<h2 class="text-title">Rebooting...<h2>'); }).error( errorMsg ); } ); @@ -361,6 +348,7 @@ $(function() if ( lock ) return; close_menu(); switch_to_section( 'dashboard' ); + history.pushState(null, selectedID, "?app=dashboard"); } ); // config button @@ -369,6 +357,7 @@ $(function() if ( lock ) return; close_menu(); switch_to_section( 'nc-config' ); + history.pushState(null, selectedID, "?app=config"); } ); // language selection diff --git a/ncp-web/ncp-launcher.php b/ncp-web/ncp-launcher.php index 9fca90c4..4d720ced 100644 --- a/ncp-web/ncp-launcher.php +++ b/ncp-web/ncp-launcher.php @@ -2,218 +2,165 @@ /// // NextCloudPi Web Panel backend // -// Copyleft 2017 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com> +// Copyleft 2018 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com> // GPL licensed (see end of file) * Use at your own risk! // -// More at https://ownyourbits.com/2017/02/13/nextcloud-ready-raspberry-pi-image/ +// More at https://nextcloudpi.com /// include ('csrf.php'); session_start(); -$modules_path = '/usr/local/etc/ncp-config.d/'; +$cfg_dir = '/usr/local/etc/ncp-config.d/'; $l10nDir = "l10n"; -ignore_user_abort( true ); - +ignore_user_abort(true); +// +// language +// require("L10N.php"); try { - $l = new L10N($_SERVER["HTTP_ACCEPT_LANGUAGE"], $l10nDir, $modules_path); + $l = new L10N($_SERVER["HTTP_ACCEPT_LANGUAGE"], $l10nDir, $cfg_dir); } catch (Exception $e) { die(json_encode("<p class='error'>Error while loading localizations!</p>")); } -if ( $_POST['action'] == "cfgreq" ) +// CSRF check +$token = isset($_POST['csrf_token']) ? $_POST['csrf_token'] : ''; +if ( empty($token) || !validateCSRFToken($token) ) + exit( '{ "output": "Unauthorized request. Try reloading the page" }' ); + +// +// launch +// +if ( $_POST['action'] == "launch" && $_POST['config'] ) { + // sanity checks if ( !$_POST['ref'] ) exit( '{ "output": "Invalid request" }' ); - //CSFR check - $token = isset($_POST['csrf_token']) ? $_POST['csrf_token'] : ''; - if ( empty($token) || !validateCSRFToken($token) ) - exit( '{ "output": "Unauthorized request. Try reloading the page" }' ); - - $path = '/usr/local/etc/ncp-config.d/'; - $files = array_diff(scandir($path), array('.', '..')); + $ncp_app = $_POST['ref']; - $fh = fopen( $path . $_POST['ref'] . '.sh' ,'r') - or exit( '{ "output": "' . $file . ' read error" }' ); - - echo '{ "token": "' . getCSRFToken() . '",'; // Get new token - echo ' "output": '; - - $output = "<table>"; + preg_match( '/^[0-9A-Za-z_-]+$/' , $_POST['ref'] , $matches ) + or exit( '{ "output": "Invalid input" , "token": "' . getCSRFToken() . '" }' ); - while ( $line = fgets($fh) ) + // save new config + if ( $_POST['config'] != "{}" ) { - // checkbox (yes/no) field - if ( preg_match('/^(\w+)_=(yes|no)$/', $line, $matches) ) - { - $checked = ""; - if ( $matches[2] == "yes" ) - $checked = "checked"; - $output .= "<tr>"; - $output .= "<td><label for=\"$matches[1]\">". $l->__($matches[1], $_POST['ref']) ."</label></td>"; - $output .= "<td><input type=\"checkbox\" id=\"$matches[1]\" name=\"$matches[1]\" value=\"$matches[2]\" $checked></td>"; - $output .= "</tr>"; - } - // drop down menu - else if(preg_match('/^(\w+)_=\[(([_\w]+,)*[_\w]+)\]$/', $line, $matches)) - { - $options = explode(",", $matches[2]); - $output .= "<tr>"; - $output .= "<td><label for=\"$matches[1]\">". $l->__($matches[1], $_POST['ref']) ."</label></td>"; - $output .= "<td><select id=\"$matches[1]\" name=\"$matches[1]\">"; - foreach($options as $option) - { - $output .= "<option value='". trim($option, "_") ."' "; - if( $option[0] == "_" && $option[count($option) - 1] == "_" ) - { - $output .="selected='selected'"; - } - $output .= ">". $l->__(trim($option, "_"), $_POST['ref']) ."</option>"; - } - $output .= "</select></td></tr>"; - } - // text field - else if ( preg_match('/^(\w+)_=(.*)$/', $line, $matches) ) - { - $output .= "<tr>"; - $output .= "<td><label for=\"$matches[1]\">". $l->__($matches[1], $_POST['ref']) ."</label></td>"; - $output .= "<td><input type=\"text\" name=\"$matches[1]\" id=\"$matches[1]\" value=\"$matches[2]\" size=\"40\"></td>"; - $output .= "</tr>"; - } - } + $cfg_file = $cfg_dir . $ncp_app . '.cfg'; - $output .= "</table>"; - fclose($fh); + $cfg_str = file_get_contents($cfg_file) + or exit('{ "output": "' . $ncp_app . ' read error" }'); - echo json_encode( $output ) . ' }'; // close JSON -} + $cfg = json_decode($cfg_str, true) + or exit('{ "output": "' . $ncp_app . ' read error" }'); -else if ( $_POST['action'] == "launch" && $_POST['config'] ) -{ - // sanity checks - if ( !$_POST['ref'] ) exit( '{ "output": "Invalid request" }' ); - - preg_match( '/^[0-9A-Za-z_-]+$/' , $_POST['ref'] , $matches ) - or exit( '{ "output": "Invalid input" , "token": "' . getCSRFToken() . '" }' ); - - // CSRF check - $token = isset($_POST['csrf_token']) ? $_POST['csrf_token'] : ''; - if ( empty($token) || !validateCSRFToken($token) ) - exit( '{ "output": "Unauthorized request. Try reloading the page" }' ); + $new_params = json_decode($_POST['config'], true) + or exit('{ "output": "Invalid request" }'); - chdir('/usr/local/etc/ncp-config.d/'); + foreach ($cfg['params'] as $index => $param) + $cfg['params'][$index]['value'] = $new_params[$cfg['params'][$index]['id']]; - $file = $_POST['ref'] . '.sh'; + $cfg_str = json_encode($cfg) + or exit('{ "output": "' . $ncp_app . ' internal error" }'); - if ( $_POST['config'] != "{}" ) - $params = json_decode( $_POST['config'], true ) - or exit( '{ "output": "Invalid request" }' ); - - $code = file_get_contents( $file ) - or exit( '{ "output": "' . $file . ' read error" }' ); - - if ( !empty( $params ) ) - foreach( $params as $name => $value ) - { - if( is_array($value)) - { - $value = "[". join(",", $value) ."]"; - } - preg_match( '/^[\[\]\w+-.,@_\/:]+$/' , $value , $matches ) - or exit( '{ "output": "Invalid input" , "token": "' . getCSRFToken() . '" }' ); - $code = preg_replace( '/\n' . $name . '_=.*' . PHP_EOL . '/' , - PHP_EOL . $name . '_=' . $value . PHP_EOL , - $code ) - or exit(); - } - - file_put_contents($file, $code ) - or exit( '{ "output": "' . $file . ' write error" }' ); + file_put_contents($cfg_file, $cfg_str) + or exit('{ "output": "' . $ncp_app . ' write error" }'); + } + // launch echo '{ "token": "' . getCSRFToken() . '",'; // Get new token - echo ' "ref": "' . $_POST['ref'] . '",'; + echo ' "ref": "' . $ncp_app . '",'; echo ' "output": "" , '; echo ' "ret": '; - exec( 'bash -c "sudo /home/www/ncp-launcher.sh ' . $file . '"' , $output , $ret ); + exec( 'bash -c "sudo /home/www/ncp-launcher.sh ' . $ncp_app . '"' , $output , $ret ); echo '"' . $ret . '" }'; } -else +// +// info +// +else if ( $_POST['action'] == "info" ) { - // CSRF check - $token = isset($_POST['csrf_token']) ? $_POST['csrf_token'] : ''; - if ( empty($token) || !validateCSRFToken($token) ) - exit( '{ "output": "Unauthorized request. Try reloading the page" }' ); + exec( 'bash /usr/local/bin/ncp-diag', $output, $ret ); - if ( $_POST['action'] == "poweroff" ) - { - shell_exec( 'bash -c "( sleep 2 && sudo halt ) 2>/dev/null >/dev/null &"' ); - } - else if ( $_POST['action'] == "reboot" ) + // info table + $table = '<table class="dashtable">'; + foreach( $output as $line ) { - shell_exec('bash -c "( sleep 2 && sudo reboot ) 2>/dev/null >/dev/null &"'); + $table .= "<tr>"; + $fields = explode( "|", $line ); + $table .= "<td>$fields[0]</td>"; + + $class = 'val-field'; + if ( strpos( $fields[1], "up" ) !== false + || strpos( $fields[1], "ok" ) !== false + || strpos( $fields[1], "open" ) !== false ) + $class = 'ok-field'; + if ( strpos( $fields[1], "down" ) !== false + || strpos( $fields[1], "error" ) !== false ) + $class = 'error-field'; + + $table .= "<td class=\"$class\">$fields[1]</td>"; + $table .= "</tr>"; } - else if ( $_POST['action'] == "info" ) - { - exec( 'bash /usr/local/bin/ncp-diag', $output, $ret ); - - // info table - $table = '<table class="dashtable">'; - foreach( $output as $line ) - { - $table .= "<tr>"; - $fields = explode( "|", $line ); - $table .= "<td>$fields[0]</td>"; - - $class = 'val-field'; - if ( strpos( $fields[1], "up" ) !== false - || strpos( $fields[1], "ok" ) !== false - || strpos( $fields[1], "open" ) !== false ) - $class = 'ok-field'; - if ( strpos( $fields[1], "down" ) !== false - || strpos( $fields[1], "error" ) !== false ) - $class = 'error-field'; - - $table .= "<td class=\"$class\">$fields[1]</td>"; - $table .= "</tr>"; - } - $table .= "</table>"; - - // suggestions - $suggestions = ""; - if ( $ret == 0 ) - { - exec( "bash /usr/local/bin/ncp-suggestions \"" . implode( "\n", $output ) . '"', $out, $ret ); - foreach( $out as $line ) - if ( $line != "" ) - $suggestions .= "<p class=\"val-field\">‣ $line</p>"; - } - - // return JSON - echo '{ "token": "' . getCSRFToken() . '",'; // Get new token - echo ' "table": ' . json_encode( $table ) . ' , '; - echo ' "suggestions": ' . json_encode( $suggestions ) . ' , '; - echo ' "ret": "' . $ret . '" }'; - } - else if ( $_POST['action'] == "sidebar" ) - { - require( "sidebar.php" ); - // return JSON - echo '{ "token": "' . getCSRFToken() . '",'; // Get new token - echo ' "output": ' . json_encode( print_sidebar( $l, true ) ) . ' , '; - echo ' "ret": "0" }'; - } - else if ( $_POST['action'] == "cfg-ui" ) + $table .= "</table>"; + + // suggestions + $suggestions = ""; + if ( $ret == 0 ) { - $ret = $l->save( $_POST['value'] ); - $ret = $ret !== FALSE ? 0 : 1; - // return JSON - echo '{ "token": "' . getCSRFToken() . '",'; // Get new token - echo ' "ret": "' . $ret . '" }'; + exec( "bash /usr/local/bin/ncp-suggestions \"" . implode( "\n", $output ) . '"', $out, $ret ); + foreach( $out as $line ) + if ( $line != "" ) + $suggestions .= "<p class=\"val-field\">‣ $line</p>"; } + + // return JSON + echo '{ "token": "' . getCSRFToken() . '",'; // Get new token + echo ' "table": ' . json_encode( $table ) . ' , '; + echo ' "suggestions": ' . json_encode( $suggestions ) . ' , '; + echo ' "ret": "' . $ret . '" }'; +} + +// +// sidebar +// +else if ( $_POST['action'] == "sidebar" ) +{ + require( "elements.php" ); + // return JSON + echo '{ "token": "' . getCSRFToken() . '",'; // Get new token + echo ' "output": ' . json_encode( print_sidebar( $l, true ) ) . ' , '; + echo ' "ret": "0" }'; +} + +// +// cfg-ui +// +else if ( $_POST['action'] == "cfg-ui" ) +{ + $ret = $l->save( $_POST['value'] ); + $ret = $ret !== FALSE ? 0 : 1; + // return JSON + echo '{ "token": "' . getCSRFToken() . '",'; // Get new token + echo ' "ret": "' . $ret . '" }'; +} + +// +// poweroff +// +else if ( $_POST['action'] == "poweroff" ) +{ + shell_exec( 'bash -c "( sleep 2 && sudo halt ) 2>/dev/null >/dev/null &"' ); +} + +// +// reboot +// +else if ( $_POST['action'] == "reboot" ) +{ + shell_exec('bash -c "( sleep 2 && sudo reboot ) 2>/dev/null >/dev/null &"'); } // License diff --git a/ncp-web/ncp-output.php b/ncp-web/ncp-output.php index 8bea03bb..704b0a58 100644 --- a/ncp-web/ncp-output.php +++ b/ncp-web/ncp-output.php @@ -78,8 +78,11 @@ function follow($file) session_write_close(); echo str_pad('',1024*1024*4); // make sure the browser buffer becomes full -touch( '/var/log/ncp.log' ); -follow( '/var/log/ncp.log' ); + +$ncp_log = '/var/log/ncp.log'; +if (!file_exists($ncp_log)) + touch($ncp_log); +follow($ncp_log); // License // diff --git a/ncp-web/sidebar.php b/ncp-web/sidebar.php deleted file mode 100644 index c90a509c..00000000 --- a/ncp-web/sidebar.php +++ /dev/null @@ -1,64 +0,0 @@ -<?php -/// -// NextCloudPi Web Panel Side bar -// -// Copyleft 2018 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com> -// GPL licensed (see end of file) * Use at your own risk! -// -// More at https://ownyourbits.com/2017/02/13/nextcloud-ready-raspberry-pi-image/ -/// - -// fill options with contents from directory - -function print_sidebar( $l /* translations l10n object */, $ticks /* wether to calculate ticks(slow) */ ) -{ - $modules_path = '/usr/local/etc/ncp-config.d/'; - $files = array_diff(scandir($modules_path), array('.', '..', 'nc-wifi.sh', 'nc-info.sh', 'l10n')); - $ret = ""; - - foreach ($files as $file) { - $script = pathinfo($file, PATHINFO_FILENAME); - $txt = file_get_contents($modules_path . $file); - - $active = ""; - if ( $ticks ) { - $etc = '/usr/local/etc'; - exec("bash -c \"source $etc/library.sh && is_active_script $etc/ncp-config.d/$script\".sh", $output, $retval); - if ($retval == 0) - $active = " ✓"; - } else if (preg_match('/^ACTIVE_=yes$/m', $txt, $matches)) - $active = " ✓"; - - $ret .= "<li id=\"$script\" class=\"nav-recent\">"; - $ret .= "<a href=\"#\"> {$l->__($script, $script)}$active </a>"; - - if (preg_match('/^DESCRIPTION="(.*)"$/m', $txt, $matches)) - $ret .= "<input id=\"$script-desc\" type=\"hidden\" value=\"{$l->__($matches[1], $script)}\" />"; - - if (preg_match('/^INFO="(.*)"/msU', $txt, $matches)) - $ret .= "<input id=\"$script-info\" type=\"hidden\" value=\"{$l->__($matches[1], $script)}\" />"; - - if (preg_match('/^INFOTITLE="(.*)"/msU', $txt, $matches)) - $ret .= "<input id=\"$script-infotitle\" type=\"hidden\" value=\"{$l->__($matches[1], $script)}\" />"; - - $ret .= "</li>"; - } - return $ret; -} -// License -// -// This script is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This script is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this script; if not, write to the -// Free Software Foundation, Inc., 59 Temple Place, Suite 330, -// Boston, MA 02111-1307 USA -?> |