minor fixes
parent
e472260de0
commit
678d1b444f
|
@ -1,312 +1,317 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package webshell.app;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import webshell.app.config.ConfigManager;
|
||||
import webshell.app.files.FileOperations;
|
||||
import webshell.app.files.FileService;
|
||||
import webshell.app.files.FileTransfer;
|
||||
import webshell.app.files.PosixPermission;
|
||||
import webshell.app.files.copy.FileCopyProgressResponse;
|
||||
import webshell.app.files.copy.FileCopyRequest;
|
||||
import webshell.app.files.search.SearchResult;
|
||||
import webshell.app.terminal.PtySession;
|
||||
|
||||
/**
|
||||
* @author subhro
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
@CrossOrigin(allowCredentials = "true")
|
||||
@RequestMapping("/api")
|
||||
public class AppController {
|
||||
|
||||
@Autowired
|
||||
private FileService service;
|
||||
|
||||
@Autowired
|
||||
private FileOperations fs;
|
||||
|
||||
@Autowired
|
||||
private BCryptPasswordEncoder passwordEncoder;
|
||||
|
||||
@PostMapping("/app/terminal/{appId}/resize")
|
||||
public void resizePty(@PathVariable String appId,
|
||||
@RequestBody Map<String, Integer> body) {
|
||||
AppContext.INSTANCES.get(appId).resizePty(body.get("row"),
|
||||
body.get("col"));
|
||||
}
|
||||
|
||||
@PostMapping("/app/terminal")
|
||||
public Map<String, String> createTerminal() throws Exception {
|
||||
PtySession pty = new PtySession();
|
||||
AppContext.INSTANCES.put(pty.getId(), pty);
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.put("id", pty.getId());
|
||||
return map;
|
||||
}
|
||||
|
||||
@GetMapping("/app/files/home")
|
||||
public Map<String, Object> listHome() throws Exception {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("files", service.list(System.getProperty("user.home")));
|
||||
map.put("folder", System.getProperty("user.home"));
|
||||
map.put("folderName",
|
||||
new File(System.getProperty("user.home")).getName());
|
||||
return map;
|
||||
}
|
||||
|
||||
@GetMapping("/app/files/list/{path}")
|
||||
public Map<String, Object> list(@PathVariable String path)
|
||||
throws Exception {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
String folder = null;
|
||||
if (path == null) {
|
||||
folder = System.getProperty("user.home");
|
||||
} else {
|
||||
folder = new String(Base64.getDecoder().decode(path), "utf-8");
|
||||
}
|
||||
System.out.println("base64: " + path + " " + folder);
|
||||
map.put("files", service.list(folder));
|
||||
map.put("folder", folder);
|
||||
map.put("folderName", new File(folder).getName());
|
||||
return map;
|
||||
}
|
||||
|
||||
@GetMapping("/app/files/up/{path}")
|
||||
public Map<String, Object> up(@PathVariable String path) throws Exception {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
path = new String(Base64.getDecoder().decode(path), "utf-8");
|
||||
if (!path.equals("/")) {
|
||||
path = new File(path).getParent();
|
||||
}
|
||||
map.put("files", service.list(path));
|
||||
map.put("folder", path);
|
||||
map.put("folderName", new File(path).getName());
|
||||
return map;
|
||||
}
|
||||
|
||||
@PostMapping("/app/upload/{folder}/{relativePath}")
|
||||
public void upload(@PathVariable String folder,
|
||||
@PathVariable String relativePath, HttpServletRequest request)
|
||||
throws Exception {
|
||||
System.out.println("uploading...");
|
||||
try {
|
||||
folder = new String(Base64.getDecoder().decode(folder), "utf-8");
|
||||
relativePath = new String(Base64.getDecoder().decode(relativePath),
|
||||
"utf-8");
|
||||
FileTransfer fs = new FileTransfer(false);
|
||||
fs.transferFile(relativePath, folder, request.getInputStream());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/app/folder/tree/home")
|
||||
public List<Map<String, ?>> listTreeHome() {
|
||||
List<Map<String, ?>> list = new ArrayList<>();
|
||||
File f = new File(System.getProperty("user.home"));
|
||||
File[] files = f.listFiles();
|
||||
if (files != null && files.length > 0) {
|
||||
for (File file : files) {
|
||||
Map<String, Object> entry = new HashMap<>();
|
||||
entry.put("name", file.getName());
|
||||
entry.put("path", file.getAbsolutePath());
|
||||
entry.put("leafNode", !file.isDirectory());
|
||||
list.add(entry);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@GetMapping("/app/folder/tree/path/{encodedPath}")
|
||||
public List<Map<String, ?>> listTreePath(@PathVariable String encodedPath)
|
||||
throws Exception {
|
||||
String path = new String(Base64.getDecoder().decode(encodedPath),
|
||||
"utf-8");
|
||||
List<Map<String, ?>> list = new ArrayList<>();
|
||||
File f = new File(path);
|
||||
File[] files = f.listFiles();
|
||||
if (files != null && files.length > 0) {
|
||||
for (File file : files) {
|
||||
Map<String, Object> entry = new HashMap<>();
|
||||
entry.put("name", file.getName());
|
||||
entry.put("path", file.getAbsolutePath());
|
||||
entry.put("leafNode", !file.isDirectory());
|
||||
list.add(entry);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@GetMapping("/app/folder/tree/fs")
|
||||
public List<Map<String, ?>> listFsRoots() throws Exception {
|
||||
List<Map<String, ?>> list = new ArrayList<>();
|
||||
File[] files = File.listRoots();
|
||||
if (files != null && files.length > 0) {
|
||||
for (File file : files) {
|
||||
Map<String, Object> entry = new HashMap<>();
|
||||
System.out.println("Root: " + file.getName());
|
||||
entry.put("name", file.getAbsolutePath());
|
||||
entry.put("path", file.getAbsolutePath());
|
||||
entry.put("leafNode", !file.isDirectory());
|
||||
list.add(entry);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/{mode}")
|
||||
public Map<String, String> startCopyOrMove(@PathVariable String mode,
|
||||
@RequestBody FileCopyRequest request) {
|
||||
List<String> sourceFile = request.getSourceFile();
|
||||
String targetFolder = request.getTargetFolder();
|
||||
Map<String, String> map = new HashMap<>();
|
||||
String id = fs.createFileCopyTask(sourceFile, targetFolder,
|
||||
"move".equals(mode));
|
||||
map.put("id", id);
|
||||
map.put("name", fs.getOpName(id));
|
||||
return map;
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/progress")
|
||||
public List<FileCopyProgressResponse> getProgress(
|
||||
@RequestBody List<String> idList) {
|
||||
return fs.getProgress(idList);
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/cancel/{id}")
|
||||
public void cancel(@PathVariable String id) {
|
||||
fs.cancelTask(id);
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/rename")
|
||||
public void rename(@RequestBody Map<String, String> body)
|
||||
throws IOException {
|
||||
fs.rename(body.get("oldName"), body.get("newName"), body.get("folder"));
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/delete")
|
||||
public void delete(@RequestBody List<String> body) throws IOException {
|
||||
fs.deleteFiles(body);
|
||||
}
|
||||
|
||||
@GetMapping("/app/fs/files/{encodedPath}")
|
||||
public String getText(@PathVariable String encodedPath) throws Exception {
|
||||
return service
|
||||
.getText(new String(Base64.getDecoder().decode(encodedPath)));
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/files/{encodedPath}")
|
||||
public void setText(@PathVariable String encodedPath,
|
||||
@RequestBody String body) throws Exception {
|
||||
service.setText(new String(Base64.getDecoder().decode(encodedPath)),
|
||||
body);
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/search")
|
||||
public Map<String, String> initSearch(
|
||||
@RequestBody Map<String, String> request) {
|
||||
String id = service.createSearch(request.get("folder"),
|
||||
request.get("searchText"));
|
||||
Map<String, String> response = new HashMap<String, String>();
|
||||
response.put("id", id);
|
||||
return response;
|
||||
}
|
||||
|
||||
@DeleteMapping("/app/fs/search/{id}")
|
||||
public void cancelSearch(@PathVariable String id) {
|
||||
this.service.cancelSearch(id);
|
||||
}
|
||||
|
||||
@GetMapping("/app/fs/search/{id}")
|
||||
public SearchResult getSearchResult(@PathVariable String id,
|
||||
@RequestParam(defaultValue = "0", required = false) int fileIndex,
|
||||
@RequestParam(defaultValue = "0", required = false) int folderIndex) {
|
||||
return this.service.getSearchResult(id, fileIndex, folderIndex);
|
||||
}
|
||||
|
||||
@GetMapping("/app/fs/posix/{encodedPath}")
|
||||
public PosixPermission getPosixPerm(@PathVariable String encodedPath)
|
||||
throws Exception {
|
||||
return this.fs.getPosixPermission(
|
||||
new String(Base64.getDecoder().decode(encodedPath), "utf-8"));
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/posix/{encodedPath}")
|
||||
public void setPosixPerm(@PathVariable String encodedPath,
|
||||
@RequestBody PosixPermission perm) throws Exception {
|
||||
this.fs.setPosixPermission(
|
||||
new String(Base64.getDecoder().decode(encodedPath), "utf-8"),
|
||||
perm);
|
||||
}
|
||||
|
||||
@GetMapping("/app/config")
|
||||
public Map<String, String> getConfig() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("app.default-user", System.getProperty("app.default-user"));
|
||||
map.put("app.default-pass", System.getProperty("app.default-pass"));
|
||||
map.put("app.default-shell", System.getProperty("app.default-shell"));
|
||||
return map;
|
||||
}
|
||||
|
||||
@PostMapping("/app/config")
|
||||
public void setConfig(@RequestBody Map<String, String> map)
|
||||
throws IOException {
|
||||
for (String key : map.keySet()) {
|
||||
String val = map.get(key);
|
||||
if (val != null && val.length() > 0) {
|
||||
if (key.equals("app.default-pass")) {
|
||||
System.setProperty(key, passwordEncoder.encode(val));
|
||||
} else {
|
||||
System.setProperty(key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
ConfigManager.saveUserDetails();
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/mkdir")
|
||||
public void mkdir(@RequestBody Map<String, String> map) throws Exception {
|
||||
String dir = map.get("dir");
|
||||
String name = map.get("name");
|
||||
Path path = Paths.get(dir, name);
|
||||
Files.createDirectories(path);
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/touch")
|
||||
public void touch(@RequestBody Map<String, String> map) throws Exception {
|
||||
String dir = map.get("dir");
|
||||
String name = map.get("name");
|
||||
Path path = Paths.get(dir, name);
|
||||
Files.createFile(path);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package webshell.app;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import webshell.app.config.ConfigManager;
|
||||
import webshell.app.files.FileOperations;
|
||||
import webshell.app.files.FileService;
|
||||
import webshell.app.files.FileTransfer;
|
||||
import webshell.app.files.PosixPermission;
|
||||
import webshell.app.files.copy.FileCopyProgressResponse;
|
||||
import webshell.app.files.copy.FileCopyRequest;
|
||||
import webshell.app.files.search.SearchResult;
|
||||
import webshell.app.terminal.PtySession;
|
||||
|
||||
/**
|
||||
* @author subhro
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
@CrossOrigin(allowCredentials = "true")
|
||||
@RequestMapping("/api")
|
||||
public class AppController {
|
||||
|
||||
@Autowired
|
||||
private FileService service;
|
||||
|
||||
@Autowired
|
||||
private FileOperations fs;
|
||||
|
||||
@Autowired
|
||||
private BCryptPasswordEncoder passwordEncoder;
|
||||
|
||||
@PostMapping("/app/terminal/{appId}/resize")
|
||||
public void resizePty(@PathVariable String appId,
|
||||
@RequestBody Map<String, Integer> body) {
|
||||
AppContext.INSTANCES.get(appId).resizePty(body.get("row"),
|
||||
body.get("col"));
|
||||
}
|
||||
|
||||
@PostMapping("/app/terminal")
|
||||
public Map<String, String> createTerminal() throws Exception {
|
||||
PtySession pty = new PtySession();
|
||||
AppContext.INSTANCES.put(pty.getId(), pty);
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.put("id", pty.getId());
|
||||
return map;
|
||||
}
|
||||
|
||||
@GetMapping("/app/files/home")
|
||||
public Map<String, Object> listHome() throws Exception {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("files", service.list(System.getProperty("user.home")));
|
||||
map.put("folder", System.getProperty("user.home"));
|
||||
map.put("folderName",
|
||||
new File(System.getProperty("user.home")).getName());
|
||||
return map;
|
||||
}
|
||||
|
||||
@GetMapping("/app/files/list/{path}")
|
||||
public Map<String, Object> list(@PathVariable String path)
|
||||
throws Exception {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
String folder = null;
|
||||
if (path == null) {
|
||||
folder = System.getProperty("user.home");
|
||||
} else {
|
||||
folder = new String(Base64.getDecoder().decode(path), "utf-8");
|
||||
}
|
||||
System.out.println("base64: " + path + " " + folder);
|
||||
map.put("files", service.list(folder));
|
||||
map.put("folder", folder);
|
||||
map.put("folderName", new File(folder).getName());
|
||||
return map;
|
||||
}
|
||||
|
||||
@GetMapping("/app/files/up/{path}")
|
||||
public Map<String, Object> up(@PathVariable String path) throws Exception {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
path = new String(Base64.getDecoder().decode(path), "utf-8");
|
||||
if (!path.equals("/")) {
|
||||
path = new File(path).getParent();
|
||||
}
|
||||
map.put("files", service.list(path));
|
||||
map.put("folder", path);
|
||||
map.put("folderName", new File(path).getName());
|
||||
return map;
|
||||
}
|
||||
|
||||
@PostMapping("/app/upload/{folder}/{relativePath}")
|
||||
public void upload(@PathVariable String folder,
|
||||
@PathVariable String relativePath, HttpServletRequest request)
|
||||
throws Exception {
|
||||
System.out.println("uploading...");
|
||||
try {
|
||||
folder = new String(Base64.getDecoder().decode(folder), "utf-8");
|
||||
relativePath = new String(Base64.getDecoder().decode(relativePath),
|
||||
"utf-8");
|
||||
FileTransfer fs = new FileTransfer(false);
|
||||
fs.transferFile(relativePath, folder, request.getInputStream());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/app/folder/tree/home")
|
||||
public List<Map<String, ?>> listTreeHome() {
|
||||
List<Map<String, ?>> list = new ArrayList<>();
|
||||
File f = new File(System.getProperty("user.home"));
|
||||
File[] files = f.listFiles();
|
||||
if (files != null && files.length > 0) {
|
||||
for (File file : files) {
|
||||
if (!file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
Map<String, Object> entry = new HashMap<>();
|
||||
entry.put("name", file.getName());
|
||||
entry.put("path", file.getAbsolutePath());
|
||||
entry.put("leafNode", !file.isDirectory());
|
||||
list.add(entry);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@GetMapping("/app/folder/tree/path/{encodedPath}")
|
||||
public List<Map<String, ?>> listTreePath(@PathVariable String encodedPath)
|
||||
throws Exception {
|
||||
String path = new String(Base64.getDecoder().decode(encodedPath),
|
||||
"utf-8");
|
||||
List<Map<String, ?>> list = new ArrayList<>();
|
||||
File f = new File(path);
|
||||
File[] files = f.listFiles();
|
||||
if (files != null && files.length > 0) {
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
Map<String, Object> entry = new HashMap<>();
|
||||
entry.put("name", file.getName());
|
||||
entry.put("path", file.getAbsolutePath());
|
||||
entry.put("leafNode", !file.isDirectory());
|
||||
list.add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@GetMapping("/app/folder/tree/fs")
|
||||
public List<Map<String, ?>> listFsRoots() throws Exception {
|
||||
List<Map<String, ?>> list = new ArrayList<>();
|
||||
File[] files = File.listRoots();
|
||||
if (files != null && files.length > 0) {
|
||||
for (File file : files) {
|
||||
Map<String, Object> entry = new HashMap<>();
|
||||
System.out.println("Root: " + file.getName());
|
||||
entry.put("name", file.getAbsolutePath());
|
||||
entry.put("path", file.getAbsolutePath());
|
||||
entry.put("leafNode", !file.isDirectory());
|
||||
list.add(entry);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/{mode}")
|
||||
public Map<String, String> startCopyOrMove(@PathVariable String mode,
|
||||
@RequestBody FileCopyRequest request) {
|
||||
List<String> sourceFile = request.getSourceFile();
|
||||
String targetFolder = request.getTargetFolder();
|
||||
Map<String, String> map = new HashMap<>();
|
||||
String id = fs.createFileCopyTask(sourceFile, targetFolder,
|
||||
"move".equals(mode));
|
||||
map.put("id", id);
|
||||
map.put("name", fs.getOpName(id));
|
||||
return map;
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/progress")
|
||||
public List<FileCopyProgressResponse> getProgress(
|
||||
@RequestBody List<String> idList) {
|
||||
return fs.getProgress(idList);
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/cancel/{id}")
|
||||
public void cancel(@PathVariable String id) {
|
||||
fs.cancelTask(id);
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/rename")
|
||||
public void rename(@RequestBody Map<String, String> body)
|
||||
throws IOException {
|
||||
fs.rename(body.get("oldName"), body.get("newName"), body.get("folder"));
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/delete")
|
||||
public void delete(@RequestBody List<String> body) throws IOException {
|
||||
fs.deleteFiles(body);
|
||||
}
|
||||
|
||||
@GetMapping("/app/fs/files/{encodedPath}")
|
||||
public String getText(@PathVariable String encodedPath) throws Exception {
|
||||
return service
|
||||
.getText(new String(Base64.getDecoder().decode(encodedPath)));
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/files/{encodedPath}")
|
||||
public void setText(@PathVariable String encodedPath,
|
||||
@RequestBody String body) throws Exception {
|
||||
service.setText(new String(Base64.getDecoder().decode(encodedPath)),
|
||||
body);
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/search")
|
||||
public Map<String, String> initSearch(
|
||||
@RequestBody Map<String, String> request) {
|
||||
String id = service.createSearch(request.get("folder"),
|
||||
request.get("searchText"));
|
||||
Map<String, String> response = new HashMap<String, String>();
|
||||
response.put("id", id);
|
||||
return response;
|
||||
}
|
||||
|
||||
@DeleteMapping("/app/fs/search/{id}")
|
||||
public void cancelSearch(@PathVariable String id) {
|
||||
this.service.cancelSearch(id);
|
||||
}
|
||||
|
||||
@GetMapping("/app/fs/search/{id}")
|
||||
public SearchResult getSearchResult(@PathVariable String id,
|
||||
@RequestParam(defaultValue = "0", required = false) int fileIndex,
|
||||
@RequestParam(defaultValue = "0", required = false) int folderIndex) {
|
||||
return this.service.getSearchResult(id, fileIndex, folderIndex);
|
||||
}
|
||||
|
||||
@GetMapping("/app/fs/posix/{encodedPath}")
|
||||
public PosixPermission getPosixPerm(@PathVariable String encodedPath)
|
||||
throws Exception {
|
||||
return this.fs.getPosixPermission(
|
||||
new String(Base64.getDecoder().decode(encodedPath), "utf-8"));
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/posix/{encodedPath}")
|
||||
public void setPosixPerm(@PathVariable String encodedPath,
|
||||
@RequestBody PosixPermission perm) throws Exception {
|
||||
this.fs.setPosixPermission(
|
||||
new String(Base64.getDecoder().decode(encodedPath), "utf-8"),
|
||||
perm);
|
||||
}
|
||||
|
||||
@GetMapping("/app/config")
|
||||
public Map<String, String> getConfig() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("app.default-user", System.getProperty("app.default-user"));
|
||||
map.put("app.default-pass", System.getProperty("app.default-pass"));
|
||||
map.put("app.default-shell", System.getProperty("app.default-shell"));
|
||||
return map;
|
||||
}
|
||||
|
||||
@PostMapping("/app/config")
|
||||
public void setConfig(@RequestBody Map<String, String> map)
|
||||
throws IOException {
|
||||
for (String key : map.keySet()) {
|
||||
String val = map.get(key);
|
||||
if (val != null && val.length() > 0) {
|
||||
if (key.equals("app.default-pass")) {
|
||||
System.setProperty(key, passwordEncoder.encode(val));
|
||||
} else {
|
||||
System.setProperty(key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
ConfigManager.saveUserDetails();
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/mkdir")
|
||||
public void mkdir(@RequestBody Map<String, String> map) throws Exception {
|
||||
String dir = map.get("dir");
|
||||
String name = map.get("name");
|
||||
Path path = Paths.get(dir, name);
|
||||
Files.createDirectories(path);
|
||||
}
|
||||
|
||||
@PostMapping("/app/fs/touch")
|
||||
public void touch(@RequestBody Map<String, String> map) throws Exception {
|
||||
String dir = map.get("dir");
|
||||
String name = map.get("name");
|
||||
Path path = Paths.get(dir, name);
|
||||
Files.createFile(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,48 +1,45 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package webshell.app.files;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import webshell.app.files.search.SearchResult;
|
||||
import webshell.app.files.search.SearchTask;
|
||||
|
||||
/**
|
||||
* @author subhro
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class SearchOperations {
|
||||
private final Map<String, SearchTask> pendingOperations = new ConcurrentHashMap<>();
|
||||
private final ExecutorService threadPool = Executors.newFixedThreadPool(5);
|
||||
|
||||
public String createSearchTask(String folder, String searchText) {
|
||||
SearchTask task = new SearchTask(folder, searchText);
|
||||
pendingOperations.put(task.getId(), task);
|
||||
threadPool.submit(task);
|
||||
return task.getId();
|
||||
}
|
||||
|
||||
public SearchResult getSearchResult(String id, int fileIndex,
|
||||
int folderIndex) {
|
||||
SearchTask task = pendingOperations.get(id);
|
||||
SearchResult res = new SearchResult(task.isDone(),
|
||||
task.getFiles().stream().skip(fileIndex)
|
||||
.collect(Collectors.toList()),
|
||||
task.getFolders().stream().skip(folderIndex)
|
||||
.collect(Collectors.toList()));
|
||||
return res;
|
||||
}
|
||||
|
||||
public void cancelSearch(String id) {
|
||||
SearchTask task = pendingOperations.get(id);
|
||||
task.stop();
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package webshell.app.files;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import webshell.app.files.search.SearchResult;
|
||||
import webshell.app.files.search.SearchTask;
|
||||
|
||||
/**
|
||||
* @author subhro
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class SearchOperations {
|
||||
private final Map<String, SearchTask> pendingOperations = new ConcurrentHashMap<>();
|
||||
private final ExecutorService threadPool = Executors.newFixedThreadPool(5);
|
||||
|
||||
public String createSearchTask(String folder, String searchText) {
|
||||
SearchTask task = new SearchTask(folder, searchText);
|
||||
pendingOperations.put(task.getId(), task);
|
||||
threadPool.submit(task);
|
||||
return task.getId();
|
||||
}
|
||||
|
||||
public SearchResult getSearchResult(String id, int fileIndex,
|
||||
int folderIndex) {
|
||||
SearchTask task = pendingOperations.get(id);
|
||||
SearchResult res = new SearchResult(task.isDone(), task.getFiles()
|
||||
.stream().skip(fileIndex).collect(Collectors.toList()));
|
||||
return res;
|
||||
}
|
||||
|
||||
public void cancelSearch(String id) {
|
||||
SearchTask task = pendingOperations.get(id);
|
||||
task.stop();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,71 +1,57 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package webshell.app.files.search;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author subhro
|
||||
*
|
||||
*/
|
||||
public class SearchResult {
|
||||
/**
|
||||
* @param isDone
|
||||
* @param files
|
||||
* @param folders
|
||||
*/
|
||||
public SearchResult(boolean isDone, List<String> files,
|
||||
List<String> folders) {
|
||||
super();
|
||||
this.isDone = isDone;
|
||||
this.files = files;
|
||||
this.folders = folders;
|
||||
}
|
||||
|
||||
private boolean isDone;
|
||||
private List<String> files = new ArrayList<>(), folders = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @return the isDone
|
||||
*/
|
||||
public boolean isDone() {
|
||||
return isDone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isDone the isDone to set
|
||||
*/
|
||||
public void setDone(boolean isDone) {
|
||||
this.isDone = isDone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the files
|
||||
*/
|
||||
public List<String> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param files the files to set
|
||||
*/
|
||||
public void setFiles(List<String> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the folders
|
||||
*/
|
||||
public List<String> getFolders() {
|
||||
return folders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param folders the folders to set
|
||||
*/
|
||||
public void setFolders(List<String> folders) {
|
||||
this.folders = folders;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package webshell.app.files.search;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import webshell.app.files.FileInfo;
|
||||
|
||||
/**
|
||||
* @author subhro
|
||||
*
|
||||
*/
|
||||
public class SearchResult {
|
||||
/**
|
||||
* @param isDone
|
||||
* @param files
|
||||
* @param folders
|
||||
*/
|
||||
public SearchResult(boolean isDone, List<FileInfo> files) {
|
||||
super();
|
||||
this.isDone = isDone;
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
private boolean isDone;
|
||||
private List<FileInfo> files = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @return the isDone
|
||||
*/
|
||||
public boolean isDone() {
|
||||
return isDone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isDone the isDone to set
|
||||
*/
|
||||
public void setDone(boolean isDone) {
|
||||
this.isDone = isDone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the files
|
||||
*/
|
||||
public List<FileInfo> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param files the files to set
|
||||
*/
|
||||
public void setFiles(List<FileInfo> files) {
|
||||
this.files = files;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,206 +1,215 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package webshell.app.files.search;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.FileVisitor;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* @author subhro
|
||||
*
|
||||
*/
|
||||
public class SearchTask implements Runnable {
|
||||
/**
|
||||
* @param folder
|
||||
* @param searchText
|
||||
*/
|
||||
public SearchTask(String folder, String searchText) {
|
||||
super();
|
||||
this.id = UUID.randomUUID().toString();
|
||||
this.folder = folder;
|
||||
this.searchText = searchText.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
private String id;
|
||||
private AtomicBoolean isDone = new AtomicBoolean(false);
|
||||
private List<String> files = new ArrayList<>(), folders = new ArrayList<>();
|
||||
private String folder;
|
||||
private String searchText;
|
||||
private AtomicBoolean stopRequested = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* @return the isDone
|
||||
*/
|
||||
public boolean isDone() {
|
||||
return isDone.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isDone the isDone to set
|
||||
*/
|
||||
public void setDone(boolean isDone) {
|
||||
this.isDone.set(isDone);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the files
|
||||
*/
|
||||
public List<String> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param files the files to set
|
||||
*/
|
||||
public void setFiles(List<String> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the folders
|
||||
*/
|
||||
public List<String> getFolders() {
|
||||
return folders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param folders the folders to set
|
||||
*/
|
||||
public void setFolders(List<String> folders) {
|
||||
this.folders = folders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the stopRequested
|
||||
*/
|
||||
public AtomicBoolean getStopRequested() {
|
||||
return stopRequested;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void stop() {
|
||||
System.out.println("Stopping...");
|
||||
this.stopRequested.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
System.out.println("Search start");
|
||||
Files.walkFileTree(Paths.get(folder), new FileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
//System.out.println("Search: " + dir.toString());
|
||||
if (stopRequested.get()) {
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
|
||||
if (isMatch(dir, searchText)) {
|
||||
folders.add(dir.toAbsolutePath().toString());
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
//System.out.println("Search: " + file);
|
||||
if (stopRequested.get()) {
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
|
||||
if (isMatch(file, searchText)) {
|
||||
files.add(file.toAbsolutePath().toString());
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(Path file,
|
||||
IOException exc) throws IOException {
|
||||
//System.out.println("visit failed: " + file);
|
||||
if (stopRequested.get()) {
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir,
|
||||
IOException exc) throws IOException {
|
||||
//System.out.println("post visit failed: " + dir);
|
||||
if (stopRequested.get()) {
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
private boolean isMatch(Path path, String text) {
|
||||
String name = path.toString();
|
||||
return name.toLowerCase(Locale.ENGLISH).contains(text);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("Search finished");
|
||||
isDone.set(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the searchText
|
||||
*/
|
||||
public String getSearchText() {
|
||||
return searchText;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param searchText the searchText to set
|
||||
*/
|
||||
public void setSearchText(String searchText) {
|
||||
this.searchText = searchText.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the folder
|
||||
*/
|
||||
public String getFolder() {
|
||||
return folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param folder the folder to set
|
||||
*/
|
||||
public void setFolder(String folder) {
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package webshell.app.files.search;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.FileVisitor;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import webshell.app.files.FileInfo;
|
||||
|
||||
/**
|
||||
* @author subhro
|
||||
*
|
||||
*/
|
||||
public class SearchTask implements Runnable {
|
||||
|
||||
private boolean posix;
|
||||
|
||||
/**
|
||||
* @param folder
|
||||
* @param searchText
|
||||
*/
|
||||
public SearchTask(String folder, String searchText) {
|
||||
super();
|
||||
this.id = UUID.randomUUID().toString();
|
||||
if (this.folder == null || this.folder.length() < 1) {
|
||||
this.folder = System.getProperty("user.home");
|
||||
} else {
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
this.searchText = searchText.toLowerCase(Locale.ENGLISH);
|
||||
posix = !System.getProperty("os.name").toLowerCase()
|
||||
.contains("windows");
|
||||
}
|
||||
|
||||
private String id;
|
||||
private AtomicBoolean isDone = new AtomicBoolean(false);
|
||||
private List<FileInfo> files = Collections
|
||||
.synchronizedList(new ArrayList<>());
|
||||
private String folder;
|
||||
private String searchText;
|
||||
private AtomicBoolean stopRequested = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* @return the isDone
|
||||
*/
|
||||
public boolean isDone() {
|
||||
return isDone.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isDone the isDone to set
|
||||
*/
|
||||
public void setDone(boolean isDone) {
|
||||
this.isDone.set(isDone);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the files
|
||||
*/
|
||||
public List<FileInfo> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param files the files to set
|
||||
*/
|
||||
public void setFiles(List<FileInfo> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the stopRequested
|
||||
*/
|
||||
public AtomicBoolean getStopRequested() {
|
||||
return stopRequested;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void stop() {
|
||||
System.out.println("Stopping...");
|
||||
this.stopRequested.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
System.out.println("Search start");
|
||||
Files.walkFileTree(Paths.get(folder), new FileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
// System.out.println("Search: " + dir.toString());
|
||||
if (stopRequested.get()) {
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
|
||||
if (isMatch(dir, searchText)) {
|
||||
File fdir = dir.toFile();
|
||||
FileInfo info = new FileInfo(fdir.getName(),
|
||||
fdir.getAbsolutePath(), "", "", "Directory", 0,
|
||||
0, null, posix);
|
||||
files.add(info);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
// System.out.println("Search: " + file);
|
||||
if (stopRequested.get()) {
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
|
||||
if (isMatch(file, searchText)) {
|
||||
File f = file.toFile();
|
||||
FileInfo info = new FileInfo(f.getName(),
|
||||
f.getAbsolutePath(), "", "", "File", 0, 0, null,
|
||||
posix);
|
||||
files.add(info);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(Path file,
|
||||
IOException exc) throws IOException {
|
||||
// System.out.println("visit failed: " + file);
|
||||
if (stopRequested.get()) {
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir,
|
||||
IOException exc) throws IOException {
|
||||
// System.out.println("post visit failed: " + dir);
|
||||
if (stopRequested.get()) {
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
private boolean isMatch(Path path, String text) {
|
||||
String name = path.toString();
|
||||
return name.toLowerCase(Locale.ENGLISH).contains(text);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("Search finished");
|
||||
isDone.set(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the searchText
|
||||
*/
|
||||
public String getSearchText() {
|
||||
return searchText;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param searchText the searchText to set
|
||||
*/
|
||||
public void setSearchText(String searchText) {
|
||||
this.searchText = searchText.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the folder
|
||||
*/
|
||||
public String getFolder() {
|
||||
return folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param folder the folder to set
|
||||
*/
|
||||
public void setFolder(String folder) {
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import { EditorContext } from './model/editor-context';
|
|||
import { FileOperationItem } from './model/file-operation-item';
|
||||
import { SearchContext } from './model/search-context';
|
||||
import { PosixPermissions } from './model/posix-permissions';
|
||||
import { FileItem } from './model/file-item';
|
||||
|
||||
|
||||
const MAX_ACTIVE_UPLOAD = 5;
|
||||
|
@ -61,7 +62,7 @@ export class DataService {
|
|||
leafNode: false
|
||||
};
|
||||
|
||||
posix:boolean;
|
||||
posix: boolean;
|
||||
|
||||
tabs: FolderTab[] = [];
|
||||
selectedTab: number;
|
||||
|
@ -73,6 +74,10 @@ export class DataService {
|
|||
|
||||
fileOpMonitor: any;
|
||||
|
||||
fileOpenRequests = new Subject<FileItem>();
|
||||
|
||||
currentViewChanger = new Subject<string>();
|
||||
|
||||
terminalSession: TerminalSession;
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
|
@ -99,7 +104,7 @@ export class DataService {
|
|||
return this.http.get<any>(environment.BASE_URL + "app/files/home");
|
||||
}
|
||||
|
||||
public downloadFiles(folder: string, files: string, tempToken:string) {
|
||||
public downloadFiles(folder: string, files: string, tempToken: string) {
|
||||
window.location.href = environment.BIN_URL + "download?folder=" + btoa(folder) + "&files=" + btoa(files) + "&token=" + tempToken;
|
||||
}
|
||||
|
||||
|
@ -393,7 +398,7 @@ export class DataService {
|
|||
return this.http.post<any>(environment.BASE_URL + "app/fs/touch", { name, dir });
|
||||
}
|
||||
|
||||
getTempToken():Observable<any> {
|
||||
getTempToken(): Observable<any> {
|
||||
return this.http.get<any>(environment.BASE_URL + "token/temp");
|
||||
}
|
||||
|
||||
|
|
|
@ -340,13 +340,13 @@
|
|||
</div>
|
||||
<!-- dropdown context menu end -->
|
||||
|
||||
<app-image-viewer [url]="getSelectedFile().path" *ngIf="previewer=='image'" (componentClosed)="previewer=null">
|
||||
<app-image-viewer [url]="fileToOpen.path" *ngIf="previewer=='image'" (componentClosed)="previewer=null">
|
||||
</app-image-viewer>
|
||||
<app-media-player [url]="getSelectedFile().path" *ngIf="previewer=='video'" (componentClosed)="previewer=null">
|
||||
<app-media-player [url]="fileToOpen.path" *ngIf="previewer=='video'" (componentClosed)="previewer=null">
|
||||
</app-media-player>
|
||||
<app-unsupported-content-viewer [url]="getSelectedFile().path" [file]="getSelectedFile().name"
|
||||
<app-unsupported-content-viewer [url]="fileToOpen.path" [file]="fileToOpen.name"
|
||||
*ngIf="previewer=='unsupported'" (componentClosed)="previewer=null" (onDownload)="downloadFiles()"
|
||||
(onOpen)="openAsText();previewer=null">
|
||||
(onOpen)="openWithTextEditor(fileToOpen.path);previewer=null">
|
||||
</app-unsupported-content-viewer>
|
||||
|
||||
<div *ngIf="toastVisible"
|
||||
|
|
|
@ -36,6 +36,8 @@ export class FilesComponent implements OnInit, OnDestroy {
|
|||
@Output()
|
||||
viewChanged = new EventEmitter<string>();
|
||||
|
||||
fileToOpen:FileItem;
|
||||
|
||||
uploadPopup: boolean;
|
||||
hoverIndex: number = -1;
|
||||
showRenameDialog: boolean = false;
|
||||
|
@ -57,6 +59,15 @@ export class FilesComponent implements OnInit, OnDestroy {
|
|||
ngOnInit() {
|
||||
console.log("File browser init")
|
||||
this.posix = this.service.posix;
|
||||
|
||||
this.service.fileOpenRequests.subscribe((file: FileItem) => {
|
||||
if (file.type == "Directory") {
|
||||
this.navigateTo(file.path);
|
||||
}else{
|
||||
this.openItem(file);
|
||||
}
|
||||
});
|
||||
|
||||
if (this.service.tabs.length < 1) {
|
||||
this.loading = true;
|
||||
this.service.listHome().subscribe((data: any) => {
|
||||
|
@ -105,6 +116,7 @@ export class FilesComponent implements OnInit, OnDestroy {
|
|||
openItem(fileItem: FileItem) {
|
||||
let file: string = fileItem.path;
|
||||
this.loading = true;
|
||||
this.fileToOpen=fileItem;
|
||||
console.log("Opening file: " + file)
|
||||
if (fileItem.type.startsWith("image")) {
|
||||
this.previewer = "image";
|
||||
|
@ -141,16 +153,16 @@ export class FilesComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
openAsText() {
|
||||
let file: string;
|
||||
for (let i = 0; i < this.service.tabs[this.service.selectedTab].files.length; i++) {
|
||||
if (this.service.tabs[this.service.selectedTab].files[i].selected) {
|
||||
file = this.service.tabs[this.service.selectedTab].files[i].path;
|
||||
this.openWithTextEditor(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// openAsText() {
|
||||
// let file: string;
|
||||
// for (let i = 0; i < this.service.tabs[this.service.selectedTab].files.length; i++) {
|
||||
// if (this.service.tabs[this.service.selectedTab].files[i].selected) {
|
||||
// file = this.service.tabs[this.service.selectedTab].files[i].path;
|
||||
// this.openWithTextEditor(file);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
navigateTo(file: string) {
|
||||
this.loading = true;
|
||||
|
@ -507,7 +519,7 @@ export class FilesComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
this.loading = true;
|
||||
if(!confirm("Are you sure, you want to delete?")){
|
||||
if (!confirm("Are you sure, you want to delete?")) {
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
|
@ -755,7 +767,7 @@ export class FilesComponent implements OnInit, OnDestroy {
|
|||
return 'fa fa-file-pdf-o';
|
||||
}
|
||||
else if (file.type.startsWith("application/javascript") ||
|
||||
file.type.includes("application/json")||
|
||||
file.type.includes("application/json") ||
|
||||
file.type.includes("application/xml")) {
|
||||
return 'fa fa-file-text-o';
|
||||
}
|
||||
|
|
|
@ -82,8 +82,10 @@ export class TreeComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
onClick() {
|
||||
console.log("tree clicked: " + this.model.path);
|
||||
this.openInTab();
|
||||
if (this.model.path) {
|
||||
console.log("tree clicked: " + this.model.path);
|
||||
this.openInTab();
|
||||
}
|
||||
}
|
||||
|
||||
onContextMenu(a: any, c: any) {
|
||||
|
@ -140,5 +142,4 @@ export class TreeComponent implements OnInit, OnChanges, OnDestroy {
|
|||
copyPath() {
|
||||
console.log("copyPath " + this.model.path);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -48,6 +48,9 @@ export class HomeComponent implements OnInit {
|
|||
constructor(private router: Router, public service: DataService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.service.currentViewChanger.subscribe((view: string) => {
|
||||
this.view = view;
|
||||
})
|
||||
if (!this.service.terminalSession) {
|
||||
this.service.connect().subscribe((data: any) => {
|
||||
console.log("terminal created on server: " + JSON.stringify(data));
|
||||
|
@ -62,7 +65,7 @@ export class HomeComponent implements OnInit {
|
|||
let ws: WebSocket = instance.createSocket(data.id, this.service.getJwtToken());
|
||||
ws.addEventListener('open', listener);
|
||||
ws.addEventListener('error', err => {
|
||||
console.log("Error: "+JSON.stringify(err));
|
||||
console.log("Error: " + JSON.stringify(err));
|
||||
});
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -37,18 +37,24 @@
|
|||
</div>
|
||||
<div *ngIf="ctx.searching" style="flex: 1; overflow: auto;">
|
||||
<div>
|
||||
<div *ngFor="let file of ctx.files" style="cursor: pointer;" (click)="openFile(file)">
|
||||
<span style="padding: 5px; padding-left: 10px;"><i class="fa fa-file" aria-hidden="true"></i></span>
|
||||
<span style="padding: 5px;">{{file}}</span>
|
||||
<div *ngFor="let file of ctx.files" style="cursor: pointer; padding: 10px; overflow: hidden;" (click)="openFile(file)">
|
||||
<div>
|
||||
<span style="padding: 5px;" *ngIf="file.type=='Directory'"><i class="fa fa-folder" aria-hidden="true"></i></span>
|
||||
<span style="padding: 5px;" *ngIf="file.type!='Directory'"><i class="fa fa-file" aria-hidden="true"></i></span>
|
||||
<span style="padding: 5px;">{{file.name}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span style="padding: 5px;">{{file.path}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngFor="let folder of ctx.folders" style="cursor: pointer;" (click)="openFolder(folder)">
|
||||
<!-- <div *ngFor="let folder of ctx.folders" style="cursor: pointer;" (click)="openFolder(folder)">
|
||||
<span style="padding: 5px; padding-left: 10px;">
|
||||
<i class="fa fa-folder" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span style="padding: 5px;">
|
||||
{{folder}}
|
||||
</span>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,7 @@ import { SearchContext } from 'src/app/model/search-context';
|
|||
import { EditorContext } from 'src/app/model/editor-context';
|
||||
import { utility } from '../../utility/utils';
|
||||
import { Router } from '@angular/router';
|
||||
import { FileItem } from 'src/app/model/file-item';
|
||||
|
||||
@Component({
|
||||
selector: 'app-search',
|
||||
|
@ -78,31 +79,33 @@ export class SearchComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
openFile(file: string) {
|
||||
this.loading = true;
|
||||
console.log("Opening file: " + file)
|
||||
this.service.getText(file).subscribe((text: string) => {
|
||||
this.service.selectedEditorTab = file;
|
||||
let ctx = new EditorContext(utility.getFileName(file), file, text);
|
||||
ctx.session.setUseWrapMode(false);
|
||||
this.service.editorContexts[file] = ctx;
|
||||
this.loading = false;
|
||||
console.log("before route init of editor: " + JSON.stringify(Object.keys(this.service.editorContexts)))
|
||||
this.router.navigate(["/app/editor"]);
|
||||
});
|
||||
openFile(file: FileItem) {
|
||||
this.service.fileOpenRequests.next(file);
|
||||
this.service.currentViewChanger.next(null);
|
||||
// this.loading = true;
|
||||
// console.log("Opening file: " + file)
|
||||
// this.service.getText(file).subscribe((text: string) => {
|
||||
// this.service.selectedEditorTab = file;
|
||||
// let ctx = new EditorContext(utility.getFileName(file), file, text);
|
||||
// ctx.session.setUseWrapMode(false);
|
||||
// this.service.editorContexts[file] = ctx;
|
||||
// this.loading = false;
|
||||
// console.log("before route init of editor: " + JSON.stringify(Object.keys(this.service.editorContexts)));
|
||||
// this.router.navigate(["/app/editor"]);
|
||||
// });
|
||||
}
|
||||
|
||||
openFolder(folder: string) {
|
||||
this.service.tabs.push({
|
||||
files: null,
|
||||
currentDirectory: folder,
|
||||
selected: true,
|
||||
folderName: utility.getFileName(folder),
|
||||
posix: false
|
||||
});
|
||||
this.service.selectedTab = this.service.tabs.length - 1;
|
||||
this.router.navigate(["/app/files"]);
|
||||
}
|
||||
// openFolder(folder: string) {
|
||||
// this.service.tabs.push({
|
||||
// files: null,
|
||||
// currentDirectory: folder,
|
||||
// selected: true,
|
||||
// folderName: utility.getFileName(folder),
|
||||
// posix: false
|
||||
// });
|
||||
// this.service.selectedTab = this.service.tabs.length - 1;
|
||||
// this.router.navigate(["/app/files"]);
|
||||
// }
|
||||
|
||||
getItemCount() {
|
||||
let count = 0;
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
export class SearchContext {
|
||||
id: string;
|
||||
searchText: string;
|
||||
files: string[]=[];
|
||||
folders: string[]=[];
|
||||
searching: boolean;
|
||||
isDone: boolean;
|
||||
folder: string;
|
||||
import { FileItem } from './file-item';
|
||||
|
||||
export class SearchContext {
|
||||
id: string;
|
||||
searchText: string;
|
||||
files: FileItem[]=[];
|
||||
folders: FileItem[]=[];
|
||||
searching: boolean;
|
||||
isDone: boolean;
|
||||
folder: string;
|
||||
}
|
|
@ -1,22 +1,22 @@
|
|||
const GB = 1024 * 1024 * 1024;
|
||||
const MB = 1024 * 1024;
|
||||
const KB = 1024;
|
||||
export const utility = {
|
||||
|
||||
getFileName(path: string): string {
|
||||
let fragments = path.split(/\\|\//);
|
||||
return fragments.pop();
|
||||
},
|
||||
|
||||
formatSize(sz: number): string {
|
||||
if (sz > GB) {
|
||||
return (sz / GB).toFixed(1) + " GB";
|
||||
} else if (sz > MB) {
|
||||
return (sz / MB).toFixed(1) + " MB";
|
||||
} else if (sz > KB) {
|
||||
return (sz / KB).toFixed(1) + " KB";
|
||||
} else {
|
||||
return sz + " B";
|
||||
}
|
||||
}
|
||||
const GB = 1024 * 1024 * 1024;
|
||||
const MB = 1024 * 1024;
|
||||
const KB = 1024;
|
||||
export const utility = {
|
||||
|
||||
getFileName(path: string): string {
|
||||
let fragments = path.split(/\\|\//);
|
||||
return fragments.pop();
|
||||
},
|
||||
|
||||
formatSize(sz: number): string {
|
||||
if (sz > GB) {
|
||||
return (sz / GB).toFixed(1) + " GB";
|
||||
} else if (sz > MB) {
|
||||
return (sz / MB).toFixed(1) + " MB";
|
||||
} else if (sz > KB) {
|
||||
return (sz / KB).toFixed(1) + " KB";
|
||||
} else {
|
||||
return sz + " B";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>WebShellJs</title>
|
||||
<title>Easy Web Shell</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
|
|
Loading…
Reference in New Issue