Refactored finish review action.

This commit is contained in:
Christian P. MOMON 2018-09-25 02:37:30 +02:00
parent f11dd169d7
commit 1e8f06f373
16 changed files with 1317 additions and 405 deletions

View File

@ -41,6 +41,7 @@ import org.april.hebdobot.bot.hooks.InputReviewHook;
import org.april.hebdobot.bot.hooks.LicenseHook;
import org.april.hebdobot.bot.hooks.MissingHook;
import org.april.hebdobot.bot.hooks.StartReviewHook;
import org.april.hebdobot.bot.hooks.StatsHook;
import org.april.hebdobot.bot.hooks.StatusHook;
import org.april.hebdobot.bot.hooks.StopReviewHook;
import org.april.hebdobot.bot.hooks.ThanksHook;
@ -134,6 +135,7 @@ public class Hebdobot extends PircBot
this.hooker.add(new MissingHook());
this.hooker.add(new StartReviewHook());
this.hooker.add(new StopReviewHook());
this.hooker.add(new StatsHook());
this.hooker.add(new StatusHook());
this.hooker.add(new DateHook());
@ -313,7 +315,7 @@ public class Hebdobot extends PircBot
{
this.hooker.attemptProcess(this, channel, sender, login, hostname, text);
}
catch (HebdobotException exception)
catch (Exception exception)
{
logger.error("Error managing post.", exception);
sendMessage("/me a choppé un bug : ", exception.getMessage());

View File

@ -28,6 +28,7 @@ import java.time.format.DateTimeFormatter;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.april.hebdobot.bot.Hebdobot;
import org.april.hebdobot.bot.review.ReviewReporter;
import org.april.hebdobot.bot.stats.ReviewData;
import org.april.hebdobot.bot.stats.ReviewDatas;
import org.april.hebdobot.bot.stats.ReviewDatasFile;
@ -37,8 +38,6 @@ import org.april.hebdobot.pastebin.Private;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.devinsy.strings.StringList;
/**
* The Class FinishReviewHook.
*/
@ -72,58 +71,36 @@ public class FinishReviewHook extends Hook
}
else if (bot.getReview().getParticipants().size() == 0)
{
bot.sendMessage("Participation nulle détecté. La revue est ignorée.");
bot.sendMessage("Participation nulle détectée. La revue est ignorée.");
bot.setReview(null);
}
else
{
String date = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
String textReview = bot.getReview().toString();
//
bot.getReview().endReview();
// Display statistics. This feature has to not break
// Hebdobot.
String newMaxUserCountReport;
String userCountReport;
String durationReport;
ReviewDatas datas;
try
{
File reviewDataFile = new File(bot.getReviewDirectory(), "reviewstats.csv");
if (reviewDataFile.exists())
{
ReviewDatas datas = ReviewDatasFile.load(reviewDataFile);
datas = ReviewDatasFile.load(reviewDataFile);
datas.clean();
newMaxUserCountReport = ReviewStatsReporter.reportNewMaxUserCount(datas, bot.getReview().getParticipants().size());
ReviewData currentReview = new ReviewData(LocalDateTime.now(), bot.getReview().getParticipants().size(),
(int) bot.getReview().getDurationInMinutes());
datas.add(currentReview);
userCountReport = ReviewStatsReporter.reportUserCount(datas, currentReview.getUserCount());
durationReport = ReviewStatsReporter.reportDuration(datas, currentReview.getDuration());
ReviewData currentReviewData = new ReviewData(LocalDateTime.now(), bot.getReview().getParticipants().size(),
bot.getReview().getDurationInMinutes());
if (bot.getReview().getParticipants().size() > 1)
{
ReviewDatasFile.append(reviewDataFile, currentReview);
}
}
else
{
logger.warn("Statistic file not found [{}]", reviewDataFile.getAbsolutePath());
bot.sendMessage("% Fichier de statistiques absent.");
newMaxUserCountReport = null;
userCountReport = null;
durationReport = null;
}
datas.add(currentReviewData);
}
catch (Exception exception)
{
logger.warn("Exception during statistics work.", exception);
newMaxUserCountReport = null;
userCountReport = null;
durationReport = null;
datas = null;
}
textReview = new StringList(textReview).appendln(newMaxUserCountReport, "\n", userCountReport, "\n", durationReport).toString();
// Conclusion message in channel.
String date = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
String textReview = ReviewReporter.report(datas, bot.getReview());
bot.sendMessage("% " + ReviewStatsReporter.reportReviewCount(datas));
//
if (bot.getPastebinSettings().isValid())
@ -171,20 +148,9 @@ public class FinishReviewHook extends Hook
bot.sendMessage("% Nombre de personnes participantes : " + bot.getReview().getParticipants().size());
// Display statistics.
if (newMaxUserCountReport != null)
{
bot.sendMessage("% " + newMaxUserCountReport);
}
if (userCountReport != null)
{
bot.sendMessage(bot.getReview().getOwner(), userCountReport);
}
if (durationReport != null)
{
bot.sendMessage(bot.getReview().getOwner(), durationReport);
}
bot.sendMessage("% " + ReviewStatsReporter.reportNewMaxUserCount(datas, bot.getReview().getParticipants().size()));
bot.sendMessage(bot.getReview().getOwner(), ReviewStatsReporter.reportUserCount(datas, bot.getReview().getParticipants().size()));
bot.sendMessage(bot.getReview().getOwner(), ReviewStatsReporter.reportDuration(datas, bot.getReview().getDurationInMinutes()));
String participants = StringUtils.join(bot.getReview().getParticipants(), " ");
bot.sendMessage("% " + participants + ", pensez à noter votre bénévalo : http://www.april.org/my?action=benevalo");

View File

@ -0,0 +1,37 @@
/**
* Copyright (C) 2018 Christian Pierre MOMON <cmomon@april.org>
*
* This file is part of (April) Hebdobot.
*
* Hebdobot is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Hebdobot 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Hebdobot. If not, see <http://www.gnu.org/licenses/>
*/
package org.april.hebdobot.bot.review;
import java.util.LinkedList;
/**
* The Class CollectiveTopics.
*/
public class CollectiveTopics extends LinkedList<CollectiveTopic>
{
private static final long serialVersionUID = -2719546135520171963L;
/**
* Instantiates a new collective topics.
*/
public CollectiveTopics()
{
super();
}
}

View File

@ -0,0 +1,37 @@
/**
* Copyright (C) 2018 Christian Pierre MOMON <cmomon@april.org>
*
* This file is part of (April) Hebdobot.
*
* Hebdobot is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Hebdobot 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Hebdobot. If not, see <http://www.gnu.org/licenses/>
*/
package org.april.hebdobot.bot.review;
import java.util.LinkedList;
/**
* The Class IndividualTopics.
*/
public class IndividualTopics extends LinkedList<IndividualTopic>
{
private static final long serialVersionUID = -5285310840777688742L;
/**
* Instantiates a new individual topics.
*/
public IndividualTopics()
{
super();
}
}

View File

@ -24,11 +24,7 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import org.apache.commons.lang3.StringUtils;
import org.april.hebdobot.bot.UserAliases;
import fr.devinsy.strings.StringSet;
@ -41,13 +37,13 @@ public class Review
private static final int LENGTH = 80;
private final StringSet participants;
private final List<IndividualTopic> individualTopics;
private final List<CollectiveTopic> collectiveTopics;
private final IndividualTopics individualTopics;
private final CollectiveTopics collectiveTopics;
private Topic currentTopic;
private final MessageList messages;
private final String owner;
private final UserAliases aliases;
private LocalDateTime startTime;
private final LocalDateTime startTime;
private LocalDateTime endTime;
/**
@ -61,8 +57,8 @@ public class Review
public Review(final String owner, final UserAliases aliases)
{
this.participants = new StringSet();
this.individualTopics = new LinkedList<>();
this.collectiveTopics = new LinkedList<>();
this.individualTopics = new IndividualTopics();
this.collectiveTopics = new CollectiveTopics();
this.messages = new MessageList();
this.owner = owner;
@ -122,6 +118,29 @@ public class Review
this.currentTopic = topic;
}
/**
* End review.
*/
public void endReview()
{
this.endTime = LocalDateTime.now();
}
public UserAliases getAliases()
{
return this.aliases;
}
/**
* Gets the collective topics.
*
* @return the collective topics
*/
public CollectiveTopics getCollectiveTopics()
{
return this.collectiveTopics;
}
/**
* Gets the current topic.
*
@ -132,6 +151,11 @@ public class Review
return this.currentTopic;
}
/**
* Gets the duration.
*
* @return the duration
*/
public long getDuration()
{
long result;
@ -211,6 +235,21 @@ public class Review
return result;
}
/**
* Gets the individual topics.
*
* @return the individual topics
*/
public IndividualTopics getIndividualTopics()
{
return this.individualTopics;
}
public MessageList getMessages()
{
return this.messages;
}
/**
* Gets the owner.
*
@ -294,300 +333,4 @@ public class Review
//
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
String result;
//
StringBuffer buffer = new StringBuffer();
addLine(buffer, '=');
addCenter(buffer, "Revue de la semaine en cours");
addEmpty(buffer);
addCenter(buffer, StringUtils.capitalize(LocalDateTime.now().format(DateTimeFormatter.ofPattern("EEEE dd MMMM yyyy", Locale.FRENCH))));
addLine(buffer, '=');
addEmpty(buffer);
addEmpty(buffer);
//
addLine(buffer, '=');
addEmpty(buffer);
addCenter(buffer, "Participants", '-');
for (final String participant : this.participants)
{
addChunk(buffer, "* " + this.aliases.getRealName(participant) + "\n");
}
//
if (!this.individualTopics.isEmpty())
{
for (final String participant : this.participants)
{
addEmpty(buffer);
addLine(buffer, '=');
addEmpty(buffer);
addCenter(buffer, this.aliases.getRealName(participant), '-');
for (final IndividualTopic topic : this.individualTopics)
{
if (topic.hasParticipant(participant))
{
addEmpty(buffer);
add(buffer, getTopic(topic));
addEmpty(buffer);
for (final Message message : topic.getMessages(participant))
{
addChunk(buffer, "* " + message.getContent() + "\n");
}
}
}
}
}
//
if (!this.collectiveTopics.isEmpty())
{
for (final CollectiveTopic topic : this.collectiveTopics)
{
addEmpty(buffer);
addLine(buffer, '=');
addCenter(buffer, topic.getTitle());
addLine(buffer, '=');
addEmpty(buffer);
for (final Message message : topic.getMessages())
{
addChunk(buffer, "* " + message.getAuthor() + " : " + message.getContent() + "\n");
}
}
}
//
addEmpty(buffer);
addCenter(buffer, "Log IRC brut");
addEmpty(buffer);
for (final Message message : this.messages)
{
addChunk(buffer, "* " + message.getAuthor() + " : " + message.getContent() + "\n");
}
//
this.endTime = LocalDateTime.now();
addEmpty(buffer);
addCenter(buffer, "Statistiques");
addEmpty(buffer);
addChunk(buffer, "Horaire de début de la revue : " + getFormattedStartTime() + "\n");
addChunk(buffer, "Horaire de fin de la revue : " + getFormattedEndTime() + "\n");
addChunk(buffer, "Durée de la revue : " + getDurationInMinutes() + " minutes\n");
addChunk(buffer, "Nombre de participants : " + this.participants.size() + "\n");
//
result = buffer.toString();
//
return result;
}
/**
* Adds the.
*
* @param buffer
* the buffer
* @param content
* the content
*/
private static void add(final StringBuffer buffer, final String content)
{
buffer.append(content);
}
/**
* Adds the center.
*
* @param buffer
* the buffer
* @param content
* the content
*/
private static void addCenter(final StringBuffer buffer, final String content)
{
addCenter(buffer, content, ' ');
}
/**
* Adds the center.
*
* @param buffer
* the buffer
* @param content
* the content
* @param c
* the c
*/
private static void addCenter(final StringBuffer buffer, final String content, final char c)
{
buffer.append(getLine(content, c));
}
/**
* Adds the chunk.
*
* @param buffer
* the buffer
* @param content
* the content
*/
private static void addChunk(final StringBuffer buffer, final String content)
{
add(buffer, chunk(content));
}
/**
* Adds the empty.
*
* @param buffer
* the buffer
*/
private static void addEmpty(final StringBuffer buffer)
{
buffer.append("\n");
}
/**
* Adds the line.
*
* @param buffer
* the buffer
* @param c
* the c
*/
private static void addLine(final StringBuffer buffer, final char c)
{
buffer.append(getLine(c));
}
/**
* Chunk.
*
* @param content
* the content
* @return the string
*/
private static String chunk(final String content)
{
String result;
result = chunk(content, LENGTH);
//
return result;
}
/**
* Chunk.
*
* @param content
* the content
* @param length
* the length
* @return the string
*/
private static String chunk(final String content, final int length)
{
String result;
final String[] words = content.split(" ");
final StringBuffer buffer = new StringBuffer();
StringBuffer current = new StringBuffer();
for (final String word : words)
{
if (current.length() + word.length() > length)
{
if (buffer.length() > 0)
{
buffer.append("\n");
}
buffer.append(current);
current = new StringBuffer(word);
}
else
{
if (current.length() > 0)
{
current.append(" ");
}
current.append(word);
}
}
if (current.length() > 0)
{
if (buffer.length() > 0)
{
buffer.append("\n");
}
buffer.append(current);
}
result = buffer.toString();
//
return result;
}
/**
* Gets the line.
*
* @param letter
* the letter
* @return the line
*/
private static String getLine(final Character letter)
{
String result;
result = StringUtils.repeat(letter.toString(), LENGTH) + "\n";
//
return result;
}
/**
* Gets the line.
*
* @param content
* the content
* @param letter
* the c
* @return the line
*/
private static String getLine(final String content, final char letter)
{
String result;
result = StringUtils.center(" " + content + " ", LENGTH, letter) + "\n";
//
return result;
}
/**
* Gets the topic.
*
* @param topic
* the topic
* @return the topic
*/
private static String getTopic(final Topic topic)
{
String result;
result = "=== " + topic.getTitle() + " ===\n";
//
return result;
}
}

