implemented search within time tracks

This commit is contained in:
2025-09-03 08:47:18 +02:00
parent bee33e84a0
commit d3c63fadff
4 changed files with 108 additions and 47 deletions

View File

@@ -16,9 +16,7 @@ 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.*;
public class SqliteDb extends BaseDb implements TimeDb {
@@ -91,6 +89,25 @@ CREATE TABLE IF NOT EXISTS {0} (
}
}
@Override
public Map<Long, Time> find(long userId, List<String> keys, boolean fulltext) {
try {
var query = select(ALL).from(TABLE_TIMES).where(USER_ID,equal(userId));
for (var key : keys) query.where(format("CONCAT({0},\" \",{1})",SUBJECT,DESCRIPTION),like("%"+key+"%"));
var rs = query.exec(db);
var times = new HashMap<Long,Time>();
while (rs.next()) {
var time = Time.of(rs);
times.put(time.id(),time);
}
rs.close();
return times;
} catch (Exception e) {
throw new UmbrellaException("Failed to search for times");
}
}
@Override
public HashMap<Long,Time> listTimes(Collection<Long> taskIds, boolean showClosed) throws UmbrellaException {
try {

View File

@@ -5,13 +5,17 @@ import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Time;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public interface TimeDb {
Long delete(long timeId);
HashMap<Long,Time> listTimes(Collection<Long> taskIds, boolean showClosed) throws UmbrellaException;
Map<Long, Time> find(long userId, List<String> keys, boolean fulltext);
HashMap<Long,Time> listUserTimes(long userId, boolean showClosed);
Map<Long,Time> listTimes(Collection<Long> taskIds, boolean showClosed) throws UmbrellaException;
Map<Long,Time> listUserTimes(long userId, boolean showClosed);
Time load(long timeId);

View File

@@ -105,6 +105,7 @@ public class TimeModule extends BaseHandler implements TimeService {
return switch (head) {
case JOIN -> joinTimes(ex,user.get());
case LIST -> listTimes(ex,user.get());
case SEARCH -> postSearch(ex, user.get());
case TRACK_TASK -> trackTask(user.get(),path,ex);
default -> {
try {
@@ -180,48 +181,6 @@ public class TimeModule extends BaseHandler implements TimeService {
return sendContent(ex,time);
}
private boolean patchTime(UmbrellaUser user, long timeId, HttpExchange ex) throws IOException {
var time = timeDb.load(timeId);
if (time.userId() != user.id()) throw forbidden("You are not allowed to alter this time!");
var json = json(ex);
timeDb.save(time.patch(json));
return sendContent(ex,time);
}
private boolean trackTask(UmbrellaUser user, Path path, HttpExchange ex) throws IOException {
if (path.empty()) throw missingFieldException(TASK_ID);
Task task;
try {
var taskId = Long.parseLong(path.pop());
task = taskService().load(List.of(taskId)).get(taskId);
if (task == null) throw UmbrellaException.notFound("Failed to load task with id = {0}",taskId);
} catch (NumberFormatException e) {
throw invalidFieldException(TASK_ID,"long value");
}
long now;
try {
now = Long.parseLong(body(ex));
} catch (NumberFormatException e) {
throw unprocessable("request body does not contain a timestamp!");
}
var opt = getStartedTime(user);
if (opt.isPresent()){
var startedTime = opt.get();
if (startedTime.taskIds().contains(task.id())) {
// if the time started last already belongs to the task, there is nothing left to do
return sendContent(ex,startedTime);
}
timeDb.save(startedTime.stop(now));
}
var track = new Time(0,user.id(),task.name(),task.description(),now,null,Started,List.of(task.id()));
timeDb.save(track);
return sendContent(ex,track);
}
private boolean getStartedTime(UmbrellaUser user, HttpExchange ex) throws IOException {
var startedTime = getStartedTime(user);
if (startedTime.isPresent()) return sendContent(ex,startedTime.get());
@@ -272,4 +231,55 @@ public class TimeModule extends BaseHandler implements TimeService {
}
private boolean patchTime(UmbrellaUser user, long timeId, HttpExchange ex) throws IOException {
var time = timeDb.load(timeId);
if (time.userId() != user.id()) throw forbidden("You are not allowed to alter this time!");
var json = json(ex);
timeDb.save(time.patch(json));
return sendContent(ex,time);
}
private boolean postSearch(HttpExchange ex, UmbrellaUser user) throws IOException {
var json = json(ex);
if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingFieldException(KEY);
var keys = Arrays.asList(key.split(" "));
var fulltext = json.has(FULLTEXT) && json.get(FULLTEXT) instanceof Boolean val && val;
var notes = timeDb.find(user.id(),keys,fulltext);
return sendContent(ex,mapValues(notes));
}
private boolean trackTask(UmbrellaUser user, Path path, HttpExchange ex) throws IOException {
if (path.empty()) throw missingFieldException(TASK_ID);
Task task;
try {
var taskId = Long.parseLong(path.pop());
task = taskService().load(List.of(taskId)).get(taskId);
if (task == null) throw UmbrellaException.notFound("Failed to load task with id = {0}",taskId);
} catch (NumberFormatException e) {
throw invalidFieldException(TASK_ID,"long value");
}
long now;
try {
now = Long.parseLong(body(ex));
} catch (NumberFormatException e) {
throw unprocessable("request body does not contain a timestamp!");
}
var opt = getStartedTime(user);
if (opt.isPresent()){
var startedTime = opt.get();
if (startedTime.taskIds().contains(task.id())) {
// if the time started last already belongs to the task, there is nothing left to do
return sendContent(ex,startedTime);
}
timeDb.save(startedTime.stop(now));
}
var track = new Time(0,user.id(),task.name(),task.description(),now,null,Started,List.of(task.id()));
timeDb.save(track);
return sendContent(ex,track);
}
}