From 326363f162b79fe6e0a27ad8ac3fb2cc5d10d800 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Thu, 2 Oct 2025 00:09:30 +0200 Subject: [PATCH] working on file deletion Signed-off-by: Stephan Richter --- .../srsoftware/umbrella/files/FileModule.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/files/src/main/java/de/srsoftware/umbrella/files/FileModule.java b/files/src/main/java/de/srsoftware/umbrella/files/FileModule.java index 1d2abfc..25960f8 100644 --- a/files/src/main/java/de/srsoftware/umbrella/files/FileModule.java +++ b/files/src/main/java/de/srsoftware/umbrella/files/FileModule.java @@ -4,11 +4,13 @@ package de.srsoftware.umbrella.files; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.ModuleRegistry.*; +import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.files.Constants.CONFIG_DATABASE; import static de.srsoftware.umbrella.files.Constants.CONFIG_FILESTORE; import static java.net.HttpURLConnection.HTTP_OK; import static java.nio.charset.StandardCharsets.UTF_8; +import static java.text.MessageFormat.format; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; @@ -51,6 +53,110 @@ public class FileModule extends BaseHandler implements FileService { ModuleRegistry.add(this); } + @Override + public boolean doDelete(Path path, HttpExchange ex) throws IOException { + addCors(ex); + try { + Optional token = SessionToken.from(ex).map(Token::of); + var user = userService().loadUser(token); + if (user.isEmpty()) return unauthorized(ex); + var head = path.pop(); + return switch (head){ + case COMPANY -> deleteCompanyFile(path, ex, user.get()); + case PROJECT -> deleteProjectFile(path, ex, user.get()); + case USER -> deleteUserFile(path, ex, user.get()); + case null, default -> throw UmbrellaException.notFound("invalid location: {0}", head); + }; + } catch (UmbrellaException e) { + return send(ex,e); + } + } + + private boolean deleteCompanyFile(Path path, HttpExchange ex, UmbrellaUser user) throws IOException { + var cpId = path.pop(); + var companies = companyService(); + Map companyList; + if (cpId == null){ + companyList = companies.listCompaniesOf(user); + var map = companyList.values().stream().collect(Collectors.toMap(company -> "/company/"+company.id(), Company::name)); + return sendContent(ex,Map.of("dirs",map)); + } + + long cid; + try { + cid = Long.parseLong(cpId); + } catch (NumberFormatException e) { + throw invalidFieldException(COMPANY_ID,"Long"); + } + + var company = companies.get(cid); + var filename = "/company/"+cid; + if (!path.empty()) filename += "/"+URLDecoder.decode(path.toString(),UTF_8); + if (!companies.membership(cid,user.id()) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + var file = new File(baseDir+filename); + if (!file.exists()) throw unprocessable("{0} does not exist!",filename); + + return false; + } + + private boolean deleteProjectFile(Path path, HttpExchange ex, UmbrellaUser user) throws IOException { + var prjId = path.pop(); + var projects = projectService(); + if (prjId == null){ + var projectList = projects.listUserProjects(user.id(),true); + var map = projectList.values().stream().collect(Collectors.toMap(prj -> "/project/"+prj.id(),Project::name)); + return sendContent(ex,Map.of("dirs",map)); + } + + long pid; + try { + pid = Long.parseLong(prjId); + } catch (NumberFormatException e) { + throw invalidFieldException(PROJECT_ID,"Long"); + } + var project = projects.loadMembers(projects.load(pid)); + var filename = "/project/"+pid; + if (!path.empty()) filename += "/"+URLDecoder.decode(path.toString(),UTF_8); + if (!project.hasMember(user) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + return deleteFile(ex, new File(baseDir+filename)); + } + + private static boolean dropDir(File dir) { + File[] nested = dir.listFiles(); + if (nested != null) { + for (File file : nested) { + if (!dropDir(file)) return false; + } + } + return dir.delete(); + } + + private boolean deleteFile(HttpExchange ex, File file) throws IOException { + if (!file.exists()) throw unprocessable("{0} does not exist!",file.getName()); + if (!dropDir(file)) return sendContent(ex,HTTP_SERVER_ERROR,format("Failed to delete {0}",file.getName())); + Map map = getDirectory(file.getParentFile()); + map.put("title",file.getName()); + return sendContent(ex,map); + + } + + private boolean deleteUserFile(Path path, HttpExchange ex, UmbrellaUser user) { + var userId = path.pop(); + if (userId == null) throw missingFieldException(USER_ID); + long uid; + try { + uid = Long.parseLong(userId); + } catch (NumberFormatException e) { + throw invalidFieldException(PROJECT_ID,"Long"); + } + var filename = "/user/"+uid; + if (!path.empty()) filename += "/"+URLDecoder.decode(path.toString(),UTF_8); + if (uid != user.id() && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + var file = new File(baseDir+filename); + if (!file.exists()) throw unprocessable("{0} does not exist!",filename); + return false; + } + @Override public boolean doGet(Path path, HttpExchange ex) throws IOException { addCors(ex);