View File

@ -0,0 +1,346 @@
/**
* Copyright (C) 2017-2018 Christian Pierre MOMON <cmomon@april.org>
* Copyright (C) 2011-2013 Nicolas Vinot <aeris@imirhil.fr>
*
* This file is part of (April) Hebdobot.
*
* Hebdobot is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Hebdobot 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Hebdobot. If not, see <http://www.gnu.org/licenses/>
*/
package org.april.hebdobot.bot.review;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import org.apache.commons.lang3.StringUtils;
import org.april.hebdobot.bot.stats.ReviewDatas;
import org.april.hebdobot.bot.stats.ReviewStatsReporter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.devinsy.strings.StringList;
/**
* The Class Review.
*/
public class ReviewReporter
{
private static final Logger logger = LoggerFactory.getLogger(ReviewReporter.class);
private static final int LENGTH_LINE = 80;
/**
* Adds the.
*
* @param buffer
* the buffer
* @param content
* the content
*/
private static void add(final StringList buffer, final String content)
{
buffer.append(content);
}
/**
* Adds the center.
*
* @param buffer
* the buffer
* @param content
* the content
*/
private static void addCenter(final StringList buffer, final String content)
{
addCenter(buffer, content, ' ');
}
/**
* Adds the center.
*
* @param buffer
* the buffer
* @param content
* the content
* @param c
* the c
*/
private static void addCenter(final StringList buffer, final String content, final char c)
{
buffer.append(getLine(content, c));
}
/**
* Adds the chunk.
*
* @param buffer
* the buffer
* @param content
* the content
*/
private static void addChunk(final StringList buffer, final String content)
{
add(buffer, chunk(content));
}
/**
* Adds the empty.
*
* @param buffer
* the buffer
*/
private static void addEmpty(final StringList buffer)
{
buffer.append("\n");
}
/**
* Adds the line.
*
* @param buffer
* the buffer
* @param c
* the c
*/
private static void addLine(final StringList buffer, final char c)
{
buffer.append(getLine(c));
}
/**
* Chunk.
*
* @param content
* the content
* @return the string
*/
private static String chunk(final String content)
{
String result;
result = chunk(content, LENGTH_LINE);
//
return result;
}
/**
* Chunk.
*
* @param content
* the content
* @param length
* the length
* @return the string
*/
private static String chunk(final String content, final int length)
{
String result;
final String[] words = content.split(" ");
final StringBuffer buffer = new StringBuffer();
StringBuffer current = new StringBuffer();
for (final String word : words)
{
if (current.length() + word.length() > length)
{
if (buffer.length() > 0)
{
buffer.append("\n");
}
buffer.append(current);
current = new StringBuffer(word);
}
else
{
if (current.length() > 0)
{
current.append(" ");
}
current.append(word);
}
}
if (current.length() > 0)
{
if (buffer.length() > 0)
{
buffer.append("\n");
}
buffer.append(current);
}
result = buffer.toString();
//
return result;
}
/**
* Gets the line.
*
* @param letter
* the letter
* @return the line
*/
private static String getLine(final Character letter)
{
String result;
result = StringUtils.repeat(letter.toString(), LENGTH_LINE) + "\n";
//
return result;
}
/**
* Gets the line.
*
* @param content
* the content
* @param letter
* the c
* @return the line
*/
private static String getLine(final String content, final char letter)
{
String result;
result = StringUtils.center(" " + content + " ", LENGTH_LINE, letter) + "\n";
//
return result;
}
/**
* Gets the topic.
*
* @param topic
* the topic
* @return the topic
*/
private static String getTopic(final Topic topic)
{
String result;
result = "=== " + topic.getTitle() + " ===\n";
//
return result;
}
/**
* Report.
*
* @param datas
* the datas
* @param review
* the review
* @return the string
*/
public static String report(final ReviewDatas datas, final Review review)
{
String result;
//
StringList buffer = new StringList();
addLine(buffer, '=');
addCenter(buffer, "Revue de la semaine en cours");
addEmpty(buffer);
addCenter(buffer, StringUtils.capitalize(LocalDateTime.now().format(DateTimeFormatter.ofPattern("EEEE dd MMMM yyyy", Locale.FRENCH))));
addLine(buffer, '=');
addEmpty(buffer);
addEmpty(buffer);
//
addLine(buffer, '=');
addEmpty(buffer);
addCenter(buffer, "Participants", '-');
for (final String participant : review.getParticipants())
{
addChunk(buffer, "* " + review.getAliases().getRealName(participant) + "\n");
}
//
if (!review.getIndividualTopics().isEmpty())
{
for (final String participant : review.getParticipants())
{
addEmpty(buffer);
addLine(buffer, '=');
addEmpty(buffer);
addCenter(buffer, review.getAliases().getRealName(participant), '-');
for (final IndividualTopic topic : review.getIndividualTopics())
{
if (topic.hasParticipant(participant))
{
addEmpty(buffer);
add(buffer, getTopic(topic));
addEmpty(buffer);
for (final Message message : topic.getMessages(participant))
{
addChunk(buffer, "* " + message.getContent() + "\n");
}
}
}
}
}
//
if (!review.getCollectiveTopics().isEmpty())
{
for (final CollectiveTopic topic : review.getCollectiveTopics())
{
addEmpty(buffer);
addLine(buffer, '=');
addCenter(buffer, topic.getTitle());
addLine(buffer, '=');
addEmpty(buffer);
for (final Message message : topic.getMessages())
{
addChunk(buffer, "* " + message.getAuthor() + " : " + message.getContent() + "\n");
}
}
}
//
addEmpty(buffer);
addCenter(buffer, "Log IRC brut");
addEmpty(buffer);
for (Message message : review.getMessages())
{
addChunk(buffer, "* " + message.getAuthor() + " : " + message.getContent() + "\n");
}
// Add statistics in text review.
addEmpty(buffer);
addCenter(buffer, "Statistiques");
addEmpty(buffer);
addChunk(buffer, ReviewStatsReporter.reportReviewCount(datas) + "\n");
addChunk(buffer, "Horaire de début de la revue : " + review.getFormattedStartTime() + "\n");
addChunk(buffer, "Horaire de fin de la revue : " + review.getFormattedEndTime() + "\n");
addChunk(buffer, "Durée de la revue : " + review.getDurationInMinutes() + " minutes\n");
addChunk(buffer, "Nombre de personnes participantes : " + review.getParticipants().size() + "\n");
addChunk(buffer, ReviewStatsReporter.reportUserCount(datas, review.getParticipants().size()) + "\n");
addChunk(buffer, ReviewStatsReporter.reportNewMaxUserCount(datas, review.getParticipants().size()) + "\n");
addChunk(buffer, ReviewStatsReporter.reportDuration(datas, review.getDurationInMinutes()) + "\n");
//
result = buffer.toString();
//
return result;
}
}

