This is an automated email from the ASF dual-hosted git repository. solomax pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/openmeetings.git
The following commit(s) were added to refs/heads/master by this push: new adabede [OPENMEETINGS-2481] cancelation email works as expected adabede is described below commit adabede9e5f42fec4f804929b682a675cae71bad Author: Maxim Solodovnik <solomax...@gmail.com> AuthorDate: Sat Oct 17 11:05:39 2020 +0700 [OPENMEETINGS-2481] cancelation email works as expected --- .../apache/openmeetings/core/mail/MailHandler.java | 2 +- .../db/dao/calendar/AppointmentDao.java | 20 +++++++---- .../db/dao/room/IInvitationManager.java | 2 +- .../openmeetings/db/entity/basic/MailMessage.java | 27 +++++++++++++-- .../service/room/InvitationManager.java | 19 +++++----- .../openmeetings/util/OpenmeetingsVariables.java | 2 +- .../apache/openmeetings/util/mail/IcalHandler.java | 40 +++++++++++++++++++--- 7 files changed, 86 insertions(+), 26 deletions(-) diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/mail/MailHandler.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/mail/MailHandler.java index 3fbcc18..5e42772 100644 --- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/mail/MailHandler.java +++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/mail/MailHandler.java @@ -98,7 +98,7 @@ public class MailHandler { BodyPart iCalContent = new MimeBodyPart(); iCalContent.addHeader("content-class", "urn:content-classes:calendarmessage"); iCalContent.setDataHandler(new DataHandler(new ByteArrayDataSource(new ByteArrayInputStream(m.getIcs()), - "text/calendar; charset=UTF-8; method=REQUEST"))); + "text/calendar; charset=UTF-8; method=" + m.getIcsMethod()))); multiBody.addBodyPart(iCalContent); BodyPart body = new MimeBodyPart(); body.setContent(multiBody); diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/AppointmentDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/AppointmentDao.java index a4b7c8d..988bc2e 100644 --- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/AppointmentDao.java +++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/AppointmentDao.java @@ -34,10 +34,12 @@ import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.persistence.TypedQuery; +import org.apache.commons.lang3.StringUtils; import org.apache.openmeetings.db.dao.IDataProviderDao; import org.apache.openmeetings.db.dao.basic.ConfigurationDao; import org.apache.openmeetings.db.dao.room.IInvitationManager; import org.apache.openmeetings.db.dao.room.RoomDao; +import org.apache.openmeetings.db.dto.calendar.AppointmentDTO; import org.apache.openmeetings.db.entity.calendar.Appointment; import org.apache.openmeetings.db.entity.calendar.Appointment.Reminder; import org.apache.openmeetings.db.entity.calendar.MeetingMember; @@ -100,10 +102,13 @@ public class AppointmentDao implements IDataProviderDao<Appointment>{ } a.setRoom(roomDao.update(r, userId)); final boolean newApp = a.getId() == null; - Appointment a0 = null; + AppointmentDTO a0 = null; Set<Long> mmIds = Set.of(); if (sendmails && !newApp) { - a0 = get(a.getId()); + Appointment prev = get(a.getId()); + if (prev != null) { + a0 = new AppointmentDTO(prev); + } mmIds = meetingMemberDao.getMeetingMemberIdsByAppointment(a.getId()); } if (newApp) { @@ -116,11 +121,12 @@ public class AppointmentDao implements IDataProviderDao<Appointment>{ } if (sendmails) { // update meeting members - boolean sendMail = a0 == null || !a0.getTitle().equals(a.getTitle()) || - !(a0.getDescription() != null ? a0.getDescription().equals(a.getDescription()) : true) || - !(a0.getLocation() != null ? a0.getLocation().equals(a.getLocation()) : true) || - !a0.getStart().equals(a.getStart()) || - !a0.getEnd().equals(a.getEnd()); + boolean sendMail = a0 == null + || !StringUtils.equals(a0.getTitle(), a.getTitle()) + || !StringUtils.equals(a0.getDescription(), a.getDescription()) + || !StringUtils.equals(a0.getLocation(), a.getLocation()) + || !a0.getStart().getTime().equals(a.getStart()) + || !a0.getEnd().getTime().equals(a.getEnd()); List<MeetingMember> mmList = a.getMeetingMembers(); if (mmList != null){ for (MeetingMember mm : mmList) { diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/IInvitationManager.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/IInvitationManager.java index 6b2dc50..2fd0c34 100644 --- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/IInvitationManager.java +++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/IInvitationManager.java @@ -43,5 +43,5 @@ public interface IInvitationManager { User createdBy, Long languageId, Date gmtTimeStart, Date gmtTimeEnd , Appointment appointment); - void sendInvitationLink(Invitation i, MessageType type, String subject, String message, boolean ical, String baseUrl) throws Exception; + void sendInvitationLink(Invitation i, MessageType type, String subject, String message, boolean ical, String baseUrl); } diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/MailMessage.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/MailMessage.java index 1e2e2b8..9478061 100644 --- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/MailMessage.java +++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/MailMessage.java @@ -18,6 +18,8 @@ */ package org.apache.openmeetings.db.entity.basic; +import java.io.IOException; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; @@ -30,6 +32,12 @@ import javax.persistence.NamedQuery; import javax.persistence.Table; import org.apache.openmeetings.db.entity.HistoricalEntity; +import org.apache.openmeetings.util.mail.IcalHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.fortuna.ical4j.model.property.Method; +import net.fortuna.ical4j.validate.ValidationException; @Entity @NamedQuery(name = "getMailMessageById", query = "SELECT m FROM MailMessage m WHERE m.id = :id") @@ -42,6 +50,7 @@ import org.apache.openmeetings.db.entity.HistoricalEntity; @Table(name = "email_queue") public class MailMessage extends HistoricalEntity { private static final long serialVersionUID = 1L; + private static final Logger log = LoggerFactory.getLogger(MailMessage.class); public enum Status { NONE, SENDING, ERROR, DONE @@ -70,6 +79,9 @@ public class MailMessage extends HistoricalEntity { @Column(name = "ics") private byte[] ics; + @Column(name = "ics_method") + private String icsMethod; + @Column(name = "status", nullable = false) @Enumerated(EnumType.STRING) private Status status = Status.NONE; @@ -89,12 +101,19 @@ public class MailMessage extends HistoricalEntity { this(recipients, replyTo, subject, body, null); } - public MailMessage(String recipients, String replyTo, String subject, String body, byte[] ics) { + public MailMessage(String recipients, String replyTo, String subject, String body, IcalHandler ical) { this.recipients = recipients; this.replyTo = replyTo; this.subject = subject; this.body = body; - this.ics = ics; + if (ical != null) { + this.icsMethod = ical.getMethod().getValue(); + try { + this.ics = ical.toByteArray(); + } catch (ValidationException|IOException e) { + log.error("Unexpected error while getting ICS", e); + } + } } @Override @@ -170,4 +189,8 @@ public class MailMessage extends HistoricalEntity { public void setLastError(String lastError) { this.lastError = lastError; } + + public String getIcsMethod() { + return icsMethod == null ? Method.REQUEST.getValue() : icsMethod; + } } diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/room/InvitationManager.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/room/InvitationManager.java index 5a36f1f..34ae0bc 100644 --- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/room/InvitationManager.java +++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/room/InvitationManager.java @@ -73,11 +73,10 @@ public class InvitationManager implements IInvitationManager { * @param mm - attendee being processed * @param type - type of the message * @param ical - should iCal appoinment be attached to message - * @throws Exception in case of error happens during sending */ - private void sendInvitionLink(Appointment a, MeetingMember mm, MessageType type, boolean ical) throws Exception { + private void sendInvitionLink(Appointment a, MeetingMember mm, MessageType type, boolean ical) { User owner = a.getOwner(); - String invitorName = owner.getFirstname() + " " + owner.getLastname(); + String invitorName = owner.getDisplayName(); TimeZone tz = getTimeZone(mm.getUser()); SubjectEmailTemplate t; switch (type) { @@ -96,7 +95,7 @@ public class InvitationManager implements IInvitationManager { } @Override - public void sendInvitationLink(Invitation i, MessageType type, String subject, String message, boolean ical, String baseUrl) throws Exception { + public void sendInvitationLink(Invitation i, MessageType type, String subject, String message, boolean ical, String baseUrl) { final String invitationLink; if (type != MessageType.CANCEL) { IApplication app = ensureApplication(1L); @@ -120,16 +119,18 @@ public class InvitationManager implements IInvitationManager { } IcalHandler handler = new IcalHandler(MessageType.CANCEL == type ? IcalHandler.ICAL_METHOD_CANCEL : IcalHandler.ICAL_METHOD_REQUEST) .createVEvent(getTimeZone(owner).getID(), a.getStart(), a.getEnd(), a.getTitle()) - .setLocation(a.getLocation()) - .setDescription(desc) + .addOrganizer(replyToEmail, owner.getDisplayName()) .setUid(a.getIcalId()) + .addAttendee(email, i.getInvitee().getDisplayName(), isOwner) + .setCreated(a.getInserted()) + .setDescription(desc) + .setModified(a.getUpdated()) + .setLocation(a.getLocation()) .setSequence(0) - .addOrganizer(replyToEmail, owner.getDisplayName()) - .addAttendee(email, i.getInvitee().getLogin(), isOwner) .build(); log.debug(handler.toString()); - mailHandler.send(new MailMessage(email, replyToEmail, subject, template, handler.toByteArray())); + mailHandler.send(new MailMessage(email, replyToEmail, subject, template, handler)); } else { mailHandler.send(email, replyToEmail, subject, template); } diff --git a/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java b/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java index 0b9fc15..d08d9b7 100644 --- a/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java +++ b/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java @@ -119,7 +119,7 @@ public class OpenmeetingsVariables { public static final String DEFAULT_APP_NAME = "OpenMeetings"; public static final String DEFAULT_CONTEXT_NAME = "openmeetings"; public static final long DEFAULT_MAX_UPLOAD_SIZE = 100 * 1024 * 1024L; // 100MB - public static final String DEFAULT_BASE_URL = "http://localhost:5080/openmeetings/"; + public static final String DEFAULT_BASE_URL = "https://localhost:5443/openmeetings/"; public static final String DEFAULT_SIP_CONTEXT = "rooms"; public static final String DEFAULT_CSP_FONT = "https://fonts.gstatic.com"; public static final String DEFAULT_CSP_STYLE = "https://fonts.googleapis.com/css"; diff --git a/openmeetings-util/src/main/java/org/apache/openmeetings/util/mail/IcalHandler.java b/openmeetings-util/src/main/java/org/apache/openmeetings/util/mail/IcalHandler.java index ff9e558..8314358 100644 --- a/openmeetings-util/src/main/java/org/apache/openmeetings/util/mail/IcalHandler.java +++ b/openmeetings-util/src/main/java/org/apache/openmeetings/util/mail/IcalHandler.java @@ -22,6 +22,7 @@ import static org.apache.openmeetings.util.mail.MailUtil.MAILTO; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.net.URI; import java.util.Date; import java.util.NoSuchElementException; @@ -37,11 +38,16 @@ import net.fortuna.ical4j.model.TimeZoneRegistry; import net.fortuna.ical4j.model.TimeZoneRegistryFactory; import net.fortuna.ical4j.model.component.VEvent; import net.fortuna.ical4j.model.parameter.Cn; +import net.fortuna.ical4j.model.parameter.CuType; 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.parameter.XParameter; import net.fortuna.ical4j.model.property.Attendee; import net.fortuna.ical4j.model.property.CalScale; +import net.fortuna.ical4j.model.property.Created; import net.fortuna.ical4j.model.property.Description; +import net.fortuna.ical4j.model.property.LastModified; import net.fortuna.ical4j.model.property.Location; import net.fortuna.ical4j.model.property.Method; import net.fortuna.ical4j.model.property.Organizer; @@ -51,6 +57,7 @@ import net.fortuna.ical4j.model.property.Status; import net.fortuna.ical4j.model.property.Transp; import net.fortuna.ical4j.model.property.Uid; import net.fortuna.ical4j.model.property.Version; +import net.fortuna.ical4j.validate.ValidationException; /** * @@ -86,7 +93,7 @@ public class IcalHandler { log.debug("Icalhandler method type : {}", method); icsCalendar = new Calendar(); - icsCalendar.getProperties().add(new ProdId("-//Events Calendar//iCal4j 1.0//EN")); + icsCalendar.getProperties().add(new ProdId("-//Apache Openmeetings//OM Calendar//EN")); icsCalendar.getProperties().add(Version.VERSION_2_0); icsCalendar.getProperties().add(CalScale.GREGORIAN); icsCalendar.getProperties().add(method); @@ -106,11 +113,21 @@ public class IcalHandler { end.setTimeZone(timeZone); meeting = new VEvent(start, end, name); - meeting.getProperties().add(Method.CANCEL == method ? Transp.TRANSPARENT : Transp.OPAQUE); + meeting.getProperties().add(Transp.OPAQUE); meeting.getProperties().add(Status.VEVENT_CONFIRMED); return this; } + public IcalHandler setCreated(Date date) { + meeting.getProperties().add(new Created(new DateTime(date))); + return this; + } + + public IcalHandler setModified(Date date) { + meeting.getProperties().add(new LastModified(new DateTime(date == null ? new Date() : date))); + return this; + } + public IcalHandler setDescription(String description) { meeting.getProperties().add(new Description(description)); return this; @@ -144,8 +161,15 @@ public class IcalHandler { public IcalHandler addAttendee(String email, String display, boolean chair) { Attendee uno = new Attendee(URI.create(MAILTO + email)); + uno.getParameters().add(CuType.INDIVIDUAL); uno.getParameters().add(chair ? Role.CHAIR : Role.REQ_PARTICIPANT); - uno.getParameters().add(Method.CANCEL == method ? PartStat.DECLINED : PartStat.ACCEPTED); + if (Method.CANCEL == method) { + uno.getParameters().add(PartStat.DECLINED); + } else { + uno.getParameters().add(chair ? PartStat.ACCEPTED : PartStat.NEEDS_ACTION); + uno.getParameters().add(Rsvp.TRUE); + } + uno.getParameters().add(new XParameter("X-NUM-GUESTS", "0")); uno.getParameters().add(new Cn(display)); meeting.getProperties().add(uno); return this; @@ -157,6 +181,10 @@ public class IcalHandler { return this; } + public Method getMethod() { + return method; + } + /** * Write iCal to File * @@ -179,10 +207,12 @@ public class IcalHandler { * Get IcalBody as ByteArray * * @return - calendar in ICS format as byte[] - * @throws Exception + * @throws IOException * - in case of error during writing to byte array + * @throws ValidationException + * - in case of invalid calendar properties */ - public byte[] toByteArray() throws Exception { + public byte[] toByteArray() throws ValidationException, IOException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); CalendarOutputter outputter = new CalendarOutputter(); outputter.output(icsCalendar, bout);