agirbot/src/org/april/hebdobot/model/Hebdobot.java

624 lines
22 KiB
Java
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright (C) 2011-2013,2017 Nicolas Vinot <aeris@imirhil.fr>
* Copyright (C) 2017 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.model;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.april.hebdobot.HebdobotException;
import org.april.hebdobot.cron.CronManager;
import org.april.hebdobot.cron.CronSettings;
import org.april.hebdobot.identica.IdenticaSettings;
import org.april.hebdobot.pastebin.PastebinClient;
import org.april.hebdobot.pastebin.PastebinSettings;
import org.april.hebdobot.pastebin.Private;
import org.april.hebdobot.review.CollectiveTopic;
import org.april.hebdobot.review.IndividualTopic;
import org.april.hebdobot.review.Message;
import org.april.hebdobot.review.Review;
import org.april.hebdobot.review.Topic;
import org.april.hebdobot.twitter.TwitterClient;
import org.april.hebdobot.twitter.TwitterSettings;
import org.jibble.pircbot.IrcException;
import org.jibble.pircbot.NickAlreadyInUseException;
import org.jibble.pircbot.PircBot;
import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.devinsy.util.strings.StringsUtils;
import twitter4j.TwitterException;
/**
* The Class Hebdobot.
*/
public class Hebdobot extends PircBot
{
private static final Logger logger = LoggerFactory.getLogger(Hebdobot.class);
private File homeDirectory;
private String host;
private int port;
private String channel;
private String reviewFileSuffix;
private Review review;
private IdenticaSettings identicaSettings;
private PastebinSettings pastebinSettings;
private TwitterSettings twitterSettings;
private CronSettings cronSettings;
private UserAliases aliases;
private CronManager cronManager;
/**
* Instantiates a new bot.
*
* @param host
* the host
* @param port
* the port
* @param name
* the name
* @param channel
* the channel
*/
public Hebdobot(final String host, final int port, final String name, final String channel, final File homeDirectory,
final String reviewFileSuffix)
{
this.homeDirectory = homeDirectory;
this.host = host;
this.port = port;
this.channel = channel;
this.setName(name);
this.reviewFileSuffix = reviewFileSuffix;
this.review = null;
this.identicaSettings = new IdenticaSettings();
this.pastebinSettings = new PastebinSettings();
this.twitterSettings = new TwitterSettings();
this.cronSettings = new CronSettings();
this.aliases = new UserAliases();
this.cronManager = null;
}
/**
* Close.
*/
public void close()
{
this.disconnect();
this.dispose();
}
/**
* Gets the aliases.
*
* @return the aliases
*/
public UserAliases getAliases()
{
return this.aliases;
}
/**
* Gets the cron settings.
*
* @return the cron settings
*/
public CronSettings getCronSettings()
{
return this.cronSettings;
}
/**
* Gets the home directory.
*
* @return the home directory
*/
public File getHomeDirectory()
{
return this.homeDirectory;
}
/**
* Gets the identica settings.
*
* @return the identica settings
*/
public IdenticaSettings getIdenticaSettings()
{
return this.identicaSettings;
}
/**
* Gets the pastebin settings.
*
* @return the pastebin settings
*/
public PastebinSettings getPastebinSettings()
{
return this.pastebinSettings;
}
/**
* Gets the twitter settings.
*
* @return the twitter settings
*/
public TwitterSettings getTwitterSettings()
{
return this.twitterSettings;
}
/**
* Notify.
*
* @param minutes
* the minutes
*/
public void notifyIrc(final String message)
{
sendMessage(message);
}
/**
* Notify twitter.
*
* @param message
* the message
*/
public void notifyTwitter(final String message)
{
if (this.twitterSettings.isValid())
{
try
{
TwitterClient twitter = new TwitterClient(this.twitterSettings.getConsumerKey(), this.twitterSettings.getConsumerSecret(),
this.twitterSettings.getAccessToken(), this.twitterSettings.getAccessTokenSecret());
twitter.tweet(message);
}
catch (TwitterException exception)
{
logger.error("Error in tweet", exception);
sendMessage("(pour information, la notification par Tweet a échoué : " + exception.getErrorMessage() + ")");
}
}
}
/* (non-Javadoc)
* @see org.jibble.pircbot.PircBot#onMessage(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
*/
@Override
protected void onMessage(final String channel, final String sender, final String login, final String hostname, final String message)
{
logger.debug("Message received - channel : {}, sender : {}, message : {}", channel, sender, message);
if (channel.equalsIgnoreCase(this.channel))
{
String text = message.trim();
if ((StringUtils.equalsIgnoreCase(text, "!aide")) || (StringUtils.equalsIgnoreCase(text, "!help")))
{
logger.info("!help caught.");
// Help.
sendMessage(sender, "Bienvenue " + sender);
sendMessage(sender, "Je suis " + getName() + ", le robot de gestion des revues hebdomadaires de l'APRIL.");
sendMessage(sender, "Voici les commandes que je comprends :");
sendMessage(sender, " ");
sendMessage(sender, " !debut,!début : commencer une nouvelle revue");
sendMessage(sender, " # titre : démarrer un sujet individuel");
sendMessage(sender, " ## titre : démarrer un sujet collectif");
sendMessage(sender, " % message : un commentaire");
sendMessage(sender, " !courant : affiche le sujet en cours");
sendMessage(sender, " !manquants : affiche les participants qui n'ont pas répondu sur le dernier sujet");
sendMessage(sender, " !fin : terminer la revue en cours");
sendMessage(sender, " !aide : afficher cette aide");
sendMessage(sender, " !licence,!license : affiche la licence du logiciel Hebdobot et le lien vers ses sources");
sendMessage(sender, " !stop : abandonner la revue en cours");
sendMessage(sender, " !vaten : faire partir le bot");
}
else if (StringUtils.equalsIgnoreCase(text, "!vaten"))
{
logger.info("!die caught.");
// Die.
if (this.review == null)
{
try
{
sendMessage(sender + ", ok bye.");
Thread.sleep(1000);
System.exit(0);
}
catch (InterruptedException exception)
{
logger.warn("Pause abort: " + exception.getMessage());
}
}
else
{
sendMessage("% Une revue est en cours, abandon impossible.");
}
}
else if (StringUtils.equalsIgnoreCase(text, "!stop"))
{
logger.info("!stop caught.");
// Stop.
if (this.review == null)
{
sendMessage("Aucune revue en cours, abandon impossible.");
}
else
{
sendMessage("Abandon de la revue en cours.");
this.review = null;
}
}
else if (StringsUtils.equalsAnyIgnoreCase(text, "!debut", "!début"))
{
logger.info("!debut caught.");
// Start.
if (this.cronManager != null)
{
try
{
this.cronManager.shutdown();
}
catch (SchedulerException exception)
{
logger.warn("Scheduler shutdown failed.", exception);
}
}
this.review = new Review(sender, this.aliases);
sendMessage(sender, "Bonjour " + sender + ", vous êtes le conducteur de réunion.");
sendMessage(sender, "Pour terminer la réunion, tapez \"!fin\"");
sendMessage("% Début de la réunion hebdomadaire");
sendMessage("% rappel : toute ligne commençant par % sera considérée comme un commentaire et non prise en compte dans la synthèse");
}
else if (StringUtils.equalsIgnoreCase(text, "!fin"))
{
logger.info("!fin caught.");
// Stop.
if (this.review == null)
{
sendMessage(sender + ", pas de revue en cours.");
}
else if (!this.review.isOwner(sender))
{
sendMessage(sender + ", vous n'êtes pas le conducteur de la réunion");
}
else
{
{
String date = ISODateTimeFormat.basicDate().print(new DateTime());
String textReview = this.review.toString();
if (this.pastebinSettings.isValid())
{
logger.info("Pastebin the review.");
try
{
PastebinClient pastebinClient = new PastebinClient(this.pastebinSettings.getApiKey());
String returnValue = pastebinClient.paste(textReview, "Revue APRIL " + date, Private.UNLISTED);
sendMessage("% Compte-rendu de la revue : " + returnValue);
}
catch (final Exception exception)
{
logger.error("Error during Pastebin submit.", exception);
}
}
if (this.reviewFileSuffix != null)
{
logger.info("Write review file.");
try
{
File file = new File(this.homeDirectory, date + "_" + this.reviewFileSuffix);
FileUtils.writeStringToFile(file, textReview, StandardCharsets.UTF_8);
sendMessage("% Compte-rendu de la revue : " + file.getName());
}
catch (final Exception exception)
{
logger.error("Error during file generation", exception);
}
}
}
sendMessage("% " + this.review.getOwner()
+ ", ne pas oublier d'ajouter le compte-rendu de la revue sur https://agir.april.org/issues/135");
String participants = StringUtils.join(this.review.getParticipants(), " ");
sendMessage("% " + participants + ", pensez à noter votre bénévalo : http://www.april.org/my?action=benevalo");
sendMessage("% Fin de la revue hebdomadaire");
this.review = null;
}
}
else if (text.matches("\\s*##.*"))
{
logger.info("\\s*##.* caught.");
// Collective topic, must be before individual topic.
if (this.review != null)
{
if (this.review.isOwner(sender))
{
CollectiveTopic topic = new CollectiveTopic(text.replaceFirst("##", "").trim());
if (!this.review.isEmpty())
{
String participants = StringUtils.join(this.review.getParticipants(), " ");
sendMessage(String.format("%% %s, on va passer à la suite : %s", participants, topic.getTitle()));
}
this.review.begin(topic);
sendMessage("Sujet collectif : " + topic.getTitle());
sendMessage("% 1 minute max");
sendMessage("% si rien à signaler vous pouvez écrire %ras");
sendMessage("% quand vous avez fini vous le dites par % fini");
}
else
{
sendMessage(sender + ", vous n'êtes pas le conducteur de la réunion");
}
}
}
else if (text.matches("\\s*#[^#].*"))
{
logger.info("\\s*#[^#].* caught.");
// Individual topic.
if (this.review != null)
{
if (this.review.isOwner(sender))
{
IndividualTopic topic = new IndividualTopic(text.replaceFirst("#", "").trim());
if (!this.review.isEmpty())
{
String participants = StringUtils.join(this.review.getParticipants(), " ");
sendMessage(String.format("%% %s, on va passer à la suite : %s", participants, topic.getTitle()));
}
this.review.begin(topic);
sendMessage("Sujet individuel : " + topic.getTitle());
sendMessage("% si rien à signaler vous pouvez écrire %ras");
sendMessage("% quand vous avez fini vous le dites par % fini");
}
else
{
sendMessage(sender + ", vous n'êtes pas le conducteur de la réunion");
}
}
}
else if (StringUtils.equalsIgnoreCase(text, "!manquants"))
{
logger.info("!manquants caught.");
// Missing.
if (this.review == null)
{
sendMessage("Pas de revue en cours.");
}
else
{
Topic topic = this.review.getCurrentTopic();
if (topic == null)
{
sendMessage("Aucun sujet traité");
}
else
{
Collection<String> participants = this.review.getParticipants();
Collection<String> currentParticipants = topic.getParticipants();
Collection<String> missing = CollectionUtils.subtract(participants, currentParticipants);
if (missing.isEmpty())
{
sendMessage("Aucun participant manquant \\o/");
}
else
{
sendMessage(String.format("Les participants suivants sont manquants : %1s", StringUtils.join(missing, ", ")));
}
}
}
}
else if (StringUtils.equalsIgnoreCase(text, "!courant"))
{
logger.info("!courant caught.");
// Current.
if (this.review == null)
{
sendMessage("Pas de revue en cours.");
}
else
{
Topic current = this.review.getCurrentTopic();
if (current == null)
{
sendMessage("% Pas de sujet en cours");
}
else if (current instanceof IndividualTopic)
{
sendMessage("% Sujet individuel en cours : " + current.getTitle());
}
else if (current instanceof CollectiveTopic)
{
sendMessage("% Sujet collectif en cours : " + current.getTitle());
}
}
}
else if (StringUtils.equalsIgnoreCase(text, "!statut"))
{
logger.info("!status caught.");
sendMessage(sender, sender + ", voici l'état d'Hebdobot :");
sendMessage(sender, " revue en cours : " + (this.review != null));
if (this.review == null)
{
sendMessage(sender, " animateur revue : none");
}
else
{
sendMessage(sender, " animateur revue : " + this.review.getOwner());
}
sendMessage(sender, " Alias settings : " + (this.aliases.size()));
sendMessage(sender, " Identica settings : " + (this.identicaSettings.isValid()));
sendMessage(sender, " Pastebin settings : " + (this.pastebinSettings.isValid()));
sendMessage(sender, " Twitter settings : " + (this.twitterSettings.isValid()));
sendMessage(sender, " Cron settings : " + (this.cronSettings.size()));
}
else if (StringsUtils.equalsAnyIgnoreCase(text, "!licence", "!license"))
{
logger.info("!licence caught.");
sendMessage(sender
+ ", Hebdobot est un logiciel libre de l'April sous licence GNU AGPL (sources : https://agir.april.org/projects/hebdobot/repository).");
}
else if (text.startsWith("%"))
{
logger.info("% caught.");
// Ignore.
}
else if (StringsUtils.equalsAnyIgnoreCase(text, "!salut", "!bonjour", "!hello"))
{
logger.info("!salut caught.");
// Command unknown.
sendMessage(sender + ", bonjour \\o/");
}
else if (text.startsWith("!"))
{
logger.info("!??? caught.");
// Command unknown.
sendMessage(sender + ", command unknown: " + text);
}
else
{
logger.info("Else caught.");
// Topic message.
if (this.review == null)
{
if ((StringsUtils.containsAnyIgnoreCase(text, "bonjour", "salut", "hello")) && (StringUtils.containsIgnoreCase(text, "hebdobot")))
{
sendMessage(sender + ", bonjour \\o/");
}
}
else
{
this.review.add(new Message(sender, text));
}
}
/*
else
{
logger.info("Else caught.");
// All the other.
if (this.review != null)
{
this.review.addRaw(new Message(sender, text));
}
}*/
}
}
/**
* Inits the.
*
* the exception
*
* @throws HebdobotException
*/
public void run() throws HebdobotException
{
try
{
logger.info("Cron initializing.");
{
this.cronManager = new CronManager(this, this.cronSettings);
this.cronManager.start();
}
logger.info("Cron initialized.");
logger.info("Bot connection.");
this.connect(this.host, this.port);
logger.info("Bot connected.");
logger.info("Bot joining channel ({}).", this.channel);
this.joinChannel(this.channel);
logger.info("Bot ready.");
}
catch (NickAlreadyInUseException exception)
{
throw new HebdobotException(exception);
}
catch (IOException exception)
{
throw new HebdobotException(exception);
}
catch (IrcException exception)
{
throw new HebdobotException(exception);
}
catch (SchedulerException exception)
{
throw new HebdobotException("Error in cron settings.", exception);
}
}
/**
* Send message.
*
* @param message
* the message
*/
public void sendMessage(final String message)
{
logger.debug("Send message : {}", message);
this.sendMessage(this.channel, message);
}
/**
* Sets the home directory.
*
* @param homeDirectory
* the new home directory
*/
public void setHomeDirectory(final File homeDirectory)
{
this.homeDirectory = homeDirectory;
}
}