View File

@ -0,0 +1,300 @@
/**
* Copyright (C) 2018 Christian Pierre MOMON <cmomon@april.org>
*
* This file is part of (April) Hebdobot.
*
* Hebdobot is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Hebdobot 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Hebdobot. If not, see <http://www.gnu.org/licenses/>
*/
package org.april.hebdobot.bot.stats;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import fr.devinsy.strings.StringList;
/**
* The Class LongBoard.
*/
public class LongBoard implements Iterable<LongStat>
{
private Map<Long, LongStat> longs;
private boolean isUptodate;
private LongStats board;
/**
* Instantiates a new distribution.
*/
public LongBoard()
{
this.longs = new HashMap<>(30);
this.isUptodate = false;
this.board = new LongStats(this.longs.size());
}
/**
* Adds the.
*
* @param value
* the value
*/
public void add(final Long value)
{
if (value != null)
{
LongStat stat = this.longs.get(value);
if (stat == null)
{
stat = new LongStat(value);
this.longs.put(value, stat);
}
stat.inc();
}
}
/**
* Gets the.
*
* @param value
* the value
* @return the long stat
*/
public LongStat get(final long value)
{
LongStat result;
result = this.longs.get(value);
//
return result;
}
/**
* Gets the average.
*
* @return the average
*/
public double getAverage()
{
double result;
int numerator = 0;
int denumerator = 0;
for (LongStat stat : this.longs.values())
{
numerator += stat.getCount() * stat.getValue();
denumerator += stat.getCount();
}
result = (numerator * 1. / denumerator);
//
return result;
}
/**
* Gets the count sum.
*
* @return the count sum
*/
public int getCountSum()
{
int result;
result = 0;
for (LongStat stat : this.longs.values())
{
result += stat.getCount();
}
//
return result;
}
public long getMaxValue()
{
long result;
if (isEmpty())
{
result = 0;
}
else
{
result = Long.MIN_VALUE;
for (LongStat stat : this.longs.values())
{
if (stat.getValue() > result)
{
result = stat.getValue();
}
}
}
//
return result;
}
/**
* Gets the min.
*
* @return the min
*/
public long getMinValue()
{
long result;
if (isEmpty())
{
result = 0;
}
else
{
result = Long.MAX_VALUE;
for (LongStat stat : this.longs.values())
{
if (stat.getValue() < result)
{
result = stat.getValue();
}
}
}
//
return result;
}
/**
* Gets the position of board item.
*
* @param search
* the search
* @return the position of
*/
public Integer getPositionOf(final long search)
{
Integer result;
update();
int index = 0;
boolean ended = false;
result = null;
while (!ended)
{
if (index < this.board.size())
{
long value = this.board.get(index).getValue();
if (value == search)
{
result = index + 1;
ended = true;
}
else
{
index += 1;
}
}
else
{
ended = true;
result = null;
}
}
//
return result;
}
/**
* Checks if is empty.
*
* @return true, if is empty
*/
public boolean isEmpty()
{
boolean result;
if (this.longs.size() == 0)
{
result = true;
}
else
{
result = false;
}
//
return result;
}
/**
* Iterator.
*
* @return the iterator
*/
@Override
public Iterator<LongStat> iterator()
{
Iterator<LongStat> result;
update();
result = this.board.iterator();
//
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
String result;
update();
StringList buffer = new StringList();
for (LongStat stat : this.board)
{
buffer.append(String.format("%d (%d)", stat.getValue(), stat.getCount()));
}
result = buffer.toStringWithBracket();
//
return result;
}
/**
* Update.
*/
public void update()
{
if (!this.isUptodate)
{
this.board.clear();
for (LongStat stat : this.longs.values())
{
this.board.add(stat);
}
this.board.sortByValue();
Collections.reverse(this.board);
this.isUptodate = false;
}
}
}

