TSK-685: added DailyEntryExitReport to taskana-rest-spring
This commit is contained in:
parent
37f48a5667
commit
4dd2415a3a
|
|
@ -124,7 +124,7 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPostgreSQL(String databaseProductName) {
|
public static boolean isPostgreSQL(String databaseProductName) {
|
||||||
return databaseProductName.equals("PostgreSQL");
|
return "PostgreSQL".equals(databaseProductName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package pro.taskana.rest;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
@ -21,7 +22,6 @@ import pro.taskana.TaskState;
|
||||||
import pro.taskana.exceptions.InvalidArgumentException;
|
import pro.taskana.exceptions.InvalidArgumentException;
|
||||||
import pro.taskana.exceptions.NotAuthorizedException;
|
import pro.taskana.exceptions.NotAuthorizedException;
|
||||||
import pro.taskana.impl.report.header.TimeIntervalColumnHeader;
|
import pro.taskana.impl.report.header.TimeIntervalColumnHeader;
|
||||||
import pro.taskana.rest.resource.ReportResource;
|
|
||||||
import pro.taskana.rest.resource.ReportAssembler;
|
import pro.taskana.rest.resource.ReportAssembler;
|
||||||
import pro.taskana.rest.resource.ReportResource;
|
import pro.taskana.rest.resource.ReportResource;
|
||||||
|
|
||||||
|
|
@ -91,6 +91,20 @@ public class MonitorController {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping(path = "/daily-entry-exit-report")
|
||||||
|
@Transactional(readOnly = true, rollbackFor = Exception.class)
|
||||||
|
public ResponseEntity<ReportResource> getDailyEntryExitReport()
|
||||||
|
throws NotAuthorizedException, InvalidArgumentException {
|
||||||
|
List<TimeIntervalColumnHeader.Date> columnHeaders = IntStream.range(-14, 0)
|
||||||
|
.mapToObj(TimeIntervalColumnHeader.Date::new)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return ResponseEntity.status(HttpStatus.OK)
|
||||||
|
.body(reportAssembler.toResource(
|
||||||
|
taskMonitorService.createDailyEntryExitReportBuilder()
|
||||||
|
.withColumnHeaders(columnHeaders)
|
||||||
|
.buildReport()));
|
||||||
|
}
|
||||||
|
|
||||||
private List<TimeIntervalColumnHeader> getTaskClassificationTimeInterval() {
|
private List<TimeIntervalColumnHeader> getTaskClassificationTimeInterval() {
|
||||||
return Stream.concat(Stream.concat(
|
return Stream.concat(Stream.concat(
|
||||||
Stream.of(new TimeIntervalColumnHeader.Range(Integer.MIN_VALUE, -10),
|
Stream.of(new TimeIntervalColumnHeader.Range(Integer.MIN_VALUE, -10),
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,16 @@ import org.springframework.stereotype.Component;
|
||||||
import pro.taskana.TaskState;
|
import pro.taskana.TaskState;
|
||||||
import pro.taskana.exceptions.InvalidArgumentException;
|
import pro.taskana.exceptions.InvalidArgumentException;
|
||||||
import pro.taskana.exceptions.NotAuthorizedException;
|
import pro.taskana.exceptions.NotAuthorizedException;
|
||||||
|
import pro.taskana.impl.report.row.FoldableRow;
|
||||||
|
import pro.taskana.impl.report.row.SingleRow;
|
||||||
import pro.taskana.report.ClassificationReport;
|
import pro.taskana.report.ClassificationReport;
|
||||||
import pro.taskana.report.structure.ColumnHeader;
|
|
||||||
import pro.taskana.report.DailyEntryExitReport;
|
import pro.taskana.report.DailyEntryExitReport;
|
||||||
|
import pro.taskana.report.TaskStatusReport;
|
||||||
|
import pro.taskana.report.WorkbasketReport;
|
||||||
|
import pro.taskana.report.structure.ColumnHeader;
|
||||||
import pro.taskana.report.structure.QueryItem;
|
import pro.taskana.report.structure.QueryItem;
|
||||||
import pro.taskana.report.structure.Report;
|
import pro.taskana.report.structure.Report;
|
||||||
import pro.taskana.report.structure.Row;
|
import pro.taskana.report.structure.Row;
|
||||||
import pro.taskana.report.TaskStatusReport;
|
|
||||||
import pro.taskana.report.WorkbasketReport;
|
|
||||||
import pro.taskana.rest.MonitorController;
|
import pro.taskana.rest.MonitorController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -57,6 +59,13 @@ public class ReportAssembler {
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReportResource toResource(DailyEntryExitReport report)
|
||||||
|
throws NotAuthorizedException, InvalidArgumentException {
|
||||||
|
ReportResource resource = toReportResource(report);
|
||||||
|
resource.add(linkTo(methodOn(MonitorController.class).getDailyEntryExitReport()).withSelfRel().expand());
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
private <I extends QueryItem, H extends ColumnHeader<? super I>> ReportResource toReportResource(
|
private <I extends QueryItem, H extends ColumnHeader<? super I>> ReportResource toReportResource(
|
||||||
Report<I, H> report) {
|
Report<I, H> report) {
|
||||||
String[] header = report.getColumnHeaders()
|
String[] header = report.getColumnHeaders()
|
||||||
|
|
@ -80,14 +89,52 @@ public class ReportAssembler {
|
||||||
return new ReportResource(meta, rows, sumRow);
|
return new ReportResource(meta, rows, sumRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <I extends QueryItem> ReportResource.RowResource transformRow(Row<I> row,
|
private <I extends QueryItem> ReportResource.RowResource transformRow(Row<I> row, String[] header) {
|
||||||
|
// This is a very dirty solution.. Personally I'd prefer to use a visitor-like pattern here.
|
||||||
|
// The issue with that: Addition of the visitor code within taskana-core - and having clean code is not
|
||||||
|
// a reason to append code somewhere where it doesn't belong.
|
||||||
|
if (row.getClass() == SingleRow.class) {
|
||||||
|
return transformSingleRow((SingleRow<I>) row, header);
|
||||||
|
}
|
||||||
|
return transformFoldableRow((FoldableRow<I>) row, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <I extends QueryItem> ReportResource.SingleRowResource transformSingleRow(SingleRow<I> row,
|
||||||
String[] header) {
|
String[] header) {
|
||||||
Map<String, Integer> result = new HashMap<>();
|
Map<String, Integer> result = new HashMap<>();
|
||||||
int[] cells = row.getCells();
|
int[] cells = row.getCells();
|
||||||
for (int i = 0; i < cells.length; i++) {
|
for (int i = 0; i < cells.length; i++) {
|
||||||
result.put(header[i], cells[i]);
|
result.put(header[i], cells[i]);
|
||||||
}
|
}
|
||||||
return new ReportResource.RowResource(result, row.getTotalValue());
|
return new ReportResource.SingleRowResource(result, row.getTotalValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private <I extends QueryItem> ReportResource.FoldableRowResource transformFoldableRow(FoldableRow<I> row,
|
||||||
|
String[] header) {
|
||||||
|
ReportResource.FoldableRowResource base = new ReportResource.FoldableRowResource(
|
||||||
|
transformSingleRow(row, header));
|
||||||
|
row.getFoldableRowKeySet().stream()
|
||||||
|
.map(k -> new Pair<>(k, row.getFoldableRow(k)))
|
||||||
|
.map(p -> new Pair<>(p.key, transformRow(p.value, header)))
|
||||||
|
.forEachOrdered(p -> base.addRow(p.key, p.value));
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple Pair (tuple).
|
||||||
|
* @param <K> key
|
||||||
|
* @param <V> value
|
||||||
|
*/
|
||||||
|
private class Pair<K, V> {
|
||||||
|
|
||||||
|
private final K key;
|
||||||
|
private final V value;
|
||||||
|
|
||||||
|
Pair(K key, V value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
package pro.taskana.rest.resource;
|
package pro.taskana.rest.resource;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.hateoas.ResourceSupport;
|
import org.springframework.hateoas.ResourceSupport;
|
||||||
|
|
||||||
import pro.taskana.impl.util.LoggerUtils;
|
import pro.taskana.impl.util.LoggerUtils;
|
||||||
import pro.taskana.report.structure.Report;
|
|
||||||
import pro.taskana.report.structure.Row;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resource class for {@link Report}.
|
* Resource class for {@link pro.taskana.report.structure.Report}.
|
||||||
*/
|
*/
|
||||||
public class ReportResource extends ResourceSupport {
|
public class ReportResource extends ResourceSupport {
|
||||||
|
|
||||||
|
|
@ -37,6 +37,68 @@ public class ReportResource extends ResourceSupport {
|
||||||
return sumRow;
|
return sumRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource Interface for {@link pro.taskana.report.structure.Row}.
|
||||||
|
*/
|
||||||
|
public interface RowResource {
|
||||||
|
|
||||||
|
Map<String, Integer> getCells();
|
||||||
|
|
||||||
|
int getTotal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource class for {@link pro.taskana.impl.report.row.SingleRow}.
|
||||||
|
*/
|
||||||
|
public static class SingleRowResource implements RowResource {
|
||||||
|
|
||||||
|
private Map<String, Integer> cells;
|
||||||
|
private int total;
|
||||||
|
|
||||||
|
public SingleRowResource(Map<String, Integer> cells, int total) {
|
||||||
|
this.cells = cells;
|
||||||
|
this.total = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getCells() {
|
||||||
|
return cells;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTotal() {
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SingleRowResource ["
|
||||||
|
+ "rowDesc= " + LoggerUtils.mapToString(this.cells)
|
||||||
|
+ "taskId= " + this.total
|
||||||
|
+ "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource class for {@link pro.taskana.impl.report.row.FoldableRow}.
|
||||||
|
*/
|
||||||
|
public static class FoldableRowResource extends SingleRowResource {
|
||||||
|
|
||||||
|
private Map<String, RowResource> foldableRows = new HashMap<>();
|
||||||
|
|
||||||
|
public FoldableRowResource(SingleRowResource row) {
|
||||||
|
super(row.getCells(), row.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRow(String desc, RowResource row) {
|
||||||
|
foldableRows.put(desc, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, RowResource> getFoldableRows() {
|
||||||
|
return foldableRows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Meta Information about this ReportResource.
|
* Meta Information about this ReportResource.
|
||||||
*/
|
*/
|
||||||
|
|
@ -81,39 +143,9 @@ public class ReportResource extends ResourceSupport {
|
||||||
return "MetaInformation ["
|
return "MetaInformation ["
|
||||||
+ "name= " + this.name
|
+ "name= " + this.name
|
||||||
+ "date= " + this.date
|
+ "date= " + this.date
|
||||||
+ "header= " + this.header
|
+ "header= " + Arrays.toString(this.header)
|
||||||
+ "rowDesc= " + this.rowDesc
|
+ "rowDesc= " + this.rowDesc
|
||||||
+ "]";
|
+ "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Resource class for {@link Row}.
|
|
||||||
*/
|
|
||||||
public static class RowResource {
|
|
||||||
|
|
||||||
private Map<String, Integer> cells;
|
|
||||||
private int total;
|
|
||||||
|
|
||||||
public RowResource(Map<String, Integer> cells, int total) {
|
|
||||||
this.cells = cells;
|
|
||||||
this.total = total;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Integer> getCells() {
|
|
||||||
return cells;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTotal() {
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "RowResource ["
|
|
||||||
+ "rowDesc= " + LoggerUtils.mapToString(this.cells)
|
|
||||||
+ "taskId= " + this.total
|
|
||||||
+ "]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue