/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <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>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <hr>
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* This file has been modified by the OpenOLAT community. Changes are licensed
* under the Apache 2.0 license as the original file.
*/
package org.olat.modules.co;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import org.olat.core.CoreSpringFactory;
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.RichTextElement;
import org.olat.core.gui.components.form.flexible.elements.SelectionElement;
import org.olat.core.gui.components.form.flexible.elements.TextElement;
import org.olat.core.gui.components.form.flexible.impl.Form;
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.util.FileUtils;
import org.olat.core.util.StringHelper;
import org.olat.core.util.Util;
import org.olat.core.util.filter.FilterFactory;
import org.olat.core.util.mail.ContactList;
import org.olat.core.util.mail.EmailAddressValidator;
import org.olat.core.util.mail.MailModule;
import org.olat.user.UserManager;
/**
* highly configurable contact form. Depending on each field value the
* corresponding fields become editable or not.
* <p>
* By creation time the defaults are: a FROM: field containing the logged in
* users e-mail, an empty TO: field not editable, empty SUBJECT: and BODY:
* fields both editable, and last but not least a submit cancel buttons pair.
* <P>
* <ul>
* Send-Limitations:
* <li>maxLength for 'body' TextAreaElement -> 10000 characters, about 4 pages
* </li>>
* <li>maxLength for 'to' TextAreaElement -> 30000 characters, enough space for
* a lot of mail group names, each mail group containing umlimited ammount of
* e-mail addresses</li>
* </ul>
*
* Initial Date: Jul 19, 2004
* @author patrick
*/
public class ContactForm extends FormBasicController {
//
private final static String NLS_CONTACT_TO = "contact.to";
private TextElement tto = null;
private TextElement ttoBig = null;
private final static String NLS_CONTACT_FROM = "contact.from";
private TextElement tfrom;
private final static String NLS_CONTACT_SUBJECT = "contact.subject";
private TextElement tsubject;
private final static String NLS_CONTACT_BODY = "contact.body";
private RichTextElement tbody;
private final static String NLS_CONTACT_ATTACHMENT = "contact.attachment";
private final static String NLS_CONTACT_ATTACHMENT_EXPL = "contact.attachment.maxsize";
private int contactAttachmentMaxSizeInMb = 5;
private FileElement attachmentEl;
private List<FormLink> attachmentLinks = new ArrayList<FormLink>();
private FormLayoutContainer uploadCont;
private boolean recipientsAreEditable = false;
private final static int emailCols = 60;
private boolean readOnly=false;
private boolean hasMsgCancel=false;
private boolean hasMsgSave=true;
private final static String NLS_CONTACT_SEND_CP_FROM = "contact.cp.from";
private SelectionElement tcpfrom;
private Identity emailFrom;
private File attachementTempDir;
private long attachmentSize = 0l;
private Map<String,String> attachmentCss = new HashMap<String,String>();
private Map<String,String> attachmentNames = new HashMap<String,String>();
private Map<String,ContactList> contactLists = new Hashtable<String,ContactList>();
private final UserManager userManager;
public ContactForm(UserRequest ureq, WindowControl wControl, Identity emailFrom, boolean readOnly, boolean isCancellable, boolean hasRecipientsEditable) {
super(ureq, wControl);
this.emailFrom = emailFrom;
this.readOnly = readOnly;
this.recipientsAreEditable = hasRecipientsEditable;
this.hasMsgCancel = isCancellable;
this.contactAttachmentMaxSizeInMb = CoreSpringFactory.getImpl(MailModule.class).getMaxSizeForAttachement();
userManager = CoreSpringFactory.getImpl(UserManager.class);
initForm(ureq);
}
public ContactForm(UserRequest ureq, WindowControl wControl, Form rootForm, Identity emailFrom, boolean readOnly, boolean isCancellable, boolean isSaveable, boolean hasRecipientsEditable) {
super(ureq, wControl, LAYOUT_DEFAULT, null, rootForm);
this.emailFrom = emailFrom;
this.readOnly = readOnly;
this.recipientsAreEditable = hasRecipientsEditable;
this.hasMsgCancel = isCancellable;
this.hasMsgSave = isSaveable;
this.contactAttachmentMaxSizeInMb = CoreSpringFactory.getImpl(MailModule.class).getMaxSizeForAttachement();
userManager = CoreSpringFactory.getImpl(UserManager.class);
initForm(ureq);
}
/**
* @param defaultSubject
*/
protected void setSubject(final String defaultSubject) {
tsubject.setValue(defaultSubject);
tsubject.setEnabled(!readOnly);
tsubject.setMandatory(tsubject.isEnabled());
}
/**
* add a ContactList as EmailTo:
*
* @param emailList
*/
public void addEmailTo(ContactList emailList) {
if (contactLists.containsKey(emailList.getName())) {
//there is already a ContactList with this name...
ContactList existing = contactLists.get(emailList.getName());
//, merge their values.
existing.add(emailList);
//the form itself must not be updated, because it already displays
// the name.
} else {
//a new ContactList, put it into contactLists
contactLists.put(emailList.getName(), emailList);
//and add its name in the form
addContactFormEmailTo("[" + emailList.getName() + "]");
}
}
/**
* @param defaultEmailTo
*/
private void addContactFormEmailTo(String defaultEmailTo) {
defaultEmailTo += tto.getValue();
tto.setValue(defaultEmailTo);
ttoBig.setValue(defaultEmailTo);
tto.setVisible(!recipientsAreEditable);
ttoBig.setVisible(recipientsAreEditable);
}
/**
* @param defaultBody
*/
public void setBody(String defaultBody) {
tbody.setValue(defaultBody);
tbody.setEnabled(!readOnly);
tbody.setVisible(true);
tbody.setMandatory(!readOnly);
}
@Override
public boolean validateFormLogic(UserRequest ureq) {
if(readOnly){
return true;
}
boolean fromMailAddOk = true;
if(tfrom.isEnabled()) {
String mailInputValue = tfrom.getValue().trim();
fromMailAddOk = EmailAddressValidator.isValidEmailAddress(mailInputValue);
if(!fromMailAddOk){
tfrom.setErrorKey("error.field.not.valid.email",null);
}
}
boolean subjectOk = !tsubject.isEmpty("error.field.not.empty");
boolean bodyOk = !tbody.isEmpty("error.field.not.empty");
// the body message may not be longer than about 4 pages or 10000
// characters
//bodyOk = bodyOk && tbody.notLongerThan(10000, "input.toolong");
boolean toOk = false;
if (tto != null) {
toOk = !tto.isEmpty("error.field.not.empty");
} else {
toOk = !ttoBig.isEmpty("error.field.not.empty");
// limit of recipients about 700 (1 emailaddress medial 40
// characters)
//toOk = toOk && ttoBig.notLongerThan(30000, "input.toolong");
}
boolean fromOk = !tfrom.isEmpty("error.field.not.empty");
return subjectOk && bodyOk && toOk && fromOk && fromMailAddOk;
}
/**
* @return
*/
public String getEmailFrom() {
return tfrom.getValue().trim();
}
/**
* a List with ContactLists as elements is returned
*
* @return
*/
public List<ContactList> getEmailToContactLists() {
List<ContactList> retVal = new ArrayList<ContactList>();
retVal.addAll(contactLists.values());
return retVal;
}
/**
* retrieve the contact list names from the to field, and map them back to the
* stored contact lists names.
*
* @return
*/
protected String getEmailTo() {
String retVal = "";
String value;
if (tto != null) value = tto.getValue();
else value = ttoBig.getValue();
String sep = "";
int i = 0;
int j = -1;
i = value.indexOf("[", j + 1);
j = value.indexOf("]", j + 2);
while (i > -1 && j > 0) {
String contactListName = value.substring(i + 1, j);
i = value.indexOf("[", j + 1);
j = value.indexOf("]", j + 2);
if (contactLists.containsKey(contactListName)) {
ContactList found = contactLists.get(contactListName);
retVal += sep + found.toString();
sep = ", ";
}
}
return retVal;
}
/**
* @return
*/
public String getSubject() {
return tsubject.getValue();
}
/**
* @return email body text
*/
public String getBody() {
return tbody.getValue(FilterFactory.getSmileysCssToDataUriFilter());
}
public File[] getAttachments() {
List<File> attachments = new ArrayList<File>();
for(FormLink removeLink : attachmentLinks) {
attachments.add((File)removeLink.getUserObject());
}
return attachments.toArray(new File[attachments.size()]);
}
public void cleanUpAttachments() {
if(attachementTempDir != null && attachementTempDir.exists()) {
FileUtils.deleteDirsAndFiles(attachementTempDir, true, true);
attachementTempDir = null;
}
}
public boolean isTcpFrom() {
return tcpfrom.isSelected(0);
}
protected void setDisplayOnly (boolean readOnly) {
this.readOnly = readOnly;
if (readOnly) {
flc.setEnabled(false);
}
}
@Override
protected void formOK(UserRequest ureq) {
fireEvent (ureq, Event.DONE_EVENT);
}
@Override
protected void formCancelled(UserRequest ureq) {
fireEvent (ureq, Event.CANCELLED_EVENT);
}
@Override
protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if(source == attachmentEl) {
String filename = attachmentEl.getUploadFileName();
if(attachementTempDir == null) {
attachementTempDir = FileUtils.createTempDir("attachements", null, null);
}
long size = attachmentEl.getUploadSize();
if(size + attachmentSize > (contactAttachmentMaxSizeInMb * 1024 * 1024)) {
showWarning(NLS_CONTACT_ATTACHMENT_EXPL, Integer.toString(contactAttachmentMaxSizeInMb));
attachmentEl.reset();
} else {
File attachment = attachmentEl.moveUploadFileTo(attachementTempDir);
// attachment = null;
// OO-48 somehow file-move can fail, check for it, display error-dialog if it failed
if(attachment == null){
attachmentEl.reset();
logError("Could not move contact-form attachment to " + attachementTempDir.getAbsolutePath(), null);
setTranslator(Util.createPackageTranslator(FileUploadController.class, getLocale(),getTranslator()));
showError("FileMoveCopyFailed","");
return;
}
attachmentEl.reset();
attachmentSize += size;
FormLink removeFile = uifactory.addFormLink(attachment.getName(), "delete", null, uploadCont, Link.BUTTON_SMALL);
removeFile.setUserObject(attachment);
attachmentLinks.add(removeFile);
//pretty labels
uploadCont.setLabel(NLS_CONTACT_ATTACHMENT, null);
attachmentNames.put(attachment.getName(), filename);
attachmentCss.put(attachment.getName(), CSSHelper.createFiletypeIconCssClassFor(filename));
uploadCont.contextPut("attachments", attachmentLinks);
uploadCont.contextPut("attachmentNames", attachmentNames);
uploadCont.contextPut("attachmentCss", attachmentCss);
attachmentEl.setLabel(null, null);
}
} else if (attachmentLinks.contains(source)) {
File uploadedFile = (File)source.getUserObject();
if(uploadedFile != null && uploadedFile.exists()) {
attachmentSize -= uploadedFile.length();
uploadedFile.delete();
}
attachmentLinks.remove(source);
uploadCont.remove(source);
if(attachmentLinks.isEmpty()) {
uploadCont.setLabel(null, null);
attachmentEl.setLabel(NLS_CONTACT_ATTACHMENT, null);
}
}
super.formInnerEvent(ureq, source, event);
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
setFormTitle("header.newcntctmsg");
String fullName = userManager.getUserDisplayName(emailFrom);
if(StringHelper.containsNonWhitespace(fullName)) {
fullName = "[" + fullName + "]";
}
tfrom = uifactory.addTextElement("ttfrom", NLS_CONTACT_FROM, 255, fullName, formLayout);
tfrom.setElementCssClass("o_sel_contact_to");
// When no identity is set, let user enter a valid email address
tfrom.setEnabled((this.emailFrom == null));
tto = uifactory.addTextElement("tto", NLS_CONTACT_TO, 255, "", formLayout);
tto.setEnabled(false);
tto.setVisible(false);
ttoBig = uifactory.addTextAreaElement("ttoBig", NLS_CONTACT_TO, -1, 2, emailCols, true, "", formLayout);
ttoBig.setEnabled(false);
ttoBig.setVisible(false);
tsubject = uifactory.addTextElement("tsubject", NLS_CONTACT_SUBJECT, 255, "", formLayout);
tsubject.setDisplaySize(emailCols);
tbody = uifactory.addRichTextElementForStringDataMinimalistic("tbody", NLS_CONTACT_BODY, "", 15, emailCols, formLayout, getWindowControl());
tbody.setEnabled(!readOnly);
tbody.getEditorConfiguration().setRelativeUrls(false);
tbody.getEditorConfiguration().setRemoveScriptHost(false);
String VELOCITY_ROOT = Util.getPackageVelocityRoot(this.getClass());
uploadCont = FormLayoutContainer.createCustomFormLayout("file_upload_inner", getTranslator(), VELOCITY_ROOT + "/attachments.html");
uploadCont.setRootForm(mainForm);
formLayout.add(uploadCont);
attachmentEl = uifactory.addFileElement(getWindowControl(), "file_upload_1", NLS_CONTACT_ATTACHMENT, formLayout);
attachmentEl.setLabel(NLS_CONTACT_ATTACHMENT, null);
attachmentEl.addActionListener(FormEvent.ONCHANGE);
attachmentEl.setExampleKey(NLS_CONTACT_ATTACHMENT_EXPL, new String[]{Integer.toString(contactAttachmentMaxSizeInMb)});
tcpfrom = uifactory.addCheckboxesVertical("tcpfrom", "", formLayout, new String[]{"xx"}, new String[]{translate(NLS_CONTACT_SEND_CP_FROM)}, 1);
FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonGroupLayout", getTranslator());
formLayout.add(buttonGroupLayout);
if(hasMsgSave) {
uifactory.addFormSubmitButton("msg.save", buttonGroupLayout);
}
if (hasMsgCancel) {
uifactory.addFormCancelButton("msg.cancel", buttonGroupLayout, ureq, getWindowControl());
}
}
@Override
protected void doDispose() {
cleanUpAttachments();
}
}