View File

@ -0,0 +1,99 @@
/**
* Copyright (C) 2018 Christian Pierre MOMON <cmomon@april.org>
*
* This file is part of (April) Hebdobot.
*
* Hebdobot is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Hebdobot 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Hebdobot. If not, see <http://www.gnu.org/licenses/>
*/
package org.april.hebdobot.bot.stats;
/**
* The Class Stat.
*/
public class LongStat
{
private long value;
private long count;
/**
* Instantiates a new distribution pair.
*
* @param value
* the value
*/
public LongStat(final long value)
{
this(value, 0);
}
/**
* Instantiates a new distribution pair.
*
* @param value
* the value
* @param count
* the count
*/
public LongStat(final long value, final long count)
{
this.value = value;
this.count = count;
}
/**
* Decrease count.
*/
public void dec()
{
this.count -= 1;
}
/**
* Gets the count.
*
* @return the count
*/
public long getCount()
{
long result;
result = this.count;
//
return result;
}
/**
* Gets the value.
*
* @return the value
*/
public long getValue()
{
long result;
result = this.value;
//
return result;
}
/**
* Increments count.
*/
public void inc()
{
this.count += 1;
}
}

View File

@ -0,0 +1,217 @@
/**
* Copyright (C) 2018 Christian Pierre MOMON <cmomon@april.org>
*
* This file is part of (April) Hebdobot.
*
* Hebdobot is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Hebdobot 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Hebdobot. If not, see <http://www.gnu.org/licenses/>
*/
package org.april.hebdobot.bot.stats;
import java.util.Comparator;
/**
* The Class Stat.
*/
public class LongStatComparator implements Comparator<LongStat>
{
public enum Sorting
{
VALUE,
COUNT
}
private Sorting sorting;
/**
* Instantiates a new review data comparator.
*
* @param sorting
* the sorting
*/
public LongStatComparator(final Sorting sorting)
{
this.sorting = sorting;
}
/* (non-Javadoc)
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
@Override
public int compare(final LongStat alpha, final LongStat bravo)
{
int result;
result = compare(alpha, bravo, this.sorting);
//
return result;
}
/**
* Compare.
*
* @param alpha
* the alpha
* @param bravo
* the bravo
* @return the int
*/
public static int compare(final Integer alpha, final Integer bravo)
{
int result;
//
if ((alpha == null) && (bravo == null))
{
result = 0;
}
else if (alpha == null)
{
result = -1;
}
else if (bravo == null)
{
result = +1;
}
else
{
result = alpha.compareTo(bravo);
}
//
return result;
}
/**
* Compare.
*
* @param alpha
* the alpha
* @param bravo
* the bravo
* @return the int
*/
public static int compare(final Long alpha, final Long bravo)
{
int result;
//
if ((alpha == null) && (bravo == null))
{
result = 0;
}
else if (alpha == null)
{
result = -1;
}
else if (bravo == null)
{
result = +1;
}
else
{
result = alpha.compareTo(bravo);
}
//
return result;
}
/**
* Compare.
*
* @param alpha
* the alpha
* @param bravo
* the bravo
* @param sorting
* the sorting
* @return the int
*/
public static int compare(final LongStat alpha, final LongStat bravo, final Sorting sorting)
{
int result;
if (sorting == null)
{
result = 0;
}
else
{
switch (sorting)
{
case VALUE:
result = compare(getValue(alpha), getValue(bravo));
break;
case COUNT:
result = compare(getCount(alpha), getCount(bravo));
break;
default:
result = 0;
}
}
//
return result;
}
/**
* Gets the user count.
*
* @param source
* the source
* @return the user count
*/
public static Long getCount(final LongStat source)
{
Long result;
if (source == null)
{
result = null;
}
else
{
result = source.getCount();
}
//
return result;
}
/**
* Gets the duration.
*
* @param source
* the source
* @return the duration
*/
public static Long getValue(final LongStat source)
{
Long result;
if (source == null)
{
result = null;
}
else
{
result = source.getValue();
}
//
return result;
}
}

