Adapt Statistic Endpoint for Statistics independent of Taskgroup
This commit is contained in:
parent
985aa5f83b
commit
e1f69b340d
@ -5,10 +5,7 @@ import core.api.models.timemanager.history.TaskgroupActivityInfo;
|
|||||||
import core.api.models.timemanager.history.WorkingStatus;
|
import core.api.models.timemanager.history.WorkingStatus;
|
||||||
import core.entities.timemanager.AbstractSchedule;
|
import core.entities.timemanager.AbstractSchedule;
|
||||||
import core.entities.timemanager.Taskgroup;
|
import core.entities.timemanager.Taskgroup;
|
||||||
import core.services.PermissionResult;
|
import core.services.*;
|
||||||
import core.services.ServiceExitCode;
|
|
||||||
import core.services.TaskScheduleService;
|
|
||||||
import core.services.TaskgroupService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
@ -24,7 +21,7 @@ import java.util.*;
|
|||||||
public class StatisticController {
|
public class StatisticController {
|
||||||
|
|
||||||
@Autowired private TaskScheduleService taskScheduleService;
|
@Autowired private TaskScheduleService taskScheduleService;
|
||||||
@Autowired private TaskgroupService taskgroupService;
|
@Autowired private StatisticService statisticService;
|
||||||
|
|
||||||
@GetMapping("/history/workingStatus")
|
@GetMapping("/history/workingStatus")
|
||||||
public ResponseEntity<?> getWorkingStatus() {
|
public ResponseEntity<?> getWorkingStatus() {
|
||||||
@ -42,24 +39,14 @@ public class StatisticController {
|
|||||||
return ResponseEntity.ok(new WorkingStatus(missedSchedules, activeTime));
|
return ResponseEntity.ok(new WorkingStatus(missedSchedules, activeTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/statistics/taskgroup-activity/{taskgroupID}/{startingDate}/{endingDate}/{includeSubTaskgroups}")
|
@GetMapping("/statistics/{startingDate}/{endingDate}/{includeSubTaskgroups}")
|
||||||
public ResponseEntity<?> getTaskgroupActivity(@PathVariable long taskgroupID, @PathVariable String startingDate, @PathVariable String endingDate, @PathVariable boolean includeSubTaskgroups){
|
public ResponseEntity<?> getTaskgroupActivity(@PathVariable String startingDate, @PathVariable String endingDate){
|
||||||
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());
|
LocalDate starting = LocalDate.parse(startingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||||
if(taskgroupPermissionResult.isNoPermissions()) {
|
LocalDate ending = LocalDate.parse(endingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||||
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
|
|
||||||
} else if(taskgroupPermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
|
|
||||||
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TaskgroupActivityInfo> activityInfos = taskgroupPermissionResult.getResult().calcActivityInfo(includeSubTaskgroups,
|
var taskgroupActivityInfos = statisticService.calcActivityByUser(SecurityContextHolder.getContext().getAuthentication().getName(), starting, ending);
|
||||||
LocalDate.parse(startingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")), LocalDate.parse(endingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
List<TaskgroupActivityInfo> outgoingResult = StatisticService.convertInternActivityInfo(taskgroupActivityInfos);
|
||||||
activityInfos.sort(new Comparator<TaskgroupActivityInfo>() {
|
return ResponseEntity.ok(outgoingResult);
|
||||||
@Override
|
|
||||||
public int compare(TaskgroupActivityInfo o1, TaskgroupActivityInfo o2) {
|
|
||||||
return o1.getDate().compareTo(o2.getDate());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return ResponseEntity.ok(activityInfos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/history/schedules/{date}")
|
@GetMapping("/history/schedules/{date}")
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
package core.api.models.timemanager.history;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
public class ActivityInfo {
|
||||||
|
|
||||||
|
private LocalDate scheduleDate;
|
||||||
|
private int workedMinutes;
|
||||||
|
|
||||||
|
public ActivityInfo(LocalDate scheduleDate, int workedMinutes) {
|
||||||
|
this.scheduleDate = scheduleDate;
|
||||||
|
this.workedMinutes = workedMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getScheduleDate() {
|
||||||
|
return scheduleDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScheduleDate(LocalDate scheduleDate) {
|
||||||
|
this.scheduleDate = scheduleDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWorkedMinutes() {
|
||||||
|
return workedMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWorkedMinutes(int workedMinutes) {
|
||||||
|
this.workedMinutes = workedMinutes;
|
||||||
|
}
|
||||||
|
}
|
@ -4,25 +4,23 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
|
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class TaskgroupActivityInfo {
|
public class TaskgroupActivityInfo {
|
||||||
|
|
||||||
@JsonProperty
|
private TaskgroupEntityInfo taskgroup;
|
||||||
private LocalDate date;
|
private List<ActivityInfo> activityInfos;
|
||||||
|
|
||||||
@JsonProperty
|
public TaskgroupActivityInfo(TaskgroupEntityInfo taskgroup, List<ActivityInfo> activityInfos) {
|
||||||
private int activeMinutes;
|
this.taskgroup = taskgroup;
|
||||||
|
this.activityInfos = activityInfos;
|
||||||
public TaskgroupActivityInfo(int activeMinutes, LocalDate localDate) {
|
|
||||||
this.date = localDate;
|
|
||||||
this.activeMinutes = activeMinutes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalDate getDate() {
|
public TaskgroupEntityInfo getTaskgroup() {
|
||||||
return date;
|
return taskgroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getActiveMinutes() {
|
public List<ActivityInfo> getActivityInfos() {
|
||||||
return activeMinutes;
|
return activityInfos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,54 +136,5 @@ public class Taskgroup {
|
|||||||
return Objects.hash(taskgroupID);
|
return Objects.hash(taskgroupID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TaskgroupActivityInfo> calcActivityInfo(boolean includeChildTasks, LocalDate start, LocalDate end) {
|
|
||||||
HashMap<LocalDate, Integer> activityInfos = new HashMap<>();
|
|
||||||
if(includeChildTasks) {
|
|
||||||
|
|
||||||
Queue<Taskgroup> queue = new LinkedList<>(children);
|
|
||||||
while(!queue.isEmpty()) {
|
|
||||||
Taskgroup childTraskgroup = queue.poll();
|
|
||||||
LocalDate currentDate = start;
|
|
||||||
while(!currentDate.isAfter(end)) {
|
|
||||||
int activeMinutes = 0;
|
|
||||||
for(Task task : childTraskgroup.getTasks()) {
|
|
||||||
activeMinutes += task.calcOverallActivityInfo(currentDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(activityInfos.containsKey(currentDate)) {
|
|
||||||
activityInfos.put(currentDate, activityInfos.get(currentDate) + activeMinutes);
|
|
||||||
} else {
|
|
||||||
activityInfos.put(currentDate, activeMinutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentDate = currentDate.plusDays(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
queue.addAll(childTraskgroup.getChildren());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalDate currentDate = start;
|
|
||||||
while(!currentDate.isAfter(end)) {
|
|
||||||
int activeMinutes = 0;
|
|
||||||
for(Task task : tasks) {
|
|
||||||
activeMinutes += task.calcOverallActivityInfo(currentDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(activityInfos.containsKey(currentDate)) {
|
|
||||||
activityInfos.put(currentDate, activityInfos.get(currentDate) + activeMinutes);
|
|
||||||
} else {
|
|
||||||
activityInfos.put(currentDate, activeMinutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentDate = currentDate.plusDays(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TaskgroupActivityInfo> taskgroupActivityInfos = new ArrayList<>();
|
|
||||||
for(Map.Entry<LocalDate, Integer> entry : activityInfos.entrySet()) {
|
|
||||||
taskgroupActivityInfos.add(new TaskgroupActivityInfo(entry.getValue(), entry.getKey()));
|
|
||||||
}
|
|
||||||
return taskgroupActivityInfos;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -27,4 +27,7 @@ public interface ScheduleRepository extends CrudRepository<AbstractSchedule, Lon
|
|||||||
@Transactional
|
@Transactional
|
||||||
@Query(value = "DELETE FROM AbstractSchedule a WHERE a.task IN (SELECT t FROM Task t WHERE t.taskgroup = ?1)")
|
@Query(value = "DELETE FROM AbstractSchedule a WHERE a.task IN (SELECT t FROM Task t WHERE t.taskgroup = ?1)")
|
||||||
void deleteByTaskgroup(Taskgroup taskgroup);
|
void deleteByTaskgroup(Taskgroup taskgroup);
|
||||||
|
|
||||||
|
@Query(value = "SELECT s FROM AbstractSchedule s WHERE s.task.taskgroup.user.username = ?1 AND s.startTime is NOT NULL AND s.stopTime IS NOT NULL")
|
||||||
|
List<AbstractSchedule> getAllFinishedSchedulesByUser(String username);
|
||||||
}
|
}
|
||||||
|
84
backend/src/main/java/core/services/StatisticService.java
Normal file
84
backend/src/main/java/core/services/StatisticService.java
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package core.services;
|
||||||
|
|
||||||
|
import core.api.models.timemanager.history.ActivityInfo;
|
||||||
|
import core.api.models.timemanager.history.TaskgroupActivityInfo;
|
||||||
|
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
|
||||||
|
import core.entities.timemanager.AbstractSchedule;
|
||||||
|
import core.entities.timemanager.Taskgroup;
|
||||||
|
import core.repositories.timemanager.ScheduleRepository;
|
||||||
|
import core.repositories.timemanager.TaskgroupRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class StatisticService {
|
||||||
|
|
||||||
|
@Autowired private ScheduleRepository scheduleRepository;
|
||||||
|
|
||||||
|
public HashMap<Taskgroup, HashMap<LocalDate, Integer>> calcActivityByUser(String username, LocalDate startinDate, LocalDate endingDate) {
|
||||||
|
HashMap<Taskgroup, HashMap<LocalDate, Integer>> taskgroupActivityInfos = new HashMap<>();
|
||||||
|
List<AbstractSchedule> startedSchedules = scheduleRepository.getAllFinishedSchedulesByUser(username);
|
||||||
|
for(AbstractSchedule schedule : startedSchedules) {
|
||||||
|
Taskgroup topTaskgroup = findTopTaskgroup(schedule.getTask().getTaskgroup());
|
||||||
|
HashMap<LocalDate, Integer> taskgroupActivity;
|
||||||
|
if(taskgroupActivityInfos.containsKey(topTaskgroup)) {
|
||||||
|
taskgroupActivity = taskgroupActivityInfos.get(topTaskgroup);
|
||||||
|
} else {
|
||||||
|
taskgroupActivity = new HashMap<>();
|
||||||
|
taskgroupActivityInfos.put(topTaskgroup, taskgroupActivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(schedule.getStartTime().toLocalDate().isEqual(schedule.getStopTime().toLocalDate())) {
|
||||||
|
insertActivity(taskgroupActivity, schedule.getStartTime().toLocalDate(), schedule.getActiveTime());
|
||||||
|
} else {
|
||||||
|
//Starting Date
|
||||||
|
LocalDateTime startingDayEnd = schedule.getStartTime().toLocalDate().atTime(LocalTime.MAX);
|
||||||
|
Duration startingActivity = Duration.between(schedule.getStartTime(), startingDayEnd);
|
||||||
|
insertActivity(taskgroupActivity, schedule.getStartTime().toLocalDate(), (int) startingActivity.toMinutes());
|
||||||
|
|
||||||
|
//Ending Date
|
||||||
|
LocalDateTime endingDayStart = schedule.getStopTime().toLocalDate().atStartOfDay();
|
||||||
|
Duration endingActivity = Duration.between(endingDayStart, schedule.getStopTime());
|
||||||
|
insertActivity(taskgroupActivity, schedule.getStopTime().toLocalDate(), (int) endingActivity.toMinutes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return taskgroupActivityInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TaskgroupActivityInfo> convertInternActivityInfo(HashMap<Taskgroup, HashMap<LocalDate, Integer>> taskgroupActivity) {
|
||||||
|
List<TaskgroupActivityInfo> taskgroupActivityInfos = new ArrayList<>();
|
||||||
|
for(Map.Entry<Taskgroup, HashMap<LocalDate, Integer>> entry: taskgroupActivity.entrySet()) {
|
||||||
|
List<ActivityInfo> activityInfos = new ArrayList<>();
|
||||||
|
for(Map.Entry<LocalDate, Integer> dateActivity : entry.getValue().entrySet()) {
|
||||||
|
activityInfos.add(new ActivityInfo(dateActivity.getKey(), dateActivity.getValue()));
|
||||||
|
}
|
||||||
|
taskgroupActivityInfos.add(new TaskgroupActivityInfo(new TaskgroupEntityInfo(entry.getKey()), activityInfos));
|
||||||
|
}
|
||||||
|
return taskgroupActivityInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void insertActivity(HashMap<LocalDate, Integer> activityInfo, LocalDate date, int deltaActivity) {
|
||||||
|
if(activityInfo.containsKey(date)) {
|
||||||
|
int activity = activityInfo.get(date);
|
||||||
|
activity += deltaActivity;
|
||||||
|
activityInfo.put(date, activity);
|
||||||
|
} else {
|
||||||
|
activityInfo.put(date, deltaActivity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Taskgroup findTopTaskgroup(Taskgroup taskgroup) {
|
||||||
|
Taskgroup currentTaskgroup = taskgroup;
|
||||||
|
while(currentTaskgroup.getParent() != null) {
|
||||||
|
currentTaskgroup = currentTaskgroup.getParent();
|
||||||
|
}
|
||||||
|
return currentTaskgroup;
|
||||||
|
}
|
||||||
|
}
|
31
openapi.yaml
31
openapi.yaml
@ -2060,20 +2060,13 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
$ref: "#/components/schemas/SimpleStatusResponse"
|
$ref: "#/components/schemas/SimpleStatusResponse"
|
||||||
/statistics/taskgroup-activity/{taskgroupID}/{startingDate}/{endingDate}/{includeSubTaskgroups}:
|
/statistics/{startingDate}/{endingDate}:
|
||||||
get:
|
get:
|
||||||
security:
|
security:
|
||||||
- API_TOKEN: []
|
- API_TOKEN: []
|
||||||
tags:
|
tags:
|
||||||
- history
|
- history
|
||||||
parameters:
|
parameters:
|
||||||
- name: taskgroupID
|
|
||||||
in: path
|
|
||||||
description: internal id of taskgroup
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: number
|
|
||||||
example: 1
|
|
||||||
- name: startingDate
|
- name: startingDate
|
||||||
in: path
|
in: path
|
||||||
description: starting date
|
description: starting date
|
||||||
@ -2088,13 +2081,6 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
format: date
|
format: date
|
||||||
- name: includeSubTaskgroups
|
|
||||||
in: path
|
|
||||||
description: determines whether to include subtaskgroups or not
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: boolean
|
|
||||||
example: false
|
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Operation successfull
|
description: Operation successfull
|
||||||
@ -2948,7 +2934,7 @@ components:
|
|||||||
rootTasktroup:
|
rootTasktroup:
|
||||||
type: object
|
type: object
|
||||||
$ref: '#/components/schemas/TaskgroupEntityInfo'
|
$ref: '#/components/schemas/TaskgroupEntityInfo'
|
||||||
TaskgroupActivityInfo:
|
ActivityInfo:
|
||||||
required:
|
required:
|
||||||
- date
|
- date
|
||||||
- activeMinutes
|
- activeMinutes
|
||||||
@ -2961,6 +2947,19 @@ components:
|
|||||||
type: number
|
type: number
|
||||||
description: Number of minutes the task was active
|
description: Number of minutes the task was active
|
||||||
example: 122
|
example: 122
|
||||||
|
TaskgroupActivityInfo:
|
||||||
|
required:
|
||||||
|
- taskgroup
|
||||||
|
- activityInfos
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
taskgroup:
|
||||||
|
type: object
|
||||||
|
$ref: '#/components/schemas/TaskgroupEntityInfo'
|
||||||
|
activityInfos:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ActivityInfo'
|
||||||
ManualScheduleStopInfo:
|
ManualScheduleStopInfo:
|
||||||
required:
|
required:
|
||||||
- duration
|
- duration
|
||||||
|
Loading…
Reference in New Issue
Block a user