overhauling constants, working on translations

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2026-01-15 13:58:50 +01:00
parent 669853352e
commit 0d1cdd35d1
103 changed files with 2161 additions and 1207 deletions

View File

@@ -2,23 +2,25 @@
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.constants.Field.*;
import static de.srsoftware.umbrella.core.constants.Path.PROJECT;
import static de.srsoftware.umbrella.core.constants.Text.LONG;
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 de.srsoftware.umbrella.core.model.Translatable.t;
import static de.srsoftware.umbrella.files.Constants.*;
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;
import de.srsoftware.tools.Path;
import de.srsoftware.tools.SessionToken;
import de.srsoftware.umbrella.core.BaseHandler;
import de.srsoftware.umbrella.core.ModuleRegistry;
import de.srsoftware.umbrella.core.api.FileService;
import de.srsoftware.umbrella.core.constants.Path;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Company;
import de.srsoftware.umbrella.core.model.Project;
@@ -39,21 +41,21 @@ public class FileModule extends BaseHandler implements FileService {
public FileModule(Configuration config) throws UmbrellaException {
super();
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
var filestore = config.get(CONFIG_FILESTORE).orElseThrow(() -> missingFieldException(CONFIG_FILESTORE));
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE));
var filestore = config.get(CONFIG_FILESTORE).orElseThrow(() -> missingField(CONFIG_FILESTORE));
baseDir = new File(filestore.toString());
if (!baseDir.exists()) try {
Files.createDirectories(baseDir.toPath());
} catch (IOException e) {
throw unprocessable("Failed to create {0}",baseDir);
throw unprocessable("Failed to create {location}", LOCATION,baseDir);
}
if (!baseDir.isDirectory()) throw unprocessable("{0} is not a directory!");
if (!baseDir.isDirectory()) throw unprocessable("{location} is not a directory!", LOCATION,baseDir);
fileDb = new SqliteDb(connect(dbFile));
ModuleRegistry.add(this);
}
@Override
public boolean doDelete(Path path, HttpExchange ex) throws IOException {
public boolean doDelete(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException {
addCors(ex);
try {
Optional<Token> token = SessionToken.from(ex).map(Token::of);
@@ -61,17 +63,17 @@ public class FileModule extends BaseHandler implements FileService {
if (user.isEmpty()) return unauthorized(ex);
var head = path.pop();
return switch (head){
case COMPANY -> deleteCompanyFile(path, ex, user.get());
case Path.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);
case Path.USER -> deleteUserFile(path, ex, user.get());
case null, default -> throw UmbrellaException.notFound("invalid location: {location}", LOCATION, head);
};
} catch (UmbrellaException e) {
return send(ex,e);
}
}
private boolean deleteCompanyFile(Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
private boolean deleteCompanyFile(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
var cpId = path.pop();
var companies = companyService();
Map<Long, Company> companyList;
@@ -85,17 +87,17 @@ public class FileModule extends BaseHandler implements FileService {
try {
cid = Long.parseLong(cpId);
} catch (NumberFormatException e) {
throw invalidFieldException(COMPANY_ID,"Long");
throw invalidField(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);
if (!companies.membership(cid,user.id()) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename);
return deleteFile(ex, new File(baseDir+filename));
}
private boolean deleteProjectFile(Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
private boolean deleteProjectFile(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
var prjId = path.pop();
var projects = projectService();
if (prjId == null){
@@ -108,12 +110,12 @@ public class FileModule extends BaseHandler implements FileService {
try {
pid = Long.parseLong(prjId);
} catch (NumberFormatException e) {
throw invalidFieldException(PROJECT_ID,"Long");
throw invalidField(PROJECT_ID,t(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);
if (!project.hasMember(user) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename);
return deleteFile(ex, new File(baseDir+filename));
}
@@ -128,7 +130,7 @@ public class FileModule extends BaseHandler implements FileService {
}
private boolean deleteFile(HttpExchange ex, File file) throws IOException {
if (!file.exists()) throw unprocessable("{0} does not exist!",file.getName());
if (!file.exists()) throw unprocessable("{file} does not exist!",FILE,file.getName());
if (!dropDir(file)) return sendContent(ex,HTTP_SERVER_ERROR,format("Failed to delete {0}",file.getName()));
Map<String,Object> map = getDirectory(file.getParentFile());
map.put("title",file.getName());
@@ -137,23 +139,23 @@ public class FileModule extends BaseHandler implements FileService {
}
private boolean deleteUserFile(Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
private boolean deleteUserFile(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
var userId = path.pop();
if (userId == null) throw missingFieldException(USER_ID);
if (userId == null) throw missingField(USER_ID);
long uid;
try {
uid = Long.parseLong(userId);
} catch (NumberFormatException e) {
throw invalidFieldException(PROJECT_ID,"Long");
throw invalidField(PROJECT_ID,t(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);
if (uid != user.id() && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename);
return deleteFile(ex, new File(baseDir+filename));
}
@Override
public boolean doGet(Path path, HttpExchange ex) throws IOException {
public boolean doGet(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException {
addCors(ex);
try {
Optional<Token> token = SessionToken.from(ex).map(Token::of);
@@ -161,10 +163,10 @@ public class FileModule extends BaseHandler implements FileService {
if (user.isEmpty()) return unauthorized(ex);
var head = path.pop();
return switch (head){
case COMPANY -> getCompanyFiles(path, ex, user.get());
case Path.COMPANY -> getCompanyFiles(path, ex, user.get());
case PROJECT -> getProjectFiles(path, ex, user.get());
case USER -> getUserFiles(path, ex, user.get());
case null, default -> throw UmbrellaException.notFound("invalid location: {0}", head);
case Path.USER -> getUserFiles(path, ex, user.get());
case null, default -> throw UmbrellaException.notFound("invalid location: {location}", LOCATION, head);
};
} catch (UmbrellaException e) {
return send(ex,e);
@@ -172,7 +174,7 @@ public class FileModule extends BaseHandler implements FileService {
}
@Override
public boolean doPost(Path path, HttpExchange ex) throws IOException {
public boolean doPost(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException {
addCors(ex);
try {
Optional<Token> token = SessionToken.from(ex).map(Token::of);
@@ -180,10 +182,10 @@ public class FileModule extends BaseHandler implements FileService {
if (user.isEmpty()) return unauthorized(ex);
var head = path.pop();
return switch (head){
case COMPANY -> postCompanyDirectory(path, ex, user.get());
case Path.COMPANY -> postCompanyDirectory(path, ex, user.get());
case PROJECT -> postProjectDirectory(path, ex, user.get());
case USER -> postUserDirectory(path, ex, user.get());
case null, default -> throw UmbrellaException.notFound("invalid location: {0}", head);
case Path.USER -> postUserDirectory(path, ex, user.get());
case null, default -> throw UmbrellaException.notFound("invalid location: {location}", LOCATION, head);
};
} catch (UmbrellaException e) {
return send(ex,e);
@@ -199,11 +201,11 @@ public class FileModule extends BaseHandler implements FileService {
body.close();
out.close();
} else {
if (file.exists()) throw unprocessable("{0} already exists!", filename);
if (file.exists()) throw unprocessable("{file} already exists!",FILE, filename);
try {
file.mkdirs();
} catch (Exception e) {
throw unprocessable("Failed to create {0}", filename);
throw unprocessable("Failed to create {file}", FILE, filename);
}
}
Map<String,Object> map = getDirectory(file.getParentFile());
@@ -211,7 +213,7 @@ public class FileModule extends BaseHandler implements FileService {
return sendContent(ex,map);
}
private boolean getCompanyFiles(Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
private boolean getCompanyFiles(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
var cpId = path.pop();
var companies = companyService();
Map<Long, Company> companyList;
@@ -225,17 +227,17 @@ public class FileModule extends BaseHandler implements FileService {
try {
cid = Long.parseLong(cpId);
} catch (NumberFormatException e) {
throw invalidFieldException(COMPANY_ID,"Long");
throw invalidField(COMPANY_ID,LONG);
}
var company = companies.get(cid);
var companyDir = "/company/"+cid;
var filename = path.empty() ? companyDir : companyDir + "/"+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);
if (!companies.membership(cid,user.id()) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}", FILE, filename);
var file = new File(baseDir+filename);
if (!file.exists()){
if (!filename.equals(companyDir)) throw unprocessable("{0} does not exist!",filename);
if (!file.mkdirs()) throw unprocessable("Failed to create directory {0}!",filename);
if (!filename.equals(companyDir)) throw unprocessable("{file} does not exist!", FILE, filename);
if (!file.mkdirs()) throw unprocessable("Failed to create directory {name}!", NAME,filename);
}
if (file.isDirectory()){
Map<String,Object> map = getDirectory(file);
@@ -273,7 +275,7 @@ public class FileModule extends BaseHandler implements FileService {
}
private boolean getProjectFiles(Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
private boolean getProjectFiles(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
var prjId = path.pop();
var projects = projectService();
if (prjId == null){
@@ -286,16 +288,16 @@ public class FileModule extends BaseHandler implements FileService {
try {
pid = Long.parseLong(prjId);
} catch (NumberFormatException e) {
throw invalidFieldException(PROJECT_ID,"Long");
throw invalidField(PROJECT_ID,t(LONG));
}
var project = projects.loadMembers(projects.load(pid));
var projectDir = "/project/"+pid;
var filename = path.empty() ? projectDir : projectDir+"/"+URLDecoder.decode(path.toString(),UTF_8);
if (!project.hasMember(user) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename);
if (!project.hasMember(user) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}", FILE,filename);
var file = new File(baseDir+filename);
if (!file.exists()){
if (!filename.equals(projectDir)) throw unprocessable("{0} does not exist!",filename);
if (!file.mkdirs()) throw unprocessable("Failed to create directory {0}!",filename);
if (!filename.equals(projectDir)) throw unprocessable("{file} does not exist!",FILE,filename);
if (!file.mkdirs()) throw unprocessable("Failed to create directory {name}!", NAME,filename);
}
if (file.isDirectory()){
Map<String,Object> map = getDirectory(file);
@@ -306,23 +308,23 @@ public class FileModule extends BaseHandler implements FileService {
return getFile(ex, file);
}
private boolean getUserFiles(Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
private boolean getUserFiles(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
var userId = path.pop();
if (userId == null) throw missingFieldException(USER_ID);
if (userId == null) throw missingField(USER_ID);
long uid;
try {
uid = Long.parseLong(userId);
} catch (NumberFormatException e) {
throw invalidFieldException(PROJECT_ID,"Long");
throw invalidField(PROJECT_ID,t(LONG));
}
var userDir = "/user/"+uid;
var filename = path.empty() ? userDir : userDir+"/"+URLDecoder.decode(path.toString(),UTF_8);
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);
if (uid != user.id() && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename);
var file = new File(baseDir+filename);
if (!file.exists()){
if (!filename.equals(userDir)) throw unprocessable("{0} does not exist!",filename);
if (!file.mkdirs()) throw unprocessable("Failed to create directory {0}!",filename);
if (!filename.equals(userDir)) throw unprocessable("{file} does not exist!",FILE,filename);
if (!file.mkdirs()) throw unprocessable("Failed to create directory {name}!", NAME,filename);
} if (file.isDirectory()){
Map<String,Object> map = getDirectory(file);
map.put("title",filename);
@@ -332,7 +334,7 @@ public class FileModule extends BaseHandler implements FileService {
return getFile(ex, file);
}
private boolean postCompanyDirectory(Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
private boolean postCompanyDirectory(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
var cpId = path.pop();
var companies = companyService();
Map<Long, Company> companyList;
@@ -346,16 +348,16 @@ public class FileModule extends BaseHandler implements FileService {
try {
cid = Long.parseLong(cpId);
} catch (NumberFormatException e) {
throw invalidFieldException(COMPANY_ID,"Long");
throw invalidField(COMPANY_ID,LONG);
}
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);
if (!companies.membership(cid,user.id()) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename);
return doPost(ex,filename);
}
private boolean postProjectDirectory(Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
private boolean postProjectDirectory(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
var prjId = path.pop();
var projects = projectService();
if (prjId == null){
@@ -368,27 +370,27 @@ public class FileModule extends BaseHandler implements FileService {
try {
pid = Long.parseLong(prjId);
} catch (NumberFormatException e) {
throw invalidFieldException(PROJECT_ID,"Long");
throw invalidField(PROJECT_ID,t(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);
if (!project.hasMember(user) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename);
return doPost(ex,filename);
}
private boolean postUserDirectory(Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
private boolean postUserDirectory(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException {
var userId = path.pop();
if (userId == null) throw missingFieldException(USER_ID);
if (userId == null) throw missingField(USER_ID);
long uid;
try {
uid = Long.parseLong(userId);
} catch (NumberFormatException e) {
throw invalidFieldException(PROJECT_ID,"Long");
throw invalidField(PROJECT_ID,t(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);
if (uid != user.id() && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename);
return doPost(ex,filename);
}
}

View File

@@ -4,10 +4,10 @@ package de.srsoftware.umbrella.files;
import static de.srsoftware.tools.jdbc.Condition.equal;
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
import static de.srsoftware.tools.jdbc.Query.select;
import static de.srsoftware.umbrella.core.Constants.USER_ID;
import static de.srsoftware.umbrella.core.Errors.FAILED_TO_CHECK_FILE_PERMISSIONS;
import static de.srsoftware.umbrella.core.Errors.FAILED_TO_CREATE_TABLE;
import static de.srsoftware.umbrella.core.constants.Field.USER_ID;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.failedToCreateTable;
import static de.srsoftware.umbrella.files.Constants.FILE;
import static de.srsoftware.umbrella.files.Constants.TABLE_FILE_SHARES;
import static java.text.MessageFormat.format;
@@ -37,9 +37,9 @@ public class SqliteDb extends BaseDb implements FileDb {
private void createShareTable() {
var sql = "CREATE TABLE IF NOT EXISTS {0} ({1} VARCHAR(2048) NOT NULL, {2} INT NOT NULL, PRIMARY KEY({1}, {2}))";
try {
db.prepareStatement(format(sql, TABLE_FILE_SHARES,FILE,USER_ID)).execute();
db.prepareStatement(format(sql, TABLE_FILE_SHARES,FILE, USER_ID)).execute();
} catch (SQLException e){
throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_FILE_SHARES).causedBy(e);
throw failedToCreateTable(TABLE_FILE_SHARES).causedBy(e);
}
}