View File

@ -0,0 +1,75 @@
/**
* Copyright (C) 2017-2018 Christian Pierre MOMON <cmomon@april.org>
*
* This file is part of (April) Hebdobot.
*
* Hebdobot is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Hebdobot 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Hebdobot. If not, see <http://www.gnu.org/licenses/>
*/
package org.april.hebdobot.bot.stats;
import java.util.ArrayList;
import java.util.Collections;
import org.april.hebdobot.bot.stats.LongStatComparator.Sorting;
/**
* The Class Stats.
*/
public class LongStats extends ArrayList<LongStat>
{
private static final long serialVersionUID = 5671191897589640804L;
/**
* Instantiates a new long stats.
*/
public LongStats()
{
super();
}
/**
* Instantiates a new long stats.
*
* @param initialCapacity
* the initial capacity
*/
public LongStats(final int initialCapacity)
{
super(initialCapacity);
}
/**
* Reverse.
*/
public void reverse()
{
Collections.reverse(this);
}
/**
* Sort by user count.
*/
public void sortByCount()
{
Collections.sort(this, new LongStatComparator(Sorting.COUNT));
}
/**
* Sort by duration.
*/
public void sortByValue()
{
Collections.sort(this, new LongStatComparator(Sorting.VALUE));
}
}

View File

