started implementing listTimes – way to complicated
This commit is contained in:
@@ -19,8 +19,9 @@ dependencies{
|
||||
implementation(project(":legacy"))
|
||||
implementation(project(":markdown"))
|
||||
implementation(project(":messages"))
|
||||
implementation(project(":task"))
|
||||
implementation(project(":project"))
|
||||
implementation(project(":task"))
|
||||
implementation(project(":time"))
|
||||
implementation(project(":translations"))
|
||||
implementation(project(":user"))
|
||||
implementation(project(":web"))
|
||||
|
||||
@@ -19,6 +19,7 @@ import de.srsoftware.umbrella.message.MessageApi;
|
||||
import de.srsoftware.umbrella.message.MessageSystem;
|
||||
import de.srsoftware.umbrella.project.ProjectModule;
|
||||
import de.srsoftware.umbrella.task.TaskModule;
|
||||
import de.srsoftware.umbrella.time.TimeModule;
|
||||
import de.srsoftware.umbrella.translations.Translations;
|
||||
import de.srsoftware.umbrella.user.UserModule;
|
||||
import de.srsoftware.umbrella.web.WebHandler;
|
||||
@@ -66,6 +67,7 @@ public class Application {
|
||||
var messageApi = new MessageApi(messageSystem);
|
||||
var projectModule = new ProjectModule(config,companyModule);
|
||||
var taskModule = new TaskModule(config,projectModule);
|
||||
var timeModule = new TimeModule(config,taskModule);
|
||||
var webHandler = new WebHandler();
|
||||
|
||||
documentApi .bindPath("/api/document") .on(server);
|
||||
@@ -74,6 +76,7 @@ public class Application {
|
||||
messageApi .bindPath("/api/messages") .on(server);
|
||||
projectModule .bindPath("/api/project") .on(server);
|
||||
taskModule .bindPath("/api/task") .on(server);
|
||||
timeModule .bindPath("/api/times") .on(server);
|
||||
translationModule.bindPath("/api/translations").on(server);
|
||||
userModule .bindPath("/api/user") .on(server);
|
||||
legacyApi .bindPath("/legacy") .on(server);
|
||||
|
||||
@@ -19,13 +19,17 @@ public class Constants {
|
||||
public static final String DEFAULT_THEME = "winter";
|
||||
public static final String DESCRIPTION = "description";
|
||||
public static final String DOMAIN = "domain";
|
||||
public static final String DUE_DATE = "due_date";
|
||||
public static final String EMAIL = "email";
|
||||
public static final String END_TIME = "end_time";
|
||||
|
||||
public static final String ERROR_FAILED_CREATE_TABLE = "Failed to create \"{0}\" table!";
|
||||
public static final String ERROR_INVALID_FIELD = "Expected {0} to be {1}!";
|
||||
public static final String ERROR_MISSING_CONFIG = "Config is missing value for {0}!";
|
||||
public static final String ERROR_MISSING_FIELD = "Json is missing {0} field!";
|
||||
public static final String ERROR_READ_TABLE = "Failed to read {0} from {1} table";
|
||||
public static final String EST_TIME = "est_time";
|
||||
public static final String ESTIMATED_TIME = "estimated_time";
|
||||
|
||||
public static final String EXPIRATION = "expiration";
|
||||
public static final String GET = "GET";
|
||||
@@ -37,11 +41,14 @@ public class Constants {
|
||||
public static final String MESSAGES = "messages";
|
||||
public static final String NAME = "name";
|
||||
public static final String MIME = "mime";
|
||||
public static final String NO_INDEX = "no_index";
|
||||
public static final String NUMBER = "number";
|
||||
public static final String OPTIONAL = "optional";
|
||||
public static final String PARENT_TASK_ID = "parent_task_id";
|
||||
public static final String PASS = "pass";
|
||||
public static final String PASSWORD = "password";
|
||||
public static final String POST = "POST";
|
||||
public static final String PROJECT_ID = "project_id";
|
||||
|
||||
public static final String RECEIVERS = "receivers";
|
||||
public static final String REDIRECT = "redirect";
|
||||
@@ -50,6 +57,8 @@ public class Constants {
|
||||
public static final String SETTINGS = "settings";
|
||||
public static final String SHOW_CLOSED = "show_closed";
|
||||
public static final String SOURCE = "source";
|
||||
public static final String START_DATE = "start_date";
|
||||
public static final String START_TIME = "start_time";
|
||||
public static final String STATE = "state";
|
||||
public static final String STATUS = "status";
|
||||
public static final String STATUS_CODE = "code";
|
||||
|
||||
@@ -15,6 +15,9 @@ import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import org.json.JSONObject;
|
||||
@@ -140,4 +143,8 @@ public class Util {
|
||||
LOG.log(INFO,"Using plantuml @ {0}",file.getAbsolutePath());
|
||||
plantumlJar = file;
|
||||
}
|
||||
|
||||
public static LocalDateTime dateTimeOf(long epocSecs){
|
||||
return LocalDateTime.ofInstant(Instant.ofEpochSecond(epocSecs), ZoneId.systemDefault());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.core.api;
|
||||
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.Task;
|
||||
import java.util.Collection;
|
||||
|
||||
public interface TaskService {
|
||||
CompanyService companyService();
|
||||
Collection<Task> listCompanyTasks(long companyId) throws UmbrellaException;
|
||||
ProjectService projectService();
|
||||
|
||||
UserService userService();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.core.api;
|
||||
|
||||
public interface TimeService {
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.task;
|
||||
package de.srsoftware.umbrella.core.model;
|
||||
|
||||
import static de.srsoftware.tools.Optionals.nullIfEmpty;
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.Constants.SHOW_CLOSED;
|
||||
import static de.srsoftware.umbrella.core.Constants.STATUS;
|
||||
import static de.srsoftware.umbrella.core.Util.markdown;
|
||||
import static de.srsoftware.umbrella.task.Constants.*;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import java.sql.ResultSet;
|
||||
@@ -0,0 +1,77 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.core.model;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.Util.dateTimeOf;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public record Time(long id, long userId, String subject, String description, LocalDateTime start, LocalDateTime end, State state, Set<Long> taskIds) implements Mappable {
|
||||
public enum State{
|
||||
Started(10),
|
||||
Open(20),
|
||||
Pending(40),
|
||||
Complete(60),
|
||||
Cancelled(100);
|
||||
|
||||
private int code;
|
||||
|
||||
State(int code){
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public int code(){
|
||||
return code;
|
||||
}
|
||||
|
||||
public static State of(int code){
|
||||
return switch (code){
|
||||
case 10 -> Started;
|
||||
case 20 -> Open;
|
||||
case 40 -> Pending;
|
||||
case 60 -> Complete;
|
||||
case 100 -> Cancelled;
|
||||
default -> throw new IllegalArgumentException();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
var map = new HashMap<String,Object>();
|
||||
map.put(ID,id);
|
||||
map.put(USER_ID,userId);
|
||||
map.put(SUBJECT,subject);
|
||||
map.put(DESCRIPTION,description);
|
||||
map.put(START_TIME,start);
|
||||
map.put(END_TIME,end);
|
||||
map.put(STATE,Map.of(STATUS_CODE,state.code,NAME,state.name()));
|
||||
return map;
|
||||
}
|
||||
|
||||
public static Time of(ResultSet rs) throws SQLException {
|
||||
var startTimestamp = rs.getLong(START_TIME);
|
||||
var start = startTimestamp == 0 ? null : dateTimeOf(startTimestamp);
|
||||
var endTimestamp = rs.getLong(END_TIME);
|
||||
var end = endTimestamp == 0 ? null : dateTimeOf(endTimestamp);
|
||||
|
||||
return new Time(
|
||||
rs.getLong(ID),
|
||||
rs.getLong(USER_ID),
|
||||
rs.getString(SUBJECT),
|
||||
rs.getString(DESCRIPTION),
|
||||
start,
|
||||
end,
|
||||
State.of(rs.getInt(STATE)),
|
||||
new HashSet<>()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
rootProject.name = "Umbrella25"
|
||||
|
||||
include("backend")
|
||||
include("company")
|
||||
include("contact")
|
||||
include("core")
|
||||
include("documents")
|
||||
include("legacy")
|
||||
include("items")
|
||||
include("messages")
|
||||
include("markdown")
|
||||
include("project")
|
||||
include("task")
|
||||
include("time")
|
||||
include("translations")
|
||||
include("user")
|
||||
include("web")
|
||||
|
||||
include("company")
|
||||
include("contact")
|
||||
|
||||
include("markdown")
|
||||
include("project")
|
||||
include("items")
|
||||
include("task")
|
||||
|
||||
@@ -6,14 +6,7 @@ public class Constants {
|
||||
|
||||
public static final String CONFIG_DATABASE = "umbrella.modules.task.database";
|
||||
public static final String CHILDREN = "children";
|
||||
public static final String DUE_DATE = "due_date";
|
||||
public static final String ESTIMATED_TIMES = "estimated_times";
|
||||
public static final String ESTIMATED_TIME = "estimated_time";
|
||||
public static final String EST_TIME = "est_time";
|
||||
public static final String NO_INDEX = "no_index";
|
||||
public static final String PARENT_TASK_ID = "parent_task_id";
|
||||
public static final String PROJECT_ID = "project_id";
|
||||
public static final String START_DATE = "start_date";
|
||||
public static final String TABLE_TASKS = "tasks";
|
||||
public static final String FIELD_TASKS = "tasks";
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@ package de.srsoftware.umbrella.task;
|
||||
|
||||
import static de.srsoftware.tools.jdbc.Condition.in;
|
||||
import static de.srsoftware.tools.jdbc.Query.select;
|
||||
import static de.srsoftware.umbrella.core.Constants.PROJECT_ID;
|
||||
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR;
|
||||
import static de.srsoftware.umbrella.task.Constants.PROJECT_ID;
|
||||
import static de.srsoftware.umbrella.task.Constants.TABLE_TASKS;
|
||||
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.Task;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -4,10 +4,10 @@ package de.srsoftware.umbrella.task;
|
||||
import static de.srsoftware.tools.Optionals.is0;
|
||||
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
|
||||
import static de.srsoftware.umbrella.core.Constants.COMPANY_ID;
|
||||
import static de.srsoftware.umbrella.core.Constants.PROJECT_ID;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.forbidden;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
|
||||
import static de.srsoftware.umbrella.task.Constants.*;
|
||||
import static java.util.Objects.isNull;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
@@ -17,16 +17,17 @@ import de.srsoftware.tools.SessionToken;
|
||||
import de.srsoftware.umbrella.core.BaseHandler;
|
||||
import de.srsoftware.umbrella.core.api.CompanyService;
|
||||
import de.srsoftware.umbrella.core.api.ProjectService;
|
||||
import de.srsoftware.umbrella.core.api.TaskService;
|
||||
import de.srsoftware.umbrella.core.api.UserService;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.Project;
|
||||
import de.srsoftware.umbrella.core.model.Task;
|
||||
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;
|
||||
|
||||
public class TaskModule extends BaseHandler {
|
||||
public class TaskModule extends BaseHandler implements TaskService {
|
||||
|
||||
private final SqliteDb taskDb;
|
||||
private final ProjectService projects;
|
||||
@@ -41,7 +42,12 @@ public class TaskModule extends BaseHandler {
|
||||
users = companies.userService();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public CompanyService companyService() {
|
||||
return companies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPost(Path path, HttpExchange ex) throws IOException {
|
||||
addCors(ex);
|
||||
try {
|
||||
@@ -81,6 +87,12 @@ public class TaskModule extends BaseHandler {
|
||||
return sendContent(ex,result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> listCompanyTasks(long companyId) throws UmbrellaException {
|
||||
var projectList = projects.listProjects(companyId,false);
|
||||
return taskDb.listTasks(projectList.stream().map(Project::id).toList());
|
||||
}
|
||||
|
||||
private Map<String,Object> placeInTree(Task task, HashMap<Long, Map<String,Object>> tree, Map<Long, Task> map) {
|
||||
var taskMap = task.toMap();
|
||||
if (task.parentTaskId() != null){
|
||||
@@ -93,4 +105,14 @@ public class TaskModule extends BaseHandler {
|
||||
tree.put(task.id(),taskMap);
|
||||
return taskMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectService projectService() {
|
||||
return projects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserService userService() {
|
||||
return users;
|
||||
}
|
||||
}
|
||||
|
||||
5
time/build.gradle.kts
Normal file
5
time/build.gradle.kts
Normal file
@@ -0,0 +1,5 @@
|
||||
description = "Umbrella : Timetracking"
|
||||
|
||||
dependencies{
|
||||
implementation(project(":core"))
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.time;
|
||||
|
||||
public class Constants {
|
||||
private Constants(){}
|
||||
|
||||
|
||||
public static final String CONFIG_DATABASE = "umbrella.modules.time.database";
|
||||
|
||||
public static final String TABLE_TASK_TIMES = "task_times";
|
||||
public static final String TABLE_TIMES = "times";
|
||||
public static final String TASK_ID = "task_id";
|
||||
public static final String TASKS = "tasks";
|
||||
public static final String TIME_ID = "time_id";
|
||||
public static final String TIMES = "times";
|
||||
public static final String CHILDREN = "children";
|
||||
|
||||
}
|
||||
50
time/src/main/java/de/srsoftware/umbrella/time/SqliteDb.java
Normal file
50
time/src/main/java/de/srsoftware/umbrella/time/SqliteDb.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.time;
|
||||
|
||||
import static de.srsoftware.tools.jdbc.Condition.in;
|
||||
import static de.srsoftware.tools.jdbc.Query.select;
|
||||
import static de.srsoftware.umbrella.core.Constants.ID;
|
||||
import static de.srsoftware.umbrella.time.Constants.*;
|
||||
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.Time;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class SqliteDb implements TimeDb {
|
||||
|
||||
private final Connection db;
|
||||
|
||||
public SqliteDb(Connection connection) {
|
||||
db = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Time> listTimes(Collection<Long> taskIds) throws UmbrellaException {
|
||||
try {
|
||||
var rs = select("*").from(TABLE_TASK_TIMES).where(TASK_ID,in(taskIds.toArray())).exec(db);
|
||||
var mapFromTimesToTasks = new HashMap<Long,HashSet<Long>>();
|
||||
while (rs.next()){
|
||||
var timeId = rs.getLong(TIME_ID);
|
||||
var taskId = rs.getLong(TASK_ID);
|
||||
mapFromTimesToTasks.computeIfAbsent(timeId, k -> new HashSet<>()).add(taskId);
|
||||
}
|
||||
rs.close();
|
||||
rs = select("*").from(TABLE_TIMES).where(ID,in(mapFromTimesToTasks.keySet().toArray())).exec(db);
|
||||
var times = new HashSet<Time>();
|
||||
while (rs.next()) {
|
||||
var time = Time.of(rs);
|
||||
time.taskIds().addAll(mapFromTimesToTasks.get(time.id()));
|
||||
times.add(time);
|
||||
}
|
||||
rs.close();
|
||||
return times;
|
||||
} catch (SQLException e) {
|
||||
throw new UmbrellaException("Failed to load times for task list");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
time/src/main/java/de/srsoftware/umbrella/time/TimeDb.java
Normal file
11
time/src/main/java/de/srsoftware/umbrella/time/TimeDb.java
Normal file
@@ -0,0 +1,11 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.time;
|
||||
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.Time;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface TimeDb {
|
||||
Collection<Time> listTimes(Collection<Long> taskIds) throws UmbrellaException;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.time;
|
||||
|
||||
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.exceptions.UmbrellaException.missingFieldException;
|
||||
import static de.srsoftware.umbrella.time.Constants.*;
|
||||
|
||||
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.api.*;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TimeModule extends BaseHandler implements TimeService {
|
||||
private final UserService users;
|
||||
private final TimeDb timeDb;
|
||||
private final TaskService tasks;
|
||||
private final CompanyService companies;
|
||||
private final ProjectService projects;
|
||||
|
||||
public TimeModule(Configuration config, TaskService taskService) throws UmbrellaException {
|
||||
companies = taskService.companyService();
|
||||
projects = taskService.projectService();
|
||||
tasks = taskService;
|
||||
users = tasks.userService();
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
timeDb = new SqliteDb(connect(dbFile));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPost(Path path, HttpExchange ex) throws IOException {
|
||||
addCors(ex);
|
||||
try {
|
||||
Optional<Token> token = SessionToken.from(ex).map(Token::of);
|
||||
var user = users.loadUser(token);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
case LIST -> listTimes(ex,user.get());
|
||||
default -> super.doPost(path,ex);
|
||||
};
|
||||
} catch (UmbrellaException e){
|
||||
return send(ex,e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean listTimes(HttpExchange ex, UmbrellaUser user) throws IOException, UmbrellaException {
|
||||
var json = json(ex);
|
||||
if (!(json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number cid)) throw missingFieldException(COMPANY_ID);
|
||||
long companyId = cid.longValue();
|
||||
if (!companies.membership(companyId,user.id())) throw UmbrellaException.forbidden("You are not a member of compayn {0}",companyId);
|
||||
var projectMap = projects.listProjects(companyId,false).stream().collect(Collectors.toMap(Project::id,p -> p));
|
||||
var taskMap = tasks.listCompanyTasks(companyId).stream().collect(Collectors.toMap(Task::id,Task::toMap));
|
||||
var timesList = timeDb.listTimes(taskMap.keySet());
|
||||
var tasksWithTime = new HashMap<Long,Map<String,Object>>();
|
||||
var tree = new HashMap<Long,Map<String,Object>>();
|
||||
for (var time : timesList) {
|
||||
if (time.state().code() >= 60) continue;
|
||||
var timeMap = time.toMap();
|
||||
for (var taskId : time.taskIds()) {
|
||||
var task = tasksWithTime.computeIfAbsent(taskId, k -> taskMap.get(taskId));
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<Long,Map<String, Object>> taskTimes = (HashMap<Long,Map<String, Object>>) task.computeIfAbsent(TIMES, k -> new HashMap<Long,Map<String, Object>>());
|
||||
taskTimes.put(time.id(),timeMap);
|
||||
while (task.get(PARENT_TASK_ID) instanceof Long parentTaskId){
|
||||
var parentTask = taskMap.get(parentTaskId);
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<Long,Map<String, Object>> children = (HashMap<Long,Map<String, Object>>) parentTask.computeIfAbsent(CHILDREN, k -> new HashMap<Long,Map<String, Object>>());
|
||||
children.put(taskId,task);
|
||||
task = parentTask;
|
||||
taskId = parentTaskId;
|
||||
}
|
||||
if (task.get(PROJECT_ID) instanceof Long projectId){
|
||||
var project = tree.computeIfAbsent(projectId,k -> new HashMap<>(projectMap.get(projectId).toMap()));
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<Long,Map<String,Object>> projectTasks = (HashMap<Long,Map<String, Object>>) project.computeIfAbsent(TASKS, k -> new HashMap<Long,Map<String,Object>>());
|
||||
projectTasks.put(taskId,task);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sendContent(ex,tree);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user