mirror of
https://git.mirrors.martin98.com/https://github.com/luc-github/ESP3D.git
synced 2025-08-11 19:59:00 +08:00
Support of subdirectories in SPIFFS
Allows navigation as normal Filesystem add /delete directory parse directory tree allows user to upload/delete in /user directory only when admin has full access
This commit is contained in:
parent
dec26403b3
commit
794ab9ec1b
@ -68,7 +68,7 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "wifi.h"
|
#include "wifi.h"
|
||||||
//version and sources location
|
//version and sources location
|
||||||
#define FW_VERSION "0.7.73"
|
#define FW_VERSION "0.7.8"
|
||||||
#define REPOSITORY "https://github.com/luc-github/ESP8266"
|
#define REPOSITORY "https://github.com/luc-github/ESP8266"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
$INCLUDE[header.inc]$
|
$INCLUDE[header.inc]$
|
||||||
$INCLUDE[css2.inc]$
|
$INCLUDE[css2.inc]$
|
||||||
<STYLE>
|
<style>
|
||||||
.panel-footer{padding:10px 15px;color:#31708f;background-color:#f5f5f5;border-color:#dddddd;border-top:1px solid #dddddd;}
|
.panel-footer{padding:10px 15px;color:#31708f;background-color:#f5f5f5;border-color:#dddddd;border-top:1px solid #dddddd;}
|
||||||
</STYLE>
|
</style>
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<div class="panel-heading">Extra Settings</div>
|
<div class="panel-heading">Extra Settings</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
@ -33,13 +33,56 @@ $SUCCESS_MSG$
|
|||||||
<input class="btn btn-primary" type="button" id="upload-button" onclick="Sendfile();" value="Upload"/> <progress style="visibility:hidden;" name='prg' id='prg' max='100'></progress>
|
<input class="btn btn-primary" type="button" id="upload-button" onclick="Sendfile();" value="Upload"/> <progress style="visibility:hidden;" name='prg' id='prg' max='100'></progress>
|
||||||
<br><br><div class="panel">
|
<br><br><div class="panel">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<table class="table table-striped" style="border:1px;solid #dddddd;margin-bottom:20px;" ><thead><tr><th>Name</th><th>size</th><th width='0%'></th><th width='100%'></th></tr></thead><tbody id="file_list"><tbody></table>
|
<table><tr><td width="0%">
|
||||||
|
<div onclick="Createdir()" class="btnimg"><svg width="40" height="40" viewBox="0 0 40 40"><rect x="5" y="10" width="30" height="20" rx="2" ry="2" fill="#31b0d5" />
|
||||||
|
<rect x="20" y="5" width="15" height="15" rx="2" ry="2" fill="#31b0d5" /><text x="15" y="25" font-size="18" font-weight="800" fill="white">+</text></svg>
|
||||||
|
</div>
|
||||||
|
</td><td width="100%"><div id="path" class="info" > </div>
|
||||||
|
</td>
|
||||||
|
</tr></table>
|
||||||
|
<table class="table table-striped" style="border:1px;solid #dddddd;margin-bottom:20px;" ><thead><tr><th width='0%'>Type</th><th>Name</th><th>Size</th><th width='0%'></th><th width='100%'></th></tr></thead><tbody id="file_list"><tbody></table>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-footer " id="status"></div>
|
<div class="panel-footer " id="status"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
var currentpath = "/";
|
||||||
|
function navbar(){
|
||||||
|
var content="<table><tr>";
|
||||||
|
var tlist = currentpath.split("/");
|
||||||
|
var path="/";
|
||||||
|
var nb = 1;
|
||||||
|
content+="<td class='btnimg' onclick=\"currentpath='/'; SendCommand('list','all');\">/</td>";
|
||||||
|
while (nb < (tlist.length-1))
|
||||||
|
{
|
||||||
|
path+=tlist[nb] + "/";
|
||||||
|
content+="<td class='btnimg' onclick=\"currentpath='"+path+"'; SendCommand('list','all');\">"+tlist[nb] +"</td><td>/</td>";
|
||||||
|
nb++;
|
||||||
|
}
|
||||||
|
content+="</tr></table>";
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
function trash_icon(){
|
||||||
|
var content ="<svg width='24' height='24' viewBox='0 0 128 128'>";
|
||||||
|
content +="<rect x='52' y='12' rx='6' ry='6' width='25' height='7' style='fill:red;' />";
|
||||||
|
content +="<rect x='52' y='16' width='25' height='2' style='fill:white;' />";
|
||||||
|
content +="<rect x='30' y='18' rx='6' ry='6' width='67' height='100' style='fill:red;' />";
|
||||||
|
content +="<rect x='20' y='18' rx='10' ry='10' width='87' height='14' style='fill:red;' />";
|
||||||
|
content +="<rect x='20' y='29' width='87' height='3' style='fill:white;' />";
|
||||||
|
content +="<rect x='40' y='43' rx='7' ry='7' width='7' height='63' style='fill:white;' />";
|
||||||
|
content +="<rect x='60' y='43' rx='7' ry='7' width='7' height='63' style='fill:white;' />";
|
||||||
|
content +="<rect x='80' y='43' rx='7' ry='7' width='7' height='63' style='fill:white;' /></svg>";
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
function back_icon(){
|
||||||
|
var content ="<svg width='24' height='24' viewBox='0 0 24 24'><path d='M7,3 L2,8 L7,13 L7,10 L17,10 L18,11 L18,15 L17,16 L10,16 L9,17 L9,19 L10,20 L20,20 L22,18 L22,8 L20,6 L7,6 z' stroke='black' fill='white' /></svg>";
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
function select_dir(directoryname){
|
||||||
|
currentpath+=directoryname + "/";
|
||||||
|
SendCommand('list','all');
|
||||||
|
}
|
||||||
function dispatchstatus(jsonresponse)
|
function dispatchstatus(jsonresponse)
|
||||||
{
|
{
|
||||||
var content ="";
|
var content ="";
|
||||||
@ -50,31 +93,62 @@ content +=" | Occupation: ";
|
|||||||
content +="<meter min='0' max='100' high='90' value='"+jsonresponse.occupation +"'></meter> "+jsonresponse.occupation +"%";
|
content +="<meter min='0' max='100' high='90' value='"+jsonresponse.occupation +"'></meter> "+jsonresponse.occupation +"%";
|
||||||
document.getElementById('status').innerHTML=content;
|
document.getElementById('status').innerHTML=content;
|
||||||
content ="";
|
content ="";
|
||||||
|
if (currentpath!="/")
|
||||||
|
{
|
||||||
|
var pos = currentpath.lastIndexOf("/",currentpath.length-2)
|
||||||
|
var previouspath = currentpath.slice(0,pos+1);
|
||||||
|
content +="<tr style='cursor:hand;' onclick=\"currentpath='"+previouspath+"'; SendCommand('list','all');\"><td >"+back_icon()+"</td><td colspan='4'> Up..</td></tr>";
|
||||||
|
}
|
||||||
for (var i=0;i <jsonresponse.files.length;i++){
|
for (var i=0;i <jsonresponse.files.length;i++){
|
||||||
content +="<TR><TD style=\"padding:0px;\"><a href=\""+jsonresponse.files[i].name+"\" target=_blank><div class=\"blacklink\">";
|
//first display files
|
||||||
content +=jsonresponse.files[i].name;
|
if (String(jsonresponse.files[i].size) != "-1")
|
||||||
content +="</div></a></TD><TD>";
|
{
|
||||||
content +=jsonresponse.files[i].size;
|
content +="<TR>";
|
||||||
content +="</TD><TD width='0%'><div class=\"btnimg\" onclick=\"Delete('"+jsonresponse.files[i].name+"')\">";
|
content +="<td><svg height='24' width='24' viewBox='0 0 24 24' > <path d='M1,2 L1,21 L2,22 L16,22 L17,21 L17,6 L12,6 L12,1, L2,1 z' stroke='black' fill='white' /> <line x1='12' y1='1' x2='17' y2='6' stroke='black' stroke-width='1'/>";
|
||||||
content +="<svg width='24' height='24' viewBox='0 0 128 128'>";
|
content +="<line x1='5' y1='10' x2='13' y2='10' stroke='black' stroke-width='1'/> <line x1='5' y1='14' x2='13' y2='14' stroke='black' stroke-width='1'/> <line x1='5' y1='18' x2='13' y2='18' stroke='black' stroke-width='1'/></svg></td>";
|
||||||
content +="<rect x='52' y='12' rx='6' ry='6' width='25' height='7' style='fill:red;' />";
|
content +="<TD class='btnimg' style=\"padding:0px;\"><a blacklinkhref=\""+jsonresponse.path+jsonresponse.files[i].name+"\" target=_blank><div class=\"blacklink\">";
|
||||||
content +="<rect x='52' y='16' width='25' height='2' style='fill:white;' />";
|
content +=jsonresponse.files[i].name;
|
||||||
content +="<rect x='30' y='18' rx='6' ry='6' width='67' height='100' style='fill:red;' />";
|
content +="</div></a></TD><TD>";
|
||||||
content +="<rect x='20' y='18' rx='10' ry='10' width='87' height='14' style='fill:red;' />";
|
content +=jsonresponse.files[i].size;
|
||||||
content +="<rect x='20' y='29' width='87' height='3' style='fill:white;' />";
|
content +="</TD><TD width='0%'><div class=\"btnimg\" onclick=\"Delete('"+jsonresponse.files[i].name+"')\">";
|
||||||
content +="<rect x='40' y='43' rx='7' ry='7' width='7' height='63' style='fill:white;' />";
|
content +=trash_icon();
|
||||||
content +="<rect x='60' y='43' rx='7' ry='7' width='7' height='63' style='fill:white;' />";
|
content +="</div></TD><td></td></TR>";
|
||||||
content +="<rect x='80' y='43' rx='7' ry='7' width='7' height='63' style='fill:white;' /></svg>";
|
}
|
||||||
content +="</div></TD><td></td></TR>";
|
|
||||||
}
|
}
|
||||||
document.getElementById('file_list').innerHTML=content;}
|
//then display directories
|
||||||
|
for (var i=0;i <jsonresponse.files.length;i++){
|
||||||
|
if (String(jsonresponse.files[i].size) == "-1")
|
||||||
|
{
|
||||||
|
content +="<TR>";
|
||||||
|
content+="<td><svg height='24' width='24' viewBox='0 0 24 24' ><path d='M19,11 L19,8 L18,7 L8,7 L8,5 L7,4 L2,4 L1,5 L1,22 L19,22 L20,21 L23,11 L5,11 L2,21 L1,22' stroke='black' fill='white' /></svg></td>";
|
||||||
|
content +="<TD class='btnimg blacklink' style='padding:10px 15px;' onclick=\"select_dir('" + jsonresponse.files[i].name+"');\">";
|
||||||
|
content +=jsonresponse.files[i].name;
|
||||||
|
content +="</TD><TD>";
|
||||||
|
content +="</TD><TD width='0%'><div class=\"btnimg\" onclick=\"Deletedir('"+jsonresponse.files[i].name+"')\">";
|
||||||
|
content +=trash_icon();
|
||||||
|
content +="</div></TD><td></td></TR>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('file_list').innerHTML=content;
|
||||||
|
document.getElementById('path').innerHTML=navbar();}
|
||||||
function Delete(filename){
|
function Delete(filename){
|
||||||
if (confirm("Confirm deletion of:" + filename))SendCommand("delete",filename);
|
if (confirm("Confirm deletion of file: " + filename))SendCommand("delete",filename);
|
||||||
|
}
|
||||||
|
function Deletedir(filename){
|
||||||
|
if (confirm("Confirm deletion of directory: " + filename))SendCommand("deletedir",filename);
|
||||||
|
}
|
||||||
|
function Createdir(){
|
||||||
|
var filename = prompt("Please enter directory name", "");
|
||||||
|
if (filename != null) {
|
||||||
|
SendCommand("createdir",filename.trim());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function SendCommand(action,filename){
|
function SendCommand(action,filename){
|
||||||
var xmlhttp = new XMLHttpRequest();
|
var xmlhttp = new XMLHttpRequest();
|
||||||
var url = "/FILES?action="+action;
|
var url = "/FILES?action="+action;
|
||||||
url += "&filename="+encodeURI(filename);
|
url += "&filename="+encodeURI(filename);
|
||||||
|
url += "&path="+encodeURI(currentpath);
|
||||||
xmlhttp.onreadystatechange = function() {
|
xmlhttp.onreadystatechange = function() {
|
||||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||||
var jsonresponse = JSON.parse(xmlhttp.responseText);
|
var jsonresponse = JSON.parse(xmlhttp.responseText);
|
||||||
@ -89,9 +163,10 @@ if (files.length==0)return;
|
|||||||
document.getElementById('upload-button').value = "Uploading...";
|
document.getElementById('upload-button').value = "Uploading...";
|
||||||
document.getElementById('prg').style.visibility = "visible";
|
document.getElementById('prg').style.visibility = "visible";
|
||||||
var formData = new FormData();
|
var formData = new FormData();
|
||||||
|
formData.append('path', currentpath);
|
||||||
for (var i = 0; i < files.length; i++) {
|
for (var i = 0; i < files.length; i++) {
|
||||||
var file = files[i];
|
var file = files[i];
|
||||||
formData.append('myfiles[]', file, "/"+file.name);}
|
formData.append('myfiles[]', file, currentpath+file.name);}
|
||||||
var xmlhttp = new XMLHttpRequest();
|
var xmlhttp = new XMLHttpRequest();
|
||||||
xmlhttp.open('POST', '/FILES', true);
|
xmlhttp.open('POST', '/FILES', true);
|
||||||
//progress upload event
|
//progress upload event
|
||||||
@ -118,6 +193,7 @@ dispatchstatus(jsonresponse);
|
|||||||
}
|
}
|
||||||
xmlhttp.send(formData);
|
xmlhttp.send(formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
SendCommand('list','all');
|
SendCommand('list','all');
|
||||||
</script>
|
</script>
|
||||||
$INCLUDE[footer.inc]$
|
$INCLUDE[footer.inc]$
|
||||||
|
@ -2764,26 +2764,141 @@ void handleFileList()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String path ;
|
String path ;
|
||||||
String status="Ok";
|
String status = "Ok";
|
||||||
|
//be sure root is correct according authentication
|
||||||
if (auth_level == LEVEL_ADMIN) path = "/";
|
if (auth_level == LEVEL_ADMIN) path = "/";
|
||||||
else path = "/user";
|
else path = "/user";
|
||||||
if(web_interface->WebServer.hasArg("path"))path += web_interface->WebServer.hasArg("path");
|
//get current path
|
||||||
|
if(web_interface->WebServer.hasArg("path"))path += web_interface->WebServer.arg("path") ;
|
||||||
|
//to have a clean path
|
||||||
|
path.trim();
|
||||||
|
path.replace("//","/");
|
||||||
|
if (path[path.length()-1] !='/')path +="/";
|
||||||
|
//check if query need some action
|
||||||
if(web_interface->WebServer.hasArg("action")) {
|
if(web_interface->WebServer.hasArg("action")) {
|
||||||
if(web_interface->WebServer.arg("action")=="delete" && web_interface->WebServer.hasArg("filename")) {
|
//delete a file
|
||||||
|
if(web_interface->WebServer.arg("action") == "delete" && web_interface->WebServer.hasArg("filename")) {
|
||||||
String filename;
|
String filename;
|
||||||
filename = web_interface->WebServer.arg("filename");
|
String shortname = web_interface->WebServer.arg("filename");
|
||||||
|
shortname.replace("/","");
|
||||||
|
filename = path + web_interface->WebServer.arg("filename");
|
||||||
|
filename.replace("//","/");
|
||||||
if(!SPIFFS.exists(filename)) {
|
if(!SPIFFS.exists(filename)) {
|
||||||
status="Cannot delete, file not found!";
|
status = shortname + F(" does not exists!");
|
||||||
} else {
|
} else {
|
||||||
SPIFFS.remove(filename);
|
if (SPIFFS.remove(filename))
|
||||||
|
{
|
||||||
|
status = shortname + F(" deleted");
|
||||||
|
//what happen if no "/." and no other subfiles ?
|
||||||
|
Dir dir = SPIFFS.openDir(path);
|
||||||
|
if (!dir.next())
|
||||||
|
{ //keep directory alive even empty
|
||||||
|
File r = SPIFFS.open(path+"/.","w");
|
||||||
|
if (r)r.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
status = F("Cannot deleted ") ;
|
||||||
|
status+=shortname ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String jsonfile = "{\"path\":\"" + path + "\",";
|
//delete a directory
|
||||||
|
if(web_interface->WebServer.arg("action") == "deletedir" && web_interface->WebServer.hasArg("filename")) {
|
||||||
|
String filename;
|
||||||
|
String shortname = web_interface->WebServer.arg("filename");
|
||||||
|
shortname.replace("/","");
|
||||||
|
filename = path + web_interface->WebServer.arg("filename");
|
||||||
|
filename += "/.";
|
||||||
|
filename.replace("//","/");
|
||||||
|
if (filename != "/")
|
||||||
|
{
|
||||||
|
bool delete_error = false;
|
||||||
|
Dir dir = SPIFFS.openDir(path + shortname);
|
||||||
|
{
|
||||||
|
while (dir.next()) {
|
||||||
|
String fullpath = dir.fileName();
|
||||||
|
if (!SPIFFS.remove(dir.fileName())) {
|
||||||
|
delete_error = true;
|
||||||
|
status = F("Cannot deleted ") ;
|
||||||
|
status+=fullpath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!delete_error){
|
||||||
|
status = shortname ;
|
||||||
|
status+=" deleted";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//create a directory
|
||||||
|
if(web_interface->WebServer.arg("action")=="createdir" && web_interface->WebServer.hasArg("filename")) {
|
||||||
|
String filename;
|
||||||
|
filename = path + web_interface->WebServer.arg("filename") +"/.";
|
||||||
|
String shortname = web_interface->WebServer.arg("filename");
|
||||||
|
shortname.replace("/","");
|
||||||
|
filename.replace("//","/");
|
||||||
|
if(SPIFFS.exists(filename)) {
|
||||||
|
status = shortname + F(" already exists!");
|
||||||
|
} else {
|
||||||
|
File r = SPIFFS.open(filename,"w");
|
||||||
|
if (!r) {
|
||||||
|
status = F("Cannot create ");
|
||||||
|
status += shortname ;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r.close();
|
||||||
|
status = shortname + F(" created");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String jsonfile = "{";
|
||||||
Dir dir = SPIFFS.openDir(path);
|
Dir dir = SPIFFS.openDir(path);
|
||||||
jsonfile+="\"files\":[";
|
jsonfile+="\"files\":[";
|
||||||
bool firstentry=true;
|
bool firstentry=true;
|
||||||
|
String subdirlist="";
|
||||||
while (dir.next()) {
|
while (dir.next()) {
|
||||||
|
String filename = dir.fileName();
|
||||||
|
String size ="";
|
||||||
|
bool addtolist=true;
|
||||||
|
//remove path from name
|
||||||
|
filename = filename.substring(path.length(),filename.length());
|
||||||
|
//check if file or subfile
|
||||||
|
if (filename.indexOf("/")>-1) {
|
||||||
|
//Do not rely on "/." to define directory as SPIFFS upload won't create it but directly files
|
||||||
|
//and no need to overload SPIFFS if not necessary to create "/." if no need
|
||||||
|
//it will reduce SPIFFS available space so limit it to creation
|
||||||
|
filename = filename.substring(0,filename.indexOf("/"));
|
||||||
|
String tag="*";
|
||||||
|
tag = filename + "*";
|
||||||
|
if (subdirlist.indexOf(tag)>-1) //already in list
|
||||||
|
{
|
||||||
|
addtolist = false; //no need to add
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size = -1; //it is subfile so display only directory, size will be -1 to describe it is directory
|
||||||
|
if (subdirlist.length()==0)subdirlist+="*";
|
||||||
|
subdirlist += filename + "*"; //add to list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//do not add "." file
|
||||||
|
if (filename!=".")
|
||||||
|
{
|
||||||
|
File f = dir.openFile("r");
|
||||||
|
size = formatBytes(f.size());
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addtolist = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(addtolist)
|
||||||
|
{
|
||||||
if (!firstentry) {
|
if (!firstentry) {
|
||||||
jsonfile+=",";
|
jsonfile+=",";
|
||||||
} else {
|
} else {
|
||||||
@ -2791,15 +2906,15 @@ void handleFileList()
|
|||||||
}
|
}
|
||||||
jsonfile+="{";
|
jsonfile+="{";
|
||||||
jsonfile+="\"name\":\"";
|
jsonfile+="\"name\":\"";
|
||||||
jsonfile+=dir.fileName();
|
jsonfile+=filename;
|
||||||
jsonfile+="\",\"size\":\"";
|
jsonfile+="\",\"size\":\"";
|
||||||
File f = dir.openFile("r");
|
jsonfile+=size;
|
||||||
jsonfile+=formatBytes(f.size());
|
|
||||||
jsonfile+="\"";
|
jsonfile+="\"";
|
||||||
jsonfile+="}";
|
jsonfile+="}";
|
||||||
f.close();
|
}
|
||||||
}
|
}
|
||||||
jsonfile+="],";
|
jsonfile+="],";
|
||||||
|
jsonfile+="\"path\":\"" + path + "\",";
|
||||||
jsonfile+="\"status\":\"" + status + "\",";
|
jsonfile+="\"status\":\"" + status + "\",";
|
||||||
FSInfo info;
|
FSInfo info;
|
||||||
SPIFFS.info(info);
|
SPIFFS.info(info);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user