@ -27,7 +27,7 @@ public class ReviewData
{
private LocalDateTime date;
private int userCount;
private Integer duration;
private Long duration;
/**
* Instantiates a new stat.
@ -39,7 +39,7 @@ public class ReviewData
* @param duration
* the duration
*/
public ReviewData(final LocalDateTime date, final int userCount, final Integer duration)
public ReviewData(final LocalDateTime date, final int userCount, final Long duration)
{
this.date = date;
this.userCount = userCount;
@ -51,7 +51,7 @@ public class ReviewData
return this.date;
}
public Integer getDuration()
public Long getDuration()
{
return this.duration;
}
@ -66,7 +66,7 @@ public class ReviewData
this.date = date;
}
public void setDuration(final Integer duration)
public void setDuration(final Long duration)
{
this.duration = duration;
}

View File

@ -230,9 +230,9 @@ public class ReviewDataComparator implements Comparator<ReviewData>
* the source
* @return the duration
*/
public static Integer getDuration(final ReviewData source)
public static Long getDuration(final ReviewData source)
{
Integer result;
Long result;
if (source == null)
{

View File

@ -67,6 +67,47 @@ public class ReviewDatas extends ArrayList<ReviewData>
return result;
}
/**
* Count by year.
*
* @param year
* the year
* @return the long
*/
public long countByYear(final long year)
{
long result;
result = getByYear(year).size();
//
return result;
}
/**
* Gets the by year.
*
* @param year
* the year
* @return the by year
*/
public ReviewDatas getByYear(final long year)
{
ReviewDatas result;
result = new ReviewDatas();
for (ReviewData data : this)
{
if (data.getDate().getYear() == year)
{
result.add(data);
}
}
//
return result;
}
/**
* Gets the last by max user count.
*

View File

@ -188,14 +188,14 @@ public class ReviewDatasFile
int userCount = Integer.parseInt(tokens[1]);
Integer duration;
Long duration;
if (tokens.length == 2)
{
duration = null;
}
else
{
duration = Integer.parseInt(tokens[2]);
duration = Long.parseLong(tokens[2]);
}
ReviewData stat = new ReviewData(date, userCount, duration);

View File

@ -18,6 +18,7 @@
*/
package org.april.hebdobot.bot.stats;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
@ -92,23 +93,31 @@ public class ReviewStatsReporter
* the current duration
* @return the string
*/
public static String reportDuration(final ReviewDatas datas, final int currentDuration)
public static String reportDuration(final ReviewDatas datas, final long currentDuration)
{
String result;
IntegerBoard board = new IntegerBoard();
if ((datas == null) || (datas.isEmpty()))
{
result = "Pas de statistique sur la durée de la revue.";
}
else
{
LongBoard board = new LongBoard();
for (ReviewData data : datas)
{
board.add(data.getDuration());
}
logger.debug("Duration board: " + board.toString());
IntegerStat stat = board.get(currentDuration);
LongStat stat = board.get(currentDuration);
int total = board.getCountSum();
result = String.format(
"Statistiques sur la durée de la revue (%d min) : position %d (min.=%d min, moy.=%.1f min, max.=%d min), fréquence %d/%d (%.0f %%)",
stat.getValue(), board.getPositionOf(stat.getValue()), board.getMinValue(), board.getAverage(), board.getMaxValue(), stat.getCount(),
total, percent(stat.getCount(), total));
stat.getValue(), board.getPositionOf(stat.getValue()), board.getMinValue(), board.getAverage(), board.getMaxValue(),
stat.getCount(), total, percent(stat.getCount(), total));
}
//
return result;
@ -125,7 +134,7 @@ public class ReviewStatsReporter
{
String result;
IntegerBoard board = new IntegerBoard();
LongBoard board = new LongBoard();
for (ReviewData data : datas)
{
board.add(data.getDuration());
@ -149,6 +158,12 @@ public class ReviewStatsReporter
{
String result;
if ((datas == null) || (datas.isEmpty()))
{
result = "Pas de stats sur le nombre maximal de personnes participantes.";
}
else
{
datas.sortByDate();
ReviewData last = datas.getLastByMaxUserCount();
if (currentUserCount == last.getUserCount())
@ -166,6 +181,33 @@ public class ReviewStatsReporter
String lastRecordDate = last.getDate().format(DateTimeFormatter.ofPattern("EEEE dd MMMM yyyy", Locale.FRENCH));
result = String.format("%s Le dernier record de %d personnes participantes remonte au %s.", result, last.getUserCount(), lastRecordDate);
}
//
return result;
}
/**
* Report review count.
*
* @param datas
* the datas
* @return the string
*/
public static String reportReviewCount(final ReviewDatas datas)
{
String result;
if ((datas == null) || (datas.isEmpty()))
{
result = "Pas de statistique sur le nombre de revues.";
}
else
{
long currentYear = LocalDateTime.now().getYear();
result = String.format("C'était la %dè revue hebdomadaire de l'April, la %dè de l'année %d.", datas.size(),
datas.countByYear(currentYear), currentYear);
}
//
return result;
@ -184,6 +226,12 @@ public class ReviewStatsReporter
{
String result;
if ((datas == null) || (datas.isEmpty()))
{
result = "Pas de statistique sur le nombre de personnes participantes.";
}
else
{
IntegerBoard board = new IntegerBoard();
for (ReviewData data : datas)
{
@ -195,8 +243,9 @@ public class ReviewStatsReporter
int total = board.getCountSum();
result = String.format(
"Statistiques sur la participation à la revue (%d personnes) : position %d (min.=%d, moy.=%.1f, max.=%d), fréquence %d/%d (%.0f %%)",
stat.getValue(), board.getPositionOf(stat.getValue()), board.getMinValue(), board.getAverage(), board.getMaxValue(), stat.getCount(),
total, percent(stat.getCount(), total));
stat.getValue(), board.getPositionOf(stat.getValue()), board.getMinValue(), board.getAverage(), board.getMaxValue(),
stat.getCount(), total, percent(stat.getCount(), total));
}
//
return result;

View File

@ -71,9 +71,9 @@ public class ReviewStatsTest
ReviewDatas datas = ReviewDatasFile.load(new File("test/org/april/hebdobot/reviewstats/reviewstats.csv"));
datas.clean();
logger.debug("File loaded.");
ReviewData currentReview = new ReviewData(LocalDateTime.now(), 12, 17);
datas.add(currentReview);
String report = ReviewStatsReporter.reportDuration(datas, currentReview.getDuration());
ReviewData currentReviewData = new ReviewData(LocalDateTime.now(), 12, 17L);
datas.add(currentReviewData);
String report = ReviewStatsReporter.reportDuration(datas, currentReviewData.getDuration());
logger.debug("Report=" + report);
Assert.assertTrue(StringUtils.contains(report,
"Statistiques sur la durée de la revue (17 min) : position 3 (min.=14 min, moy.=17,2 min, max.=20 min), fréquence 7/14 (50 %)"));
@ -92,7 +92,7 @@ public class ReviewStatsTest
ReviewDatas datas = ReviewDatasFile.load(new File("test/org/april/hebdobot/reviewstats/reviewstats.csv"));
datas.clean();
logger.debug("File loaded.");
ReviewData currentReview = new ReviewData(LocalDateTime.now(), 12, 17);
ReviewData currentReview = new ReviewData(LocalDateTime.now(), 12, 17L);
String report = ReviewStatsReporter.reportNewMaxUserCount(datas, currentReview.getUserCount());
logger.debug("Report=" + report);
Assert.assertTrue(StringUtils.startsWith(report, "Pas de nouveau record"));
@ -111,7 +111,7 @@ public class ReviewStatsTest
ReviewDatas datas = ReviewDatasFile.load(new File("test/org/april/hebdobot/reviewstats/reviewstats.csv"));
datas.clean();
logger.debug("File loaded.");
ReviewData currentReview = new ReviewData(LocalDateTime.now(), 42000, 17);
ReviewData currentReview = new ReviewData(LocalDateTime.now(), 42000, 17L);
String report = ReviewStatsReporter.reportNewMaxUserCount(datas, currentReview.getUserCount());
logger.debug("Report=" + report);
Assert.assertTrue(StringUtils.startsWith(report, "Nouveau record de personnes participantes !"));
@ -130,7 +130,7 @@ public class ReviewStatsTest
ReviewDatas datas = ReviewDatasFile.load(new File("test/org/april/hebdobot/reviewstats/reviewstats.csv"));
datas.clean();
logger.debug("File loaded.");
ReviewData currentReview = new ReviewData(LocalDateTime.now(), 12, 17);
ReviewData currentReview = new ReviewData(LocalDateTime.now(), 12, 17L);
datas.add(currentReview);
String report = ReviewStatsReporter.reportUserCount(datas, currentReview.getUserCount());
logger.debug("Report=" + report);