Implement Identi.ca client

Implement cron job for review reminder
This commit is contained in:
Nicolas VINOT 2011-12-11 15:02:17 +01:00
parent c5b2e101a9
commit 58511c43b7
23 changed files with 650 additions and 67 deletions

View File

@ -4,12 +4,16 @@
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/> <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/> <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/> <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="src" output="target/classes" path="target/generated-sources/jaxb"> <classpathentry kind="src" output="target/classes" path="target/generated-sources/jaxb">
<attributes> <attributes>
<attribute name="optional" value="true"/> <attribute name="optional" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
<attributes>
<attribute name="owner.project.facets" value="java"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/> <classpathentry kind="output" path="target/classes"/>
</classpath> </classpath>

View File

@ -1,5 +1,4 @@
syntax:glob syntax:regexp
conf.properties ^users\.xml$
users.xml ^conf\.xml$
target ^target$
*.log

View File

@ -5,6 +5,11 @@
<projects> <projects>
</projects> </projects>
<buildSpec> <buildSpec>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name> <name>org.eclipse.jdt.core.javabuilder</name>
<arguments> <arguments>
@ -19,5 +24,6 @@
<natures> <natures>
<nature>org.eclipse.jdt.core.javanature</nature> <nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature> <nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
</natures> </natures>
</projectDescription> </projectDescription>

View File

@ -1,6 +1,9 @@
#Wed Sep 28 23:04:47 CEST 2011 #Sat Dec 10 17:49:06 CET 2011
eclipse.preferences.version=1 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6 org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6 org.eclipse.jdt.core.compiler.source=1.6

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<installed facet="java" version="1.6"/>
</faceted-project>

83
conf.sample.xml Normal file
View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="fr.imirhil.april.hebdobot" />
<bean id="properties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="file.suffix">revue.txt</prop>
</props>
</property>
</bean>
<bean id="userAliases" class="fr.imirhil.april.hebdobot.xml.UserAlias">
<constructor-arg name="source" value="file:users.xml" />
</bean>
<bean id="bot" class="fr.imirhil.april.hebdobot.irc.Bot"
init-method="init" destroy-method="close">
<constructor-arg name="host" value="irc.freenode.org" />
<constructor-arg name="port" value="6667" />
<constructor-arg name="name" value="Hebdobot" />
<constructor-arg name="channel" value="#april" />
</bean>
<bean id="pastebin" class="fr.imirhil.april.hebdobot.pastebin.PastebinClient">
<constructor-arg name="apiKey"
value="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" />
</bean>
<bean id="identi.ca" class="fr.imirhil.april.hebdobot.statusnet.IdentiCaClient">
<constructor-arg name="apiKey"
value="ef8ad74a5ab4a92138ff397763776a14" />
<constructor-arg name="apiSecret"
value="70400fa3b7c1aebba6d72b46399f45c7" />
<constructor-arg name="tokenKey"
value="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" />
<constructor-arg name="tokenSecret"
value="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" />
</bean>
<bean id="job" class="fr.imirhil.april.hebdobot.Job" />
<bean id="trigger30" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<bean
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="job" />
<property name="targetMethod" value="at30" />
</bean>
</property>
<property name="cronExpression" value="* 30 11 ? * FRI" />
</bean>
<bean id="trigger45" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<bean
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="job" />
<property name="targetMethod" value="at45" />
</bean>
</property>
<property name="cronExpression" value="0 45 11 ? * FRI" />
</bean>
<bean id="trigger55" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<bean
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="job" />
<property name="targetMethod" value="at55" />
</bean>
</property>
<property name="cronExpression" value="0 55 11 ? * FRI" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="trigger30" />
<ref bean="trigger45" />
<ref bean="trigger55" />
</list>
</property>
</bean>
</beans>

41
pom.xml
View File

