working on project list: introducing task list
This commit is contained in:
@@ -41,7 +41,7 @@ subprojects {
|
|||||||
testImplementation(platform("org.junit:junit-bom:5.10.0"))
|
testImplementation(platform("org.junit:junit-bom:5.10.0"))
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
implementation("de.srsoftware:configuration.api:1.0.2")
|
implementation("de.srsoftware:configuration.api:1.0.2")
|
||||||
implementation("de.srsoftware:tools.jdbc:1.3.2")
|
implementation("de.srsoftware:tools.jdbc:1.3.3")
|
||||||
implementation("de.srsoftware:tools.http:6.0.4")
|
implementation("de.srsoftware:tools.http:6.0.4")
|
||||||
implementation("de.srsoftware:tools.logging:1.3.2")
|
implementation("de.srsoftware:tools.logging:1.3.2")
|
||||||
implementation("de.srsoftware:tools.optionals:1.0.0")
|
implementation("de.srsoftware:tools.optionals:1.0.0")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
package de.srsoftware.umbrella.company;
|
package de.srsoftware.umbrella.company;
|
||||||
|
|
||||||
import static de.srsoftware.tools.jdbc.Condition.equal;
|
import static de.srsoftware.tools.jdbc.Condition.equal;
|
||||||
|
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||||
import static de.srsoftware.tools.jdbc.Query.select;
|
import static de.srsoftware.tools.jdbc.Query.select;
|
||||||
import static de.srsoftware.umbrella.company.Constants.TABLE_COMPANIES;
|
import static de.srsoftware.umbrella.company.Constants.TABLE_COMPANIES;
|
||||||
import static de.srsoftware.umbrella.company.Constants.TABLE_COMPANIES_USERS;
|
import static de.srsoftware.umbrella.company.Constants.TABLE_COMPANIES_USERS;
|
||||||
@@ -29,7 +30,7 @@ public class SqliteDb implements CompanyDb {
|
|||||||
@Override
|
@Override
|
||||||
public Collection<Long> getMembers(long companyId) throws UmbrellaException {
|
public Collection<Long> getMembers(long companyId) throws UmbrellaException {
|
||||||
try {
|
try {
|
||||||
var rs = select("*").from(TABLE_COMPANIES_USERS).where(COMPANY_ID, equal(companyId)).exec(db);
|
var rs = select(ALL).from(TABLE_COMPANIES_USERS).where(COMPANY_ID, equal(companyId)).exec(db);
|
||||||
var ids = new HashSet<Long>();
|
var ids = new HashSet<Long>();
|
||||||
while (rs.next()) ids.add(rs.getLong(USER_ID));
|
while (rs.next()) ids.add(rs.getLong(USER_ID));
|
||||||
rs.close();
|
rs.close();
|
||||||
@@ -42,7 +43,7 @@ public class SqliteDb implements CompanyDb {
|
|||||||
@Override
|
@Override
|
||||||
public Map<Long,Company> listCompaniesOf(long userId) throws UmbrellaException {
|
public Map<Long,Company> listCompaniesOf(long userId) throws UmbrellaException {
|
||||||
try {
|
try {
|
||||||
var rs = select("*").from(TABLE_COMPANIES).leftJoin(ID,TABLE_COMPANIES_USERS,COMPANY_ID).where(USER_ID,equal(userId)).exec(db);
|
var rs = select(ALL).from(TABLE_COMPANIES).leftJoin(ID,TABLE_COMPANIES_USERS,COMPANY_ID).where(USER_ID,equal(userId)).exec(db);
|
||||||
var companies = new HashMap<Long,Company>();
|
var companies = new HashMap<Long,Company>();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
var company = Company.of(rs);
|
var company = Company.of(rs);
|
||||||
@@ -58,7 +59,7 @@ public class SqliteDb implements CompanyDb {
|
|||||||
@Override
|
@Override
|
||||||
public Company load(long companyId) throws UmbrellaException {
|
public Company load(long companyId) throws UmbrellaException {
|
||||||
try {
|
try {
|
||||||
var rs = select("*").from(TABLE_COMPANIES).where(ID, equal(companyId)).exec(db);
|
var rs = select(ALL).from(TABLE_COMPANIES).where(ID, equal(companyId)).exec(db);
|
||||||
Company company = null;
|
Company company = null;
|
||||||
if (rs.next()) company = Company.of(rs);
|
if (rs.next()) company = Company.of(rs);
|
||||||
rs.close();
|
rs.close();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
package de.srsoftware.umbrella.contact;
|
package de.srsoftware.umbrella.contact;
|
||||||
|
|
||||||
import static de.srsoftware.tools.jdbc.Condition.equal;
|
import static de.srsoftware.tools.jdbc.Condition.equal;
|
||||||
|
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||||
import static de.srsoftware.tools.jdbc.Query.select;
|
import static de.srsoftware.tools.jdbc.Query.select;
|
||||||
import static de.srsoftware.umbrella.contact.Constants.TABLE_CONTACTS;
|
import static de.srsoftware.umbrella.contact.Constants.TABLE_CONTACTS;
|
||||||
import static de.srsoftware.umbrella.contact.Constants.TABLE_CONTACTS_USERS;
|
import static de.srsoftware.umbrella.contact.Constants.TABLE_CONTACTS_USERS;
|
||||||
@@ -24,7 +25,7 @@ public class SqliteDb implements ContactDb{
|
|||||||
@Override
|
@Override
|
||||||
public Collection<Contact> listContactsOf(long userId) throws UmbrellaException{
|
public Collection<Contact> listContactsOf(long userId) throws UmbrellaException{
|
||||||
try {
|
try {
|
||||||
var rs = select("*").from(TABLE_CONTACTS).leftJoin(ID,TABLE_CONTACTS_USERS,USER_ID).where(USER_ID,equal(userId)).exec(conn);
|
var rs = select(ALL).from(TABLE_CONTACTS).leftJoin(ID,TABLE_CONTACTS_USERS,USER_ID).where(USER_ID,equal(userId)).exec(conn);
|
||||||
var contacts = new HashSet<Contact>();
|
var contacts = new HashSet<Contact>();
|
||||||
while (rs.next()) contacts.add(Contact.of(rs));
|
while (rs.next()) contacts.add(Contact.of(rs));
|
||||||
rs.close();
|
rs.close();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import static java.lang.System.Logger.Level.WARNING;
|
|||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
import com.xrbpowered.jparsedown.JParsedown;
|
import com.xrbpowered.jparsedown.JParsedown;
|
||||||
|
import de.srsoftware.tools.Mappable;
|
||||||
import de.srsoftware.tools.Query;
|
import de.srsoftware.tools.Query;
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@@ -18,6 +19,7 @@ import java.net.URL;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@@ -40,6 +42,12 @@ public class Util {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<Long,Map<String,Object>> mapValues(Map<Long, ? extends Mappable> map){
|
||||||
|
var result = new HashMap<Long,Map<String,Object>>();
|
||||||
|
for (var entry : map.entrySet()) result.put(entry.getKey(),entry.getValue().toMap());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static String markdown(String source){
|
public static String markdown(String source){
|
||||||
try {
|
try {
|
||||||
if (plantumlJar.exists()) {
|
if (plantumlJar.exists()) {
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ package de.srsoftware.umbrella.core.api;
|
|||||||
|
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||||
import de.srsoftware.umbrella.core.model.Task;
|
import de.srsoftware.umbrella.core.model.Task;
|
||||||
import java.util.Collection;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public interface TaskService {
|
public interface TaskService {
|
||||||
CompanyService companyService();
|
CompanyService companyService();
|
||||||
Collection<Task> listCompanyTasks(long companyId) throws UmbrellaException;
|
HashMap<Long, Task> listCompanyTasks(long companyId) throws UmbrellaException;
|
||||||
Collection<Task> listProjectTasks(long projectId) throws UmbrellaException;
|
HashMap<Long, Task> listProjectTasks(long projectId) throws UmbrellaException;
|
||||||
|
|
||||||
ProjectService projectService();
|
ProjectService projectService();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
/* © SRSoftware 2025 */
|
/* © SRSoftware 2025 */
|
||||||
package de.srsoftware.umbrella.core.model;
|
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.*;
|
||||||
import static de.srsoftware.umbrella.core.Util.markdown;
|
import static de.srsoftware.umbrella.core.Util.markdown;
|
||||||
|
|
||||||
|
|||||||
15
frontend/src/Components/TaskList.svelte
Normal file
15
frontend/src/Components/TaskList.svelte
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<script>
|
||||||
|
import { t } from '../translations.svelte.js';
|
||||||
|
|
||||||
|
let { tasks } = $props();
|
||||||
|
|
||||||
|
let sortedTasks = $derived.by(() => Object.values(tasks).sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{#each sortedTasks as task}
|
||||||
|
<li>{task.name}</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
let projects = $state(null);
|
let projects = $state(null);
|
||||||
let companies = $state(null);
|
let companies = $state(null);
|
||||||
|
|
||||||
|
let sortedProjects = $derived.by(() => Object.values(projects).sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
|
|
||||||
async function loadProjects(){
|
async function loadProjects(){
|
||||||
let url = `${location.protocol}//${location.host.replace('5173','8080')}/api/company/list`;
|
let url = `${location.protocol}//${location.host.replace('5173','8080')}/api/company/list`;
|
||||||
let resp = await fetch(url,{credentials:'include'});
|
let resp = await fetch(url,{credentials:'include'});
|
||||||
@@ -48,8 +50,8 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#each Object.entries(projects) as [pid,project]}
|
{#each sortedProjects as project}
|
||||||
<tr onclick={() => router.navigate(`/project/${pid}/view`)}>
|
<tr onclick={() => router.navigate(`/project/${project.id}/view`)}>
|
||||||
<td>{project.name}</td>
|
<td>{project.name}</td>
|
||||||
<td>
|
<td>
|
||||||
{#if project.company_id}
|
{#if project.company_id}
|
||||||
|
|||||||
@@ -1,21 +1,39 @@
|
|||||||
<script>
|
<script>
|
||||||
import { t } from '../../translations.svelte.js';
|
import { t } from '../../translations.svelte.js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import TaskList from '../../Components/TaskList.svelte';
|
||||||
|
|
||||||
let { id } = $props();
|
let { id } = $props();
|
||||||
let project = $state(null);
|
let project = $state(null);
|
||||||
let error = $state(null);
|
let error = $state(null);
|
||||||
|
let tasks = $state(null);
|
||||||
|
|
||||||
async function loadProject(){
|
async function loadProject(){
|
||||||
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/project/${id}`;
|
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/project/${id}`;
|
||||||
const resp = await fetch(url,{credentials:'include'});
|
const resp = await fetch(url,{credentials:'include'});
|
||||||
if (resp.ok){
|
if (resp.ok){
|
||||||
project = await resp.json();
|
project = await resp.json();
|
||||||
error = null;
|
error = null;
|
||||||
|
loadTasks();
|
||||||
} else {
|
} else {
|
||||||
error = await resp.text();
|
error = await resp.text();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadTasks(){
|
||||||
|
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/task/list`;
|
||||||
|
const resp = await fetch(url,{
|
||||||
|
credentials:'include',
|
||||||
|
method:'POST',
|
||||||
|
body:JSON.stringify({project_id:+id})
|
||||||
|
});
|
||||||
|
if (resp.ok){
|
||||||
|
tasks = await resp.json();
|
||||||
|
error = null;
|
||||||
|
} else {
|
||||||
|
error = await resp.text();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMount(loadProject);
|
onMount(loadProject);
|
||||||
</script>
|
</script>
|
||||||
@@ -55,7 +73,11 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{t('tasks')}</th>
|
<th>{t('tasks')}</th>
|
||||||
<td class="error">TODO</td>
|
<td>
|
||||||
|
{#if tasks}
|
||||||
|
<TaskList {tasks} />
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{t('members')}</th>
|
<th>{t('members')}</th>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
package de.srsoftware.umbrella.items;
|
package de.srsoftware.umbrella.items;
|
||||||
|
|
||||||
import static de.srsoftware.tools.jdbc.Condition.equal;
|
import static de.srsoftware.tools.jdbc.Condition.equal;
|
||||||
|
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||||
import static de.srsoftware.tools.jdbc.Query.select;
|
import static de.srsoftware.tools.jdbc.Query.select;
|
||||||
import static de.srsoftware.umbrella.core.Constants.COMPANY_ID;
|
import static de.srsoftware.umbrella.core.Constants.COMPANY_ID;
|
||||||
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR;
|
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR;
|
||||||
@@ -25,7 +26,7 @@ public class SqliteDb implements ItemDb{
|
|||||||
public Collection<Item> list(long companyId) throws UmbrellaException {
|
public Collection<Item> list(long companyId) throws UmbrellaException {
|
||||||
try {
|
try {
|
||||||
var items = new HashSet<Item>();
|
var items = new HashSet<Item>();
|
||||||
var rs = select("*").from(TABLE_ITEMS).where(COMPANY_ID, equal(companyId)).exec(db);
|
var rs = select(ALL).from(TABLE_ITEMS).where(COMPANY_ID, equal(companyId)).exec(db);
|
||||||
while (rs.next()) items.add(Item.of(rs));
|
while (rs.next()) items.add(Item.of(rs));
|
||||||
rs.close();
|
rs.close();
|
||||||
return items;
|
return items;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
package de.srsoftware.umbrella.project;
|
package de.srsoftware.umbrella.project;
|
||||||
|
|
||||||
import static de.srsoftware.tools.jdbc.Condition.*;
|
import static de.srsoftware.tools.jdbc.Condition.*;
|
||||||
|
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||||
import static de.srsoftware.tools.jdbc.Query.insertInto;
|
import static de.srsoftware.tools.jdbc.Query.insertInto;
|
||||||
import static de.srsoftware.tools.jdbc.Query.select;
|
import static de.srsoftware.tools.jdbc.Query.select;
|
||||||
import static de.srsoftware.umbrella.core.Constants.*;
|
import static de.srsoftware.umbrella.core.Constants.*;
|
||||||
@@ -37,7 +38,7 @@ public class SqliteDb implements ProjectDb {
|
|||||||
|
|
||||||
private Map<Long, Project> addMembers(Map<Long, Project> projects) throws SQLException, UmbrellaException {
|
private Map<Long, Project> addMembers(Map<Long, Project> projects) throws SQLException, UmbrellaException {
|
||||||
Object[] ids = projects.keySet().toArray();
|
Object[] ids = projects.keySet().toArray();
|
||||||
var rs = select("*").from(TABLE_PROJECT_USERS).where(PROJECT_ID,in(ids)).exec(db);
|
var rs = select(ALL).from(TABLE_PROJECT_USERS).where(PROJECT_ID,in(ids)).exec(db);
|
||||||
while (rs.next()){
|
while (rs.next()){
|
||||||
var userId = rs.getLong(USER_ID);
|
var userId = rs.getLong(USER_ID);
|
||||||
var projectId = rs.getLong(PROJECT_ID);
|
var projectId = rs.getLong(PROJECT_ID);
|
||||||
@@ -136,7 +137,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
|
|||||||
@Override
|
@Override
|
||||||
public Project load(long projectId) throws UmbrellaException {
|
public Project load(long projectId) throws UmbrellaException {
|
||||||
try {
|
try {
|
||||||
var rs = select("*").from(TABLE_PROJECTS).where(ID, equal(projectId)).exec(db);
|
var rs = select(ALL).from(TABLE_PROJECTS).where(ID, equal(projectId)).exec(db);
|
||||||
Project result = null;
|
Project result = null;
|
||||||
if (rs.next()) result = Project.of(rs);
|
if (rs.next()) result = Project.of(rs);
|
||||||
rs.close();
|
rs.close();
|
||||||
@@ -152,7 +153,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
|
|||||||
public Map<Long, Project> ofCompany(long companyId, boolean includeClosed) throws UmbrellaException {
|
public Map<Long, Project> ofCompany(long companyId, boolean includeClosed) throws UmbrellaException {
|
||||||
try {
|
try {
|
||||||
var projects = new HashMap<Long,Project>();
|
var projects = new HashMap<Long,Project>();
|
||||||
var query = select("*").from(TABLE_PROJECTS).where(COMPANY_ID, equal(companyId));
|
var query = select(ALL).from(TABLE_PROJECTS).where(COMPANY_ID, equal(companyId));
|
||||||
if (!includeClosed) query = query.where(STATUS,lessThan(Project.Status.Complete.code()));
|
if (!includeClosed) query = query.where(STATUS,lessThan(Project.Status.Complete.code()));
|
||||||
var rs = query.exec(db);
|
var rs = query.exec(db);
|
||||||
while (rs.next()){
|
while (rs.next()){
|
||||||
@@ -172,7 +173,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
|
|||||||
public Map<Long, Project> ofUser(long userId, boolean includeClosed) throws UmbrellaException {
|
public Map<Long, Project> ofUser(long userId, boolean includeClosed) throws UmbrellaException {
|
||||||
try {
|
try {
|
||||||
var projects = new HashMap<Long,Project>();
|
var projects = new HashMap<Long,Project>();
|
||||||
var query = select("*").from(TABLE_PROJECTS).leftJoin(ID,TABLE_PROJECT_USERS,PROJECT_ID).where(USER_ID, equal(userId));
|
var query = select(ALL).from(TABLE_PROJECTS).leftJoin(ID,TABLE_PROJECT_USERS,PROJECT_ID).where(USER_ID, equal(userId));
|
||||||
if (!includeClosed) query = query.where(STATUS,lessThan(Project.Status.Complete.code()));
|
if (!includeClosed) query = query.where(STATUS,lessThan(Project.Status.Complete.code()));
|
||||||
var rs = query.exec(db);
|
var rs = query.exec(db);
|
||||||
while (rs.next()){
|
while (rs.next()){
|
||||||
|
|||||||
@@ -8,5 +8,7 @@ public class Constants {
|
|||||||
public static final String CHILDREN = "children";
|
public static final String CHILDREN = "children";
|
||||||
public static final String ESTIMATED_TIMES = "estimated_times";
|
public static final String ESTIMATED_TIMES = "estimated_times";
|
||||||
public static final String TABLE_TASKS = "tasks";
|
public static final String TABLE_TASKS = "tasks";
|
||||||
public static final String FIELD_TASKS = "tasks";
|
public static final String TABLE_TASKS_USERS = "tasks_users";
|
||||||
|
public static final String TASKS = "tasks";
|
||||||
|
public static final String TASK_ID = "task_id";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,38 +2,63 @@
|
|||||||
package de.srsoftware.umbrella.task;
|
package de.srsoftware.umbrella.task;
|
||||||
|
|
||||||
|
|
||||||
import static de.srsoftware.tools.jdbc.Condition.in;
|
import static de.srsoftware.tools.jdbc.Condition.*;
|
||||||
|
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||||
import static de.srsoftware.tools.jdbc.Query.select;
|
import static de.srsoftware.tools.jdbc.Query.select;
|
||||||
import static de.srsoftware.umbrella.core.Constants.PROJECT_ID;
|
import static de.srsoftware.umbrella.core.Constants.*;
|
||||||
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR;
|
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR;
|
||||||
import static de.srsoftware.umbrella.task.Constants.TABLE_TASKS;
|
import static de.srsoftware.umbrella.task.Constants.*;
|
||||||
|
import static java.lang.System.Logger.Level.WARNING;
|
||||||
|
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||||
import de.srsoftware.umbrella.core.model.Task;
|
import de.srsoftware.umbrella.core.model.Task;
|
||||||
|
import de.srsoftware.umbrella.core.model.UmbrellaUser;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Collection;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class SqliteDb implements TaskDb {
|
public class SqliteDb implements TaskDb {
|
||||||
|
private static final System.Logger LOG = System.getLogger("TaskDb");
|
||||||
private final Connection db;
|
private final Connection db;
|
||||||
|
|
||||||
public SqliteDb(Connection connection) {
|
public SqliteDb(Connection connection) {
|
||||||
db = connection;
|
db = connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Task> listTasks(List<Long> projectIds) throws UmbrellaException {
|
public HashMap<Long, Task> listTasks(List<Long> projectIds) throws UmbrellaException {
|
||||||
try {
|
try {
|
||||||
var rs = select("*").from(TABLE_TASKS).where(PROJECT_ID, in(projectIds.toArray())).exec(db);
|
var tasks = new HashMap<Long,Task>();
|
||||||
var list = new HashSet<Task>();
|
var rs = select(ALL).from(TABLE_TASKS).where(PROJECT_ID, in(projectIds.toArray())).exec(db);
|
||||||
while (rs.next()) list.add(Task.of(rs));
|
while (rs.next()){
|
||||||
|
var task = Task.of(rs);
|
||||||
|
tasks.put(task.id(),task);
|
||||||
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
return list;
|
return tasks;
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to load tasks for project ids");
|
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to load tasks for project ids");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HashMap<Long, Task> listRootTasks(UmbrellaUser user, Long projectId) {
|
||||||
|
try {
|
||||||
|
var tasks = new HashMap<Long,Task>();
|
||||||
|
var rs = select(ALL).from(TABLE_TASKS).leftJoin(ID,TABLE_TASKS_USERS,TASK_ID)
|
||||||
|
.where(PROJECT_ID,equal(projectId))
|
||||||
|
.where(USER_ID,equal(user.id()))
|
||||||
|
.where(PARENT_TASK_ID,isNull())
|
||||||
|
.exec(db);
|
||||||
|
while (rs.next()){
|
||||||
|
var task = Task.of(rs);
|
||||||
|
tasks.put(task.id(),task);
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
return tasks;
|
||||||
|
} catch (SQLException e){
|
||||||
|
LOG.log(WARNING,"Failed to load tasks for project (pid: {0}, user_id: {1}",projectId,user.id(),e);
|
||||||
|
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to load tasks for project id");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,16 @@
|
|||||||
package de.srsoftware.umbrella.task;
|
package de.srsoftware.umbrella.task;
|
||||||
|
|
||||||
import static de.srsoftware.tools.Optionals.is0;
|
import static de.srsoftware.tools.Optionals.is0;
|
||||||
|
import static de.srsoftware.tools.Optionals.isSet;
|
||||||
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
|
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
|
||||||
import static de.srsoftware.umbrella.core.Constants.COMPANY_ID;
|
import static de.srsoftware.umbrella.core.Constants.COMPANY_ID;
|
||||||
import static de.srsoftware.umbrella.core.Constants.PROJECT_ID;
|
import static de.srsoftware.umbrella.core.Constants.PROJECT_ID;
|
||||||
|
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.forbidden;
|
||||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
|
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
|
||||||
import static de.srsoftware.umbrella.task.Constants.*;
|
import static de.srsoftware.umbrella.task.Constants.*;
|
||||||
import static java.util.stream.Collectors.toMap;
|
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
import de.srsoftware.configuration.Configuration;
|
import de.srsoftware.configuration.Configuration;
|
||||||
@@ -57,6 +60,7 @@ public class TaskModule extends BaseHandler implements TaskService {
|
|||||||
var head = path.pop();
|
var head = path.pop();
|
||||||
return switch (head) {
|
return switch (head) {
|
||||||
case ESTIMATED_TIMES -> estimatedTimes(user.get(),ex);
|
case ESTIMATED_TIMES -> estimatedTimes(user.get(),ex);
|
||||||
|
case LIST -> postTaskList(user.get(),ex);
|
||||||
default -> super.doGet(path,ex);
|
default -> super.doGet(path,ex);
|
||||||
};
|
};
|
||||||
} catch (UmbrellaException e){
|
} catch (UmbrellaException e){
|
||||||
@@ -71,16 +75,15 @@ public class TaskModule extends BaseHandler implements TaskService {
|
|||||||
var company = companies.get(companyId);
|
var company = companies.get(companyId);
|
||||||
if (!companies.membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
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 projects = this.projects.listCompanyProjects(companyId,false);
|
||||||
var taskList = taskDb.listTasks(projects.stream().map(Project::id).toList());
|
var map = 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>>();
|
var tree = new HashMap<Long,Map<String,Object>>();
|
||||||
taskList.stream().filter(task -> !is0(task.estimatedTime())).forEach(task -> placeInTree(task,tree,map));
|
map.values().stream().filter(task -> !is0(task.estimatedTime())).forEach(task -> placeInTree(task,tree,map));
|
||||||
var result = new ArrayList<Map<String,Object>>();
|
var result = new ArrayList<Map<String,Object>>();
|
||||||
projects.forEach(project -> {
|
projects.forEach(project -> {
|
||||||
var projectMap = new HashMap<>(project.toMap());
|
var projectMap = new HashMap<>(project.toMap());
|
||||||
var children = tree.values().stream().filter(root -> project.id() == (Long)root.get(PROJECT_ID)).toList();
|
var children = tree.values().stream().filter(root -> project.id() == (Long)root.get(PROJECT_ID)).toList();
|
||||||
if (!children.isEmpty()) {
|
if (!children.isEmpty()) {
|
||||||
projectMap.put(FIELD_TASKS, children);
|
projectMap.put(TASKS, children);
|
||||||
result.add(projectMap);
|
result.add(projectMap);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -88,13 +91,13 @@ public class TaskModule extends BaseHandler implements TaskService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Task> listCompanyTasks(long companyId) throws UmbrellaException {
|
public HashMap<Long, Task> listCompanyTasks(long companyId) throws UmbrellaException {
|
||||||
var projectList = projects.listCompanyProjects(companyId,false);
|
var projectList = projects.listCompanyProjects(companyId,false);
|
||||||
return taskDb.listTasks(projectList.stream().map(Project::id).toList());
|
return taskDb.listTasks(projectList.stream().map(Project::id).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Task> listProjectTasks(long projectId) throws UmbrellaException {
|
public HashMap<Long, Task> listProjectTasks(long projectId) throws UmbrellaException {
|
||||||
return taskDb.listTasks(List.of(projectId));
|
return taskDb.listTasks(List.of(projectId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,6 +106,7 @@ public class TaskModule extends BaseHandler implements TaskService {
|
|||||||
if (task.parentTaskId() != null){
|
if (task.parentTaskId() != null){
|
||||||
Task parent = map.get(task.parentTaskId());
|
Task parent = map.get(task.parentTaskId());
|
||||||
var trunk = placeInTree(parent,tree,map);
|
var trunk = placeInTree(parent,tree,map);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
ArrayList<Object> children = (ArrayList<Object>) trunk.computeIfAbsent(CHILDREN, k -> new ArrayList<Object>());
|
ArrayList<Object> children = (ArrayList<Object>) trunk.computeIfAbsent(CHILDREN, k -> new ArrayList<Object>());
|
||||||
children.add(taskMap);
|
children.add(taskMap);
|
||||||
return taskMap;
|
return taskMap;
|
||||||
@@ -111,6 +115,13 @@ public class TaskModule extends BaseHandler implements TaskService {
|
|||||||
return taskMap;
|
return taskMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean postTaskList(UmbrellaUser user, HttpExchange ex) throws IOException {
|
||||||
|
var json = json(ex);
|
||||||
|
var projectId = json.has(PROJECT_ID) && json.get(PROJECT_ID) instanceof Number number ? number.longValue() : null;
|
||||||
|
if (isSet(projectId)) return sendContent(ex,mapValues(taskDb.listRootTasks(user,projectId)));
|
||||||
|
return sendEmptyResponse(HTTP_NOT_IMPLEMENTED,ex);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProjectService projectService() {
|
public ProjectService projectService() {
|
||||||
return projects;
|
return projects;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
package de.srsoftware.umbrella.time;
|
package de.srsoftware.umbrella.time;
|
||||||
|
|
||||||
import static de.srsoftware.tools.jdbc.Condition.in;
|
import static de.srsoftware.tools.jdbc.Condition.in;
|
||||||
|
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||||
import static de.srsoftware.tools.jdbc.Query.select;
|
import static de.srsoftware.tools.jdbc.Query.select;
|
||||||
import static de.srsoftware.umbrella.core.Constants.ID;
|
import static de.srsoftware.umbrella.core.Constants.ID;
|
||||||
import static de.srsoftware.umbrella.time.Constants.*;
|
import static de.srsoftware.umbrella.time.Constants.*;
|
||||||
@@ -25,7 +26,7 @@ public class SqliteDb implements TimeDb {
|
|||||||
@Override
|
@Override
|
||||||
public Collection<Time> listTimes(Collection<Long> taskIds) throws UmbrellaException {
|
public Collection<Time> listTimes(Collection<Long> taskIds) throws UmbrellaException {
|
||||||
try {
|
try {
|
||||||
var rs = select("*").from(TABLE_TASK_TIMES).where(TASK_ID,in(taskIds.toArray())).exec(db);
|
var rs = select(ALL).from(TABLE_TASK_TIMES).where(TASK_ID,in(taskIds.toArray())).exec(db);
|
||||||
var mapFromTimesToTasks = new HashMap<Long,HashSet<Long>>();
|
var mapFromTimesToTasks = new HashMap<Long,HashSet<Long>>();
|
||||||
while (rs.next()){
|
while (rs.next()){
|
||||||
var timeId = rs.getLong(TIME_ID);
|
var timeId = rs.getLong(TIME_ID);
|
||||||
@@ -33,7 +34,7 @@ public class SqliteDb implements TimeDb {
|
|||||||
mapFromTimesToTasks.computeIfAbsent(timeId, k -> new HashSet<>()).add(taskId);
|
mapFromTimesToTasks.computeIfAbsent(timeId, k -> new HashSet<>()).add(taskId);
|
||||||
}
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
rs = select("*").from(TABLE_TIMES).where(ID,in(mapFromTimesToTasks.keySet().toArray())).exec(db);
|
rs = select(ALL).from(TABLE_TIMES).where(ID,in(mapFromTimesToTasks.keySet().toArray())).exec(db);
|
||||||
var times = new HashSet<Time>();
|
var times = new HashSet<Time>();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
var time = Time.of(rs);
|
var time = Time.of(rs);
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import de.srsoftware.umbrella.core.model.*;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class TimeModule extends BaseHandler implements TimeService {
|
public class TimeModule extends BaseHandler implements TimeService {
|
||||||
|
|
||||||
@@ -114,7 +113,7 @@ public class TimeModule extends BaseHandler implements TimeService {
|
|||||||
if (!companies.membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
if (!companies.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);
|
if (!(json.has(PROJECT_ID) && json.get(PROJECT_ID) instanceof Number pid)) throw missingFieldException(PROJECT_ID);
|
||||||
long projectId = pid.longValue();
|
long projectId = pid.longValue();
|
||||||
Map<Long,Task> tasksOfProject = tasks.listProjectTasks(projectId).stream().collect(Collectors.toMap(Task::id,t->t));
|
Map<Long,Task> tasksOfProject = tasks.listProjectTasks(projectId);
|
||||||
|
|
||||||
List<Map<String, Object>> times = timeDb.listTimes(tasksOfProject.keySet())
|
List<Map<String, Object>> times = timeDb.listTimes(tasksOfProject.keySet())
|
||||||
.stream().filter(not(Time::isClosed))
|
.stream().filter(not(Time::isClosed))
|
||||||
|
|||||||
Reference in New Issue
Block a user