/** * This file is part of lavagna. * * lavagna is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * lavagna is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with lavagna. If not, see <http://www.gnu.org/licenses/>. */ package io.lavagna.service; import io.lavagna.model.*; import io.lavagna.query.StatisticsQuery; import org.apache.commons.lang3.ObjectUtils; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; @Service @Transactional(readOnly = true) public class StatisticsService { private final StatisticsQuery queries; public StatisticsService(StatisticsQuery queries) { this.queries = queries; } @Transactional(readOnly = false) public void snapshotCardsStatus() { queries.snapshotCardsStatus(new Date()); queries.cleanOldCardsStatusSnapshots(); } private Map<Long, Map<ColumnDefinition, Long>> toStatusByDay(List<StatisticsResult> results) { Map<Long, Map<ColumnDefinition, Long>> statusByDay = new HashMap<>(); for (StatisticsResult result : results) { if (!statusByDay.containsKey(result.getDay())) { statusByDay.put(result.getDay(), new EnumMap<ColumnDefinition, Long>(ColumnDefinition.class)); } Map<ColumnDefinition, Long> day = statusByDay.get(result.getDay()); day.put(result.getColumnDefinition(), result.getCount()); } return statusByDay; } public Map<Long, Map<ColumnDefinition, Long>> getCardsStatusByBoard(int boardId, Date fromDate) { return toStatusByDay(queries.getCardsStatusByBoard(boardId, fromDate)); } public Map<Long, Map<ColumnDefinition, Long>> getCardsStatusByProject(int projectId, Date fromDate) { return toStatusByDay(queries.getCardsStatusByProject(projectId, fromDate)); } public Integer getActiveUsersOnBoard(int boardId, Date fromDate) { return queries.getActiveUsersOnBoard(boardId, fromDate); } public Integer getActiveUsersOnProject(int projectId, Date fromDate) { return queries.getActiveUsersOnProject(projectId, fromDate); } // Average users per card public double getAverageUsersPerCardOnBoard(int boardId) { return ObjectUtils.<Double>firstNonNull(queries.getAverageUsersPerCardOnBoard(boardId), 0d); } public double getAverageUsersPerCardOnProject(int projectId) { return ObjectUtils.<Double>firstNonNull(queries.getAverageUsersPerCardOnProject(projectId), 0d); } // Average cards per user public double getAverageCardsPerUserOnBoard(int boardId) { return ObjectUtils.<Double>firstNonNull(queries.getAverageCardsPerUserOnBoard(boardId), 0d); } public double getAverageCardsPerUserOnProject(int projectId) { return ObjectUtils.<Double>firstNonNull(queries.getAverageCardsPerUserOnProject(projectId), 0d); } // Cards by label public List<LabelAndValueWithCount> getCardsByLabelOnBoard(int boardId) { return queries.getCardsByLabelOnBoard(boardId); } public List<LabelAndValueWithCount> getCardsByLabelOnProject(int projectId) { return queries.getCardsByLabelOnProject(projectId); } // Created / closed cards private Map<Long, Pair<Long, Long>> mergeCounts(List<EventsCount> createdCards, List<EventsCount> closedCards) { Map<Long, Pair<Long, Long>> counts = new HashMap<>(); for (EventsCount count : createdCards) { counts.put(count.getDate(), new Pair<>(count.getCount(), 0L)); } for (EventsCount count : closedCards) { long created = 0; if (counts.containsKey(count.getDate())) { created = counts.get(count.getDate()).getFirst(); counts.remove(count.getDate()); } counts.put(count.getDate(), new Pair<>(created, count.getCount())); } return counts; } public Map<Long, Pair<Long, Long>> getCreatedAndClosedCardsByBoard(int boardId, Date fromDate) { return mergeCounts(queries.getCreatedCardsByBoard(boardId, fromDate), queries.getClosedCardsByBoard(boardId, fromDate)); } public Map<Long, Pair<Long, Long>> getCreatedAndClosedCardsByProject(int projectId, Date fromDate) { return mergeCounts(queries.getCreatedCardsByProject(projectId, fromDate), queries.getClosedCardsByProject(projectId, fromDate)); } // Most active card public CardFull getMostActiveCardByBoard(int boardId, Date fromDate) { try { return queries.getMostActiveCardByBoard(boardId, fromDate); } catch (EmptyResultDataAccessException ex) { return null; } } public CardFull getMostActiveCardByProject(int projectId, Date fromDate) { try { return queries.getMostActiveCardByProject(projectId, fromDate); } catch (EmptyResultDataAccessException ex) { return null; } } // Milestones public Map<Long, Pair<Long, Long>> getAssignedAndClosedCardsByMilestone(LabelListValue milestone, Date fromDate) { return mergeCounts(queries.getAssignedCardsByMilestone(milestone.getValue(), fromDate), queries.getClosedCardsByMilestone(milestone.getId(), fromDate)); } public List<MilestoneCount> findCardsCountByMilestone(int projectId) { return queries.findCardsCountByMilestone(projectId); } public List<MilestoneCount> findUnassignedCardsCountByMilestone(int projectId) { return queries.findUnassignedCardsCountByMilestone(projectId); } public List<MilestoneCount> findCardsCountByMilestone(int projectId, int milestoneId) { return queries.findCardsCountByMilestone(projectId, milestoneId); } }