Browse Source

Merge branch 'dev' into feature/projects

kanban
Stephan Richter 4 months ago
parent
commit
cb1e186d24
  1. 2
      core/src/main/java/de/srsoftware/umbrella/core/Constants.java
  2. 11
      core/src/main/java/de/srsoftware/umbrella/core/api/ProjectService.java
  3. 4
      core/src/main/java/de/srsoftware/umbrella/core/model/Member.java
  4. 3
      core/src/main/java/de/srsoftware/umbrella/core/model/Permission.java
  5. 23
      core/src/main/java/de/srsoftware/umbrella/core/model/Project.java
  6. 6
      project/src/main/java/de/srsoftware/umbrella/project/ProjectDb.java
  7. 100
      project/src/main/java/de/srsoftware/umbrella/project/ProjectModule.java
  8. 34
      project/src/main/java/de/srsoftware/umbrella/project/SqliteDb.java
  9. 4
      task/src/main/java/de/srsoftware/umbrella/task/SqliteDb.java
  10. 41
      task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java

2
core/src/main/java/de/srsoftware/umbrella/core/Constants.java

@ -11,7 +11,9 @@ public class Constants { @@ -11,7 +11,9 @@ public class Constants {
public static final String ADDRESS = "address";
public static final String ATTACHMENTS = "attachments";
public static final String AUTHORIZATION = "Authorization";
public static final String BODY = "body";
public static final String CODE = "code";
public static final String COMPANY = "company";
public static final String COMPANY_ID = "company_id";

11
core/src/main/java/de/srsoftware/umbrella/core/api/ProjectService.java

@ -4,10 +4,17 @@ package de.srsoftware.umbrella.core.api; @@ -4,10 +4,17 @@ package de.srsoftware.umbrella.core.api;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Project;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public interface ProjectService {
public Collection<Project> listCompanyProjects(long companyId, boolean includeClosed) throws UmbrellaException;
public Map<Long,Project> listUserProjects(long userId, boolean includeClosed) throws UmbrellaException;
CompanyService companyService();
public Map<Long,Project> listCompanyProjects(long companyId, boolean includeClosed) throws UmbrellaException;
public Map<Long,Project> listUserProjects(long userId, boolean includeClosed) throws UmbrellaException;
public Collection<Project> loadMembers(Collection<Project> projects);
public default Project loadMembers(Project project){
loadMembers(List.of(project));
return project;
}
Map<Long, Map<String,Object>> mapProjects(Map<Long, Project> projects);
}

4
core/src/main/java/de/srsoftware/umbrella/core/model/Member.java

@ -7,9 +7,9 @@ import static de.srsoftware.umbrella.core.Constants.*; @@ -7,9 +7,9 @@ import static de.srsoftware.umbrella.core.Constants.*;
import de.srsoftware.tools.Mappable;
import java.util.Map;
public record Member(long userId, Permission permission) implements Mappable {
public record Member(UmbrellaUser user, Permission permission) implements Mappable {
@Override
public Map<String, Object> toMap() {
return Map.of(USER_ID,userId,PERMISSION,permission.toMap());
return Map.of(USER,user.toMap(),PERMISSION,permission.toMap());
}
}

3
core/src/main/java/de/srsoftware/umbrella/core/model/Permission.java

@ -1,12 +1,11 @@ @@ -1,12 +1,11 @@
/* © SRSoftware 2025 */
package de.srsoftware.umbrella.core.model;
import de.srsoftware.tools.Mappable;
import static de.srsoftware.umbrella.core.Constants.CODE;
import static de.srsoftware.umbrella.core.Constants.NAME;
import static java.text.MessageFormat.format;
import de.srsoftware.tools.Mappable;
import java.security.InvalidParameterException;
import java.util.Map;

23
core/src/main/java/de/srsoftware/umbrella/core/model/Project.java

@ -1,19 +1,14 @@ @@ -1,19 +1,14 @@
/* © SRSoftware 2025 */
package de.srsoftware.umbrella.core.model;
import static de.srsoftware.tools.Optionals.isSet;
import static de.srsoftware.tools.Optionals.nullable;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Util.markdown;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFieldException;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
import de.srsoftware.tools.Mappable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import org.json.JSONObject;
public class Project implements Mappable {
@ -49,8 +44,7 @@ public class Project implements Mappable { @@ -49,8 +44,7 @@ public class Project implements Mappable {
}
public boolean hasMember(UmbrellaUser user) {
var member = members.get(user.id());
return isSet(member) && member.userId() == user.id();
return members.containsKey(user.id());
}
public long id(){
@ -74,7 +68,6 @@ public class Project implements Mappable { @@ -74,7 +68,6 @@ public class Project implements Mappable {
for (var key : json.keySet()){
switch (key){
case DESCRIPTION: description = json.getString(key); break;
case MEMBERS: patchMembers(json.getJSONObject(MEMBERS)); break;
case NAME: name = json.getString(key); break;
case STATUS: status = json.get(key) instanceof Number number ? Status.of(number.intValue()) : Status.valueOf(json.getString(key)); break;
default: key = null;
@ -84,20 +77,6 @@ public class Project implements Mappable { @@ -84,20 +77,6 @@ public class Project implements Mappable {
return this;
}
private void patchMembers(JSONObject json) throws UmbrellaException {
for (var key : json.keySet()){
long userId;
try {
userId = Long.parseLong(key);
} catch (NumberFormatException e) {
throw invalidFieldException(USER_ID,"long");
}
if (!(json.get(key) instanceof Number number)) throw invalidFieldException(PERMISSION,"int");
var permission = Permission.of(number.intValue());
members.put(userId,new Member(userId,permission));
}
}
public boolean showClosed(){
return showClosed;
}

6
project/src/main/java/de/srsoftware/umbrella/project/ProjectDb.java

@ -2,14 +2,14 @@ @@ -2,14 +2,14 @@
package de.srsoftware.umbrella.project;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Permission;
import de.srsoftware.umbrella.core.model.Project;
import java.util.Map;
public interface ProjectDb {
Map<Long, Permission> getMembers(Project project);
Project load(long projectId) throws UmbrellaException;
Map<Long, Project> ofCompany(long companyId, boolean includeClosed) throws UmbrellaException;
Map<Long, Project> ofUser(long userId, boolean includeClosed) throws UmbrellaException;
Project save(Project prj) throws UmbrellaException;
Project load(long projectId) throws UmbrellaException;
}

100
project/src/main/java/de/srsoftware/umbrella/project/ProjectModule.java

@ -10,7 +10,6 @@ import static de.srsoftware.umbrella.core.model.Status.OPEN; @@ -10,7 +10,6 @@ import static de.srsoftware.umbrella.core.model.Status.OPEN;
import static de.srsoftware.umbrella.project.Constants.CONFIG_DATABASE;
import static java.lang.Boolean.TRUE;
import static java.net.HttpURLConnection.HTTP_OK;
import static java.util.Comparator.comparing;
import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.configuration.Configuration;
@ -39,19 +38,6 @@ public class ProjectModule extends BaseHandler implements ProjectService { @@ -39,19 +38,6 @@ public class ProjectModule extends BaseHandler implements ProjectService {
users = companies.userService();
}
private boolean addMembers(Project project, HttpExchange ex) throws IOException {
var map = project.toMap();
var members = new HashMap<Long,Map<String,Object>>();
for (var entry : project.members().entrySet()){
var userId = entry.getKey();
var perm = entry.getValue().permission().toMap();
members.put(userId,Map.of(USER,users.loadUser(userId).toMap(),PERMISSION,perm));
}
if (!members.isEmpty()) map.put(MEMBERS,members);
project.companyId().map(companies::get).map(Company::toMap).ifPresent(data -> map.put(COMPANY,data));
return sendContent(ex,map);
}
@Override
public CompanyService companyService() {
return companies;
@ -70,10 +56,7 @@ public class ProjectModule extends BaseHandler implements ProjectService { @@ -70,10 +56,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
default -> {
var projectId = Long.parseLong(head);
head = path.pop();
yield switch (head){
case null -> getProject(ex,projectId,user.get());
default -> super.doGet(path,ex);
};
yield head == null ? getProject(ex,projectId,user.get()) : super.doGet(path,ex);
}
};
} catch (UmbrellaException e){
@ -129,56 +112,81 @@ public class ProjectModule extends BaseHandler implements ProjectService { @@ -129,56 +112,81 @@ public class ProjectModule extends BaseHandler implements ProjectService {
}
private boolean getProject(HttpExchange ex, long projectId, UmbrellaUser user) throws IOException, UmbrellaException {
var project = projects.load(projectId);
var project = loadMembers(projects.load(projectId));
if (!project.hasMember(user)) throw forbidden("You are not a member of {0}",project.name());
return addMembers(project,ex);
var map = project.toMap();
project.companyId().map(companies::get).map(Company::toMap).ifPresent(data -> map.put(COMPANY,data));
return sendContent(ex,map);
}
public Collection<Project> listCompanyProjects(long companyId, boolean includeClosed) throws UmbrellaException {
return projects.ofCompany(companyId, includeClosed).values().stream().sorted(comparing(Project::name)).toList();
public Map<Long, Project> listCompanyProjects(long companyId, boolean includeClosed) throws UmbrellaException {
var projectList = projects.ofCompany(companyId, includeClosed);
loadMembers(projectList.values());
return projectList;
}
private boolean listCompanyProjects(HttpExchange ex, UmbrellaUser user, long companyId) throws IOException, UmbrellaException {
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 = listCompanyProjects(companyId,false)
.stream()
.map(Project::toMap)
.map(HashMap::new);
return sendContent(ex,projects);
var projects = listCompanyProjects(companyId,false);
return sendContent(ex,mapProjects(projects));
}
@Override
public Map<Long, Project> listUserProjects(long userId, boolean includeClosed) throws UmbrellaException {
return projects.ofUser(userId, includeClosed);
var projectMap = projects.ofUser(userId, includeClosed);
loadMembers(projectMap.values());
return projectMap;
}
private boolean listUserProjects(HttpExchange ex, UmbrellaUser user, boolean showClosed) throws IOException, UmbrellaException {
var projects = new HashMap<Long,Map<String,Object>>();
for (var entry : listUserProjects(user.id(),showClosed).entrySet()) {
var project = entry.getValue();
var map = project.toMap();
var members = new HashMap<Long,Map<String,Object>>();
var projects = listUserProjects(user.id(),showClosed);
return sendContent(ex,mapProjects(projects));
}
@Override
public Collection<Project> loadMembers(Collection<Project> projectList) {
var userMap = new HashMap<Long,UmbrellaUser>();
for (var memberEntry : project.members().entrySet()){
var perm = memberEntry.getValue().permission().name();
var userId = memberEntry.getKey();
var u = userMap.get(userId);
if (u == null) userMap.put(userId,u = users.loadUser(userId));
members.put(userId,Map.of(USER,u.toMap(),PERMISSION,perm));
for (var project : projectList){
for (var entry : projects.getMembers(project).entrySet()){
var userId = entry.getKey();
var permission = entry.getValue();
var user = userMap.computeIfAbsent(userId,k -> users.loadUser(userId));
project.members().put(userId,new Member(user,permission));
}
if (!members.isEmpty()) map.put(MEMBERS,members);
projects.put(entry.getKey(),map);
}
return sendContent(ex,projects);
return projectList;
}
@Override
public Map<Long, Map<String, Object>> mapProjects(Map<Long, Project> projects) {
var mapped = new HashMap<Long,Map<String,Object>>();
for (var entry : projects.entrySet()) mapped.put(entry.getKey(),entry.getValue().toMap());
return mapped;
}
private void patchMembers(Project project, JSONObject json) {
var members = project.members();
for (var key : json.keySet()){
long userId;
try {
userId = Long.parseLong(key);
} catch (NumberFormatException e) {
throw invalidFieldException(USER_ID,"long");
}
if (!(json.get(key) instanceof Number number)) throw invalidFieldException(PERMISSION,"int");
var permission = Permission.of(number.intValue());
members.put(userId,new Member(users.loadUser(userId),permission));
}
}
private boolean patchProject(HttpExchange ex, long projectId, UmbrellaUser user) throws IOException, UmbrellaException {
var project = projects.load(projectId);
var project = loadMembers(projects.load(projectId));
if (!project.hasMember(user)) throw forbidden("You are not a member of {0}",project.name());
var json = json(ex);
if (json.has(MEMBERS) && json.get(MEMBERS) instanceof JSONObject memberJson) patchMembers(project,memberJson);
projects.save(project.patch(json));
return addMembers(project,ex);
return sendContent(ex,project.toMap());
}
@ -195,7 +203,8 @@ public class ProjectModule extends BaseHandler implements ProjectService { @@ -195,7 +203,8 @@ public class ProjectModule extends BaseHandler implements ProjectService {
if (json.has(SETTINGS) && json.get(SETTINGS) instanceof JSONObject settingsJson){
showClosed = settingsJson.has(SHOW_CLOSED) && settingsJson.get(SHOW_CLOSED) == TRUE;
}
var prj = new Project(0,name,description, OPEN,companyId,showClosed, Map.of(user.id(),new Member(user.id(), OWNER)));
var owner = Map.of(user.id(),new Member(user,OWNER));
var prj = new Project(0,name,description, OPEN,companyId,showClosed, owner);
prj = projects.save(prj);
return sendContent(ex,prj);
}
@ -205,6 +214,5 @@ public class ProjectModule extends BaseHandler implements ProjectService { @@ -205,6 +214,5 @@ public class ProjectModule extends BaseHandler implements ProjectService {
var showClosed = json.has(SHOW_CLOSED) && json.get(SHOW_CLOSED) instanceof Boolean bool ? bool : false;
if (json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number companyId) return listCompanyProjects(ex, user, companyId.longValue());
return listUserProjects(ex,user,showClosed);
}
}

34
project/src/main/java/de/srsoftware/umbrella/project/SqliteDb.java

@ -16,7 +16,6 @@ import static java.text.MessageFormat.format; @@ -16,7 +16,6 @@ import static java.text.MessageFormat.format;
import de.srsoftware.tools.jdbc.Query;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Member;
import de.srsoftware.umbrella.core.model.Permission;
import de.srsoftware.umbrella.core.model.Project;
import java.sql.Connection;
@ -36,19 +35,6 @@ public class SqliteDb implements ProjectDb { @@ -36,19 +35,6 @@ public class SqliteDb implements ProjectDb {
init();
}
private Map<Long, Project> addMembers(Map<Long, Project> projects) throws SQLException, UmbrellaException {
Object[] ids = projects.keySet().toArray();
var rs = select(ALL).from(TABLE_PROJECT_USERS).where(PROJECT_ID,in(ids)).exec(db);
while (rs.next()){
var userId = rs.getLong(USER_ID);
var projectId = rs.getLong(PROJECT_ID);
var permission = Permission.of(rs.getInt(PERMISSIONS));
projects.get(projectId).members().put(userId, new Member(userId,permission));
}
rs.close();
return projects;
}
private int createTables() {
createProjectTables();
return createSettingsTable();
@ -129,6 +115,19 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) @@ -129,6 +115,19 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
}
}
@Override
public Map<Long, Permission> getMembers(Project project) {
try {
var result = new HashMap<Long,Permission>();
var rs = select(ALL).from(TABLE_PROJECT_USERS).where(PROJECT_ID,equal(project.id())).exec(db);
while (rs.next()) result.put(rs.getLong(USER_ID),Permission.of(rs.getInt(PERMISSIONS)));
rs.close();
return result;
} catch (SQLException e){
throw new UmbrellaException(HTTP_SERVER_ERROR,"Faailed to load project members");
}
}
private void init(){
var version = createTables();
LOG.log(INFO,"Updated project db to version {0}",version);
@ -142,7 +141,6 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) @@ -142,7 +141,6 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
if (rs.next()) result = Project.of(rs);
rs.close();
if (result == null) throw UmbrellaException.notFound("No project found for id {0}",projectId);
addMembers(Map.of(projectId,result));
return result;
} catch (SQLException e) {
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to load items from database");
@ -161,7 +159,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) @@ -161,7 +159,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
projects.put(project.id(),project);
}
rs.close();
return addMembers(projects);
return projects;
} catch (SQLException e) {
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to load items from database");
}
@ -181,7 +179,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) @@ -181,7 +179,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
projects.put(project.id(),project);
}
rs.close();
return addMembers(projects);
return projects;
} catch (SQLException e) {
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to load items from database");
}
@ -198,7 +196,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) @@ -198,7 +196,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
if (id != null){
if (!prj.members().isEmpty()) {
var query = insertInto(TABLE_PROJECT_USERS, PROJECT_ID, USER_ID, PERMISSIONS);
for (var entry : prj.members().entrySet()) query.values(id, entry.getKey(), entry.getValue().permission().code());
for (var member : prj.members().entrySet()) query.values(id, member.getKey(), member.getValue().permission().code());
query.execute(db).close();
}
return new Project(id, prj.name(), prj.description(),prj.status(),prj.companyId().orElse(null),prj.showClosed(),prj.members());

4
task/src/main/java/de/srsoftware/umbrella/task/SqliteDb.java

@ -16,8 +16,8 @@ import de.srsoftware.umbrella.core.model.Task; @@ -16,8 +16,8 @@ import de.srsoftware.umbrella.core.model.Task;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
public class SqliteDb implements TaskDb {
@ -28,7 +28,7 @@ public class SqliteDb implements TaskDb { @@ -28,7 +28,7 @@ public class SqliteDb implements TaskDb {
db = connection;
}
public HashMap<Long, Task> listTasks(List<Long> projectIds) throws UmbrellaException {
public HashMap<Long, Task> listTasks(Collection<Long> projectIds) throws UmbrellaException {
try {
var tasks = new HashMap<Long,Task>();
var rs = select(ALL).from(TABLE_TASKS).where(PROJECT_ID, in(projectIds.toArray())).exec(db);

41
task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java

@ -25,6 +25,9 @@ import de.srsoftware.umbrella.core.api.TaskService; @@ -25,6 +25,9 @@ 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.*;
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.*;
@ -90,17 +93,17 @@ public class TaskModule extends BaseHandler implements TaskService { @@ -90,17 +93,17 @@ public class TaskModule extends BaseHandler implements TaskService {
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.listCompanyProjects(companyId,false);
var map = taskDb.listTasks(projects.stream().map(Project::id).toList());
var tree = new HashMap<Long,Map<String,Object>>();
map.values().stream().filter(task -> !is0(task.estimatedTime())).forEach(task -> placeInTree(task,tree,map));
var projectMap = this.projects.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));
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.values().forEach(project -> {
var mappedProject = new HashMap<>(project.toMap());
var children = taskTree.values().stream().filter(root -> project.id() == (Long)root.get(PROJECT_ID)).toList();
if (!children.isEmpty()) {
projectMap.put(TASKS, children);
result.add(projectMap);
mappedProject.put(TASKS, children);
result.add(mappedProject);
}
});
return sendContent(ex,result);
@ -121,7 +124,7 @@ public class TaskModule extends BaseHandler implements TaskService { @@ -121,7 +124,7 @@ public class TaskModule extends BaseHandler implements TaskService {
@Override
public HashMap<Long, Task> listCompanyTasks(long companyId) throws UmbrellaException {
var projectList = projects.listCompanyProjects(companyId,false);
return taskDb.listTasks(projectList.stream().map(Project::id).toList());
return taskDb.listTasks(projectList.keySet());
}
@Override
@ -129,18 +132,18 @@ public class TaskModule extends BaseHandler implements TaskService { @@ -129,18 +132,18 @@ public class TaskModule extends BaseHandler implements TaskService {
return taskDb.listTasks(List.of(projectId));
}
private Map<String,Object> placeInTree(Task task, HashMap<Long, Map<String,Object>> tree, Map<Long, Task> map) {
var taskMap = task.toMap();
private Map<String,Object> placeInTree(Task task, HashMap<Long, Map<String,Object>> taskTree, Map<Long, Task> taskMap) {
var mappedTask = task.toMap();
if (task.parentTaskId() != null){
Task parent = map.get(task.parentTaskId());
var trunk = placeInTree(parent,tree,map);
Task parent = taskMap.get(task.parentTaskId());
var trunk = placeInTree(parent,taskTree,taskMap);
@SuppressWarnings("unchecked")
ArrayList<Object> children = (ArrayList<Object>) trunk.computeIfAbsent(CHILDREN, k -> new ArrayList<Object>());
children.add(taskMap);
return taskMap;
ArrayList<Object> children = (ArrayList<Object>) trunk.computeIfAbsent(CHILDREN, k -> new ArrayList<>());
children.add(mappedTask);
return mappedTask;
}
tree.put(task.id(),taskMap);
return taskMap;
taskTree.put(task.id(),mappedTask);
return mappedTask;
}
private boolean postTaskList(UmbrellaUser user, HttpExchange ex) throws IOException {

Loading…
Cancel
Save