@ -73,14 +73,15 @@
<version>2.6</version> <version>2.6</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.xml</groupId> <groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId> <artifactId>jaxb-api</artifactId>
<version>2.1</version> <version>2.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.quartz-scheduler</groupId> <groupId>opensymphony</groupId>
<artifactId>quartz</artifactId> <artifactId>quartz</artifactId>
<version>2.0.2</version> <version>1.6.2</version>
<scope>runtime</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>
@ -104,5 +105,39 @@
<version>1.6.1</version> <version>1.6.1</version>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency>
<groupId>org.scribe</groupId>
<artifactId>scribe</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.0.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>3.0.6.RELEASE</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.0.6.RELEASE</version>
<scope>runtime</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,8 +1,6 @@
package fr.imirhil.april.hebdobot; package fr.imirhil.april.hebdobot;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.util.Properties; import java.util.Properties;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
@ -10,62 +8,37 @@ import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat; import org.joda.time.format.ISODateTimeFormat;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import fr.imirhil.april.hebdobot.irc.Bot; import fr.imirhil.april.hebdobot.irc.Bot;
import fr.imirhil.april.hebdobot.irc.ReviewListener; import fr.imirhil.april.hebdobot.irc.ReviewListener;
import fr.imirhil.april.hebdobot.pastebin.PastebinClient; import fr.imirhil.april.hebdobot.pastebin.PastebinClient;
import fr.imirhil.april.hebdobot.review.Review; import fr.imirhil.april.hebdobot.review.Review;
import fr.imirhil.april.hebdobot.xml.UserAlias;
public class Application implements ReviewListener { public class Application implements ReviewListener {
private static final String USERS_FILE = "users.xml";
private static final Logger LOGGER = LoggerFactory private static final Logger LOGGER = LoggerFactory
.getLogger(Application.class); .getLogger(Application.class);
private static final String CONF_PROPERTIES = "conf.properties";
private static final String IRC_HOST = "irc.host";
private static final String IRC_PORT = "irc.port";
private static final String IRC_NICK = "irc.nick";
private static final String IRC_CHAN = "irc.chan";
private static final String PASTEBIN_KEY = "pastebin.key";
private static final String FILE_SUFFIX = "file.suffix"; private static final String FILE_SUFFIX = "file.suffix";
private final Properties properties = new Properties(); private final Properties properties = Context.getBean("properties");
private final Bot bot; private final Bot bot = Context.getBean(Bot.class);
private final UserAlias userAlias; private final PastebinClient pastebinClient = Context
private final String channel; .getBean(PastebinClient.class);
private Application() throws Exception { private Application() throws Exception {
this.userAlias = new UserAlias(new FileInputStream(USERS_FILE));
this.properties.load(new FileReader(CONF_PROPERTIES));
final String name = this.properties.getProperty(IRC_NICK);
this.channel = this.properties.getProperty(IRC_CHAN);
this.bot = new Bot(name, this.channel);
this.bot.add(this); this.bot.add(this);
} }
public void start() throws Exception {
this.bot.connect(this.properties.getProperty(IRC_HOST),
Integer.valueOf(this.properties.getProperty(IRC_PORT)));
this.bot.joinChannel(this.channel);
}
@Override @Override
public void onEnd(final Review review) { public void onEnd(final Review review) {
final String date = ISODateTimeFormat.basicDate().print(new DateTime()); final String date = ISODateTimeFormat.basicDate().print(new DateTime());
final String text = review.toString(this.userAlias); final String text = review.toString();
if (this.properties.containsKey(PASTEBIN_KEY)) { try {
try { this.bot.sendMessage("Compte-rendu de la revue : "
this.bot.sendMessage("Compte-rendu de la revue : " + this.pastebinClient.paste(text, "Revue APRIL " + date));
+ new PastebinClient(this.properties } catch (final Exception e) {
.getProperty(PASTEBIN_KEY)).paste(text, LOGGER.error("Error during Pastebin submit", e);
"Revue APRIL " + date));
} catch (final Exception e) {
LOGGER.error("Error during Pastebin submit", e);
}
} }
if (this.properties.containsKey(FILE_SUFFIX)) { if (this.properties.containsKey(FILE_SUFFIX)) {
@ -83,6 +56,7 @@ public class Application implements ReviewListener {
} }
public static void main(final String[] args) throws Exception { public static void main(final String[] args) throws Exception {
new Application().start(); new FileSystemXmlApplicationContext("conf.xml");
new Application();
} }
} }

View File

@ -0,0 +1,30 @@
package fr.imirhil.april.hebdobot;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public final class Context implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
@Override
public void setApplicationContext(
final ApplicationContext applicationContext) throws BeansException {
CONTEXT = applicationContext;
}
public static <T> T getBean(final Class<T> clazz) {
return CONTEXT.getBean(clazz);
}
public static void load() {
}
@SuppressWarnings("unchecked")
public static <T> T getBean(final String name) {
return (T) CONTEXT.getBean(name);
}
}

View File

@ -0,0 +1,30 @@
package fr.imirhil.april.hebdobot;
import javax.annotation.Resource;
import fr.imirhil.april.hebdobot.irc.Bot;
import fr.imirhil.april.hebdobot.statusnet.IdentiCaClient;
public class Job {
@Resource
private Bot bot;
@Resource
private IdentiCaClient identiCaClient;
private void notify(final String message) {
this.bot.sendMessage(message);
this.identiCaClient.post(message);
}
public void at30() {
this.notify("Revue hebdomadaire dans 30min !");
}
public void at45() {
this.notify("Revue hebdomadaire dans 15min !");
}
public void at55() {
this.notify("Revue hebdomadaire dans 5min !");
}
}

View File

@ -12,14 +12,29 @@ import fr.imirhil.april.hebdobot.review.Review;
import fr.imirhil.april.hebdobot.review.Topic; import fr.imirhil.april.hebdobot.review.Topic;
public class Bot extends PircBot { public class Bot extends PircBot {
private Review review = null; private final String host;
private final int port;
private final String channel; private final String channel;
private Review review = null;
private final Collection<ReviewListener> listeners = private final Collection<ReviewListener> listeners =
new LinkedList<ReviewListener>(); new LinkedList<ReviewListener>();
public Bot(final String name, final String channel) { public Bot(final String host, final int port, final String name,
this.setName(name); final String channel) {
this.host = host;
this.port = port;
this.channel = channel; this.channel = channel;
this.setName(name);
}
public void init() throws Exception {
this.connect(this.host, this.port);
this.joinChannel(this.channel);
}
public void close() {
this.disconnect();
this.dispose();
} }
public void add(final ReviewListener listener) { public void add(final ReviewListener listener) {
@ -85,8 +100,7 @@ public class Bot extends PircBot {
return false; return false;
} }
this.disconnect(); this.close();
this.dispose();
return true; return true;
} }

View File

@ -42,18 +42,18 @@ public class PastebinClient {
} }
} }
private final String apiDevKey; private final String apiKey;
private String apiUserKey = null; private String apiUserKey = null;
HttpClient httpClient = new DefaultHttpClient(); HttpClient httpClient = new DefaultHttpClient();
public PastebinClient(final String apiDevKey) { public PastebinClient(final String apiKey) {
this.apiDevKey = apiDevKey; this.apiKey = apiKey;
} }
public void login(final String name, final String password) public void login(final String name, final String password)
throws Exception { throws Exception {
final List<NameValuePair> params = new LinkedList<NameValuePair>(); final List<NameValuePair> params = new LinkedList<NameValuePair>();
setParameter(params, API_DEV_KEY, this.apiDevKey); setParameter(params, API_DEV_KEY, this.apiKey);
setParameter(params, API_USER_NAME, name); setParameter(params, API_USER_NAME, name);
setParameter(params, API_USER_PASSWORD, password); setParameter(params, API_USER_PASSWORD, password);
@ -72,7 +72,7 @@ public class PastebinClient {
final Format format, final boolean privat, final Format format, final boolean privat,
final Expiration expiration) throws Exception { final Expiration expiration) throws Exception {
final List<NameValuePair> params = new LinkedList<NameValuePair>(); final List<NameValuePair> params = new LinkedList<NameValuePair>();
setParameter(params, API_DEV_KEY, this.apiDevKey); setParameter(params, API_DEV_KEY, this.apiKey);
setParameter(params, API_USER_KEY, this.apiUserKey); setParameter(params, API_USER_KEY, this.apiUserKey);
setParameter(params, API_OPTION, Option.PASTE.getValue()); setParameter(params, API_OPTION, Option.PASTE.getValue());
setParameter(params, API_PASTE_PRIVATE, privat ? "1" : "0"); setParameter(params, API_PASTE_PRIVATE, privat ? "1" : "0");

View File

@ -9,11 +9,14 @@ import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import fr.imirhil.april.hebdobot.Context;
import fr.imirhil.april.hebdobot.xml.UserAlias; import fr.imirhil.april.hebdobot.xml.UserAlias;
public class Review { public class Review {
private static final int LENGTH = 80; private static final int LENGTH = 80;
private static final UserAlias USER_ALIAS = Context
.getBean(UserAlias.class);
private final Set<String> participants = new HashSet<String>(); private final Set<String> participants = new HashSet<String>();
private final List<IndividualTopic> individualTopics = private final List<IndividualTopic> individualTopics =
new LinkedList<IndividualTopic>(); new LinkedList<IndividualTopic>();
@ -60,7 +63,8 @@ public class Review {
this.messages.add(message); this.messages.add(message);
} }
public String toString(final UserAlias userService) { @Override
public String toString() {
final StringBuffer buffer = new StringBuffer(); final StringBuffer buffer = new StringBuffer();
addLine(buffer, '='); addLine(buffer, '=');
addCenter(buffer, "Revue de la semaine en cours"); addCenter(buffer, "Revue de la semaine en cours");
@ -74,7 +78,7 @@ public class Review {
addEmpty(buffer); addEmpty(buffer);
addCenter(buffer, "Participants", '-'); addCenter(buffer, "Participants", '-');
for (final String participant : this.participants) { for (final String participant : this.participants) {
addChunk(buffer, "* " + userService.getRealName(participant) + "\n"); addChunk(buffer, "* " + USER_ALIAS.getRealName(participant) + "\n");
} }
if (!this.individualTopics.isEmpty()) { if (!this.individualTopics.isEmpty()) {
@ -82,7 +86,7 @@ public class Review {
addEmpty(buffer); addEmpty(buffer);
addLine(buffer, '='); addLine(buffer, '=');
addEmpty(buffer); addEmpty(buffer);
addCenter(buffer, userService.getRealName(participant), '-'); addCenter(buffer, USER_ALIAS.getRealName(participant), '-');
for (final IndividualTopic topic : this.individualTopics) { for (final IndividualTopic topic : this.individualTopics) {
if (topic.hasParticipant(participant)) { if (topic.hasParticipant(participant)) {
addEmpty(buffer); addEmpty(buffer);

View File

@ -1,5 +0,0 @@
package fr.imirhil.april.hebdobot.statusnet;
public class Client {
}

View File

@ -0,0 +1,31 @@
package fr.imirhil.april.hebdobot.statusnet;
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;
public class IdentiCaApi extends DefaultApi10a {
private static final String IDENTI_CA_OAUTH_API_URL =
"https://identi.ca/api/oauth";
private static final String IDENTI_CA_OAUTH_API_REQUEST_TOKEN_URL =
IDENTI_CA_OAUTH_API_URL + "/request_token";
private static final String IDENTI_CA_OAUTH_API_ACCESS_TOKEN_URL =
IDENTI_CA_OAUTH_API_URL + "/access_token";
private static final String IDENTI_CA_OAUTH_API_AUTHORIZE_URL =
IDENTI_CA_OAUTH_API_URL + "/authorize?oauth_token=%s";
@Override
public String getRequestTokenEndpoint() {
return IDENTI_CA_OAUTH_API_REQUEST_TOKEN_URL;
}
@Override
public String getAccessTokenEndpoint() {
return IDENTI_CA_OAUTH_API_ACCESS_TOKEN_URL;
}
@Override
public String getAuthorizationUrl(final Token requestToken) {
return String.format(IDENTI_CA_OAUTH_API_AUTHORIZE_URL,
requestToken.getToken());
}
}

View File

@ -0,0 +1,21 @@
package fr.imirhil.april.hebdobot.statusnet;
public class IdentiCaClient extends StatusNetClient {
private static final Class<IdentiCaApi> API_CLASS = IdentiCaApi.class;
private static final String IDENTICA_API_URL = "https://identi.ca/api";
public IdentiCaClient(final String apiKey, final String apiSecret,
final String tokenKey, final String tokenSecret) {
super(API_CLASS, apiKey, apiSecret, tokenKey, tokenSecret);
}
public static void register(final String apiKey, final String apiSecret) {
StatusNetClient.register(API_CLASS, apiKey, apiSecret);
}
@Override
protected String getApiUrl() {
return IDENTICA_API_URL;
}
}

View File

@ -0,0 +1,52 @@
package fr.imirhil.april.hebdobot.statusnet;
import java.util.Scanner;
import org.scribe.builder.ServiceBuilder;
import org.scribe.builder.api.Api;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;
public abstract class StatusNetClient {
private final OAuthService service;
private final Token token;
public StatusNetClient(final Class<? extends Api> apiClass,
final String apiKey, final String apiSecret, final String tokenKey,
final String tokenSecret) {
this.service = getService(apiClass, apiKey, apiSecret);
this.token = new Token(tokenKey, tokenSecret);
}
private static OAuthService getService(final Class<? extends Api> apiClass,
final String apiKey, final String apiSecret) {
return new ServiceBuilder().provider(apiClass).apiKey(apiKey)
.apiSecret(apiSecret).build();
}
public static void register(final Class<? extends Api> apiClass,
final String apiKey, final String apiSecret) {
final OAuthService service = getService(apiClass, apiKey, apiSecret);
final Token requestToken = service.getRequestToken();
System.out.println(service.getAuthorizationUrl(requestToken));
System.out.print(">>");
final Scanner scanner = new Scanner(System.in);
Verifier verifier = new Verifier(scanner.nextLine());
final Token token = service.getAccessToken(requestToken, verifier);
System.out.println(token);
}
public void post(final String message) {
final OAuthRequest request =
new OAuthRequest(Verb.POST, this.getApiUrl()
+ "/statuses/update.json");
request.addBodyParameter("status", message);
this.service.signRequest(this.token, request);
request.send();
}
protected abstract String getApiUrl();
}

View File

@ -0,0 +1,86 @@
package fr.imirhil.april.hebdobot.irc;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import fr.imirhil.april.hebdobot.review.Review;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/fr/imirhil/april/hebdobot/conf.xml")
public class BotTest implements ReviewListener {
private static class BotMock extends Bot {
public BotMock() throws Exception {
super("", 0, "bot", "channel");
}
@Override
public void
onMessage(final String channel, final String sender,
final String login, final String hostname,
final String message) {
super.onMessage(channel, sender, login, hostname, message);
}
}
@Test
public void redo() throws Exception {
final Bot bot = new BotMock();
bot.add(this);
final InputStream is =
BotTest.class
.getResourceAsStream("/fr/imirhil/april/hebdobot/review.log");
try {
final Reader isr = new InputStreamReader(is);
try {
final BufferedReader isbr = new BufferedReader(isr);
try {
String line;
final Pattern pattern =
Pattern.compile(".*\\s+<([^>]+)>\\s+(.*)");
while ((line = isbr.readLine()) != null) {
final Matcher matcher = pattern.matcher(line);
if (matcher.matches()) {
bot.onMessage("channel", matcher.group(1), "", "",
matcher.group(2));
}
}
} finally {
isbr.close();
}
} finally {
isr.close();
}
} finally {
is.close();
}
}
@Override
public void onEnd(final Review review) {
try {
final String date =
ISODateTimeFormat.basicDate().print(new DateTime());
final String text = review.toString();
final File file = new File("target/" + date + "_revue.txt");
FileUtils.writeStringToFile(file, text);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,13 @@
package fr.imirhil.april.hebdobot.pastebin;
import org.junit.Test;
public class PastebinClientTest {
private final PastebinClient client = new PastebinClient(
"b95ea42d539ec9dca02a7da1f5b229c7");
@Test
public void testPaste() throws Exception {
System.out.println(this.client.paste("ééé", Expiration.MINUTE_10));
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="fr.imirhil.april.hebdobot" />
<bean id="properties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="file.suffix">revue.txt</prop>
</props>
</property>
</bean>
<bean id="userAliases" class="fr.imirhil.april.hebdobot.xml.UserAlias">
<constructor-arg name="source" value="classpath:/fr/imirhil/april/hebdobot/users.xml" />
</bean>
<bean id="bot" class="fr.imirhil.april.hebdobot.irc.BotTest.BotMock" />
</beans>

View File

@ -0,0 +1,166 @@
2011-09-02 12:00:36 <janchou> !debut
2011-09-02 12:00:36 <janchou> % rappel : toute ligne commençant par % ne sera considérée comme un commentaire et non prise en compte dans la synthèse
2011-09-02 12:00:36 <janchou> # 1/ Actions passées ou en cours % quand vous avez fini vous le dites par
2011-09-02 12:00:36 <janchou> % fini
2011-09-02 12:00:55 * coinpan (500c6ecb@gateway/web/freenode/ip.80.12.110.203) a rejoint #april
2011-09-02 12:00:59 <coinpan> coin
2011-09-02 12:01:03 <_PoLuX_> Institutionnel : travail sur consultation cloud
2011-09-02 12:01:10 <janchou> % coinpan : pile à temps, on démarre :)
2011-09-02 12:01:10 <galilea> cloud : fin de la réponse à la consultation européenne
2011-09-02 12:01:15 <_PoLuX_> Institutionnel : remarques sur tv connectée
2011-09-02 12:01:19 <galilea> cloud note en cours
2011-09-02 12:01:24 <aurelia> commande cartes de visites pour _PoLuX_
2011-09-02 12:01:27 <benj> Initiatives Candidats.fr: amélioration de la plate-forme
2011-09-02 12:01:34 <benj> Suivi achat portable Jeanne
2011-09-02 12:01:34 <galilea> cloud : mise en ligne de la consultation
2011-09-02 12:01:37 <aurelia> dépot chèque à la banque
2011-09-02 12:01:41 <janchou> cloud : finalisation réponse consultation européenne, envoi, mise en ligne de la réponse sur le site de l'April
2011-09-02 12:01:42 <benj> Création d'un compte SVN pour galilea
2011-09-02 12:01:46 <benj> Divers relectures
2011-09-02 12:01:48 <_PoLuX_> Suivi divers en trésorerie
2011-09-02 12:01:54 <galilea> cloud : remerciement des participants
2011-09-02 12:01:55 <coinpan> traductions : relayé l'appel à trad de Simon Descarpentries (livre Eloquent Javascript)
2011-09-02 12:01:56 <janchou> TV connectée : suite préparation réponse de l'April
2011-09-02 12:01:58 <benj> %fini
2011-09-02 12:02:11 <coinpan> traductions : publié traduction relue (déclaration d'utilisation de LL)
2011-09-02 12:02:16 <teymour> %oups je suis en retard
2011-09-02 12:02:18 <galilea> agenda 2020 : bilan en cours 2012
2011-09-02 12:02:25 <_PoLuX_> Entretient avec Antoine Chao + CR
2011-09-02 12:02:26 <janchou> Formats ouverts : préparation de l'actu sur la généralisation des standards ouverts dans l'administration
2011-09-02 12:02:32 <aurelia> prise de contact avec nouveau fournisseur poru les t-shirts
2011-09-02 12:02:33 <teymour> réu dossier instit/réunion d'équipe
2011-09-02 12:02:35 <janchou> % teymour : on en est encore aux activités semaine passée
2011-09-02 12:02:38 <_PoLuX_> Relances diverses sur projet de guide libreasso
2011-09-02 12:02:42 <teymour> format ouverts push des infos
2011-09-02 12:02:42 <galilea> pt déj dossiers institutionnels
2011-09-02 12:02:46 <coinpan> traductions : rédaction d'une niouze pour la publication de nouvelles trad + demande de publication
2011-09-02 12:02:48 <benj> Réunion dossiers institutionnels / point d'équipe
2011-09-02 12:02:49 <aurelia> appel à particpation pour la braderie de lille
2011-09-02 12:02:53 <benj> %fini
2011-09-02 12:02:57 <galilea> rapport d'étonnement 1 mois de stage
2011-09-02 12:02:58 <teymour> RPVA rdv ministère de la justice + récupération d'infos
2011-09-02 12:02:59 <aurelia> crétaion page wiki braderie de lille
2011-09-02 12:03:06 <_PoLuX_> Préparation du stand pour la braprendre rdv avec le conseiller credit mut derie de lille
2011-09-02 12:03:07 <coinpan> %fini
2011-09-02 12:03:09 <janchou> entretien journaliste sur Hadopi
2011-09-02 12:03:18 <_PoLuX_> Suivi divers pour le CA
2011-09-02 12:03:19 <teymour> Loop suiv et correction du draft de _PoluX_
2011-09-02 12:03:22 <aurelia> petit dèj institutionnel
2011-09-02 12:03:26 <galilea> examen compétence hadopi sur accès aux info essentielles d'interop
2011-09-02 12:03:31 <janchou> petit déjeuner point d'équipe
2011-09-02 12:03:34 <teymour> envoi du courriel Loop au CA en cours
2011-09-02 12:03:35 <_PoLuX_> Proposition de lettre de soutien au loop
2011-09-02 12:03:39 <galilea> %fini
2011-09-02 12:04:00 <janchou> discussions sur le bilan France Numérique 2012 et réponse à la consultation france numérique 2020
2011-09-02 12:04:02 <aurelia> mise a jour bilan financier des rmll
2011-09-02 12:04:14 <janchou> suivi reprise des travaux parlementaires (et réponses aux QE)
2011-09-02 12:04:23 <teymour> routing d'un appel journaliste RFI sur HADOPI vers axx_ de LQDN
2011-09-02 12:04:23 <_PoLuX_> Participation au petit dej institutionnel
2011-09-02 12:04:27 <aurelia> commabde d'affiches et catalibre pour le stand de la braderie de lille
2011-09-02 12:04:41 <janchou> % teymour : c'était Clare ?
2011-09-02 12:04:49 <_PoLuX_> % fini
2011-09-02 12:05:10 <teymour> %janchou oui elle m'a rappelé en fin de semaine derenière. Tu l'as rajoutée dans les contacts presse ou il faut que je le fasse ?
2011-09-02 12:05:21 <teymour> relecture Cloud Computing
2011-09-02 12:05:41 <janchou> % teymour : je m'en occupe (je l'ai vue mardi)
2011-09-02 12:05:42 <aurelia> prise de rdv avec le conseiller bancaire
2011-09-02 12:05:59 <teymour> % janchou galilea pour info, on m'a fait des compliments sur le draft de note sur le cloud ce matin
2011-09-02 12:06:20 <galilea> %teymour :)
2011-09-02 12:06:30 <teymour> %janchou cool pour Clare, je pensais qu'elle avait laché l'affaire avec nous pour son sujet
2011-09-02 12:06:36 <aurelia> gestion relance 1er septembre
2011-09-02 12:06:45 <PhilippeVay> commande d'un livre sur Drupal chez Eyrolles ^^
2011-09-02 12:06:46 <teymour> %fini
2011-09-02 12:06:48 <aurelia> gestion radiation 1er septembre
2011-09-02 12:06:52 <PhilippeVay> % fini
2011-09-02 12:07:10 <aurelia> mise a jour lettre interne
2011-09-02 12:07:29 <janchou> % fini
2011-09-02 12:07:39 <janchou> mise à jour lettre interme
2011-09-02 12:07:42 <janchou> % fini pour de vrai
2011-09-02 12:07:53 <aurelia> % fini
2011-09-02 12:08:13 <janchou> % on va passer à la suite : Actions à venir
2011-09-02 12:08:13 <janchou> # 2/ Actions à venir
2011-09-02 12:08:13 <janchou> % quand vous avez fini vous le dites par % fini
2011-09-02 12:08:23 <_PoLuX_> Participation Braderie de Lille
2011-09-02 12:08:27 <echarp> revue de presse
2011-09-02 12:08:29 <janchou> cloud : relecture de la note
2011-09-02 12:08:30 <galilea> cloud : note en cours
2011-09-02 12:08:31 <benj> Réception/configuration éventuelle portable Jeanne
2011-09-02 12:08:33 <_PoLuX_> Rédaction du guide libreasso
2011-09-02 12:08:38 <echarp> 4 questions à responsable de groupe
2011-09-02 12:08:43 <_PoLuX_> Relance des contributeurs pour libreasso
2011-09-02 12:08:46 <benj> Améliorations initiatives candidats.fr
2011-09-02 12:08:48 <janchou> TV connectée : envoi de la réponse à l'appel à contribution
2011-09-02 12:08:49 <galilea> mise à jour cahiers candidats. fr
2011-09-02 12:09:00 <janchou> france numérique : suite discussion, préparation réponse
2011-09-02 12:09:01 <galilea> agenda numérique 2020
2011-09-02 12:09:11 <janchou> marchés publics : conférence à l'AMIF
2011-09-02 12:09:11 <_PoLuX_> + Suivi divers et dépillage post-été
2011-09-02 12:09:14 <coinpan> traductions : faire une trad
2011-09-02 12:09:16 * xpo est parti (Quit: xpo)
2011-09-02 12:09:17 <galilea> RPVA: voir pour les contacts
2011-09-02 12:09:18 <aurelia> pointage compta aout
2011-09-02 12:09:23 <coinpan> traductions : générer un nouveau listing de documents àtraduire
2011-09-02 12:09:25 <benj> %fini
2011-09-02 12:09:29 <janchou> RPVA : suivi contacts
2011-09-02 12:09:33 <benj> Formation SVN Marie
2011-09-02 12:09:33 <coinpan> %fini
2011-09-02 12:09:34 <teymour> RPVA contacts
2011-09-02 12:09:35 <janchou> vente liée : diverses relances
2011-09-02 12:09:35 <galilea> comprendre SVN
2011-09-02 12:09:35 <echarp> %fini
2011-09-02 12:09:36 <benj> %fini pour de vrai
2011-09-02 12:09:44 <teymour> Cloud relecture
2011-09-02 12:09:47 <janchou> % galilea : impossible :)
2011-09-02 12:09:52 <galilea> %fini
2011-09-02 12:09:52 <aurelia> % galilea bonne chance :)
2011-09-02 12:10:02 <benj> %/me aime les défis
2011-09-02 12:10:03 <teymour> Marchés public, mettre en relation janchou avec Justice
2011-09-02 12:10:05 <galilea> % l'espoir fait vivre
2011-09-02 12:10:10 <aurelia> suivi bounce aout et septembre
2011-09-02 12:10:18 <janchou> ACTA : mise à jour sur le site de l'April
2011-09-02 12:10:23 <aurelia> suivi relance
2011-09-02 12:10:30 <teymour> mettre nouveaux contacts dans dotproject
2011-09-02 12:10:45 <teymour> Envoi lettre Loop
2011-09-02 12:10:56 <aurelia> contacter ppsj pour arret
2011-09-02 12:11:17 <janchou> france numérique : envoyer commentaire sur le projet de consultation
2011-09-02 12:11:33 <janchou> vente liée : finalisation / validation de la synthèse ?
2011-09-02 12:11:46 <janchou> %fini
2011-09-02 12:11:48 <aurelia> % fini
2011-09-02 12:12:12 <janchou> % teymour fini ?
2011-09-02 12:12:16 <teymour> %fini
2011-09-02 12:12:27 <janchou> % on va passer à la suite : Points de blocage
2011-09-02 12:12:27 <janchou> ## 3/ Points de blocage existants ou levés cette semaine
2011-09-02 12:12:27 <janchou> % si rien à dire vous dites %ras
2011-09-02 12:12:38 <janchou> laptop : en cours de résolution
2011-09-02 12:12:49 <coinpan> %ras
2011-09-02 12:12:55 <galilea> %ras
2011-09-02 12:12:56 <aurelia> prendre rdv avec le conseiller credit mut > réglé
2011-09-02 12:12:56 <benj> Débloqué bug javascript/json bloquant pour les initiatives
2011-09-02 12:13:08 <teymour> %ras
2011-09-02 12:13:14 <benj> Recu confirmation livraison laptop
2011-09-02 12:13:16 <benj> %fini
2011-09-02 12:13:46 <aurelia> oubli de la braderie de lille, appel à participation tardif
2011-09-02 12:14:11 <janchou> % on va passer à la suite : Points Forts et Points de Vigilance de la réunion
2011-09-02 12:14:12 <janchou> ## 4/ Points forts de la réunion
2011-09-02 12:14:12 <janchou> % 1 mn max
2011-09-02 12:14:12 <janchou> % si rien à dire vous dites %ras
2011-09-02 12:14:25 <coinpan> toujours aussi rapide et motivant
2011-09-02 12:14:30 <janchou> beaucoup de présents, effet rentrée ?
2011-09-02 12:14:41 <aurelia> beaucoup de boulot aussi
2011-09-02 12:14:44 * _bibi (~obibi@office.bearstech.com) a rejoint #april
2011-09-02 12:15:02 <galilea> du boulot on s'ennuie pas !
2011-09-02 12:15:07 <galilea> %fini
2011-09-02 12:15:16 <benj> Retour de plein de gens
2011-09-02 12:15:22 * _bibi (~obibi@office.bearstech.com) a quitté #april
2011-09-02 12:15:26 <galilea> %trop bien le stage :)
2011-09-02 12:15:29 <janchou> % on va passer à la suite : Points de Vigilance de la réunion
2011-09-02 12:15:29 <janchou> ## 5/ Points de vigilance de la réunion
2011-09-02 12:15:29 <janchou> % si rien à dire vous dites
2011-09-02 12:15:29 <janchou> %ras % 1 mn max
2011-09-02 12:15:36 <coinpan> %ras
2011-09-02 12:15:48 <galilea> %ras
2011-09-02 12:16:02 <aurelia> % galilea tu dira plus ça quand tu aura ouvert svn :P
2011-09-02 12:16:05 <janchou> % galilea : oui, tu apprends plein de trucs techniques... /o\
2011-09-02 12:16:26 <benj> %ras
2011-09-02 12:16:26 <janchou> % Fin de la revue hebdomadaire, merci à vous
2011-09-02 12:16:26 <janchou> % Pensez à noter votre bénévalo : http://www.april.org/my?action=benevalo
2011-09-02 12:16:26 <janchou> !fin

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<users xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="users.xsd" />

8
users.sample.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<users xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="users.xsd">
<user>
<realName>Foo Bar</realName>
<nick>foo</nick>
<nick>foo_</nick>
</user>
</users>