Merge branch 'main' into module/timetracking
This commit is contained in:
@@ -15,10 +15,7 @@ import de.srsoftware.umbrella.core.Util;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.documents.DocumentApi;
|
||||
import de.srsoftware.umbrella.items.ItemApi;
|
||||
import de.srsoftware.umbrella.legacy.CompanyLegacy;
|
||||
import de.srsoftware.umbrella.legacy.NotesLegacy;
|
||||
import de.srsoftware.umbrella.legacy.ProjectLegacy;
|
||||
import de.srsoftware.umbrella.legacy.UserLegacy;
|
||||
import de.srsoftware.umbrella.legacy.*;
|
||||
import de.srsoftware.umbrella.markdown.MarkdownApi;
|
||||
import de.srsoftware.umbrella.message.MessageSystem;
|
||||
import de.srsoftware.umbrella.notes.NoteModule;
|
||||
@@ -79,8 +76,9 @@ public class Application {
|
||||
new ProjectModule(registry, config).bindPath("/api/project").on(server);
|
||||
new ProjectLegacy(registry,config).bindPath("/legacy/project").on(server);
|
||||
new TaskModule(registry, config).bindPath("/api/task").on(server);
|
||||
new TaskLegacy(registry, config).bindPath("/legacy/task").on(server);
|
||||
new TimeModule(registry, config).bindPath("/api/time").on(server);
|
||||
new WebHandler().bindPath("/").on(server);
|
||||
new WebHandler(registry).bindPath("/").on(server);
|
||||
|
||||
server.setExecutor(Executors.newFixedThreadPool(threads));
|
||||
server.start();
|
||||
|
||||
@@ -26,12 +26,11 @@ import org.json.JSONArray;
|
||||
|
||||
public class BookmarkApi extends BaseHandler implements BookmarkService {
|
||||
private final BookmarkDb db;
|
||||
private final ModuleRegistry registry;
|
||||
|
||||
public BookmarkApi(ModuleRegistry registry, Configuration config) {
|
||||
super(registry);
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
db = new SqliteDb(connect(dbFile));
|
||||
this.registry = registry.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,7 +38,7 @@ public class BookmarkApi extends BaseHandler implements BookmarkService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -59,7 +58,7 @@ public class BookmarkApi extends BaseHandler implements BookmarkService {
|
||||
|
||||
private boolean getBookmark(UmbrellaUser user, long id, HttpExchange ex) throws IOException {
|
||||
var bookmark = db.load(id,user.id());
|
||||
registry.tagService().getTags(BOOKMARK, id, user).forEach(bookmark.tags()::add);
|
||||
tagService().getTags(BOOKMARK, id, user).forEach(bookmark.tags()::add);
|
||||
return sendContent(ex,bookmark);
|
||||
}
|
||||
|
||||
@@ -68,7 +67,7 @@ public class BookmarkApi extends BaseHandler implements BookmarkService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -115,7 +114,7 @@ public class BookmarkApi extends BaseHandler implements BookmarkService {
|
||||
|
||||
if (json.has(TAGS) && json.get(TAGS) instanceof JSONArray tagList){
|
||||
var list = tagList.toList().stream().map(Object::toString).toList();
|
||||
registry.tagService().save(BOOKMARK,bookmark.urlId(), userList, list);
|
||||
tagService().save(BOOKMARK,bookmark.urlId(), userList, list);
|
||||
}
|
||||
return sendContent(ex,bookmark);
|
||||
}
|
||||
|
||||
@@ -24,20 +24,19 @@ import java.util.*;
|
||||
public class CompanyModule extends BaseHandler implements CompanyService {
|
||||
|
||||
private final CompanyDb companyDb;
|
||||
private final ModuleRegistry registry;
|
||||
|
||||
public CompanyModule(ModuleRegistry registry, Configuration config) throws UmbrellaException {
|
||||
super(registry);
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
companyDb = new SqliteDb(connect(dbFile));
|
||||
this.registry = registry.add(this);
|
||||
}
|
||||
|
||||
private boolean deleteCompany(long companyId, UmbrellaUser user, HttpExchange ex) throws IOException {
|
||||
var company = get(companyId);
|
||||
if (!membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
if (!registry.documentService().list(companyId).isEmpty()) throw forbidden("There are documents owned by {0}",company.name());
|
||||
if (!registry.itemService().list(companyId).isEmpty()) throw forbidden("There are items owned by {0}",company.name());
|
||||
if (!registry.projectService().listCompanyProjects(companyId,true).isEmpty()) throw forbidden("There are projects owned by {0}",company.name());
|
||||
if (!documentService().list(companyId).isEmpty()) throw forbidden("There are documents owned by {0}",company.name());
|
||||
if (!itemService().list(companyId).isEmpty()) throw forbidden("There are items owned by {0}",company.name());
|
||||
if (!projectService().listCompanyProjects(companyId,true).isEmpty()) throw forbidden("There are projects owned by {0}",company.name());
|
||||
return sendContent(ex, companyDb.drop(companyId));
|
||||
}
|
||||
|
||||
@@ -46,7 +45,7 @@ public class CompanyModule extends BaseHandler implements CompanyService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -65,7 +64,7 @@ public class CompanyModule extends BaseHandler implements CompanyService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head){
|
||||
@@ -83,7 +82,7 @@ public class CompanyModule extends BaseHandler implements CompanyService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -102,7 +101,7 @@ public class CompanyModule extends BaseHandler implements CompanyService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -130,7 +129,7 @@ public class CompanyModule extends BaseHandler implements CompanyService {
|
||||
@Override
|
||||
public Collection<UmbrellaUser> getMembers(long companyId) throws UmbrellaException {
|
||||
var members = new HashSet<UmbrellaUser>();
|
||||
for (var userId : companyDb.getMembers(companyId)) members.add(registry.userService().loadUser(userId));
|
||||
for (var userId : companyDb.getMembers(companyId)) members.add(userService().loadUser(userId));
|
||||
return members;
|
||||
}
|
||||
|
||||
@@ -148,7 +147,7 @@ public class CompanyModule extends BaseHandler implements CompanyService {
|
||||
var userMap = new HashMap<Long,UmbrellaUser>();
|
||||
for (var company : companyList){
|
||||
for (var userId : companyDb.getMembers(company.id())){
|
||||
var user = userMap.computeIfAbsent(userId,k -> registry.userService().loadUser(userId));
|
||||
var user = userMap.computeIfAbsent(userId,k -> userService().loadUser(userId));
|
||||
company.members().put(userId,user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import static java.net.HttpURLConnection.*;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.tools.Path;
|
||||
import de.srsoftware.tools.PathHandler;
|
||||
import de.srsoftware.umbrella.core.api.*;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -16,8 +17,14 @@ import java.util.List;
|
||||
|
||||
public abstract class BaseHandler extends PathHandler {
|
||||
|
||||
private final ModuleRegistry registry;
|
||||
|
||||
public record Page(String mime, byte[] bytes){}
|
||||
|
||||
public BaseHandler(ModuleRegistry registry){
|
||||
this.registry = registry.add(this);
|
||||
}
|
||||
|
||||
public HttpExchange addCors(HttpExchange ex){
|
||||
var headers = ex.getRequestHeaders();
|
||||
var origin = nullable(headers.get("Origin")).orElse(List.of()).stream().filter(url -> url.contains("://localhost")||url.contains("://127.0.0.1")).findAny();
|
||||
@@ -34,11 +41,23 @@ public abstract class BaseHandler extends PathHandler {
|
||||
return ex;
|
||||
}
|
||||
|
||||
public CompanyService companyService(){
|
||||
return registry.companyService();
|
||||
}
|
||||
|
||||
public DocumentService documentService(){
|
||||
return registry.documentService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doOptions(Path path, HttpExchange ex) throws IOException {
|
||||
return ok(addCors(ex));
|
||||
}
|
||||
|
||||
public ItemService itemService(){
|
||||
return registry.itemService();
|
||||
}
|
||||
|
||||
public boolean load(Path path, HttpExchange ex) throws IOException {
|
||||
try {
|
||||
var doc = load(path.toString());
|
||||
@@ -65,17 +84,43 @@ public abstract class BaseHandler extends PathHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public NoteService noteService(){
|
||||
return registry.noteService();
|
||||
}
|
||||
|
||||
public boolean ok(HttpExchange ex) throws IOException {
|
||||
return sendEmptyResponse(HTTP_OK,ex);
|
||||
}
|
||||
|
||||
public PostBox postBox() {
|
||||
return registry.postBox();
|
||||
}
|
||||
|
||||
public ProjectService projectService(){
|
||||
return registry.projectService();
|
||||
}
|
||||
|
||||
public boolean send(HttpExchange ex, UmbrellaException e) throws IOException {
|
||||
return sendContent(ex,e.statusCode(),e.getMessage());
|
||||
}
|
||||
|
||||
public TagService tagService(){
|
||||
return registry.tagService();
|
||||
}
|
||||
|
||||
public TaskService taskService(){
|
||||
return registry.taskService();
|
||||
}
|
||||
|
||||
public Translator translator(){
|
||||
return registry.translator();
|
||||
}
|
||||
|
||||
public boolean unauthorized(HttpExchange ex) throws IOException {
|
||||
return sendEmptyResponse(HTTP_UNAUTHORIZED,ex);
|
||||
}
|
||||
|
||||
|
||||
public UserService userService(){
|
||||
return registry.userService();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,86 +1,49 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.core;
|
||||
|
||||
|
||||
import de.srsoftware.umbrella.core.api.*;
|
||||
|
||||
public class ModuleRegistry {
|
||||
private Translator translator;
|
||||
private PostBox postBox;
|
||||
private UserService userService;
|
||||
private TagService tagService;
|
||||
private BookmarkService bookmarkService;
|
||||
private CompanyService companyService;
|
||||
private DocumentService documentService;
|
||||
private ItemService itemService;
|
||||
private MarkdownService markdownService;
|
||||
private NoteService noteService;
|
||||
private PostBox postBox;
|
||||
private ProjectService projectService;
|
||||
private TagService tagService;
|
||||
private TaskService taskService;
|
||||
private TimeService timeService;
|
||||
private Translator translator;
|
||||
private UserService userService;
|
||||
|
||||
public ModuleRegistry add(BookmarkService bookmarkService) {
|
||||
this.bookmarkService = bookmarkService;
|
||||
|
||||
|
||||
public ModuleRegistry add(Object service) {
|
||||
switch (service) {
|
||||
case BookmarkService bs: bookmarkService = bs; break;
|
||||
case CompanyService cs: companyService = cs; break;
|
||||
case DocumentService ds: documentService = ds; break;
|
||||
case ItemService is: itemService = is; break;
|
||||
case MarkdownService ms: markdownService = ms; break;
|
||||
case NoteService ns: noteService = ns; break;
|
||||
case PostBox pb: postBox = pb; break;
|
||||
case ProjectService ps: projectService = ps; break;
|
||||
case TagService ts: tagService = ts; break;
|
||||
case TaskService ts: taskService = ts; break;
|
||||
case TimeService ts: timeService = ts; break;
|
||||
case Translator tr: translator = tr; break;
|
||||
case UserService us: userService = us; break;
|
||||
case null: break;
|
||||
default: System.getLogger(getClass().getSimpleName()).log(System.Logger.Level.WARNING,"Trying to add untracked class {0} to {1}",service.getClass().getSimpleName(),getClass().getSimpleName());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(CompanyService companyService) {
|
||||
this.companyService = companyService;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(DocumentService documentService) {
|
||||
this.documentService = documentService;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(ItemService itemService) {
|
||||
this.itemService = itemService;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(MarkdownService markdownService) {
|
||||
this.markdownService = markdownService;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(NoteService noteService) {
|
||||
this.noteService = noteService;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(PostBox postBox) {
|
||||
this.postBox = postBox;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(ProjectService projectService) {
|
||||
this.projectService = projectService;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(TagService tagService) {
|
||||
this.tagService = tagService;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(TaskService taskService) {
|
||||
this.taskService = taskService;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(TimeService timeService) {
|
||||
this.timeService = timeService;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(Translator translator) {
|
||||
this.translator = translator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModuleRegistry add(UserService userService) {
|
||||
this.userService = userService;
|
||||
return this;
|
||||
public BookmarkService bookmarkService(){
|
||||
return bookmarkService;
|
||||
}
|
||||
|
||||
public CompanyService companyService(){
|
||||
@@ -95,6 +58,10 @@ public class ModuleRegistry {
|
||||
return itemService;
|
||||
}
|
||||
|
||||
public MarkdownService markdownService(){
|
||||
return markdownService;
|
||||
}
|
||||
|
||||
public NoteService noteService(){
|
||||
return noteService;
|
||||
}
|
||||
@@ -115,6 +82,10 @@ public class ModuleRegistry {
|
||||
return taskService;
|
||||
}
|
||||
|
||||
public TimeService timeService(){
|
||||
return timeService;
|
||||
}
|
||||
|
||||
public Translator translator(){
|
||||
return translator;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@ import java.util.List;
|
||||
public interface TaskService {
|
||||
HashMap<Long, Task> listCompanyTasks(long companyId) throws UmbrellaException;
|
||||
HashMap<Long, Task> listProjectTasks(long projectId) throws UmbrellaException;
|
||||
HashMap<Long, Task> load(List<Long> taskIds);
|
||||
Collection<Task> loadMembers(Collection<Task> tasks);
|
||||
|
||||
default Task loadMembers(Task task){
|
||||
loadMembers(List.of(task));
|
||||
return task;
|
||||
|
||||
@@ -74,13 +74,12 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
|
||||
private final Configuration config;
|
||||
private final DocumentDb db;
|
||||
private final ModuleRegistry modules;
|
||||
|
||||
public DocumentApi(ModuleRegistry registry, Configuration config) throws UmbrellaException {
|
||||
super(registry);
|
||||
this.config = config;
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
db = new SqliteDb(connect(dbFile));
|
||||
modules = registry.add(this);
|
||||
|
||||
Optional<String> templates = config.get(CONFIG_TEMPLATES);
|
||||
if (templates.isEmpty()) throw missingFieldException(CONFIG_TEMPLATES);
|
||||
@@ -95,7 +94,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = modules.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
long docId = Long.parseLong(head);
|
||||
@@ -114,7 +113,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
private boolean deleteDocument(HttpExchange ex, long docId, UmbrellaUser user) throws IOException, UmbrellaException {
|
||||
var doc = db.loadDoc(docId);
|
||||
var companyId = doc.companyId();
|
||||
if (!modules.companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",doc.companyId());
|
||||
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",doc.companyId());
|
||||
if (doc.state() != NEW) throw new UmbrellaException(HTTP_BAD_REQUEST,"This document has already been sent");
|
||||
return sendContent(ex,db.deleteDoc(docId));
|
||||
}
|
||||
@@ -122,7 +121,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
private boolean deletePosition(HttpExchange ex, long docId, UmbrellaUser user) throws UmbrellaException, IOException {
|
||||
var doc = db.loadDoc(docId);
|
||||
var companyId = doc.companyId();
|
||||
if (!modules.companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",doc.companyId());
|
||||
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",doc.companyId());
|
||||
if (doc.state() != NEW) throw new UmbrellaException(HTTP_BAD_REQUEST,"This document has already been sent");
|
||||
var json = json(ex);
|
||||
if (!(json.has(POSITION) && json.get(POSITION) instanceof Number number)) throw missingFieldException(POSITION);
|
||||
@@ -135,7 +134,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = modules.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head){
|
||||
@@ -166,7 +165,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = modules.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
var docId = Long.parseLong(head);
|
||||
@@ -188,7 +187,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = modules.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head){
|
||||
@@ -220,7 +219,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
var attachment = new Attachment(doc.number()+".pdf",rendered.mimeType(),rendered.bytes());
|
||||
var message = new Message(user,subject,content,null,List.of(attachment));
|
||||
var envelope = new Envelope(message,new User(doc.customer().shortName(),new EmailAddress(email),doc.customer().language()));
|
||||
modules.postBox().send(envelope);
|
||||
postBox().send(envelope);
|
||||
db.save(doc.set(SENT));
|
||||
return ok(ex);
|
||||
}
|
||||
@@ -245,8 +244,8 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
private Tuple<Document,Company> getDocument(long docId, UmbrellaUser user) throws UmbrellaException {
|
||||
var doc = db.loadDoc(docId);
|
||||
var companyId = doc.companyId();
|
||||
var company = modules.companyService().get(companyId);
|
||||
if (!modules.companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
var company = companyService().get(companyId);
|
||||
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
return Tuple.of(doc,company);
|
||||
}
|
||||
|
||||
@@ -365,7 +364,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
.filter(filter)
|
||||
.findAny();
|
||||
if (optDoc.isEmpty()) throw UmbrellaException.notFound("Cannot render {0} {1}: Missing template \"{2}\"",type,document.number(),template);
|
||||
Function<String,String> translate = text -> modules.translator().translate(user.language(),text);
|
||||
Function<String,String> translate = text -> translator().translate(user.language(),text);
|
||||
var pdfData = new HashMap<String,Object>();
|
||||
pdfData.put(FIELD_DOCUMENT,document.renderToMap());
|
||||
pdfData.put("translate",translate);
|
||||
@@ -419,8 +418,8 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
var json = json(ex);
|
||||
if (!json.has(COMPANY)) throw missingFieldException(COMPANY);
|
||||
long companyId = json.getLong(COMPANY);
|
||||
var company = modules.companyService().get(companyId);
|
||||
if (!modules.companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company);
|
||||
var company = companyService().get(companyId);
|
||||
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company);
|
||||
var docs = list(companyId);
|
||||
var map = new HashMap<Long,Object>();
|
||||
for (var entry : docs.entrySet()) map.put(entry.getKey(),entry.getValue().summary());
|
||||
@@ -466,8 +465,8 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
if (!(json.has(SENDER) && json.get(SENDER) instanceof JSONObject senderData)) throw missingFieldException(SENDER);
|
||||
if (!senderData.has(FIELD_COMPANY) || !(senderData.get(FIELD_COMPANY) instanceof Number companyId)) throw missingFieldException(FIELD_COMPANY);
|
||||
|
||||
var company = modules.companyService().get(companyId.longValue());
|
||||
if (!modules.companyService().membership(companyId.longValue(),user.id())) throw forbidden("You are mot a member of company {0}",company);
|
||||
var company = companyService().get(companyId.longValue());
|
||||
if (!companyService().membership(companyId.longValue(),user.id())) throw forbidden("You are mot a member of company {0}",company);
|
||||
|
||||
if (!json.has(FIELD_CUSTOMER) || !(json.get(FIELD_CUSTOMER) instanceof JSONObject customerData)) throw missingFieldException(FIELD_CUSTOMER);
|
||||
if (!json.has(FIELD_TYPE) || !(json.get(FIELD_TYPE) instanceof Number docTypeId)) throw missingFieldException(FIELD_TYPE);
|
||||
@@ -513,8 +512,8 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
private boolean postTemplateList(HttpExchange ex, UmbrellaUser user) throws UmbrellaException, IOException {
|
||||
var json = json(ex);
|
||||
if (!(json.has(COMPANY) && json.get(COMPANY) instanceof Number companyId)) throw missingFieldException(COMPANY);
|
||||
var company = modules.companyService().get(companyId.longValue());
|
||||
if (!modules.companyService().membership(companyId.longValue(),user.id())) throw forbidden("You are not a member of {0}",company.name());
|
||||
var company = companyService().get(companyId.longValue());
|
||||
if (!companyService().membership(companyId.longValue(),user.id())) throw forbidden("You are not a member of {0}",company.name());
|
||||
var templates = db.getCompanyTemplates(companyId.longValue());
|
||||
return sendContent(ex,templates.stream().map(Template::toMap));
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
const router = useTinyRouter();
|
||||
let services = $state([]);
|
||||
|
||||
|
||||
|
||||
function doLogin(ev){
|
||||
ev.preventDefault();
|
||||
tryLogin(credentials);
|
||||
@@ -46,6 +48,8 @@
|
||||
ev.preventDefault();
|
||||
router.navigate('/user/reset/pw');
|
||||
}
|
||||
|
||||
if (router.fullPath.endsWith('/openid_login') && router.query.service) redirectTo(router.query.service);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -27,12 +27,11 @@ import java.util.Optional;
|
||||
public class ItemApi extends BaseHandler implements ItemService {
|
||||
|
||||
private final ItemDb itemDb;
|
||||
private final ModuleRegistry registry;
|
||||
|
||||
public ItemApi(ModuleRegistry registry, Configuration config) throws UmbrellaException {
|
||||
super(registry);
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
itemDb = new SqliteDb(connect(dbFile));
|
||||
this.registry = registry.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -40,7 +39,7 @@ public class ItemApi extends BaseHandler implements ItemService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -61,8 +60,8 @@ public class ItemApi extends BaseHandler implements ItemService {
|
||||
var json = json(ex);
|
||||
if (!(json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number cid)) throw missingFieldException(COMPANY_ID);
|
||||
var companyId = cid.longValue();
|
||||
var company = registry.companyService().get(companyId);
|
||||
if (!registry.companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
var company = companyService().get(companyId);
|
||||
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
var items = list(companyId)
|
||||
.stream()
|
||||
.map(Item::toMap)
|
||||
|
||||
@@ -20,34 +20,19 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class CompanyLegacy extends BaseHandler {
|
||||
private final ModuleRegistry registry;
|
||||
private final Configuration config;
|
||||
|
||||
public CompanyLegacy(ModuleRegistry registry, Configuration config) {
|
||||
this.registry = registry;
|
||||
super(registry);
|
||||
this.config = config.subset("umbrella.modules").orElseThrow(() -> new RuntimeException("Missing configuration: umbrella.modules"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doDelete(Path path, HttpExchange ex) throws IOException {
|
||||
return super.doDelete(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doGet(Path path, HttpExchange ex) throws IOException {
|
||||
if (path.empty()) return sendRedirect(ex, url(ex).replaceAll("/legacy/","/"));
|
||||
return super.doGet(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doOptions(Path path, HttpExchange ex) throws IOException {
|
||||
return super.doOptions(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPatch(Path path, HttpExchange ex) throws IOException {
|
||||
return super.doPatch(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPost(Path path, HttpExchange ex) throws IOException{
|
||||
@@ -55,7 +40,7 @@ public class CompanyLegacy extends BaseHandler {
|
||||
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
if (token.isEmpty()) token = nullable(params.get(TOKEN)).map(Object::toString).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
|
||||
return switch (path.pop()){
|
||||
@@ -65,7 +50,7 @@ public class CompanyLegacy extends BaseHandler {
|
||||
}
|
||||
|
||||
private boolean postCompanyJson(HttpExchange ex, Map<String, Object> params, UmbrellaUser user) throws IOException {
|
||||
var companies = registry.companyService().listCompaniesOf(user);
|
||||
var companies = companyService().listCompaniesOf(user);
|
||||
return sendContent(ex, mapValues(companies));
|
||||
}
|
||||
|
||||
|
||||
@@ -24,42 +24,26 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class NotesLegacy extends BaseHandler {
|
||||
private final ModuleRegistry registry;
|
||||
private final Configuration config;
|
||||
|
||||
public NotesLegacy(ModuleRegistry registry, Configuration config) {
|
||||
this.registry = registry;
|
||||
super(registry);
|
||||
this.config = config.subset("umbrella.modules").orElseThrow(() -> new RuntimeException("Missing configuration: umbrella.modules"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doDelete(Path path, HttpExchange ex) throws IOException {
|
||||
return super.doDelete(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doGet(Path path, HttpExchange ex) throws IOException {
|
||||
if (path.empty()) return sendRedirect(ex, url(ex).replaceAll("/legacy/","/"));
|
||||
return super.doGet(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doOptions(Path path, HttpExchange ex) throws IOException {
|
||||
return super.doOptions(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPatch(Path path, HttpExchange ex) throws IOException {
|
||||
return super.doPatch(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPost(Path path, HttpExchange ex) throws IOException {
|
||||
var params = formData(ex);
|
||||
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
if (token.isEmpty()) token = nullable(params.get(TOKEN)).map(Object::toString).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
|
||||
return switch (path.pop()){
|
||||
@@ -74,9 +58,9 @@ public class NotesLegacy extends BaseHandler {
|
||||
if (parts.length<2) throw invalidFieldException(URI,"URI of the form \"module:entry-id\"");
|
||||
var module = parts[0];
|
||||
var entryId = parts[1];
|
||||
var notes = registry.noteService().getNotes(module,entryId);
|
||||
var notes = noteService().getNotes(module,entryId);
|
||||
var authors = new HashMap<Long, UmbrellaUser> ();
|
||||
var users = registry.userService();
|
||||
var users = userService();
|
||||
for (var note : notes.values()) {
|
||||
var userId = note.authorId();
|
||||
authors.computeIfAbsent(userId,k -> users.loadUser(userId));
|
||||
|
||||
@@ -20,11 +20,10 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ProjectLegacy extends BaseHandler {
|
||||
private final ModuleRegistry registry;
|
||||
private final Configuration config;
|
||||
|
||||
public ProjectLegacy(ModuleRegistry registry, Configuration config) {
|
||||
this.registry = registry;
|
||||
super(registry);
|
||||
this.config = config.subset("umbrella.modules").orElseThrow(() -> new RuntimeException("Missing configuration: umbrella.modules"));
|
||||
}
|
||||
|
||||
@@ -39,23 +38,13 @@ public class ProjectLegacy extends BaseHandler {
|
||||
return super.doGet(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doOptions(Path path, HttpExchange ex) throws IOException {
|
||||
return super.doOptions(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPatch(Path path, HttpExchange ex) throws IOException {
|
||||
return super.doPatch(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPost(Path path, HttpExchange ex) throws IOException{
|
||||
var params = formData(ex);
|
||||
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
if (token.isEmpty()) token = nullable(params.get(TOKEN)).map(Object::toString).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
|
||||
return switch (path.pop()){
|
||||
@@ -66,7 +55,7 @@ public class ProjectLegacy extends BaseHandler {
|
||||
|
||||
private boolean postProjectJson(HttpExchange ex, Map<String, Object> params, UmbrellaUser user) throws IOException {
|
||||
var includeUsers = "1".equals(params.get(USERS));
|
||||
var projects = registry.projectService().listUserProjects(user.id(), false);
|
||||
var projects = projectService().listUserProjects(user.id(), false);
|
||||
return sendContent(ex, mapValues(projects));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.legacy;
|
||||
|
||||
|
||||
|
||||
import static de.srsoftware.tools.Optionals.nullable;
|
||||
import static de.srsoftware.umbrella.core.Constants.TOKEN;
|
||||
import static de.srsoftware.umbrella.core.Paths.JSON;
|
||||
import static de.srsoftware.umbrella.core.Util.mapValues;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.unprocessable;
|
||||
|
||||
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.model.Token;
|
||||
import de.srsoftware.umbrella.core.model.UmbrellaUser;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class TaskLegacy extends BaseHandler {
|
||||
private final Configuration config;
|
||||
|
||||
public TaskLegacy(ModuleRegistry registry, Configuration config) {
|
||||
super(registry);
|
||||
this.config = config.subset("umbrella.modules").orElseThrow(() -> new RuntimeException("Missing configuration: umbrella.modules"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doGet(Path path, HttpExchange ex) throws IOException {
|
||||
if (path.empty()) return sendRedirect(ex, url(ex).replaceAll("/legacy/","/"));
|
||||
return super.doGet(path, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPost(Path path, HttpExchange ex) throws IOException {
|
||||
var params = formData(ex);
|
||||
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
if (token.isEmpty()) token = nullable(params.get(TOKEN)).map(Object::toString).map(Token::of);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
|
||||
return switch (path.pop()){
|
||||
case JSON -> postJson(user.get(),params,ex);
|
||||
case null, default -> super.doPost(path,ex);
|
||||
};
|
||||
}
|
||||
|
||||
private boolean postJson(UmbrellaUser umbrellaUser, Map<String, Object> params, HttpExchange ex) throws IOException {
|
||||
if (params.get("ids") instanceof Map<?,?> taskIdMap){
|
||||
var taskIds = taskIdMap.values().stream().map(Object::toString).map(Long::parseLong).toList();
|
||||
return sendContent(ex,mapValues(taskService().load(taskIds)));
|
||||
}
|
||||
throw unprocessable("Invalid request");
|
||||
}
|
||||
}
|
||||
@@ -33,10 +33,9 @@ public class UserLegacy extends BaseHandler {
|
||||
|
||||
private final Configuration config;
|
||||
private final String messageUrl;
|
||||
private final ModuleRegistry registry;
|
||||
|
||||
public UserLegacy(ModuleRegistry registry, Configuration config) {
|
||||
this.registry = registry;
|
||||
super(registry);
|
||||
this.config = config.subset("umbrella.modules").orElseThrow(() -> new RuntimeException("Missing configuration: umbrella.modules"));
|
||||
this.messageUrl = null;
|
||||
}
|
||||
@@ -128,7 +127,7 @@ public class UserLegacy extends BaseHandler {
|
||||
throw new UmbrellaException(400,"Fetching related users not implemented, yet!");
|
||||
}
|
||||
|
||||
Map<Long, UmbrellaUser> userMap = registry.userService().list(0, null, ids);
|
||||
Map<Long, UmbrellaUser> userMap = userService().list(0, null, ids);
|
||||
if (arrayPassed || userMap.size() != 1) {
|
||||
var userData = new HashMap<Long, Map<String, Object>>();
|
||||
for (var entry : userMap.entrySet()) userData.put(entry.getKey(),entry.getValue().toMap());
|
||||
@@ -180,7 +179,7 @@ public class UserLegacy extends BaseHandler {
|
||||
}
|
||||
}
|
||||
if (!recipients.isEmpty()){ // replace legacy user ids by user objects in receivers field
|
||||
Map<Long, UmbrellaUser> resp = registry.userService().list(0, null, recipients);
|
||||
Map<Long, UmbrellaUser> resp = userService().list(0, null, recipients);
|
||||
data.put("receivers",resp.values().stream().map(UmbrellaUser::toMap).toList());
|
||||
}
|
||||
|
||||
@@ -203,7 +202,7 @@ public class UserLegacy extends BaseHandler {
|
||||
var optToken = SessionToken.from(ex).map(Token::of);
|
||||
if (optToken.isPresent()) try{
|
||||
var token = optToken.get();
|
||||
registry.userService().dropSession(token);
|
||||
userService().dropSession(token);
|
||||
var expiredToken = new SessionToken(token.toString(),"/", Instant.now().minus(1, DAYS),true);
|
||||
expiredToken.addTo(ex);
|
||||
if (returnTo instanceof String location) return sendRedirect(ex,location);
|
||||
@@ -245,8 +244,8 @@ public class UserLegacy extends BaseHandler {
|
||||
};
|
||||
|
||||
protected Session requestSession(Token token) throws UmbrellaException {
|
||||
var session = registry.userService().load(token);
|
||||
session = registry.userService().extend(session);
|
||||
var session = userService().load(token);
|
||||
session = userService().extend(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
@@ -280,8 +279,8 @@ public class UserLegacy extends BaseHandler {
|
||||
|
||||
var o = map.get(TOKEN);
|
||||
if (!(o instanceof String token)) throw new UmbrellaException(500,"Request did not contain token!");
|
||||
var session = registry.userService().load(Token.of(token));
|
||||
var user = registry.userService().load(session);
|
||||
var session = userService().load(Token.of(token));
|
||||
var user = userService().load(session);
|
||||
var userMap = user.toMap();
|
||||
userMap.put(TOKEN,Map.of(TOKEN,token,EXPIRATION,session.expiration().getEpochSecond()));
|
||||
return sendContent(ex,userMap);
|
||||
|
||||
@@ -17,10 +17,9 @@ import java.util.Optional;
|
||||
|
||||
public class MarkdownApi extends BaseHandler implements MarkdownService {
|
||||
|
||||
private final ModuleRegistry registry;
|
||||
|
||||
public MarkdownApi(ModuleRegistry registry) {
|
||||
this.registry = registry.add(this);
|
||||
super(registry);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -28,7 +27,7 @@ public class MarkdownApi extends BaseHandler implements MarkdownService {
|
||||
try {
|
||||
addCors(ex);
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
|
||||
if (user.isEmpty()) throw UmbrellaException.forbidden("You must be logged in to use the markdown renderer!");
|
||||
var rendered = Util.markdown(body(ex));
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.message;
|
||||
|
||||
import de.srsoftware.umbrella.core.BaseHandler;
|
||||
import de.srsoftware.umbrella.core.ModuleRegistry;
|
||||
|
||||
public class MessageApi extends BaseHandler {
|
||||
private final ModuleRegistry registry;
|
||||
|
||||
public MessageApi(ModuleRegistry moduleRegistry) {
|
||||
super();
|
||||
this.registry = moduleRegistry;
|
||||
}
|
||||
}
|
||||
@@ -28,12 +28,11 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class NoteModule extends BaseHandler implements NoteService {
|
||||
private final NotesDb notesDb;
|
||||
private final ModuleRegistry registry;
|
||||
|
||||
public NoteModule(ModuleRegistry registry, Configuration config) {
|
||||
super(registry);
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
notesDb = new SqliteDb(connect(dbFile));
|
||||
this.registry = registry.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,7 +45,7 @@ public class NoteModule extends BaseHandler implements NoteService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
if (head == null) throw unprocessable("Module missing in path.");
|
||||
@@ -73,7 +72,7 @@ public class NoteModule extends BaseHandler implements NoteService {
|
||||
public boolean doGet(Path path, HttpExchange ex) throws IOException {
|
||||
addCors(ex);
|
||||
try {
|
||||
var user = registry.userService().refreshSession(ex);
|
||||
var user = userService().refreshSession(ex);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var module = path.pop();
|
||||
return switch (module){
|
||||
@@ -105,7 +104,7 @@ public class NoteModule extends BaseHandler implements NoteService {
|
||||
}
|
||||
|
||||
private Map<String, Object> addUsers(Map<Long, Note> notes) {
|
||||
var authors = notes.values().stream().map(Note::authorId).distinct().map(registry.userService()::loadUser).collect(Collectors.toMap(UmbrellaUser::id,UmbrellaUser::toMap));
|
||||
var authors = notes.values().stream().map(Note::authorId).distinct().map(userService()::loadUser).collect(Collectors.toMap(UmbrellaUser::id,UmbrellaUser::toMap));
|
||||
return Map.of("notes",mapValues(notes),"authors",authors);
|
||||
}
|
||||
|
||||
@@ -114,7 +113,7 @@ public class NoteModule extends BaseHandler implements NoteService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
long noteId = Long.parseLong(head);
|
||||
@@ -137,7 +136,7 @@ public class NoteModule extends BaseHandler implements NoteService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var module = path.pop();
|
||||
if (module == null) throw unprocessable("Module missing in path.");
|
||||
|
||||
@@ -30,16 +30,15 @@ import org.json.JSONObject;
|
||||
public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
|
||||
private final ProjectDb projects;
|
||||
private final ModuleRegistry registy;
|
||||
|
||||
public ProjectModule(ModuleRegistry registry, Configuration config) throws UmbrellaException {
|
||||
super(registry);
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
projects = new SqliteDb(connect(dbFile));
|
||||
this.registy = registry.add(this);
|
||||
}
|
||||
|
||||
private void addMember(Project project, long userId) {
|
||||
var user = registy.userService().loadUser(userId);
|
||||
var user = userService().loadUser(userId);
|
||||
var member = new Member(user,READ_ONLY);
|
||||
project.members().put(userId,member);
|
||||
project.dirty(MEMBERS);
|
||||
@@ -50,7 +49,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registy.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -74,7 +73,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registy.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -97,7 +96,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registy.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -129,7 +128,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
var project = loadMembers(projects.load(projectId));
|
||||
if (!project.hasMember(user)) throw forbidden("You are not a member of {0}",project.name());
|
||||
var map = project.toMap();
|
||||
project.companyId().map(registy.companyService()::get).map(Company::toMap).ifPresent(data -> map.put(COMPANY,data));
|
||||
project.companyId().map(companyService()::get).map(Company::toMap).ifPresent(data -> map.put(COMPANY,data));
|
||||
return sendContent(ex,map);
|
||||
}
|
||||
|
||||
@@ -140,8 +139,8 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
}
|
||||
|
||||
private boolean listCompanyProjects(HttpExchange ex, UmbrellaUser user, long companyId) throws IOException, UmbrellaException {
|
||||
var company = registy.companyService().get(companyId);
|
||||
if (!registy.companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
var company = companyService().get(companyId);
|
||||
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
var projects = listCompanyProjects(companyId,false);
|
||||
return sendContent(ex,mapValues(projects));
|
||||
}
|
||||
@@ -170,7 +169,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
for (var entry : projects.getMembers(project).entrySet()){
|
||||
var userId = entry.getKey();
|
||||
var permission = entry.getValue();
|
||||
var user = userMap.computeIfAbsent(userId,k -> registy.userService().loadUser(userId));
|
||||
var user = userMap.computeIfAbsent(userId,k -> userService().loadUser(userId));
|
||||
project.members().put(userId,new Member(user,permission));
|
||||
}
|
||||
}
|
||||
@@ -194,7 +193,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
if (member.permission() == OWNER) members.put(member.user().id(),new Member(member.user(),EDIT));
|
||||
}
|
||||
}
|
||||
members.put(userId,new Member(registy.userService().loadUser(userId),permission));
|
||||
members.put(userId,new Member(userService().loadUser(userId),permission));
|
||||
project.dirty(MEMBERS);
|
||||
}
|
||||
}
|
||||
@@ -233,7 +232,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
}
|
||||
Long companyId = null;
|
||||
if (json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number number){
|
||||
if (!registy.companyService().membership(number.longValue(), user.id())) throw forbidden("You are not a member of company {0}!",number);
|
||||
if (!companyService().membership(number.longValue(), user.id())) throw forbidden("You are not a member of company {0}!",number);
|
||||
companyId = number.longValue();
|
||||
}
|
||||
var showClosed = false;
|
||||
@@ -246,7 +245,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
|
||||
if (json.has(TAGS) && json.get(TAGS) instanceof JSONArray arr){
|
||||
var tagList = arr.toList().stream().filter(elem -> elem instanceof String).map(String.class::cast).toList();
|
||||
registy.tagService().save(PROJECT,prj.id(),null,tagList);
|
||||
tagService().save(PROJECT,prj.id(),null,tagList);
|
||||
}
|
||||
|
||||
return sendContent(ex,prj);
|
||||
|
||||
@@ -25,13 +25,12 @@ import org.json.JSONArray;
|
||||
|
||||
public class TagModule extends BaseHandler implements TagService {
|
||||
private final SqliteDb tagDb;
|
||||
private final ModuleRegistry registry;
|
||||
|
||||
public TagModule(ModuleRegistry registry, Configuration config) {
|
||||
super(registry);
|
||||
var tagDbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
var bmDbFile = config.get(de.srsoftware.umbrella.bookmarks.Constants.CONFIG_DATABASE).orElseThrow(() -> missingFieldException(de.srsoftware.umbrella.bookmarks.Constants.CONFIG_DATABASE));
|
||||
tagDb = new SqliteDb(connect(tagDbFile),connect(bmDbFile));
|
||||
this.registry = registry.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,7 +43,7 @@ public class TagModule extends BaseHandler implements TagService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var module = path.pop();
|
||||
if (module == null) throw unprocessable("Module missing in path.");
|
||||
@@ -63,7 +62,7 @@ public class TagModule extends BaseHandler implements TagService {
|
||||
public boolean doGet(Path path, HttpExchange ex) throws IOException {
|
||||
addCors(ex);
|
||||
try {
|
||||
var user = registry.userService().refreshSession(ex);
|
||||
var user = userService().refreshSession(ex);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var module = path.pop();
|
||||
if (module == null) throw unprocessable("Module missing in path.");
|
||||
@@ -87,7 +86,7 @@ public class TagModule extends BaseHandler implements TagService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var module = path.pop();
|
||||
if (module == null) throw unprocessable("Module missing in path.");
|
||||
|
||||
@@ -29,22 +29,22 @@ import de.srsoftware.umbrella.core.model.Token;
|
||||
import de.srsoftware.umbrella.core.model.UmbrellaUser;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class TaskModule extends BaseHandler implements TaskService {
|
||||
|
||||
private final TaskDb taskDb;
|
||||
private final ModuleRegistry registry;
|
||||
|
||||
public TaskModule(ModuleRegistry registry, Configuration config) throws UmbrellaException {
|
||||
super(registry);
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
taskDb = new SqliteDb(connect(dbFile));
|
||||
this.registry = registry.add(this);
|
||||
}
|
||||
|
||||
private void addMember(Task task, long userId) {
|
||||
var user = registry.userService().loadUser(userId);
|
||||
var user = userService().loadUser(userId);
|
||||
var member = new Member(user,READ_ONLY);
|
||||
task.members().put(userId,member);
|
||||
task.dirty(MEMBERS);
|
||||
@@ -55,8 +55,8 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
var member = task.members().get(user.id());
|
||||
if (member == null || !member.mayWrite()) throw forbidden("You are not allowed to delete {0}",task.name());
|
||||
taskDb.delete(task);
|
||||
registry.noteService().deleteEntity(TASK,""+taskId);
|
||||
registry.tagService().deleteEntity(TASK,taskId);
|
||||
noteService().deleteEntity(TASK,""+taskId);
|
||||
tagService().deleteEntity(TASK,taskId);
|
||||
return sendContent(ex,Map.of(DELETED,taskId));
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -85,7 +85,7 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -107,7 +107,7 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -128,7 +128,7 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -152,9 +152,9 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
var json = json(ex);
|
||||
if (!(json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number cid)) throw missingFieldException(COMPANY_ID);
|
||||
var companyId = cid.longValue();
|
||||
var company = registry.companyService().get(companyId);
|
||||
if (!registry.companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
var projectMap = registry.projectService().listCompanyProjects(companyId,false);
|
||||
var company = companyService().get(companyId);
|
||||
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
var projectMap = projectService().listCompanyProjects(companyId,false);
|
||||
var taskMap = taskDb.listTasks(projectMap.keySet());
|
||||
var taskTree = new HashMap<Long,Map<String,Object>>();
|
||||
taskMap.values().stream().filter(task -> !is0(task.estimatedTime())).forEach(task -> placeInTree(task,taskTree,taskMap));
|
||||
@@ -196,7 +196,7 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
} catch (NumberFormatException e) {
|
||||
throw invalidFieldException(LIMIT,"number");
|
||||
}
|
||||
Set<Long> projectIds = registry.projectService().listUserProjects(user.id(), true).keySet();
|
||||
Set<Long> projectIds = projectService().listUserProjects(user.id(), true).keySet();
|
||||
var list = taskDb.listUserTasks(user.id(), limit, offset, false).stream()
|
||||
.filter(task -> projectIds.contains(task.projectId())) // drop tasks assigned to project we are not member of
|
||||
.map(Task::toMap)
|
||||
@@ -206,7 +206,7 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
|
||||
@Override
|
||||
public HashMap<Long, Task> listCompanyTasks(long companyId) throws UmbrellaException {
|
||||
var projectList = registry.projectService().listCompanyProjects(companyId,false);
|
||||
var projectList = projectService().listCompanyProjects(companyId,false);
|
||||
return taskDb.listTasks(projectList.keySet());
|
||||
}
|
||||
|
||||
@@ -215,6 +215,16 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
return taskDb.listTasks(List.of(projectId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<Long, Task> load(List<Long> taskIds) {
|
||||
try {
|
||||
var map = taskIds.stream().map(taskDb::load).collect(Collectors.toMap(Task::id, t -> t));
|
||||
return new HashMap<>(map);
|
||||
} catch (Exception e){
|
||||
throw new UmbrellaException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> loadMembers(Collection<Task> taskList) {
|
||||
var userMap = new HashMap<Long,UmbrellaUser>();
|
||||
@@ -222,7 +232,7 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
for (var entry : taskDb.getMembers(task).entrySet()){
|
||||
var userId = entry.getKey();
|
||||
var permission = entry.getValue();
|
||||
var user = userMap.computeIfAbsent(userId,k -> registry.userService().loadUser(userId));
|
||||
var user = userMap.computeIfAbsent(userId,k -> userService().loadUser(userId));
|
||||
task.members().put(userId,new Member(user,permission));
|
||||
}
|
||||
}
|
||||
@@ -267,7 +277,7 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
if (member.permission() == ASSIGNEE) members.put(member.user().id(),new Member(member.user(),EDIT));
|
||||
}
|
||||
}
|
||||
members.put(userId,new Member(registry.userService().loadUser(userId),permission));
|
||||
members.put(userId,new Member(userService().loadUser(userId),permission));
|
||||
task.dirty(MEMBERS);
|
||||
}
|
||||
}
|
||||
@@ -301,8 +311,8 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
if (!(json.has(PROJECT_ID) && json.get(PROJECT_ID) instanceof Number pid)) throw missingFieldException(PROJECT_ID);
|
||||
if (!(json.has(MEMBERS) && json.get(MEMBERS) instanceof JSONObject memberData)) throw missingFieldException(MEMBERS);
|
||||
long projectId = pid.longValue();
|
||||
var project = registry.projectService().load(projectId);
|
||||
registry.projectService().loadMembers(List.of(project));
|
||||
var project = projectService().load(projectId);
|
||||
projectService().loadMembers(List.of(project));
|
||||
var member = project.members().get(user.id());
|
||||
if (member == null || member.permission() == READ_ONLY) throw forbidden("You are not allowed to create new tasks in this project");
|
||||
for (var key : memberData.keySet()){
|
||||
@@ -331,7 +341,7 @@ public class TaskModule extends BaseHandler implements TaskService {
|
||||
}
|
||||
if (json.has(TAGS) && json.get(TAGS) instanceof JSONArray arr){
|
||||
var tagList = arr.toList().stream().filter(e -> e instanceof String).map(String.class::cast).toList();
|
||||
registry.tagService().save(TASK,task.id(),null,tagList);
|
||||
tagService().save(TASK,task.id(),null,tagList);
|
||||
}
|
||||
return sendContent(ex,loadMembers(task));
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.Paths.LIST;
|
||||
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_NOT_IMPLEMENTED;
|
||||
import static de.srsoftware.umbrella.core.Util.mapValues;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.forbidden;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
|
||||
import static de.srsoftware.umbrella.time.Constants.*;
|
||||
@@ -38,14 +37,13 @@ public class TimeModule extends BaseHandler implements TimeService {
|
||||
|
||||
}
|
||||
|
||||
private final ModuleRegistry registry;
|
||||
private final TimeDb timeDb;
|
||||
|
||||
|
||||
public TimeModule(ModuleRegistry registry, Configuration config) throws UmbrellaException {
|
||||
super(registry);
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
timeDb = new SqliteDb(connect(dbFile));
|
||||
this.registry = registry.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,7 +51,7 @@ public class TimeModule extends BaseHandler implements TimeService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -70,7 +68,7 @@ public class TimeModule extends BaseHandler implements TimeService {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = registry.userService().loadUser(token);
|
||||
var user = userService().loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
@@ -84,7 +82,7 @@ public class TimeModule extends BaseHandler implements TimeService {
|
||||
|
||||
private boolean getUserTimes(UmbrellaUser user, HttpExchange ex) throws IOException {
|
||||
// TODO
|
||||
Map<Long, Project> projects = registry.projectService().listUserProjects(user.id(), true);
|
||||
Map<Long, Project> projects = projectService().listUserProjects(user.id(), true);
|
||||
//timeDb.
|
||||
return sendEmptyResponse(HTTP_NOT_IMPLEMENTED,ex);
|
||||
}
|
||||
@@ -133,11 +131,11 @@ public class TimeModule extends BaseHandler implements TimeService {
|
||||
var json = json(ex);
|
||||
if (!(json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number cid)) throw missingFieldException(COMPANY_ID);
|
||||
var companyId = cid.longValue();
|
||||
var company = registry.companyService().get(companyId);
|
||||
if (!registry.companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
var company = companyService().get(companyId);
|
||||
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
if (!(json.has(PROJECT_ID) && json.get(PROJECT_ID) instanceof Number pid)) throw missingFieldException(PROJECT_ID);
|
||||
long projectId = pid.longValue();
|
||||
Map<Long,Task> tasksOfProject = registry.taskService().listProjectTasks(projectId);
|
||||
Map<Long,Task> tasksOfProject = taskService().listProjectTasks(projectId);
|
||||
|
||||
List<Map<String, Object>> times = timeDb.listTimes(tasksOfProject.keySet())
|
||||
.stream().filter(not(Time::isClosed))
|
||||
|
||||
@@ -69,7 +69,6 @@ public class UserModule extends BaseHandler implements UserService {
|
||||
private static final System.Logger LOG = System.getLogger("User");
|
||||
private final UserDb users;
|
||||
private final LoginServiceDb logins;
|
||||
private final ModuleRegistry registry;
|
||||
private final HashMap<String, State> stateMap = new HashMap<>(); // map from state to OIDC provider name
|
||||
private final HashMap<String,String> tokenMap = new HashMap<>();
|
||||
|
||||
@@ -82,11 +81,11 @@ public class UserModule extends BaseHandler implements UserService {
|
||||
}
|
||||
|
||||
public UserModule(ModuleRegistry registry, Configuration config) throws UmbrellaException {
|
||||
super(registry);
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingConfigException(CONFIG_DATABASE));
|
||||
// may be splitted in separate db files later
|
||||
logins = new SqliteDB(connect(dbFile));
|
||||
users = new SqliteDB(connect(dbFile));
|
||||
this.registry = registry.add(this);
|
||||
}
|
||||
|
||||
private boolean deleteOIDC(HttpExchange ex, UmbrellaUser user, Path path) throws IOException {
|
||||
@@ -504,7 +503,7 @@ public class UserModule extends BaseHandler implements UserService {
|
||||
var fills = Map.of("url",url);
|
||||
var message = new Message(user,subject,content,fills,null);
|
||||
var envelope = new Envelope(message,user);
|
||||
registry.postBox().send(envelope);
|
||||
postBox().send(envelope);
|
||||
} catch (UmbrellaException e){
|
||||
return send(ex,e);
|
||||
}
|
||||
|
||||
@@ -8,11 +8,16 @@ import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.tools.Path;
|
||||
import de.srsoftware.umbrella.core.BaseHandler;
|
||||
import de.srsoftware.umbrella.core.ModuleRegistry;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class WebHandler extends BaseHandler {
|
||||
|
||||
public WebHandler(ModuleRegistry registry){
|
||||
super(registry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doGet(Path path, HttpExchange ex) throws IOException {
|
||||
LOG.log(DEBUG,"doGet({0},ex)",path);
|
||||
|
||||
Reference in New Issue
Block a user