Author: vjrj_ Date: 2011-12-27 02:32:05 +0100 (Tue, 27 Dec 2011) New Revision: 1648 Added: trunk/src/main/java/cc/kune/core/server/notifier/ trunk/src/main/java/cc/kune/core/server/notifier/NotifyService.java trunk/src/main/java/cc/kune/core/server/notifier/NotifyServiceDefault.java trunk/src/main/java/cc/kune/core/server/notifier/NotifyType.java trunk/src/main/java/cc/kune/core/server/notifier/UserOnlineSimpleManager.java trunk/src/main/java/cc/kune/core/server/notifier/UsersOnline.java trunk/src/main/java/cc/kune/core/server/scheduler/ trunk/src/main/java/cc/kune/core/server/scheduler/AbstractJob.java trunk/src/main/java/cc/kune/core/server/scheduler/CronServerTasksManager.java trunk/src/main/java/cc/kune/core/server/scheduler/DailyJob.java trunk/src/main/java/cc/kune/core/server/scheduler/HourlyJob.java trunk/src/main/java/cc/kune/core/server/testhelper/ trunk/src/main/java/cc/kune/core/server/testhelper/ctx/ trunk/src/main/java/cc/kune/core/shared/domain/dto/ trunk/src/main/java/cc/kune/core/shared/domain/dto/EmailNotificationFrequency.java trunk/src/main/java/cc/kune/wave/server/WaveEmailNotifier.java trunk/src/test/java/cc/kune/core/server/mail/ trunk/src/test/java/cc/kune/core/server/mail/MailServiceDefaultTest.java Removed: trunk/src/test/java/cc/kune/core/server/testhelper/ Modified: trunk/.classpath trunk/TODO trunk/pom.xml trunk/src/main/java/cc/kune/common/client/actions/ui/descrip/PushButtonDescriptor.java trunk/src/main/java/cc/kune/core/server/KuneRackModule.java trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java trunk/src/main/java/cc/kune/core/server/UserSessionManager.java trunk/src/main/java/cc/kune/core/server/mail/MailService.java trunk/src/main/java/cc/kune/core/server/mail/MailServiceDefault.java trunk/src/main/java/cc/kune/core/server/properties/KuneBasicProperties.java trunk/src/main/java/cc/kune/core/server/rack/RackServletFilter.java trunk/src/main/java/cc/kune/core/server/rpc/UserRPC.java trunk/src/main/java/cc/kune/core/shared/dto/UserDTO.java trunk/src/main/java/cc/kune/domain/User.java trunk/src/main/java/cc/kune/events/client/actions/EventAddMenuItem.java trunk/src/main/java/cc/kune/events/client/viewer/CalendarViewerPresenter.java trunk/src/main/java/cc/kune/wave/server/KuneAgent.java trunk/src/main/java/cc/kune/wave/server/KuneWaveService.java trunk/src/main/java/cc/kune/wave/server/KuneWaveServiceDefault.java trunk/src/main/java/cc/kune/wave/server/ParticipantUtils.java trunk/src/main/resources/kune.properties Log: NEW - # 164: NotificationManager in server side http://kune.ourproject.org/issues/ticket/164 Modified: trunk/.classpath =================================================================== --- trunk/.classpath 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/.classpath 2011-12-27 01:32:05 UTC (rev 1648) @@ -124,6 +124,7 @@ <classpathentry kind="var" path="M2_REPO/org/codehaus/plexus/plexus-container-default/1.0-alpha-8/plexus-container-default-1.0-alpha-8.jar" sourcepath="M2_REPO/org/codehaus/plexus/plexus-container-default/1.0-alpha-8/plexus-container-default-1.0-alpha-8-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.jar" sourcepath="M2_REPO/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/waveprotocol/proto-msg/0.3.8/proto-msg-0.3.8.jar"/> + <classpathentry kind="var" path="M2_REPO/org/quartz-scheduler/quartz/2.1.0/quartz-2.1.0.jar" sourcepath="M2_REPO/org/quartz-scheduler/quartz/2.1.0/quartz-2.1.0-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/w3c/css/sac/1.3/sac-1.3.jar" sourcepath="M2_REPO/org/w3c/css/sac/1.3/sac-1.3-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/seleniumhq/selenium/selenium-android-driver/2.12.0/selenium-android-driver-2.12.0.jar" sourcepath="M2_REPO/org/seleniumhq/selenium/selenium-android-driver/2.12.0/selenium-android-driver-2.12.0-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/seleniumhq/selenium/selenium-api/2.12.0/selenium-api-2.12.0.jar" sourcepath="M2_REPO/org/seleniumhq/selenium/selenium-api/2.12.0/selenium-api-2.12.0-sources.jar"/> Modified: trunk/TODO =================================================================== --- trunk/TODO 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/TODO 2011-12-27 01:32:05 UTC (rev 1648) @@ -12,6 +12,13 @@ nick == assigned to * SHORT-TERM (URGENT) +** Emil notifications for new waves +Email Notifications +How often do you want to receive notifications? + almost immediately + at most hourly + at most daily + I don't need email notifications ** group.inexistentTool nasty error ** calendar support *** gwt-cal + http://ical4j.sourceforge.net/introduction.html Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/pom.xml 2011-12-27 01:32:05 UTC (rev 1648) @@ -694,6 +694,11 @@ <artifactId>mail</artifactId> <version>1.4.4</version> </dependency> + <dependency> + <groupId>org.quartz-scheduler</groupId> + <artifactId>quartz</artifactId> + <version>2.1.0</version> + </dependency> <!-- calendar --> <dependency> <groupId>com.bradrydzewski</groupId> Modified: trunk/src/main/java/cc/kune/common/client/actions/ui/descrip/PushButtonDescriptor.java =================================================================== --- trunk/src/main/java/cc/kune/common/client/actions/ui/descrip/PushButtonDescriptor.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/common/client/actions/ui/descrip/PushButtonDescriptor.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -20,34 +20,40 @@ package cc.kune.common.client.actions.ui.descrip; import cc.kune.common.client.actions.AbstractAction; +import cc.kune.common.client.actions.Action; public class PushButtonDescriptor extends ButtonDescriptor { - public static final String PUSHED = "pushed"; + public static final String PUSHED = "pushed"; - public PushButtonDescriptor(final AbstractAction action) { - super(action); - setPushedImpl(false); - } + public PushButtonDescriptor(final AbstractAction action) { + super(action); + setPushedImpl(false); + } - public PushButtonDescriptor(final PushButtonDescriptor button) { - this(button.getAction()); - } + public PushButtonDescriptor(final PushButtonDescriptor button) { + this(button.getAction()); + } - @Override - public Class<?> getType() { - return PushButtonDescriptor.class; - } + public PushButtonDescriptor(final String text, final AbstractAction action) { + this(action); + putValue(Action.NAME, text); + } - public boolean isPushed() { - return (Boolean) getValue(PUSHED); - } + @Override + public Class<?> getType() { + return PushButtonDescriptor.class; + } - public void setPushed(final boolean pushed) { - setPushedImpl(pushed); - } + public boolean isPushed() { + return (Boolean) getValue(PUSHED); + } - private void setPushedImpl(final boolean pushed) { - putValue(PUSHED, pushed); - } + public void setPushed(final boolean pushed) { + setPushedImpl(pushed); + } + + private void setPushedImpl(final boolean pushed) { + putValue(PUSHED, pushed); + } } Modified: trunk/src/main/java/cc/kune/core/server/KuneRackModule.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/KuneRackModule.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/core/server/KuneRackModule.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -115,7 +115,6 @@ install(FinderRegistry.init(jpaPersistModule)); bindInterceptor(Matchers.annotatedWith(LogThis.class), new NotInObject(), new LoggerMethodInterceptor()); - // bindConstant().annotatedWith(PropertiesFileName.class).to(kuneConfig); if (sessionScope != null) { bindScope(SessionScoped.class, sessionScope); } Modified: trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -86,6 +86,9 @@ import cc.kune.core.server.manager.impl.UserManagerDefault; import cc.kune.core.server.mapper.DozerMapper; import cc.kune.core.server.mapper.Mapper; +import cc.kune.core.server.notifier.NotifyService; +import cc.kune.core.server.notifier.NotifyServiceDefault; +import cc.kune.core.server.notifier.UsersOnline; import cc.kune.core.server.rpc.ContentRPC; import cc.kune.core.server.rpc.GroupRPC; import cc.kune.core.server.rpc.I18nRPC; @@ -93,6 +96,7 @@ import cc.kune.core.server.rpc.SocialNetworkRPC; import cc.kune.core.server.rpc.StatsRPC; import cc.kune.core.server.rpc.UserRPC; +import cc.kune.core.server.scheduler.CronServerTasksManager; import cc.kune.core.server.state.StateService; import cc.kune.core.server.state.StateServiceDefault; import cc.kune.core.server.stats.StatsService; @@ -109,7 +113,9 @@ import cc.kune.wave.server.KuneWaveService; import cc.kune.wave.server.KuneWaveServiceDefault; import cc.kune.wave.server.ParticipantUtils; +import cc.kune.wave.server.WaveEmailNotifier; +import com.google.inject.Singleton; import com.google.inject.matcher.Matchers; public class PlatformServerModule extends AbstractExtendedModule { @@ -186,7 +192,11 @@ bind(EntityLogoUploadManager.class); bind(EntityLogoDownloadManager.class); bind(ParticipantUtils.class); + bind(UsersOnline.class).to(UserSessionManager.class).in(Singleton.class); requestStaticInjection(AccessRightsUtils.class); + bind(CronServerTasksManager.class).in(Singleton.class); + bind(NotifyService.class).to(NotifyServiceDefault.class).in(Singleton.class); + bind(WaveEmailNotifier.class).in(Singleton.class); bindInterceptor(Matchers.any(), Matchers.annotatedWith(Authenticated.class), outermostCall(new AuthenticatedMethodInterceptor())); bindInterceptor(Matchers.any(), Matchers.annotatedWith(Authorizated.class), Modified: trunk/src/main/java/cc/kune/core/server/UserSessionManager.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/UserSessionManager.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/core/server/UserSessionManager.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -19,7 +19,11 @@ */ package cc.kune.core.server; +import java.util.HashSet; +import java.util.Set; + import cc.kune.core.server.manager.UserManager; +import cc.kune.core.server.notifier.UsersOnline; import cc.kune.domain.User; import com.google.inject.Inject; @@ -27,8 +31,9 @@ import com.google.inject.Singleton; @Singleton -public class UserSessionManager { +public class UserSessionManager implements UsersOnline { + private final Set<String> logins; private final UserManager manager; private final Provider<UserSession> userSessionProv; @@ -36,12 +41,25 @@ public UserSessionManager(final UserManager manager, final Provider<UserSession> userSessionProv) { this.manager = manager; this.userSessionProv = userSessionProv; + // For now the implementation of this can be very inaccurate (if we + // login/logout several times with different clients) and not scalable + // (stored in a MAP). Possible fix, to use jabber status + // More info: + // http://stackoverflow.com/questions/4592961/how-can-i-check-which-all-users-a... + // + // Best way maybe it's accessing openfire db: + // http://www.mastertheboss.com/jboss-howto/45-jboss-persistence/110-jboss-pers... + logins = new HashSet<String>(); } public String getHash() { return getUserSession().getHash(); } + private String getUserLoggedShortName() { + return getUser().getShortName(); + } + public User getUser() { return manager.find(getUserSession().getUserId()); } @@ -50,6 +68,11 @@ return userSessionProv.get(); } + @Override + public boolean isLogged(final String shortname) { + return logins.contains(shortname); + } + public boolean isUserLoggedIn() { return getUserSession().getUserId() != null; } @@ -61,10 +84,20 @@ public void login(final Long userId, final String newUserHash) { getUserSession().setUserId(userId); getUserSession().setHash(newUserHash); + updateLoggedUser(); } public void logout() { + if (isUserLoggedIn()) { + logins.remove(getUserLoggedShortName()); + } getUserSession().setUserId(null); getUserSession().setHash(null); } + + public void updateLoggedUser() { + if (isUserLoggedIn()) { + logins.add(getUserLoggedShortName()); + } + } } Modified: trunk/src/main/java/cc/kune/core/server/mail/MailService.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/mail/MailService.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/core/server/mail/MailService.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -30,10 +30,10 @@ * the email subject * @param body * the body of the email in html format - * @param to - * the recipient + * @param tos + * the recipients */ - void sendHtml(FormatedString subject, FormatedString body, String to); + void sendHtml(FormatedString subject, FormatedString body, String... tos); /** * Sends html email @@ -47,7 +47,7 @@ * @param tos * the recipients */ - void sendHtml(FormatedString subject, FormatedString body, String from, String... tos); + void sendHtml(String from, FormatedString subject, FormatedString body, String... tos); /** * @@ -57,10 +57,10 @@ * the email subject * @param body * the body of the email in text format - * @param to - * the recipient + * @param tos + * the recipients */ - void sendPlain(FormatedString subject, FormatedString body, String to); + void sendPlain(FormatedString subject, FormatedString body, String... tos); /** * Sends plain email @@ -74,6 +74,6 @@ * @param tos * the recipients */ - void sendPlain(FormatedString subject, FormatedString body, String from, String... tos); + void sendPlain(String from, FormatedString subject, FormatedString body, String... tos); } Modified: trunk/src/main/java/cc/kune/core/server/mail/MailServiceDefault.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/mail/MailServiceDefault.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/core/server/mail/MailServiceDefault.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -32,26 +32,55 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import cc.kune.core.client.errors.DefaultException; +import cc.kune.core.server.LogThis; import cc.kune.core.server.properties.KuneProperties; +import com.google.common.base.Preconditions; import com.google.inject.Inject; import com.google.inject.Singleton; @Singleton +@LogThis public class MailServiceDefault implements MailService { public static class FormatedString { + public static FormatedString build(final String plainMsg) { + return new FormatedString(plainMsg); + } - private final String string; + public static FormatedString build(final String template, final Object... args) { + return new FormatedString(template, args); + } + private final Object[] args; + private String template; + + public FormatedString(final String plainMsg) { + template = plainMsg; + args = null; + } + public FormatedString(final String template, final Object... args) { - string = String.format(template, args); + this.template = template; + this.args = args; } public String getString() { - return string; + Preconditions.checkNotNull(template, "Template of FormatedString cannot be null"); + return args == null ? template : String.format(template, args); } + + public String getTemplate() { + return template; + } + + /* + * Used to translate the template to the user language (when you don't know + * already the language of the user) + */ + public void setTemplate(final String template) { + this.template = template; + } } Log log = LogFactory.getLog(MailServiceDefault.class); @@ -68,8 +97,8 @@ props.put("mail.smtp.host", smtpServer); } - private void send(final FormatedString subject, final FormatedString body, final boolean isHtml, - final String from, final String... tos) { + private void send(final String from, final FormatedString subject, final FormatedString body, + final boolean isHtml, final String... tos) { if (smtpSkip) { return; } @@ -79,47 +108,50 @@ // Define message final MimeMessage message = new MimeMessage(session); - try { - message.setFrom(new InternetAddress(from)); - for (final String to : tos) { + for (final String to : tos) { + try { + message.setFrom(new InternetAddress(from)); message.addRecipient(Message.RecipientType.TO, new InternetAddress(to)); + final String formatedSubject = subject.getString(); + message.setSubject(formatedSubject); + final String formatedBody = body.getString(); + if (isHtml) { + message.setContent(formatedBody, "text/html"); + } else { + message.setText(formatedBody); + } + // Send message + Transport.send(message); + } catch (final AddressException e) { + } catch (final MessagingException e) { + final String error = String.format( + "Error sendind an email to %s, with subject: %s, and body: %s", from, subject, to); + log.error(error, e); + // Better not to throw exceptions because users emails can be wrong... + // throw new DefaultException(error, e); } - final String formatedSubject = subject.getString(); - message.setSubject(formatedSubject); - final String formatedBody = body.getString(); - if (isHtml) { - message.setContent(formatedBody, "text/html"); - } else { - message.setText(formatedBody); - } - // Send message - Transport.send(message); - } catch (final AddressException e) { - } catch (final MessagingException e) { - log.error("Error sending the email", e); - throw new DefaultException("Error sending an email"); } } @Override - public void sendHtml(final FormatedString subject, final FormatedString body, final String to) { - send(subject, body, true, smtpDefaultFrom, to); + public void sendHtml(final FormatedString subject, final FormatedString body, final String... tos) { + send(smtpDefaultFrom, subject, body, true, tos); } @Override - public void sendHtml(final FormatedString subject, final FormatedString body, final String from, + public void sendHtml(final String from, final FormatedString subject, final FormatedString body, final String... tos) { - send(subject, body, true, from, tos); + send(from, subject, body, true, tos); } @Override - public void sendPlain(final FormatedString subject, final FormatedString body, final String to) { - send(subject, body, false, smtpDefaultFrom, to); + public void sendPlain(final FormatedString subject, final FormatedString body, final String... tos) { + send(smtpDefaultFrom, subject, body, false, tos); } @Override - public void sendPlain(final FormatedString subject, final FormatedString body, final String from, + public void sendPlain(final String from, final FormatedString subject, final FormatedString body, final String... tos) { - send(subject, body, false, from, tos); + send(from, subject, body, false, tos); } } Added: trunk/src/main/java/cc/kune/core/server/notifier/NotifyService.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/notifier/NotifyService.java (rev 0) +++ trunk/src/main/java/cc/kune/core/server/notifier/NotifyService.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,45 @@ +package cc.kune.core.server.notifier; + +import cc.kune.core.server.mail.MailServiceDefault.FormatedString; + +/** + * The Interface NotifyService. + */ +public interface NotifyService { + + /** + * Send a message to the recipients (also translate the subject/body using the + * user language) + * + * @param notifyType + * the notify type (email, etc) + * @param subject + * the subject of the message (not translated) + * @param body + * the body of the message (not translated) but with %s + * {@link String.format} args + * @param isHtml + * if the body is html + * @param recipients + * the recipients shortnames (without domain) + */ + void send(NotifyType notifyType, FormatedString subject, FormatedString body, boolean isHtml, + String... recipients); + + /** + * Send a message to the recipients (also translate the subject/body using the + * user language) + * + * @param notifyType + * the notify type (email, etc) + * @param subject + * the subject of the message + * @param body + * the body of the message (no translated) but with some %s + * {@link String.format} args + * @param recipients + * the recipients shortnames (without domain) + */ + void send(NotifyType notifyType, FormatedString subject, FormatedString body, String... recipients); + +} Added: trunk/src/main/java/cc/kune/core/server/notifier/NotifyServiceDefault.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/notifier/NotifyServiceDefault.java (rev 0) +++ trunk/src/main/java/cc/kune/core/server/notifier/NotifyServiceDefault.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,89 @@ +package cc.kune.core.server.notifier; + +import javax.persistence.NoResultException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import cc.kune.core.server.mail.MailService; +import cc.kune.core.server.mail.MailServiceDefault.FormatedString; +import cc.kune.core.server.manager.I18nTranslationManager; +import cc.kune.core.server.manager.UserManager; +import cc.kune.core.server.xmpp.XmppManager; +import cc.kune.domain.User; +import cc.kune.wave.server.KuneWaveService; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +@Singleton +public class NotifyServiceDefault implements NotifyService { + public static final Log LOG = LogFactory.getLog(NotifyServiceDefault.class); + private final I18nTranslationManager i18n; + private final MailService mailService; + private final UserManager userManager; + private final KuneWaveService waveService; + private final XmppManager xmppManager; + + @Inject + public NotifyServiceDefault(final MailService mailService, final KuneWaveService waveService, + final XmppManager xmppManager, final UserManager userManager, final I18nTranslationManager i18n) { + this.mailService = mailService; + this.waveService = waveService; + this.xmppManager = xmppManager; + this.userManager = userManager; + this.i18n = i18n; + } + + @Override + public void send(final NotifyType notifyType, final FormatedString subject, final FormatedString body, + final boolean isHtml, final String... recipients) { + for (final String recipient : recipients) { + User user; + try { + user = userManager.findByShortname(recipient); + } catch (final NoResultException e) { + LOG.info(String.format("The recipient %s is not a local user, don't notify", recipient)); + continue; + } + // Translate per recipient language + final String subjectTranslation = i18n.getTranslation(user.getLanguage().getCode(), + subject.getTemplate(), ""); + if (subjectTranslation != null) { + subject.setTemplate(subjectTranslation); + } + final String bodyTranslation = i18n.getTranslation(user.getLanguage().getCode(), + body.getTemplate(), ""); + if (bodyTranslation != null) { + body.setTemplate(bodyTranslation); + } + switch (notifyType) { + case chat: + xmppManager.sendMessage(recipient, + String.format("<b>%s</b>%s", subject.getString(), body.getString())); + break; + case email: + final String email = user.getEmail(); + if (isHtml) { + mailService.sendHtml(subject, body, email); + } else { + mailService.sendPlain(subject, body, email); + } + break; + case wave: + if (isHtml) { + LOG.error("Wave html messages not supported yet"); + } + waveService.createWave(subject.getString(), body.getString(), recipient); + break; + } + } + } + + @Override + public void send(final NotifyType notifyType, final FormatedString subject, final FormatedString body, + final String... dests) { + send(notifyType, subject, body, false, dests); + } + +} Added: trunk/src/main/java/cc/kune/core/server/notifier/NotifyType.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/notifier/NotifyType.java (rev 0) +++ trunk/src/main/java/cc/kune/core/server/notifier/NotifyType.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,9 @@ +package cc.kune.core.server.notifier; + +/** + * Type of notifications for users + * + */ +public enum NotifyType { + chat, email, wave +} Added: trunk/src/main/java/cc/kune/core/server/notifier/UserOnlineSimpleManager.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/notifier/UserOnlineSimpleManager.java (rev 0) +++ trunk/src/main/java/cc/kune/core/server/notifier/UserOnlineSimpleManager.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,5 @@ +package cc.kune.core.server.notifier; + +public class UserOnlineSimpleManager { + +} Added: trunk/src/main/java/cc/kune/core/server/notifier/UsersOnline.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/notifier/UsersOnline.java (rev 0) +++ trunk/src/main/java/cc/kune/core/server/notifier/UsersOnline.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,16 @@ +package cc.kune.core.server.notifier; + +public interface UsersOnline { + + /** + * For now the implementation of this can be very inaccurate (if we + * login/logout several times with different clients) and not scalable (stored + * in a MAP). Possible fix, to use jabber status + * + * @param shortname + * of the user + * @return true if is logged + */ + boolean isLogged(String shortname); + +} Modified: trunk/src/main/java/cc/kune/core/server/properties/KuneBasicProperties.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/properties/KuneBasicProperties.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/core/server/properties/KuneBasicProperties.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -62,10 +62,25 @@ return properties.get(KuneProperties.SITE_SHORTNAME); } + /** + * Gets the site common name (can be something like "this foo site" not + * necessary a domain) + * + * @return the site common name + */ public String getSiteCommonName() { return properties.get(KuneProperties.SITE_COMMON_NAME); } + /** + * Gets the site domain (something like example.org) + * + * @return the site domain + */ + public String getSiteDomain() { + return properties.get(KuneProperties.SITE_DOMAIN); + } + public String getWelcomewave() { return properties.get(KuneProperties.WELCOME_WAVE); } Modified: trunk/src/main/java/cc/kune/core/server/rack/RackServletFilter.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/rack/RackServletFilter.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/core/server/rack/RackServletFilter.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -32,11 +32,14 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.quartz.SchedulerException; import org.waveprotocol.box.server.rpc.ServerRpcProvider; import cc.kune.core.server.ServerException; import cc.kune.core.server.rack.dock.Dock; import cc.kune.core.server.rack.dock.RequestMatcher; +import cc.kune.core.server.scheduler.CronServerTasksManager; +import cc.kune.wave.server.WaveEmailNotifier; import com.google.inject.Injector; @@ -137,14 +140,18 @@ final RackBuilder builder = new RackBuilder(); module.configure(builder); rack = builder.getRack(); - // final WaveStarter waveStarter = new WaveStarter(); - // final Injector waveChildInjector = waveStarter.runMain(); injector = (Injector) filterConfig.getServletContext().getAttribute(INJECTOR_PARENT_ATTRIBUTE); final Injector kuneChildInjector = installInjector(filterConfig, rack, injector); startContainerListeners(rack.getListeners(), kuneChildInjector); docks = rack.getDocks(); excludes = rack.getExcludes(); initFilters(filterConfig); + kuneChildInjector.getInstance(WaveEmailNotifier.class); + try { + kuneChildInjector.getInstance(CronServerTasksManager.class).start(); + } catch (final SchedulerException e) { + LOG.error("Error starting cron scheduler", e); + } LOG.debug("INITIALIZATION DONE!"); } Modified: trunk/src/main/java/cc/kune/core/server/rpc/UserRPC.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/rpc/UserRPC.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/core/server/rpc/UserRPC.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -162,16 +162,14 @@ @Transactional public void logout(final String userHash) throws DefaultException { userSessionManager.logout(); - // FIXME final SessionService sessionService = - // sessionServiceProvider.get(); - // FIXME sessionService.getNewSession(); } @Override @Authenticated(mandatory = false) @Transactional public void onlyCheckSession(final String userHash) throws DefaultException { - // Do nothing @Authenticated checks user session + // Do almost nothing @Authenticated checks user session + userSessionManager.updateLoggedUser(); } @Override @@ -179,6 +177,7 @@ @Transactional public UserInfoDTO reloadUserInfo(final String userHash) throws DefaultException { final User user = userSessionManager.getUser(); + userSessionManager.updateLoggedUser(); return loadUserInfo(user); } @@ -205,6 +204,7 @@ throw new AccessViolationException(); } final User userUpdated = userManager.update(id, user, lang); + userSessionManager.updateLoggedUser(); return contentRPC.getContent(userHash, userUpdated.getUserGroup().getStateToken()); } } Added: trunk/src/main/java/cc/kune/core/server/scheduler/AbstractJob.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/scheduler/AbstractJob.java (rev 0) +++ trunk/src/main/java/cc/kune/core/server/scheduler/AbstractJob.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,26 @@ +package cc.kune.core.server.scheduler; + +import static org.quartz.CronScheduleBuilder.cronSchedule; +import static org.quartz.JobBuilder.newJob; +import static org.quartz.TriggerBuilder.newTrigger; + +import java.text.ParseException; + +import org.quartz.CronTrigger; +import org.quartz.Job; +import org.quartz.JobDetail; +import org.quartz.SchedulerException; + +public abstract class AbstractJob implements Job { + private static final String DEF_GROUP = "groupdef"; + + public AbstractJob(final CronServerTasksManager manager, final String cronExpression) + throws ParseException, SchedulerException { + final JobDetail job = newJob(HourlyJob.class).withIdentity("hourlyjob1", DEF_GROUP).build(); + + final CronTrigger trigger = newTrigger().withIdentity("hourlytrigger1", DEF_GROUP).withSchedule( + cronSchedule(cronExpression)).build(); + + manager.scheduleJob(job, trigger); + } +} Added: trunk/src/main/java/cc/kune/core/server/scheduler/CronServerTasksManager.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/scheduler/CronServerTasksManager.java (rev 0) +++ trunk/src/main/java/cc/kune/core/server/scheduler/CronServerTasksManager.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,34 @@ +package cc.kune.core.server.scheduler; + +import java.util.Date; + +import org.quartz.CronTrigger; +import org.quartz.JobDetail; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.impl.StdSchedulerFactory; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +@Singleton +public class CronServerTasksManager { + private final Scheduler sched; + + @Inject + public CronServerTasksManager(final StdSchedulerFactory sf) throws SchedulerException { + sched = sf.getScheduler(); + } + + public Date scheduleJob(final JobDetail job, final CronTrigger trigger) throws SchedulerException { + return sched.scheduleJob(job, trigger); + } + + public void start() throws SchedulerException { + sched.start(); + } + + public void stop() throws SchedulerException { + sched.shutdown(true); + } +} Added: trunk/src/main/java/cc/kune/core/server/scheduler/DailyJob.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/scheduler/DailyJob.java (rev 0) +++ trunk/src/main/java/cc/kune/core/server/scheduler/DailyJob.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,13 @@ +package cc.kune.core.server.scheduler; + +import java.text.ParseException; + +import org.quartz.SchedulerException; + +public abstract class DailyJob extends AbstractJob { + + public DailyJob(final CronServerTasksManager manager) throws ParseException, SchedulerException { + super(manager, "0 0 * * * ?"); + } + +} Added: trunk/src/main/java/cc/kune/core/server/scheduler/HourlyJob.java =================================================================== --- trunk/src/main/java/cc/kune/core/server/scheduler/HourlyJob.java (rev 0) +++ trunk/src/main/java/cc/kune/core/server/scheduler/HourlyJob.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,13 @@ +package cc.kune.core.server.scheduler; + +import java.text.ParseException; + +import org.quartz.SchedulerException; + +public abstract class HourlyJob extends AbstractJob { + + public HourlyJob(final CronServerTasksManager manager) throws ParseException, SchedulerException { + super(manager, "0 * * * * ?"); + } + +} Copied: trunk/src/main/java/cc/kune/core/server/testhelper/ctx (from rev 1647, trunk/src/test/java/cc/kune/core/server/testhelper/ctx) Added: trunk/src/main/java/cc/kune/core/shared/domain/dto/EmailNotificationFrequency.java =================================================================== --- trunk/src/main/java/cc/kune/core/shared/domain/dto/EmailNotificationFrequency.java (rev 0) +++ trunk/src/main/java/cc/kune/core/shared/domain/dto/EmailNotificationFrequency.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,29 @@ +/* + * + * Copyright (C) 2007-2009 The kune development team (see CREDITS for details) + * This file is part of kune. + * + * This program 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. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +package cc.kune.core.shared.domain.dto; + +import com.google.gwt.user.client.rpc.IsSerializable; + +public enum EmailNotificationFrequency implements IsSerializable { + daily, // at most daily, + hourly, // at most hourly + immediately, // almost immediately + no // I don't need email notifications +} Modified: trunk/src/main/java/cc/kune/core/shared/dto/UserDTO.java =================================================================== --- trunk/src/main/java/cc/kune/core/shared/dto/UserDTO.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/core/shared/dto/UserDTO.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -19,142 +19,153 @@ */ package cc.kune.core.shared.dto; +import cc.kune.core.shared.domain.dto.EmailNotificationFrequency; + import com.google.gwt.user.client.rpc.IsSerializable; public class UserDTO implements IsSerializable { - private Long id; - private String name; - private String shortName; - private I18nLanguageDTO language; - private I18nCountryDTO country; - private TimeZoneDTO timezone; - private String password; - private String email; - private String avatar; - private boolean publishRoster; - private SubscriptionMode subscriptionMode; - private String chatColor; + private String avatar; + private String chatColor; + private I18nCountryDTO country; + private String email; + private EmailNotificationFrequency emailNotifFreq; + private Long id; + private I18nLanguageDTO language; + private String name; + private String password; + private boolean publishRoster; + private String shortName; + private SubscriptionMode subscriptionMode; + private TimeZoneDTO timezone; - public UserDTO() { - this(null, null, null, null, null, null, null, null, true, null, null); - } + public UserDTO() { + this(null, null, null, null, null, null, null, null, true, null, null); + } - public UserDTO(final String shortName, final String name, final String password, final String email, - final I18nLanguageDTO language, final I18nCountryDTO country, final TimeZoneDTO timezone, - final String avatar, final boolean publishRoster, final SubscriptionMode subscriptionMode, - final String chatColor) { - this.name = name; - this.shortName = shortName; - this.password = password; - this.email = email; - this.language = language; - this.country = country; - this.timezone = timezone; - this.avatar = avatar; - this.publishRoster = publishRoster; - this.subscriptionMode = subscriptionMode; - this.chatColor = chatColor; - } + public UserDTO(final String shortName, final String name, final String password, final String email, + final I18nLanguageDTO language, final I18nCountryDTO country, final TimeZoneDTO timezone, + final String avatar, final boolean publishRoster, final SubscriptionMode subscriptionMode, + final String chatColor) { + this.name = name; + this.shortName = shortName; + this.password = password; + this.email = email; + this.language = language; + this.country = country; + this.timezone = timezone; + this.avatar = avatar; + this.publishRoster = publishRoster; + this.subscriptionMode = subscriptionMode; + this.chatColor = chatColor; + } - public String getAvatar() { - return avatar; - } + public String getAvatar() { + return avatar; + } - public String getChatColor() { - return chatColor; - } + public String getChatColor() { + return chatColor; + } - public I18nCountryDTO getCountry() { - return country; - } + public I18nCountryDTO getCountry() { + return country; + } - public String getEmail() { - return email; - } + public String getEmail() { + return email; + } - public Long getId() { - return id; - } + public EmailNotificationFrequency getEmailNotifFreq() { + return emailNotifFreq; + } - public I18nLanguageDTO getLanguage() { - return language; - } + public Long getId() { + return id; + } - public String getName() { - return name; - } + public I18nLanguageDTO getLanguage() { + return language; + } - public String getPassword() { - return password; - } + public String getName() { + return name; + } - public String getShortName() { - return shortName; - } + public String getPassword() { + return password; + } - public SubscriptionMode getSubscriptionMode() { - return subscriptionMode; - } + public String getShortName() { + return shortName; + } - public TimeZoneDTO getTimezone() { - return timezone; - } + public SubscriptionMode getSubscriptionMode() { + return subscriptionMode; + } - public boolean isPublishRoster() { - return publishRoster; - } + public TimeZoneDTO getTimezone() { + return timezone; + } - public void setAvatar(final String avatar) { - this.avatar = avatar; - } + public boolean isPublishRoster() { + return publishRoster; + } - public void setChatColor(final String chatColor) { - this.chatColor = chatColor; - } + public void setAvatar(final String avatar) { + this.avatar = avatar; + } - public void setCountry(final I18nCountryDTO country) { - this.country = country; - } + public void setChatColor(final String chatColor) { + this.chatColor = chatColor; + } - public void setEmail(final String email) { - this.email = email; - } + public void setCountry(final I18nCountryDTO country) { + this.country = country; + } - public void setId(final Long id) { - this.id = id; - } + public void setEmail(final String email) { + this.email = email; + } - public void setLanguage(final I18nLanguageDTO language) { - this.language = language; - } + public void setEmailNotifFreq(final EmailNotificationFrequency emailNotifFreq) { + this.emailNotifFreq = emailNotifFreq; + } - public void setName(final String name) { - this.name = name; - } + public void setId(final Long id) { + this.id = id; + } - public void setPassword(final String password) { - this.password = password; - } + public void setLanguage(final I18nLanguageDTO language) { + this.language = language; + } - public void setPublishRoster(final boolean publishRoster) { - this.publishRoster = publishRoster; - } + public void setName(final String name) { + this.name = name; + } - public void setShortName(final String shortName) { - this.shortName = shortName; - } + public void setPassword(final String password) { + this.password = password; + } - public void setSubscriptionMode(final SubscriptionMode subscriptionMode) { - this.subscriptionMode = subscriptionMode; - } + public void setPublishRoster(final boolean publishRoster) { + this.publishRoster = publishRoster; + } - public void setTimezone(final TimeZoneDTO timezone) { - this.timezone = timezone; - } + public void setShortName(final String shortName) { + this.shortName = shortName; + } - @Override - public String toString() { - return "UserDTO[" + shortName + "]"; - } + public void setSubscriptionMode(final SubscriptionMode subscriptionMode) { + this.subscriptionMode = subscriptionMode; + } + public void setTimezone(final TimeZoneDTO timezone) { + this.timezone = timezone; + } + + @Override + public String toString() { + return "UserDTO[" + shortName + "]"; + } + } Modified: trunk/src/main/java/cc/kune/domain/User.java =================================================================== --- trunk/src/main/java/cc/kune/domain/User.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/domain/User.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -46,6 +46,7 @@ import org.hibernate.validator.Pattern; import cc.kune.core.shared.domain.UserSNetVisibility; +import cc.kune.core.shared.domain.dto.EmailNotificationFrequency; import cc.kune.core.shared.domain.utils.StateToken; import cc.kune.domain.utils.HasId; @@ -54,6 +55,8 @@ @Table(name = "kusers") public class User implements HasId { + private static final EmailNotificationFrequency DEF_EMAIL_FREQ = EmailNotificationFrequency.immediately; + // public static final String PROPS_ID = "userprops"; // see: http://docs.codehaus.org/display/PICO/Good+Citizen: // Never expect or return null @@ -80,14 +83,17 @@ @Length(min = 1) private String email; + @Enumerated(EnumType.STRING) + private EmailNotificationFrequency emailNotifFreq; + + // @OneToOne(cascade = CascadeType.REMOVE) + // private final CustomProperties customProperties; + @Id @DocumentId @GeneratedValue private Long id; - // @OneToOne(cascade = CascadeType.REMOVE) - // private final CustomProperties customProperties; - @ManyToOne @NotNull private I18nLanguage language; @@ -146,6 +152,7 @@ sNetVisibility = UserSNetVisibility.anyone; this.createdOn = System.currentTimeMillis(); this.lastLogin = null; + emailNotifFreq = DEF_EMAIL_FREQ; // this.properties = properties; } @@ -204,6 +211,10 @@ // return customProperties; // } + public EmailNotificationFrequency getEmailNotifFreq() { + return emailNotifFreq == null ? DEF_EMAIL_FREQ : emailNotifFreq; + } + public boolean getHasLogo() { return hasLogo(); } @@ -229,14 +240,14 @@ return password; } + // public Properties getProperties() { + // return properties; + // } + public byte[] getSalt() { return salt; } - // public Properties getProperties() { - // return properties; - // } - public String getShortName() { return shortName; } @@ -283,6 +294,10 @@ this.email = email; } + public void setEmailNotifFreq(final EmailNotificationFrequency emailNotifFreq) { + this.emailNotifFreq = emailNotifFreq; + } + @Override public void setId(final Long id) { this.id = id; Modified: trunk/src/main/java/cc/kune/events/client/actions/EventAddMenuItem.java =================================================================== --- trunk/src/main/java/cc/kune/events/client/actions/EventAddMenuItem.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/events/client/actions/EventAddMenuItem.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -28,7 +28,7 @@ super(AccessRolDTO.Editor, true); this.i18n = i18n; this.calendar = calendar; - withText(i18n.t("Add a appointment")).withIcon(res.calendarAdd()); + withText(i18n.t("Add an appointment")).withIcon(res.calendarAdd()); } @Override Modified: trunk/src/main/java/cc/kune/events/client/viewer/CalendarViewerPresenter.java =================================================================== --- trunk/src/main/java/cc/kune/events/client/viewer/CalendarViewerPresenter.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/events/client/viewer/CalendarViewerPresenter.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -139,6 +139,7 @@ event.setCancelled(!editable); // event.setCancelled(true); NotifyUser.info("updated handler"); + hideMenu(); } }); getView().addOpenHandler(new OpenHandler<Appointment>() { @@ -194,7 +195,7 @@ getView().goToday(); } - private void hide() { + private void hideMenu() { onOverMenu.get().hide(); } Modified: trunk/src/main/java/cc/kune/wave/server/KuneAgent.java =================================================================== --- trunk/src/main/java/cc/kune/wave/server/KuneAgent.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/wave/server/KuneAgent.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -81,6 +81,12 @@ } @Override + public WaveRef createWave(final String title, final String message, final String... participantsArray) { + // TODO Auto-generated method stub + return null; + } + + @Override public WaveRef createWave(final String title, final String message, final String waveIdToCopy, final URL gadgetUrl, final ParticipantId... participantsArray) { // TODO Auto-generated method stub Modified: trunk/src/main/java/cc/kune/wave/server/KuneWaveService.java =================================================================== --- trunk/src/main/java/cc/kune/wave/server/KuneWaveService.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/wave/server/KuneWaveService.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -41,6 +41,8 @@ WaveRef createWave(String title, String message, ParticipantId... participantsArray); + WaveRef createWave(String title, String message, String... participantsArray); + WaveRef createWave(String title, String message, String waveIdToCopy, URL gadgetUrl, ParticipantId... participantsArray); Modified: trunk/src/main/java/cc/kune/wave/server/KuneWaveServiceDefault.java =================================================================== --- trunk/src/main/java/cc/kune/wave/server/KuneWaveServiceDefault.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/wave/server/KuneWaveServiceDefault.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -221,6 +221,11 @@ } @Override + public WaveRef createWave(final String title, final String message, final String... participantsArray) { + return createWave(title, message, participantUtils.listFrom(participantsArray)); + } + + @Override public WaveRef createWave(@Nonnull final String title, final String message, final String waveIdToCopy, final URL gadgetUrl, @Nonnull final ParticipantId... participantsArray) { String newWaveId = null; Modified: trunk/src/main/java/cc/kune/wave/server/ParticipantUtils.java =================================================================== --- trunk/src/main/java/cc/kune/wave/server/ParticipantUtils.java 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/java/cc/kune/wave/server/ParticipantUtils.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -37,6 +37,7 @@ @Singleton public class ParticipantUtils { + private String atDomain; private final String domain; private final ParticipantId superAdmin; @@ -47,10 +48,26 @@ superAdmin = ofImpl(databaseProperties.getAdminShortName()); } + public String getAddressName(final String address) { + return address.contains(ParticipantId.DOMAIN_PREFIX) ? address.split(ParticipantId.DOMAIN_PREFIX)[0] + : address; + } + + private String getAtDomain() { + if (atDomain == null) { + atDomain = ParticipantId.DOMAIN_PREFIX + domain; + } + return atDomain; + } + public ParticipantId getSuperAdmin() { return superAdmin; } + public boolean isLocal(final String address) { + return address.contains(getAtDomain()); + } + public ParticipantId[] listFrom(final Set<Group> list) { final ParticipantId[] array = new ParticipantId[list.size()]; final Iterator<Group> iterator = list.iterator(); @@ -60,6 +77,14 @@ return array; } + public ParticipantId[] listFrom(final String... list) { + final ParticipantId[] array = new ParticipantId[list.length]; + for (int i = 0; i < list.length; i++) { + array[i] = of(list[i]); + } + return array; + } + public ParticipantId of(final String username) { return ofImpl(username); } @@ -69,7 +94,7 @@ if (username.contains(ParticipantId.DOMAIN_PREFIX)) { return ParticipantId.of(username); } else { - return ParticipantId.of(username + ParticipantId.DOMAIN_PREFIX + domain); + return ParticipantId.of(username + getAtDomain()); } } catch (final InvalidParticipantAddress e) { throw new DefaultException("Error getting Wave participant Id"); Added: trunk/src/main/java/cc/kune/wave/server/WaveEmailNotifier.java =================================================================== --- trunk/src/main/java/cc/kune/wave/server/WaveEmailNotifier.java (rev 0) +++ trunk/src/main/java/cc/kune/wave/server/WaveEmailNotifier.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,75 @@ +package cc.kune.wave.server; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.waveprotocol.box.common.DeltaSequence; +import org.waveprotocol.box.server.waveserver.WaveBus; +import org.waveprotocol.box.server.waveserver.WaveBus.Subscriber; +import org.waveprotocol.wave.model.id.IdUtil; +import org.waveprotocol.wave.model.id.WaveletId; +import org.waveprotocol.wave.model.id.WaveletName; +import org.waveprotocol.wave.model.operation.wave.AddParticipant; +import org.waveprotocol.wave.model.operation.wave.TransformedWaveletDelta; +import org.waveprotocol.wave.model.operation.wave.WaveletBlipOperation; +import org.waveprotocol.wave.model.operation.wave.WaveletOperation; +import org.waveprotocol.wave.model.version.HashedVersion; +import org.waveprotocol.wave.model.wave.ParticipantId; +import org.waveprotocol.wave.model.wave.data.ReadableWaveletData; +import org.waveprotocol.wave.model.waveref.WaveRef; + +import cc.kune.core.server.LogThis; +import cc.kune.core.server.mail.MailServiceDefault.FormatedString; +import cc.kune.core.server.notifier.NotifyService; +import cc.kune.core.server.notifier.NotifyType; +import cc.kune.core.server.notifier.UsersOnline; +import cc.kune.core.server.properties.KuneBasicProperties; + +import com.google.inject.Inject; + +@LogThis +public class WaveEmailNotifier { + public static final Log LOG = LogFactory.getLog(WaveEmailNotifier.class); + + @Inject + public WaveEmailNotifier(final WaveBus waveBus, final NotifyService notifyService, + final UsersOnline usersOnline, final KuneBasicProperties basicProperties, + final ParticipantUtils partUtils) { + waveBus.subscribe(new Subscriber() { + @Override + public void waveletCommitted(final WaveletName waveletName, final HashedVersion version) { + } + + @Override + public void waveletUpdate(final ReadableWaveletData wavelet, final DeltaSequence deltas) { + final WaveletId waveletId = wavelet.getWaveletId(); + if (IdUtil.isUserDataWavelet(waveletId)) { + return; + } + for (final TransformedWaveletDelta delta : deltas) { + for (final WaveletOperation op : delta) { + if (op instanceof AddParticipant) { + final ParticipantId user = ((AddParticipant) op).getParticipantId(); + final String url = KuneWaveUtils.getUrl(WaveRef.of(wavelet.getWaveId(), waveletId)); + final FormatedString body = FormatedString.build( + // FIXME when SSL/ssl support + "Hi there,<br><br>You have a new message in %s. <a href=\"http://%s/#%s\">Read more</a>.<br>", + basicProperties.getSiteCommonName(), basicProperties.getSiteDomain(), url); + final String address = user.getAddress(); + if (partUtils.isLocal(address)) { + final String userName = partUtils.getAddressName(address); + if (!usersOnline.isLogged(userName)) { + notifyService.send(NotifyType.email, FormatedString.build("You have a new message"), + body, true, userName); + notifyService.send(NotifyType.chat, FormatedString.build("New message"), body, true, + userName); + } + } + } else if (op instanceof WaveletBlipOperation) { + + } + } + } + } + }); + } +} Modified: trunk/src/main/resources/kune.properties =================================================================== --- trunk/src/main/resources/kune.properties 2011-12-21 23:32:22 UTC (rev 1647) +++ trunk/src/main/resources/kune.properties 2011-12-27 01:32:05 UTC (rev 1648) @@ -27,7 +27,7 @@ kune.site.smtp.host = localhost kune.site.smtp.defaultfrom = noreply@localhost # If we should avoid the use of smtp (use only for avoid emails during development) -kune.site.smtp.skip = true +kune.site.smtp.skip = false ### Database Added: trunk/src/test/java/cc/kune/core/server/mail/MailServiceDefaultTest.java =================================================================== --- trunk/src/test/java/cc/kune/core/server/mail/MailServiceDefaultTest.java (rev 0) +++ trunk/src/test/java/cc/kune/core/server/mail/MailServiceDefaultTest.java 2011-12-27 01:32:05 UTC (rev 1648) @@ -0,0 +1,43 @@ +package cc.kune.core.server.mail; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +import cc.kune.core.server.mail.MailServiceDefault.FormatedString; +import cc.kune.core.server.properties.KunePropertiesDefault; + +public class MailServiceDefaultTest { + + private MailServiceDefault service; + + @Test(expected = NullPointerException.class) + public void basicException() { + assertEquals(null, FormatedString.build(null).getString()); + } + + @Test(expected = NullPointerException.class) + public void basicExceptionWithArgs() { + assertEquals(null, FormatedString.build(null).getString()); + assertEquals(null, FormatedString.build(null, "arg").getString()); + } + + @Test + public void basicFormat() { + assertEquals("basic", FormatedString.build("basic").getString()); + assertEquals("basic arg", FormatedString.build("basic %s", "arg").getString()); + assertEquals("basic %s", FormatedString.build("basic %s", null).getString()); + } + + @Before + public void before() { + service = new MailServiceDefault(new KunePropertiesDefault("kune.properties")); + } + + @Test + public void simpleTest() { + service.sendPlain(FormatedString.build("Some test subject"), FormatedString.build("Some body"), + "vjrj@localhost"); + } +}