diff --git a/www/api/controllers/files.php b/www/api/controllers/files.php index d9826c6c9..057fa6fe7 100644 --- a/www/api/controllers/files.php +++ b/www/api/controllers/files.php @@ -75,41 +75,54 @@ function files_rename() ///////////////////////////////////////////////////////////////////////////// // GET /api/files/:DirName -function GetFiles() -{ +function GetFilesHelper($dirName, $prefix = '') { $files = array(); - $dirName = params("DirName"); - check($dirName, "dirName", __FUNCTION__); - $dirName = GetDirSetting($dirName); - if ($dirName == "") { - return json(array("status" => "Invalid Directory")); - } + if ($prefix != '') + $prefix .= '/'; // if ?nameOnly=1 was passed, then just array of names if (isset($_GET['nameOnly']) && ($_GET['nameOnly'] == '1')) { $rc = array(); foreach (scandir($dirName) as $fileName) { if ($fileName != '.' && $fileName != '..') { - if (!preg_match("//u", $fileName)) { - $fileName = iconv("ISO-8859-1", 'UTF-8//TRANSLIT', $fileName); + if (is_dir($dirName . '/' . $fileName)) { + $rc = array_merge($rc, GetFilesHelper($dirName . '/' . $fileName, $prefix . $fileName)); + } else { + if (!preg_match("//u", $fileName)) { + $fileName = iconv("ISO-8859-1", 'UTF-8//TRANSLIT', $fileName); + } + array_push($rc, $prefix . $fileName); } - array_push($rc, $fileName); } } if (strtolower(params("DirName")) == "logs") { array_push($rc, "/var/log/messages"); array_push($rc, "/var/log/syslog"); } - return json($rc); + return $rc; } foreach (scandir($dirName) as $fileName) { if ($fileName != '.' && $fileName != '..') { - if (!preg_match("//u", $fileName)) { - $fileName = iconv("ISO-8859-1", 'UTF-8//TRANSLIT', $fileName); + if (is_dir($dirName . '/' . $fileName)) { + $entries = GetFilesHelper($dirName . '/' . $fileName, $prefix . $fileName); + if (!count($entries)) { + $current = array(); + $current["name"] = $prefix . $fileName; + $current["mtime"] = date('m/d/y h:i A', filemtime($dirName . '/' . $fileName)); + $current["sizeBytes"] = 0; + $current["sizeHuman"] = 'Directory'; + + $entries = array($current); + } + $files = array_merge($files, $entries); + } else { + if (!preg_match("//u", $fileName)) { + $fileName = iconv("ISO-8859-1", 'UTF-8//TRANSLIT', $fileName); + } + GetFileInfo($files, $dirName, $fileName, $prefix); } - GetFileInfo($files, $dirName, $fileName); } } @@ -124,7 +137,23 @@ function GetFiles() } - return json(array("status" => "ok", "files" => $files)); + return $files; +} + +function GetFiles() +{ + $dirName = params("DirName"); + check($dirName, "dirName", __FUNCTION__); + $dirName = GetDirSetting($dirName); + if ($dirName == "") { + return json(array("status" => "Invalid Directory")); + } + + if (isset($_GET['nameOnly']) && ($_GET['nameOnly'] == '1')) { + return json(GetFilesHelper($dirName)); + } else { + return json(array("status" => "ok", "files" => GetFilesHelper($dirName))); + } } function GetFile() @@ -166,13 +195,13 @@ function GetFileImpl($dir, $filename, $lines, $play, $attach) return; } - if ($isLog && (substr($filename, 0, 9) == "_var_log_")) { + if ($isLog && (substr($filename, 0, 8) == "var/log/")) { $dir = "/var/log"; - $filename = substr($filename, 9); + $filename = substr($filename, 8); } if (!file_exists($dir . '/' . $filename)){ - echo "File does not exist."; + echo "File $dir/$filename does not exist."; return; } @@ -514,11 +543,13 @@ function DeleteFile() $status = "File not found"; $dirName = params("DirName"); $dir = GetDirSetting($dirName); - $fileName = findFile($dir, params("Name")); + $fileName = findFile($dir, params(0)); $fullPath = "$dir/$fileName"; - if ($dir == "") { + if (preg_match('/\/\.\.\//', $fileName)) { + $status = 'Cannot access parent directory'; + } else if ($dir == "") { $status = "Invalid Directory"; } else if (!file_exists($fullPath)) { $status = "File Not Found"; @@ -698,7 +729,7 @@ function PostFile() return json(array("status" => $status, "file" => $fileName, "dir" => $dirName, "written" => $size, "size" => $totalSize, "offset" => $offset)); } -function GetFileInfo(&$list, $dirName, $fileName) +function GetFileInfo(&$list, $dirName, $fileName, $prefix = '') { $fileFullName = $dirName . '/' . $fileName; $filesize = real_filesize($fileFullName); @@ -706,7 +737,7 @@ function GetFileInfo(&$list, $dirName, $fileName) $filesize = intval($filesize); } $current = array(); - $current["name"] = $fileName; + $current["name"] = $prefix . $fileName; $current["mtime"] = date('m/d/y h:i A', filemtime($fileFullName)); $current["sizeBytes"] = $filesize; $current["sizeHuman"] = human_filesize($fileFullName); @@ -738,3 +769,57 @@ function GetFileInfo(&$list, $dirName, $fileName) } array_push($list, $current); } + +function CreateDir() +{ + $status = "Unable to create directory"; + $dirName = params("DirName"); + $subDir = params("SubDir"); + $sanitized = sanitizeFilename($subDir); + $dir = GetDirSetting($dirName); + $fullPath = "$dir/$subDir"; + + if ($sanitized != $subDir) { + $status = "Invalid subdirectory name"; + } else if ($dir == "") { + $status = "Invalid Directory"; + } else if (file_exists($fullPath)) { + $status = "Subdirectory already exists"; + } else { + if (mkdir($fullPath)) { + chmod($fullPath, 0755); + $status = "OK"; + } else { + $status = "Unable to delete file"; + } + } + + return json(array("status" => $status, "subdir" => $subDir, "dir" => $dirName)); +} + +function DeleteDir() +{ + $status = "SubDir not found"; + $dirName = params("DirName"); + $subDir = params("SubDir"); + $sanitized = sanitizeFilename($subDir); + $dir = GetDirSetting($dirName); + $fullPath = "$dir/$subDir"; + + if ($sanitized != $subDir) { + $status = "Invalid subdirectory name"; + } else if ($dir == "") { + $status = "Invalid Directory"; + } else if (!file_exists($fullPath)) { + $status = "Subdirectory '$subDir' does not exist"; + } else { + if (rmdir($fullPath)) { + $status = "OK"; + } else { + $status = "Unable to delete subdirectory, does it contain any files?"; + } + } + + return json(array("status" => $status, "subdir" => $subDir, "dir" => $dirName)); +} + diff --git a/www/api/index.php b/www/api/index.php index 6cf40ca51..16607c29f 100644 --- a/www/api/index.php +++ b/www/api/index.php @@ -43,6 +43,9 @@ dispatch_post('/configfile/**', 'UploadConfigFile'); dispatch_delete('/configfile/**', 'DeleteConfigFile'); +dispatch_post('/dir/:DirName/:SubDir', 'CreateDir'); +dispatch_delete('/dir/:DirName/:SubDir', 'DeleteDir'); + dispatch_get('/effects', 'effects_list'); dispatch_get('/effects/ALL', 'effects_list_ALL'); @@ -59,7 +62,7 @@ dispatch_post('/file/:DirName/copy/:source/:dest', 'files_copy'); dispatch_post('/file/:DirName/rename/:source/:dest', 'files_rename'); dispatch_get('/file/:DirName/**', 'GetFile'); -dispatch_delete('/file/:DirName/:Name', 'DeleteFile'); +dispatch_delete('/file/:DirName/**', 'DeleteFile'); dispatch_post('/file/:DirName', 'PatchFile'); dispatch_patch('/file/:DirName', 'PatchFile'); dispatch_post('/file/:DirName/:Name', 'PostFile'); diff --git a/www/js/fpp.js b/www/js/fpp.js index c5b91f3f0..d6d6dd4a7 100644 --- a/www/js/fpp.js +++ b/www/js/fpp.js @@ -863,7 +863,8 @@ function AddTableRowFromTemplate(table) { function HandleTableRowMouseClick(event, row) { if ((event.target.nodeName == 'INPUT') || (event.target.nodeName == 'TEXTAREA') || - (event.target.nodeName == 'SELECT')) + (event.target.nodeName == 'SELECT') || + (row.hasClass('unselectableRow'))) return; event.preventDefault(); // prevent mouse move from highlighting text @@ -3281,7 +3282,21 @@ function GetFiles(dir) { detail = f.playtimeSeconds; } - var tableRow = "
" + text.replace(//g, '>') + ""); - }); + if (html == '') { + $.get(url, function (text) { + var ext = file.split('.').pop(); + if (ext != "html") + $('#fileViewerText').html("
" + text.replace(//g, '>') + ""); + }); + } else { + $('#fileViewerText').html(html); + } } function DeleteFile(dir, row, file, silent = false) { - if (file.indexOf("/") > -1) { - alert("You can not delete this file."); - return; - } - $.ajax({ - url: "api/file/" + dir + "/" + encodeURIComponent(file), + url: "api/file/" + dir + "/" + encodeURIComponent(file).replace('%2F','/'), type: 'DELETE' }).done(function (data) { if (data.status == "OK") { @@ -5040,16 +5054,30 @@ function DeleteFile(dir, row, file, silent = false) { function SetupSelectableTableRow(info) { $('#' + info.tableName + ' > tbody').on('mousedown', 'tr', function (event, ui) { - $('#' + info.tableName + ' > tbody > tr').removeClass('fppTableSelectedEntry'); - $(this).addClass('fppTableSelectedEntry'); - var items = $('#' + info.tableName + ' > tbody > tr'); - info.selected = items.index(this); + var enabledButtonState; + var disabledButtonState; + + if ($(this).hasClass('fppTableSelectedEntry')) { + $(this).removeClass('fppTableSelectedEntry'); + + info.selected = -1; + enabledButtonState = 'disable'; + disabledButtonState = 'enable'; + } else { + $('#' + info.tableName + ' > tbody > tr').removeClass('fppTableSelectedEntry'); + $(this).addClass('fppTableSelectedEntry'); + + var items = $('#' + info.tableName + ' > tbody > tr'); + info.selected = items.index(this); + enabledButtonState = 'enable'; + disabledButtonState = 'disable'; + } for (var i = 0; i < info.enableButtons.length; i++) { - SetButtonState('#' + info.enableButtons[i], "enable"); + SetButtonState('#' + info.enableButtons[i], enabledButtonState); } for (var i = 0; i < info.disableButtons.length; i++) { - SetButtonState('#' + info.disableButtons[i], "disable"); + SetButtonState('#' + info.disableButtons[i], disabledButtonState); } }); diff --git a/www/settings.json b/www/settings.json index 569760228..4905a7fab 100644 --- a/www/settings.json +++ b/www/settings.json @@ -215,7 +215,8 @@ "disableUIWarnings", "DateFormat", "TimeFormat", - "temperatureInF" + "temperatureInF", + "fileManagerThumbnailSize" ] }, "uiColors": { @@ -916,6 +917,24 @@ "Disabled": 2 } }, + "fileManagerThumbnailSize": { + "name": "fileManagerThumbnailSize", + "description": "File Manager Thumbnail Size", + "tip": "The max height and width of the thumbnail preview for image files in the FPP File Manager UI. The UI will preserve the aspect ratio to fit the image within this height and width.", + "default": 75, + "type": "select", + "options": { + "Disabled": 0, + "25 pixels": 25, + "50 pixels": 50, + "75 pixels": 75, + "100 pixels": 100, + "125 pixels": 125, + "150 pixels": 150, + "175 pixels": 175, + "200 pixels": 200 + } + }, "FPP_UUID": { "name": "FPP_UUID", "description": "UUID to use for stats collection", @@ -2226,4 +2245,4 @@ ] } } -} \ No newline at end of file +}