Package org.projectforge.plugins.teamcal.event

Source Code of org.projectforge.plugins.teamcal.event.TeamEventMailer

/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
//         www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////

package org.projectforge.plugins.teamcal.event;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.ParameterList;
import net.fortuna.ical4j.model.TimeZoneRegistry;
import net.fortuna.ical4j.model.TimeZoneRegistryFactory;
import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.component.VTimeZone;
import net.fortuna.ical4j.model.parameter.Cn;
import net.fortuna.ical4j.model.parameter.PartStat;
import net.fortuna.ical4j.model.parameter.Role;
import net.fortuna.ical4j.model.parameter.Rsvp;
import net.fortuna.ical4j.model.property.Attendee;
import net.fortuna.ical4j.model.property.CalScale;
import net.fortuna.ical4j.model.property.Comment;
import net.fortuna.ical4j.model.property.Contact;
import net.fortuna.ical4j.model.property.Location;
import net.fortuna.ical4j.model.property.Method;
import net.fortuna.ical4j.model.property.Organizer;
import net.fortuna.ical4j.model.property.ProdId;
import net.fortuna.ical4j.model.property.RRule;
import net.fortuna.ical4j.model.property.Sequence;
import net.fortuna.ical4j.model.property.Version;

import org.apache.commons.lang.StringUtils;
import org.projectforge.calendar.ICal4JUtils;
import org.projectforge.core.ConfigXml;
import org.projectforge.mail.Mail;
import org.projectforge.mail.SendMail;
import org.projectforge.registry.Registry;
import org.projectforge.scripting.I18n;
import org.projectforge.user.PFUserContext;
import org.projectforge.user.PFUserDO;

import de.micromata.hibernate.history.HistoryEntry;
import de.micromata.hibernate.history.delta.PropertyDelta;

/**
* @author Kai Reinhard (k.reinhard@micromata.de)
*
*/
public class TeamEventMailer
{

  private static TeamEventMailer instance = null;

