/**
*
*/
package com.qprogramming.tasq.task.worklog;
import com.qprogramming.tasq.agile.Release;
import com.qprogramming.tasq.agile.Sprint;
import com.qprogramming.tasq.events.EventsService;
import com.qprogramming.tasq.projects.Project;
import com.qprogramming.tasq.support.PeriodHelper;
import com.qprogramming.tasq.support.Utils;
import com.qprogramming.tasq.support.sorters.WorkLogSorter;
import com.qprogramming.tasq.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Hibernate;
import org.joda.time.DateTime;
import org.joda.time.Period;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author romanjak
* @date 28 maj 2014
*/
@Service
public class WorkLogService {
private WorkLogRepository wlRepo;
private EventsService eventSrv;
@Autowired
public WorkLogService(WorkLogRepository wlRepo, EventsService eventSrv) {
this.wlRepo = wlRepo;
this.eventSrv = eventSrv;
}
@Transactional
public Task addTimedWorkLog(Task loggedTask, String msg, Date when, Period remaining, Period activity, LogType type) {
WorkLog wl = new WorkLog();
wl.setTask(loggedTask);
wl.setProject_id(loggedTask.getProject().getId());
wl.setAccount(Utils.getCurrentAccount());
wl.setTimeLogged(new Date());
wl.setTime(when);
wl.setType(type);
wl.setMessage(msg);
wl.setActivity(activity);
wl = wlRepo.save(wl);
Hibernate.initialize(loggedTask.getWorklog());
loggedTask.addWorkLog(wl);
if (remaining == null) {
loggedTask.reduceRemaining(activity);
} else {
loggedTask.setRemaining(remaining);
}
loggedTask.addLoggedWork(activity);
loggedTask.setLastUpdate(new Date());
eventSrv.addWatchEvent(wl, PeriodHelper.outFormat(activity), when);
return loggedTask;
}
@Transactional
public Task addDatedWorkLog(Task loggedTask, String msg, Date when, LogType type) {
WorkLog wl = new WorkLog();
wl.setTask(loggedTask);
wl.setProject_id(loggedTask.getProject().getId());
wl.setAccount(Utils.getCurrentAccount());
wl.setTimeLogged(new Date());
wl.setTime(when);
wl.setType(type);
wl.setMessage(msg);
wl = wlRepo.save(wl);
Hibernate.initialize(loggedTask.getWorklog());
loggedTask.addWorkLog(wl);
loggedTask.setLastUpdate(new Date());
eventSrv.addWatchEvent(wl, msg, when);
return loggedTask;
}
/**
* @param loggedTask
* @param msg
* @param type
*/
@Transactional
public void addActivityLog(Task loggedTask, String msg, LogType type) {
WorkLog wl = new WorkLog();
wl.setTask(loggedTask);
wl.setProject_id(loggedTask.getProject().getId());
wl.setAccount(Utils.getCurrentAccount());
wl.setTime(new Date());
wl.setTimeLogged(new Date());
wl.setType(type);
if (StringUtils.isNotBlank(msg)) {
wl.setMessage(msg);
}
wl = wlRepo.save(wl);
Hibernate.initialize(loggedTask.getWorklog());
loggedTask.addWorkLog(wl);
loggedTask.setLastUpdate(new Date());
eventSrv.addWatchEvent(wl, msg, new Date());
}
@Transactional
public void addActivityPeriodLog(Task loggedTask, String msg, Period activity, LogType type) {
WorkLog wl = new WorkLog();
wl.setTask(loggedTask);
wl.setProject_id(loggedTask.getProject().getId());
wl.setAccount(Utils.getCurrentAccount());
wl.setTime(new Date());
wl.setTimeLogged(new Date());
wl.setType(type);
wl.setMessage(msg);
wl.setActivity(activity);
wl = wlRepo.save(wl);
Hibernate.initialize(loggedTask.getWorklog());
loggedTask.addWorkLog(wl);
loggedTask.setLastUpdate(new Date());
eventSrv.addWatchEvent(wl, PeriodHelper.outFormat(activity), new Date());
}
/**
* Add worklog without task ( for example for project only )
*
* @param msg
* @param project
* @param type
*/
public void addWorkLogNoTask(String msg, Project project, LogType type) {
WorkLog wl = new WorkLog();
wl.setProject_id(project.getId());
wl.setAccount(Utils.getCurrentAccount());
wl.setTimeLogged(new Date());
wl.setTime(new Date());
wl.setType(type);
wl.setMessage(msg);
wlRepo.save(wl);
}
public List<DisplayWorkLog> getProjectEvents(Project project) {
List<WorkLog> workLogs = wlRepo.findByProjectId(project.getId());
Collections.sort(workLogs, new WorkLogSorter(true));
return packIntoDisplay(workLogs);
}
/**
* Returns all sprint events. If timeTracked will be set to true, only
* events with logged activity ( time ) will be returned, otherwise only
* events which were closing task will be returned
*
* @param sprint sprint for which all events must be fetched
* @return
*/
@Transactional
public List<WorkLog> getAllSprintEvents(Sprint sprint) {
DateTime start = new DateTime(sprint.getRawStart_date());
DateTime end = new DateTime(sprint.getRawEnd_date()).plusDays(1);
List<WorkLog> list = wlRepo.findByProjectIdAndTimeBetweenAndWorklogtaskNotNullOrderByTimeAsc(
sprint.getProject().getId(), start.toDate(), end.toDate());
// Filter out not important events
return list.stream().filter(workLog -> isSprintRelevant(workLog, sprint)).collect(Collectors.toList());
}
@Transactional
public List<WorkLog> getAllReleaseEvents(Release release) {
DateTime start = release.getStartDate();
DateTime end = release.getEndDate();
List<WorkLog> list = wlRepo.findByProjectIdAndTimeBetweenAndWorklogtaskNotNullOrderByTimeAsc(
release.getProject().getId(), start.toDate(), end.toDate());
// Filter out events for task which are part of this release
return list.stream().filter(workLog -> isReleaseRelevant(workLog, release)).collect(Collectors.toList());
}
public Page<WorkLog> findByProjectId(Long id, Pageable p) {
return wlRepo.findByProjectId(id, p);
}
public Page<WorkLog> findByProjectIdIn(Collection<Long> id, Pageable p) {
return wlRepo.findByProjectIdIn(id, p);
}
public List<WorkLog> findProjectCreateCloseEvents(Project project, boolean all) {
DateTime beginDate = new DateTime().minusDays(30);
List<WorkLog> list;
if (all) {
list = wlRepo.findByProjectIdOrderByTimeAsc(project.getId());
} else {
list = wlRepo.findByProjectIdAndTimeBetweenOrderByTimeAsc(project.getId(), beginDate.toDate(), new Date());
}
return list.stream().parallel().filter(workLog -> LogType.CREATE.equals(workLog.getType()) || LogType.REOPEN.equals(workLog.getType())
|| LogType.CLOSED.equals(workLog.getType())).collect(Collectors.toCollection(LinkedList::new));
}
private List<DisplayWorkLog> packIntoDisplay(List<WorkLog> list) {
return list.stream().map(DisplayWorkLog::new).collect(Collectors.toCollection(LinkedList::new));
}
private boolean isSprintRelevant(WorkLog workLog, Sprint sprint) {
LogType type = (LogType) workLog.getType();
return workLog.getTask().inSprint(sprint) && (type.equals(LogType.DELETED) || type.equals(LogType.LOG)
|| type.equals(LogType.TASKSPRINTREMOVE) || type.equals(LogType.TASKSPRINTADD)
|| type.equals(LogType.ESTIMATE) || type.equals(LogType.CLOSED) || type.equals(LogType.REOPEN));
}
private boolean isReleaseRelevant(WorkLog workLog, Release release) {
LogType type = (LogType) workLog.getType();
return (release.equals(workLog.getTask().getRelease()) || release.isActive())
&& (type.equals(LogType.CREATE) || type.equals(LogType.DELETED) || type.equals(LogType.LOG)
|| type.equals(LogType.STATUS) || type.equals(LogType.CLOSED) || type.equals(LogType.REOPEN));
}
public List<DisplayWorkLog> getTaskDisplayEvents(String id) {
return packIntoDisplay(wlRepo.findByWorklogtaskIdOrderByTimeLoggedDesc(id));
}
public List<WorkLog> getTaskEvents(String taskID) {
return wlRepo.findByWorklogtaskIdOrderByTimeLoggedDesc(taskID);
}
public void deleteTaskWorklogs(Task task) {
List<WorkLog> workLogList = wlRepo.findByWorklogtaskId(task.getId());
wlRepo.delete(workLogList);
}
public void delete(WorkLog log) {
wlRepo.delete(log);
}
public WorkLog findById(Long id) {
return wlRepo.findById(id);
}
}