implemented function to return estimated times of company.
Therefore task and project module had to be created and partially implemented
This commit is contained in:
6
task/build.gradle.kts
Normal file
6
task/build.gradle.kts
Normal file
@@ -0,0 +1,6 @@
|
||||
description = "Umbrella : Tasks"
|
||||
|
||||
dependencies{
|
||||
implementation(project(":core"))
|
||||
implementation(project(":project"))
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.task;
|
||||
|
||||
public class Constants {
|
||||
private 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";
|
||||
}
|
||||
38
task/src/main/java/de/srsoftware/umbrella/task/SqliteDb.java
Normal file
38
task/src/main/java/de/srsoftware/umbrella/task/SqliteDb.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/* © SRSoftware 2025 */
|
||||
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.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 java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class SqliteDb implements TaskDb {
|
||||
|
||||
private final Connection db;
|
||||
|
||||
public SqliteDb(Connection connection) {
|
||||
db = connection;
|
||||
}
|
||||
|
||||
public Collection<Task> listTasks(List<Long> projectIds) throws UmbrellaException {
|
||||
try {
|
||||
var rs = select("*").from(TABLE_TASKS).where(PROJECT_ID, in(projectIds.toArray())).exec(db);
|
||||
var list = new HashSet<Task>();
|
||||
while (rs.next()) list.add(Task.of(rs));
|
||||
rs.close();
|
||||
return list;
|
||||
} catch (SQLException e) {
|
||||
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to load tasks for project ids");
|
||||
}
|
||||
}
|
||||
}
|
||||
54
task/src/main/java/de/srsoftware/umbrella/task/Task.java
Normal file
54
task/src/main/java/de/srsoftware/umbrella/task/Task.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.task;
|
||||
|
||||
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.task.Constants.*;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public record Task(long id, long projectId, Long parentTaskId, String name, String description, int status, Double estimatedTime, LocalDate start, LocalDate dueDate,boolean showClosed, boolean noIndex) implements Mappable {
|
||||
public static Task of(ResultSet rs) throws SQLException {
|
||||
var estTime = rs.getDouble(EST_TIME);
|
||||
var parentTaskId = rs.getLong(PARENT_TASK_ID);
|
||||
var startDate = nullIfEmpty(rs.getString(START_DATE));
|
||||
var dueDate = nullIfEmpty(rs.getString(DUE_DATE));
|
||||
return new Task(
|
||||
rs.getLong(ID),
|
||||
rs.getLong(PROJECT_ID),
|
||||
parentTaskId == 0d ? null : parentTaskId,
|
||||
rs.getString(NAME),
|
||||
rs.getString(DESCRIPTION),
|
||||
rs.getInt(STATUS),
|
||||
estTime == 0d ? null : estTime,
|
||||
startDate != null ? LocalDate.parse(startDate) : null,
|
||||
dueDate != null ? LocalDate.parse(dueDate) : null,
|
||||
rs.getBoolean(SHOW_CLOSED),
|
||||
rs.getBoolean(NO_INDEX)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
var map = new HashMap<String,Object>();
|
||||
map.put(ID, id);
|
||||
map.put(PROJECT_ID, projectId);
|
||||
map.put(PARENT_TASK_ID, parentTaskId);
|
||||
map.put(NAME, name);
|
||||
map.put(DESCRIPTION, description);
|
||||
map.put(STATUS, status);
|
||||
map.put(ESTIMATED_TIME, estimatedTime);
|
||||
map.put(START_DATE,start);
|
||||
map.put(DUE_DATE,dueDate);
|
||||
map.put(SHOW_CLOSED,showClosed);
|
||||
map.put(NO_INDEX,noIndex);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.task;
|
||||
|
||||
|
||||
|
||||
public interface TaskDb {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/* © SRSoftware 2025 */
|
||||
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.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;
|
||||
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.CompanyService;
|
||||
import de.srsoftware.umbrella.core.api.ProjectService;
|
||||
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.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 {
|
||||
|
||||
private final SqliteDb taskDb;
|
||||
private final ProjectService projects;
|
||||
private final UserService users;
|
||||
private final CompanyService companies;
|
||||
|
||||
public TaskModule(Configuration config, ProjectService projectService) throws UmbrellaException {
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
taskDb = new SqliteDb(connect(dbFile));
|
||||
projects = projectService;
|
||||
companies = projectService.companyService();
|
||||
users = companies.userService();
|
||||
}
|
||||
|
||||
@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 ESTIMATED_TIMES -> estimatedTimes(user.get(),ex);
|
||||
default -> super.doGet(path,ex);
|
||||
};
|
||||
} catch (UmbrellaException e){
|
||||
return send(ex,e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean estimatedTimes(UmbrellaUser user, HttpExchange ex) throws IOException, UmbrellaException {
|
||||
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 = companies.get(companyId);
|
||||
if (!companies.membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
var projects = this.projects.listProjects(companyId,false);
|
||||
var taskList = taskDb.listTasks(projects.stream().map(Project::id).toList());
|
||||
var map = taskList.stream().collect(toMap(Task::id, t -> t));
|
||||
var tree = new HashMap<Long,Map<String,Object>>();
|
||||
taskList.stream().filter(task -> !is0(task.estimatedTime())).forEach(task -> placeInTree(task,tree,map));
|
||||
var result = new ArrayList<Map<String,Object>>();
|
||||
projects.forEach(project -> {
|
||||
var projectMap = new HashMap<>(project.toMap());
|
||||
var children = tree.values().stream().filter(root -> project.id() == (Long)root.get(PROJECT_ID)).toList();
|
||||
projectMap.put(FIELD_TASKS,children);
|
||||
result.add(projectMap);
|
||||
});
|
||||
return sendContent(ex,result);
|
||||
}
|
||||
|
||||
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){
|
||||
Task parent = map.get(task.parentTaskId());
|
||||
var trunk = placeInTree(parent,tree,map);
|
||||
ArrayList<Object> children = (ArrayList<Object>) trunk.computeIfAbsent(CHILDREN, k -> new ArrayList<Object>());
|
||||
children.add(taskMap);
|
||||
return taskMap;
|
||||
}
|
||||
tree.put(task.id(),taskMap);
|
||||
return taskMap;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user