  private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TeamEventMailer.class);

  private final Queue<TeamEventMailValue> queue;

  private final TeamEventDao teamEventDao;

  class Marker {
    protected final Date lastEmail;
    protected final HistoryEntry[] entries;
    private final List<HistoryEntry> list;
    private boolean locationChanged;
    private boolean dateChanged;
    private boolean recurrenceChanged;

    public Marker(final HistoryEntry[] entries, final Date lastEmail) {
      this.entries = entries;
      this.lastEmail=lastEmail;
      list = new LinkedList<HistoryEntry>();
      for (int i=0; i < entries.length-1; i++) {
        if (entries[i].getTimestamp().getTime() > lastEmail.getTime()) {
          list.add(entries[i]);
        }
      }
      locationChanged = hasLocationChanged();
      dateChanged = hasDateChanged();
      recurrenceChanged = hasRecurrenceChanged();
    }
    private boolean hasLocationChanged() {
      for (final HistoryEntry entry : list) {
        for (final PropertyDelta delta : entry.getDelta()) {
          if (StringUtils.contains(delta.getPropertyName(), "location") == true) {
            return true;
          }
        }
      }
      return false;
    }
    private boolean hasDateChanged() {
      for (final HistoryEntry entry : list) {
        for (final PropertyDelta delta : entry.getDelta()) {
          if (StringUtils.contains(delta.getPropertyName(), "startDate") == true ||
              StringUtils.contains(delta.getPropertyName(), "endDate") == true ) {
            return true;
          }
        }
      }
      return false;
    }
    private boolean hasRecurrenceChanged() {
      for (final HistoryEntry entry : list) {
        for (final PropertyDelta delta : entry.getDelta()) {
          if (StringUtils.contains(delta.getPropertyName(), "recurrenceRule") == true) {
            return true;
          }
        }
      }
      return false;
    }
    public void computeChanges(final TeamEventDO event, final TeamEventDO orgEvent) {
      if (StringUtils.equals(event.getLocation(), orgEvent.getLocation()) == false) {
        locationChanged = true;
      }
      if (event.getStartDate() != null && orgEvent.getStartDate() != null &&
          event.getEndDate() != null && orgEvent.getEndDate() != null) {
        if (event.getStartDate().equals(orgEvent.getStartDate()) == false ||
            event.getEndDate().equals(orgEvent.getEndDate()) == false) {
          dateChanged = true;
        }
      }
      if (StringUtils.equals(event.getRecurrenceRule(), orgEvent.getRecurrenceRule()) == false) {
        recurrenceChanged = true;
      }
    }
    public boolean isLocationChanged()
    {
      return locationChanged;
    }
    public boolean isDateChanged()
    {
      return dateChanged;
    }
    public boolean isRecurrenceChanged()
    {
      return recurrenceChanged;
    }
  }

  private TeamEventMailer() {
    queue =  new LinkedList<TeamEventMailValue>();
    teamEventDao = Registry.instance().getDao(TeamEventDao.class);
  }

  public static TeamEventMailer getInstance() {
    if (instance == null) {
      instance = new TeamEventMailer();
    }
    return instance;
  }

  public Queue<TeamEventMailValue> getQueue()
  {
    return queue;
  }

  public boolean send() {
    int failures = 0;
    while (queue.isEmpty() == false) {
      final TeamEventMailValue value = queue.poll();
      final TeamEventDO event = teamEventDao.getById(value.getId());
      if (sendIcsFile(event, value.getType(), value.getOrgId()) == false) {
        failures++;
        log.error("Can't send all emails for TeamEvent: " + event.getSubject());
      } else {
        final Timestamp t = new Timestamp(event.getLastUpdate().getTime());
        event.setLastEmail(t);
        teamEventDao.saveOrUpdate(event);
      }
    }
    return failures == 0 ? true : false;
  }

  private boolean sendIcsFile(final TeamEventDO event, final TeamEventMailType type, final Integer orgId) {
    int failures = 0;
    final Marker marker = new Marker(teamEventDao.getHistoryEntries(event), event.getLastEmail());
    if (orgId != null) {
      final TeamEventDO orgEvent = teamEventDao.getById(orgId);
      marker.computeChanges(event, orgEvent);
    }
    final String content = getICal(event, type);
    final Mail msg = new Mail();
    msg.setProjectForgeSubject(composeSubject(event, type));
    msg.setContentType(Mail.CONTENTTYPE_HTML);
    final SendMail sendMail = new SendMail();
    sendMail.setConfigXml(ConfigXml.getInstance());
    for (final TeamEventAttendeeDO attendee : event.getAttendees()) {
      msg.setContent(composeHtmlContent(event, attendee.getNumber(), type, marker));
      if (attendee.getUserId() == null) {
        msg.setTo(attendee.getUrl());
      } else {
        msg.setTo(attendee.getUser());
        if (attendee.getUser().equals(PFUserContext.getUser()) == true) {
          continue;
        }
      }
      switch (type) {
        case INVITATION:
          if (sendMail.send(msg, content, event.getAttachments()) == false) {
            failures++;
          }
          break;
        case UPDATE:
        case REJECTION:
          if (sendMail.send(msg, content, null) == false) {
            failures++;
          }
          break;
      }

    }
    return failures == 0 ? true : false;
  }

  private String composeHtmlContent(final TeamEventDO event, final Short number, final TeamEventMailType type, final Marker marker) {
    final StringBuffer buf = new StringBuffer();
    buf.append("<html><body><h2>").append(composeSubject(event, type)).append("</h2>");
    buf.append("<table>");
    buf.append(composeDate(event, type, marker));
    buf.append(composeRecurrence(event, number, type, marker));
    buf.append(composeLocation(event, type, marker));
    buf.append(composeAttendees(event, number, type));
    buf.append(composeModifier(event, type));
    buf.append("</table>");
    buf.append(composeButtons(event, number, type));
    buf.append("</body></html>");
    return buf.toString();
  }

  private String composeSubject(final TeamEventDO event, final TeamEventMailType type) {
    final StringBuffer buf = new StringBuffer();
    switch (type) {
      case INVITATION: {
        buf.append(PFUserContext.getUser().getFullname());
        buf.append(" ").append(I18n.getString("plugins.teamcal.event.invitation1"));
        buf.append(" „").append(event.getSubject()).append("“ ");
        buf.append(I18n.getString("plugins.teamcal.event.invitation2"));
        return buf.toString();
      }
      case UPDATE: {
        buf.append(" „").append(event.getSubject()).append("“ ");
        buf.append(I18n.getString("plugins.teamcal.event.update"));
        return buf.toString();
      }
      case REJECTION: {
        buf.append(" „").append(event.getSubject()).append("“ ");
        buf.append(I18n.getString("plugins.teamcal.event.rejection"));
        return buf.toString();
      }
      default:
        buf.append("Unsupported TeamEventMailType: ").append(type);
        log.error(buf.toString());
        return buf.toString();
    }
  }

  private String composeDate(final TeamEventDO event, final TeamEventMailType type, final Marker marker) {
    final StringBuffer buf = new StringBuffer();
    buf.append("<tr>");
    switch (type) {
      case UPDATE:
        if (marker.isDateChanged() == true) {
          buf.append("<td>").append(I18n.getString("plugins.teamcal.event.changed")).append("</td>");
          break;
        }
      case REJECTION:
      case INVITATION:
        buf.append("<td>").append(I18n.getString("plugins.teamcal.event.event")).append("</td>");
    }
    final Date d1 = new Date(event.getStartDate().getTime());
    final Date d2 = new Date(event.getEndDate().getTime());
    final SimpleDateFormat df1 = new SimpleDateFormat("EEEEE, dd. MMMM yyyy, HH:mm");
    final SimpleDateFormat df2 = new SimpleDateFormat("HH:mm");
    df1.setTimeZone(PFUserContext.getTimeZone());
    df2.setTimeZone(PFUserContext.getTimeZone());
    final String s = df1.format(d1) + " Uhr - " + df2.format(d2) + " Uhr";
    buf.append("<td>").append(s).append("</td>");
    buf.append("</tr>");
    return buf.toString();
  }

  private String composeRecurrence(final TeamEventDO event, final Short number, final TeamEventMailType type, final Marker marker) {
    final StringBuffer buf = new StringBuffer();
    if (StringUtils.isNotBlank(event.getRecurrenceRule()) == true) {
      buf.append("<tr>");
      switch (type) {
        case UPDATE:
          if (marker.isRecurrenceChanged() == true) {
            buf.append("<td>").append(I18n.getString("plugins.teamcal.event.recurrence.changed")).append("</td>");
          } else {
            buf.append("<td></td>");
          }
          buf.append("<td>").append("<a href=\"http://localhost:8080/ProjectForge/Calendar/Event/?e=").append(event.getUid()).append("&p=p").append(number.toString()).append("\">").append(I18n.getString("plugins.teamcal.event.recurrence.show")).append("</a></td>");
          break;
        case INVITATION:
          buf.append("<td></td>");
          buf.append("<td>").append("<a href=\"http://localhost:8080/ProjectForge/Calendar/Event/?e=").append(event.getUid()).append("&p=p").append(number.toString()).append("\">").append(I18n.getString("plugins.teamcal.event.recurrence.show")).append("</a></td>");
          break;
        case REJECTION:
          buf.append("<td></td>");
          buf.append("<td>").append(I18n.getString("plugins.teamcal.event.recurrence.show")).append("</td>");
          break;
      }
      buf.append("</tr>");
    }
    return buf.toString();
  }

  private String composeLocation(final TeamEventDO event, final TeamEventMailType type, final Marker marker) {
    final StringBuffer buf = new StringBuffer();
    if (StringUtils.isNotBlank(event.getLocation()) == true) {
      buf.append("<tr>");
      switch (type) {
        case INVITATION:
        case REJECTION:
          buf.append("<td>").append(I18n.getString("plugins.teamcal.event.location")).append("</td>");
          break;
        case UPDATE:
          if (marker.isLocationChanged() ==true) {
            buf.append("<td>").append(I18n.getString("plugins.teamcal.event.location.changed")).append("</td>");
          } else {
            buf.append("<td>").append(I18n.getString("plugins.teamcal.event.location")).append("</td>");
          }
      }
      buf.append("<td>").append(event.getLocation()).append("</td></tr>");
    }
    return buf.toString();
  }

  private String composeAttendees(final TeamEventDO event, final Short number, final TeamEventMailType type) {
    final StringBuffer buf = new StringBuffer();
    if (event.getAttendees() != null || event.getAttendees().isEmpty() == false) {
      buf.append("<tr>");
      buf.append("<td>").append(I18n.getString("plugins.teamcal.attendees")).append("</td>");
      buf.append("<td>").append(PFUserContext.getUser().getFullname()).append(" ").append(I18n.getString("plugins.teamcal.event.andyou")).append("</td>");
      buf.append("</tr>");
      switch (type) {
        case REJECTION:
          break;
        case INVITATION:
        case UPDATE:
          buf.append("<tr>");
          buf.append("<td></td>");
          buf.append("<td>").append("<a href=\"http://localhost:8080/ProjectForge/Calendar/Event/?e=").append(event.getUid()).append("&p=p").append(number.toString()).append("\">").append(I18n.getString("plugins.teamcal.event.showreplies")).append("</a></td>");
          buf.append("</tr>");
      }
    }
    return buf.toString();
  }

  private String composeModifier(final TeamEventDO event, final TeamEventMailType type) {
    final StringBuffer buf = new StringBuffer();
    switch (type) {
      case INVITATION:
        break;
      case UPDATE:
        buf.append("<tr>");
        buf.append("<td>").append(I18n.getString("plugins.teamcal.event.changedby")).append("</td>");
        buf.append("<td>").append(PFUserContext.getUser().getFullname()).append("</td>");
        buf.append("</tr>");
        break;
      case REJECTION:
        buf.append("<tr>");
        buf.append("<td>").append(I18n.getString("plugins.teamcal.event.deletedby")).append("</td>");
        buf.append("<td>").append(PFUserContext.getUser().getFullname()).append("</td>");
        buf.append("</tr>");
    }
    return buf.toString();
  }

  private String composeButtons(final TeamEventDO event, final Short number, final TeamEventMailType type) {
    final StringBuffer buf = new StringBuffer();
    buf.append("</br>");
    switch(type) {
      case REJECTION:
        break;
      case INVITATION:
      case UPDATE:
        buf.append("<table>");
        buf.append("<tr>");
        buf.append("<td>").append("<a href=\"http://localhost:8080/ProjectForge/Calendar/Eventreply/?e=").append(event.getUid()).append("&p=p").append(number.toString()).append("&r=accept\">").append(I18n.getString("plugins.teamcal.event.accept")).append("</a></td>");
        buf.append("<td>").append("<a href=\"http://localhost:8080/ProjectForge/Calendar/Eventreply/?e=").append(event.getUid()).append("&p=p").append(number.toString()).append("&r=decline\">").append(I18n.getString("plugins.teamcal.event.decline")).append("</a></td>");
        buf.append("<td>").append("<a href=\"http://localhost:8080/ProjectForge/Calendar/Eventreply/?e=").append(event.getUid()).append("&p=p").append(number.toString()).append("&r=tentative\">").append(I18n.getString("plugins.teamcal.event.tentative")).append("</a></td>");
        buf.append("</tr>");
        buf.append("</table></br>");
    }
    return buf.toString();
  }

  public static String getICal(final TeamEventDO teamEvent, final TeamEventMailType type) {
    final StringBuffer buf = new StringBuffer();
    final Calendar calendar = new Calendar();
    calendar.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
    calendar.getProperties().add(Version.VERSION_2_0);
    calendar.getProperties().add(CalScale.GREGORIAN);
    final TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
    final VTimeZone tz = registry.getTimeZone(PFUserContext.getTimeZone().getID()).getVTimeZone();
    calendar.getComponents().add(tz);
    switch (type) {
      case INVITATION:
      case UPDATE:
        calendar.getProperties().add(Method.REQUEST);
        break;
      case REJECTION:
        calendar.getProperties().add(Method.CANCEL);
    }
    final VEvent vEvent = ICal4JUtils.createVEvent(teamEvent.getStartDate(), teamEvent.getEndDate(), teamEvent.getUid(), teamEvent.getSubject(), teamEvent.isAllDay());
    vEvent.getProperties().add(new Sequence(teamEvent.getSequence()));
    if (teamEvent.hasRecurrence() == true) {
      vEvent.getProperties().add(new RRule(teamEvent.getRecurrenceObject()));
    }
    if (StringUtils.isNotBlank(teamEvent.getLocation()) == true) {
      vEvent.getProperties().add(new Location(teamEvent.getLocation()));
    }
    if (StringUtils.isNotBlank(teamEvent.getNote()) == true) {
      vEvent.getProperties().add(new Comment(teamEvent.getNote()));
    }
    final PFUserDO user = PFUserContext.getUser();
    String s = user.getFullname();
    if (user.getOrganization() != null) {
      s += "\n" + user.getOrganization();
    }
    if (user.getPersonalPhoneIdentifiers() != null) {
      s += "\n" + user.getPersonalPhoneIdentifiers();
    }
    vEvent.getProperties().add(new Contact(s));
    try {
      if (StringUtils.isNotBlank(user.getEmail()) == true) {
        final ParameterList organizerParams = new ParameterList();
        organizerParams.add(new Cn(user.getFullname()));
        final Organizer organizer = new Organizer(organizerParams, "mailto:" + user.getEmail());
        vEvent.getProperties().add(organizer);
      }
    } catch (final Exception e) {
      log.error("Cant't build organizer " + e.getMessage());
    }
    if (teamEvent.getAttendees() != null) {
      for (final TeamEventAttendeeDO attendee : teamEvent.getAttendees() ) {
        final ParameterList attendeeParams = new ParameterList();
        if (attendee.getUser() != null) {
          try {
            attendeeParams.add(new Cn(attendee.getUser().getFullname()));
            //            attendeeParams.add(new SentBy(attendee.getUser().getEmail()));
            attendeeParams.add(new PartStat(attendee.getStatus().name()));
            if (attendee.getStatus().equals(TeamAttendeeStatus.NEEDS_ACTION) == true) {
              attendeeParams.add(Role.REQ_PARTICIPANT);
              attendeeParams.add(Rsvp.TRUE);
            }
            vEvent.getProperties().add(new Attendee(attendeeParams, "mailto:" + attendee.getUser().getEmail()));
          } catch (final Exception e) {
            log.error("Cant't build attendee " + e.getMessage());
          }
        } else {
          try {
            //            attendeeParams.add(new SentBy(attendee.getUrl()));
            attendeeParams.add(new PartStat(attendee.getStatus().name()));
            if (attendee.getStatus().equals(TeamAttendeeStatus.NEEDS_ACTION) == true) {
              attendeeParams.add(Role.REQ_PARTICIPANT);
              attendeeParams.add(Rsvp.TRUE);
            }
            vEvent.getProperties().add(new Attendee(attendeeParams, "mailto:" + attendee.getUrl()));
          catch (final Exception e) {
            log.error("Cant't build attendee " + e.getMessage());
          }
        }
      }
    }
    calendar.getComponents().add(vEvent);
    buf.append(calendar.toString());
    return buf.toString();
  }

}
TOP

Related Classes of org.projectforge.plugins.teamcal.event.TeamEventMailer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.