/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.repository.ui.author; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.olat.basesecurity.GroupRoles; import org.olat.core.commons.modules.bc.FileUploadController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FileElement; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.RichTextElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.util.CSSHelper; import org.olat.core.id.Identity; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.FileUtils; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.mail.ContactList; import org.olat.core.util.mail.MailBundle; import org.olat.core.util.mail.MailContext; import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailLoggingAction; import org.olat.core.util.mail.MailManager; import org.olat.core.util.mail.MailModule; import org.olat.core.util.mail.MailerResult; import org.olat.repository.RepositoryEntryRef; import org.olat.repository.RepositoryEntryRelationType; import org.olat.repository.RepositoryService; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; /** * * Initial date: 27 avr. 2017<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class SendMailController extends FormBasicController { private static final String[] onKeys = new String[]{ "on" }; private static final String[] contactKeys = new String[]{ GroupRoles.owner.name(), GroupRoles.coach.name(), GroupRoles.participant.name() }; private RichTextElement bodyEl; private FileElement attachmentEl; private TextElement subjectEl; private MultipleSelectionElement contactEl, copyFromEl; private FormLayoutContainer uploadCont; private int counter = 0; private long attachmentSize = 0l; private File attachementTempDir; private final int contactAttachmentMaxSizeInMb; private List<Attachment> attachments = new ArrayList<>(); private final List<? extends RepositoryEntryRef> repoEntries; @Autowired private UserManager userManager; @Autowired private MailManager mailService; @Autowired private MailModule mailModule; @Autowired private RepositoryService repositoryService; public SendMailController(UserRequest ureq, WindowControl wControl, List<? extends RepositoryEntryRef> repoEntries) { super(ureq, wControl); setTranslator(Util.createPackageTranslator(RepositoryService.class, getLocale(), getTranslator())); this.repoEntries = repoEntries; this.contactAttachmentMaxSizeInMb = mailModule.getMaxSizeForAttachement(); initForm(ureq); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { String fullName = userManager.getUserDisplayName(getIdentity()); if(StringHelper.containsNonWhitespace(fullName)) { fullName = "[" + fullName + "]"; } TextElement fromEl = uifactory.addTextElement("from", "contact.from", 255, fullName, formLayout); fromEl.setEnabled(false); String[] contactValues = new String[] { translate("contact.to.owner"), translate("contact.to.coach"), translate("contact.to.participant"), }; contactEl = uifactory.addCheckboxesVertical("to", "contact.to", formLayout, contactKeys, contactValues, 1); subjectEl = uifactory.addTextElement("subject", "contact.subject", 255, "", formLayout); subjectEl.setDisplaySize(255); subjectEl.setMandatory(true); bodyEl = uifactory.addRichTextElementForStringDataMinimalistic("body", "contact.body", "", 15, 8, formLayout, getWindowControl()); bodyEl.setMandatory(true); attachmentEl = uifactory.addFileElement(getWindowControl(), "file_upload_1", "contact.attachment", formLayout); attachmentEl.addActionListener(FormEvent.ONCHANGE); attachmentEl.setExampleKey("contact.attachment.maxsize", new String[]{ Integer.toString(contactAttachmentMaxSizeInMb) }); String attachmentPage = velocity_root + "/attachments.html"; uploadCont = FormLayoutContainer.createCustomFormLayout("file_upload_inner", getTranslator(), attachmentPage); uploadCont.setRootForm(mainForm); uploadCont.setVisible(false); uploadCont.contextPut("attachments", attachments); formLayout.add(uploadCont); copyFromEl = uifactory.addCheckboxesHorizontal("copy.from", "contact.cp.from", formLayout, onKeys, new String[] { "" }); FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonGroupLayout", getTranslator()); formLayout.add(buttonGroupLayout); uifactory.addFormCancelButton("cancel", buttonGroupLayout, ureq, getWindowControl()); uifactory.addFormSubmitButton("tools.send.mail", buttonGroupLayout); } @Override protected void doDispose() { if(attachementTempDir != null && attachementTempDir.exists()) { FileUtils.deleteDirsAndFiles(attachementTempDir, true, true); } } @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; subjectEl.clearError(); if(!StringHelper.containsNonWhitespace(subjectEl.getValue())) { subjectEl.setErrorKey("form.legende.mandatory", null); allOk &= false; } bodyEl.clearError(); if(!StringHelper.containsNonWhitespace(bodyEl.getValue())) { bodyEl.setErrorKey("form.legende.mandatory", null); allOk &= false; } contactEl.clearError(); if(contactEl.getSelectedKeys().isEmpty()) { contactEl.setErrorKey("form.legende.mandatory", null); allOk &= false; } return allOk & super.validateFormLogic(ureq); } private File[] getAttachments() { File[] atttachmentArr = new File[attachments.size()]; for(int i=attachments.size(); i-->0; ) { atttachmentArr[i] = attachments.get(i).getFile(); } return atttachmentArr; } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(source == attachmentEl) { doUploadAttachement(); } if(source instanceof FormLink) { FormLink link = (FormLink)source; String cmd = link.getCmd(); if("delete".equals(cmd)) { Attachment attachment = (Attachment)link.getUserObject(); doDeleteAttachment(attachment); } } super.formInnerEvent(ureq, source, event); } private void doDeleteAttachment(Attachment attachment) { attachmentSize -= attachment.getFile().length(); attachment.getFile().delete(); attachments.remove(attachment); uploadCont.setVisible(attachments.size() > 0); uploadCont.setDirty(true); } private void doUploadAttachement() { if(attachementTempDir == null) { attachementTempDir = FileUtils.createTempDir("attachements", null, null); } long size = attachmentEl.getUploadSize(); String filename = attachmentEl.getUploadFileName(); if(size + attachmentSize > (contactAttachmentMaxSizeInMb * 1024 * 1024)) { showWarning("contact.attachment,maxsize", Integer.toString(contactAttachmentMaxSizeInMb)); attachmentEl.reset(); } else { File attachment = attachmentEl.moveUploadFileTo(attachementTempDir); attachmentEl.reset(); if(attachment == null) { logError("Could not move contact-form attachment to " + attachementTempDir.getAbsolutePath(), null); setTranslator(Util.createPackageTranslator(FileUploadController.class, getLocale(), getTranslator())); showError("FileMoveCopyFailed",""); } else { attachmentSize += size; FormLink removeFile = uifactory.addFormLink("delete_" + (++counter), "delete", "delete", null, uploadCont, Link.LINK); removeFile.setIconLeftCSS("o_icon o_icon-fw o_icon_delete"); String css = CSSHelper.createFiletypeIconCssClassFor(filename); Attachment wrapper = new Attachment(attachment, attachment.getName(), css, removeFile); removeFile.setUserObject(wrapper); attachments.add(wrapper); uploadCont.setVisible(true); } } } private void handleAddressException(boolean success) { StringBuilder error = new StringBuilder(); if (success) { error.append(translate("error.msg.send.partially.nok")) .append("<br />") .append(translate("error.msg.send.invalid.rcps")); } else { error.append(translate("error.msg.send.nok")) .append("<br />") .append(translate("error.msg.send.553")); } getWindowControl().setError(error.toString()); } @Override protected void formOK(UserRequest ureq) { ContactList contactList = new ContactList(""); Collection<String> roleList = contactEl.getSelectedKeys(); String[] roles = roleList.toArray(new String[roleList.size()]); List<Identity> identities = repositoryService.getMembers(repoEntries, RepositoryEntryRelationType.both, roles); if(identities.isEmpty()) { showWarning("error.contact.to.empty"); } else { Set<Identity> deduplicates = new HashSet<>(identities); contactList.addAllIdentites(deduplicates); boolean success = false; try { File[] attachmentArr = getAttachments(); MailContext context = null; if(repoEntries.size() == 1) { context = new MailContextImpl("[RepositoryEntry:" + repoEntries.get(0).getKey() + "]"); } MailBundle bundle = new MailBundle(); bundle.setContext(context); bundle.setFromId(getIdentity()); bundle.setContactLists(Collections.singletonList(contactList)); bundle.setContent(subjectEl.getValue(), bodyEl.getValue(), attachmentArr); MailerResult result = mailService.sendMessage(bundle); if(copyFromEl.isAtLeastSelected(1)) { MailBundle ccBundle = new MailBundle(); ccBundle.setContext(context); ccBundle.setFromId(getIdentity()); ccBundle.setCc(getIdentity()); ccBundle.setContent(subjectEl.getValue(), bodyEl.getValue(), attachmentArr); MailerResult ccResult = mailService.sendMessage(ccBundle); result.append(ccResult); } success = result.isSuccessful(); } catch (Exception e) { //error in recipient email address(es) handleAddressException(success); } if (success) { showInfo("msg.send.ok"); // do logging ThreadLocalUserActivityLogger.log(MailLoggingAction.MAIL_SENT, getClass()); fireEvent(ureq, Event.DONE_EVENT); } else { showInfo("error.msg.send.nok"); fireEvent(ureq, Event.FAILED_EVENT); } } } @Override protected void formCancelled(UserRequest ureq) { fireEvent(ureq, Event.CANCELLED_EVENT); } public static class Attachment { private final File file; private final String filename; private final String cssClass; private final FormLink deleteLink; public Attachment(File file, String filename, String cssClass, FormLink deleteLink) { this.file = file; this.filename = filename; this.cssClass = cssClass; this.deleteLink = deleteLink; } public File getFile() { return file; } public String getCssClass() { return cssClass; } public String getFilename() { return filename; } public FormLink getDeleteLink() { return deleteLink; } public String getDeleteComponentName() { return deleteLink.getComponent().getComponentName(); } } }