From 99a4ccdcfe1e53fccc61c1d7ca181873703a4987 Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Thu, 8 Dec 2011 12:34:09 +0100 Subject: [PATCH] FXOLAT-391: backport mail management --- .../ui/ViteroUserToGroupController.java | 9 + .../assessment/AssessmentMainController.java | 11 + .../den/DENManageParticipantsController.java | 10 +- .../handlers/QTITestHandlerOnyx.java | 6 +- .../ChecklistManageCheckpointsController.java | 4 + .../InstitutionPortletRunController.java | 2 +- .../bps/olat/user/ChangeEMailController.java | 2 +- .../course/nodes/iq/IQEditReplaceWizard.java | 6 +- .../CourseCreationMailHelper.java | 5 +- .../olat/admin/user/SendTokenToUserForm.java | 4 +- .../user/delete/BulkDeleteController.java | 3 +- .../InfoMessageFrontendManagerImpl.java | 6 +- .../commons/info/manager/MailFormatter.java | 2 + .../info/ui/InfoCourseNodeResourceable.java | 23 + .../commons/info/ui/InfoDisplayHelper.java | 89 ++ .../org/olat/core/commons/persistence/DB.java | 19 + .../olat/core/commons/persistence/DBImpl.java | 33 +- .../core/commons/persistence/DBManager.java | 29 + .../_spring/databaseCorecontext.xml | 4 +- .../core/dispatcher/ErrorFeedbackMailer.java | 64 +- .../java/org/olat/core/id/Preferences.java | 14 + .../org/olat/core/util/mail/ContactList.java | 86 +- .../olat/core/util/mail/ContactMessage.java | 6 +- .../java/org/olat/core/util/mail/Emailer.java | 126 +- .../olat/core/util/mail/MailContextImpl.java | 119 ++ .../org/olat/core/util/mail/MailHelper.java | 160 +-- .../org/olat/core/util/mail/MailModule.java | 155 +++ .../olat/core/util/mail/MailUIFactory.java | 60 + .../org/olat/core/util/mail/MailerResult.java | 4 +- .../core/util/mail/MailerWithTemplate.java | 164 ++- .../mail/_i18n/LocalStrings_ar.properties | 2 +- .../mail/_i18n/LocalStrings_bg.properties | 2 +- .../mail/_i18n/LocalStrings_cs.properties | 2 +- .../mail/_i18n/LocalStrings_da.properties | 2 +- .../mail/_i18n/LocalStrings_de.properties | 51 +- .../mail/_i18n/LocalStrings_en.properties | 52 +- .../mail/_i18n/LocalStrings_es.properties | 2 +- .../mail/_i18n/LocalStrings_fa.properties | 2 +- .../mail/_i18n/LocalStrings_fr.properties | 2 +- .../mail/_i18n/LocalStrings_it.properties | 2 +- .../mail/_i18n/LocalStrings_jp.properties | 2 +- .../mail/_i18n/LocalStrings_lt.properties | 2 +- .../mail/_i18n/LocalStrings_nl_NL.properties | 2 +- .../mail/_i18n/LocalStrings_pl.properties | 2 +- .../mail/_i18n/LocalStrings_pt_BR.properties | 2 +- .../mail/_i18n/LocalStrings_pt_PT.properties | 2 +- .../mail/_i18n/LocalStrings_ru.properties | 2 +- .../mail/_i18n/LocalStrings_zh_CN.properties | 2 +- .../mail/_i18n/LocalStrings_zh_TW.properties | 2 +- .../core/util/mail/_spring/mailContext.xml | 137 ++ .../core/util/mail/manager/MailManager.java | 1202 +++++++++++++++++ .../manager/MailNotificationsHandler.java | 126 ++ .../olat/core/util/mail/model/DBMail.hbm.xml | 33 + .../org/olat/core/util/mail/model/DBMail.java | 54 + .../util/mail/model/DBMailAttachment.hbm.xml | 30 + .../util/mail/model/DBMailAttachment.java | 85 ++ .../util/mail/model/DBMailAttachmentData.java | 89 ++ .../core/util/mail/model/DBMailContext.java | 94 ++ .../olat/core/util/mail/model/DBMailImpl.java | 138 ++ .../util/mail/model/DBMailRecipient.hbm.xml | 23 + .../core/util/mail/model/DBMailRecipient.java | 127 ++ .../util/mail/ui/BooleanCSSCellRenderer.java | 71 + .../util/mail/ui/MailActionExtension.java | 53 + .../util/mail/ui/MailAdminController.java | 143 ++ .../util/mail/ui/MailAttachmentMapper.java | 144 ++ .../util/mail/ui/MailContextCellRenderer.java | 76 ++ .../util/mail/ui/MailContextResolver.java | 23 + .../util/mail/ui/MailContextShortName.java | 59 + .../core/util/mail/ui/MailController.java | 188 +++ .../olat/core/util/mail/ui/MailDataModel.java | 243 ++++ .../util/mail/ui/MailFromCellRenderer.java | 82 ++ .../core/util/mail/ui/MailListController.java | 447 ++++++ .../olat/core/util/mail/ui/MailTreeNode.java | 57 + .../ContextualSubscriptionController.java | 2 +- .../notifications/NotificationsManager.java | 10 + .../_i18n/LocalStrings_de.properties | 2 +- .../_i18n/LocalStrings_en.properties | 2 +- .../items/SubscriptionListItem.java | 12 +- .../course/nodes/en/EnrollmentManager.java | 18 +- .../info/SendMailFormatterForCourse.java | 6 + .../nodes/info/_chelp/ced-info-config.html | 2 +- .../course/nodes/iq/IQEditReplaceWizard.java | 6 +- .../projectbroker/ProjectGroupController.java | 6 +- .../service/ProjectBrokerMailerImpl.java | 14 +- .../course/nodes/ta/DropboxController.java | 6 +- .../ta/DropboxScoringViewController.java | 7 +- .../nodes/ta/TACourseNodeEditController.java | 6 +- .../olat/group/BusinessGroupManagerImpl.java | 12 +- .../ui/edit/BusinessGroupEditController.java | 8 +- .../ui/edit/_i18n/LocalStrings_en.properties | 5 +- .../home/_i18n/LocalStrings_de.properties | 4 + .../home/_i18n/LocalStrings_en.properties | 4 + .../java/org/olat/modules/co/ContactForm.java | 5 +- .../modules/co/ContactFormController.java | 10 +- .../NotificationNewsController.java | 3 +- ...ificationSubscriptionAndNewsFormatter.java | 14 +- .../NotificationsManagerImpl.java | 58 +- .../NotificationsPortletRunController.java | 40 +- .../ui/structel/EPShareListController.java | 6 +- .../registration/RegistrationController.java | 12 +- .../registration/RegistrationManager.java | 12 +- .../_i18n/LocalStrings_de.properties | 1 + .../_i18n/LocalStrings_en.properties | 1 + .../WizardCloseCourseController.java | 6 +- .../org/olat/upgrade/OLATUpgrade_7_1_1.java | 136 ++ .../olat/user/ChangePasswordController.java | 2 + .../java/org/olat/user/MailBoxExtension.java | 159 +++ .../olat/user/PreferencesFormController.java | 31 +- .../java/org/olat/user/PreferencesImpl.java | 20 +- src/main/java/org/olat/user/UserImpl.hbm.xml | 6 +- src/main/java/org/olat/user/UserManager.java | 6 +- .../java/org/olat/user/UserManagerImpl.java | 22 + .../java/org/olat/user/_chelp/home-prefs.html | 1 + .../user/_i18n/LocalStrings_de.properties | 6 +- .../user/_i18n/LocalStrings_en.properties | 6 +- .../resources/serviceconfig/olat.properties | 17 +- .../test/OlatcoreTestCaseWithMocking.java | 2 + .../core/test/_spring/coordinatorMock.xml | 5 + .../olat/core/test/_spring/mailModuleMock.xml | 40 + .../org/olat/core/util/mail/MailTest.java | 10 + .../nodes/en/EnrollmentManagerTest.java | 47 +- 121 files changed, 5394 insertions(+), 508 deletions(-) create mode 100644 src/main/java/org/olat/commons/info/ui/InfoCourseNodeResourceable.java create mode 100644 src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java create mode 100644 src/main/java/org/olat/core/util/mail/MailContextImpl.java create mode 100644 src/main/java/org/olat/core/util/mail/MailModule.java create mode 100644 src/main/java/org/olat/core/util/mail/MailUIFactory.java create mode 100644 src/main/java/org/olat/core/util/mail/_spring/mailContext.xml create mode 100644 src/main/java/org/olat/core/util/mail/manager/MailManager.java create mode 100644 src/main/java/org/olat/core/util/mail/manager/MailNotificationsHandler.java create mode 100644 src/main/java/org/olat/core/util/mail/model/DBMail.hbm.xml create mode 100644 src/main/java/org/olat/core/util/mail/model/DBMail.java create mode 100644 src/main/java/org/olat/core/util/mail/model/DBMailAttachment.hbm.xml create mode 100644 src/main/java/org/olat/core/util/mail/model/DBMailAttachment.java create mode 100644 src/main/java/org/olat/core/util/mail/model/DBMailAttachmentData.java create mode 100644 src/main/java/org/olat/core/util/mail/model/DBMailContext.java create mode 100644 src/main/java/org/olat/core/util/mail/model/DBMailImpl.java create mode 100644 src/main/java/org/olat/core/util/mail/model/DBMailRecipient.hbm.xml create mode 100644 src/main/java/org/olat/core/util/mail/model/DBMailRecipient.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/BooleanCSSCellRenderer.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/MailActionExtension.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/MailAdminController.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/MailAttachmentMapper.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/MailContextCellRenderer.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/MailContextResolver.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/MailContextShortName.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/MailController.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/MailDataModel.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/MailFromCellRenderer.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/MailListController.java create mode 100644 src/main/java/org/olat/core/util/mail/ui/MailTreeNode.java create mode 100644 src/main/java/org/olat/user/MailBoxExtension.java create mode 100644 src/test/java/org/olat/core/test/_spring/mailModuleMock.xml diff --git a/src/main/java/com/frentix/olat/vitero/ui/ViteroUserToGroupController.java b/src/main/java/com/frentix/olat/vitero/ui/ViteroUserToGroupController.java index 04a35ff6272..9f657b2639c 100644 --- a/src/main/java/com/frentix/olat/vitero/ui/ViteroUserToGroupController.java +++ b/src/main/java/com/frentix/olat/vitero/ui/ViteroUserToGroupController.java @@ -249,6 +249,15 @@ public class ViteroUserToGroupController extends BasicController { List<Identity> repoOwners = securityManager.getIdentitiesOfSecurityGroup(repoEntry.getOwnerGroup()); owners.addAll(repoOwners); + + if(repoEntry.getParticipantGroup() != null) { + List<Identity> repoParticipants = securityManager.getIdentitiesOfSecurityGroup(repoEntry.getParticipantGroup()); + participants.addAll(repoParticipants); + } + if(repoEntry.getTutorGroup() != null) { + List<Identity> repoTutors = securityManager.getIdentitiesOfSecurityGroup(repoEntry.getTutorGroup()); + coaches.addAll(repoTutors); + } } return new ResourceMembers(owners, coaches, participants); } diff --git a/src/main/java/de/bps/course/assessment/AssessmentMainController.java b/src/main/java/de/bps/course/assessment/AssessmentMainController.java index c75aec78bd1..f0b1c4a8946 100644 --- a/src/main/java/de/bps/course/assessment/AssessmentMainController.java +++ b/src/main/java/de/bps/course/assessment/AssessmentMainController.java @@ -104,6 +104,8 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.group.BusinessGroup; import org.olat.group.ui.context.BGContextTableModel; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryManager; import org.olat.user.UserManager; import de.bps.onyx.plugin.OnyxModule; @@ -708,6 +710,15 @@ AssessmentMainController(UserRequest ureq, WindowControl wControl, OLATResourcea } } } + //fxdiff VCRP-1,2: access control of resources + RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(ores, false); + if(re.getParticipantGroup() != null) { + for (Identity identity : secMgr.getIdentitiesOfSecurityGroup(re.getParticipantGroup())) { + if (!PersistenceHelper.listContainsObjectByKey(allUsersList, identity)) { + allUsersList.add(identity); + } + } + } return allUsersList; } diff --git a/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java b/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java index 26a7c6a60eb..e574fb83f47 100644 --- a/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java +++ b/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java @@ -39,6 +39,8 @@ import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.util.mail.ContactList; import org.olat.core.util.mail.ContactMessage; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailNotificationEditController; import org.olat.core.util.mail.MailTemplate; @@ -239,7 +241,9 @@ public class DENManageParticipantsController extends BasicController { } else { ccIdentities = null; } - MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(added, null, null, addedNotificationCtr.getMailTemplate(), ureq.getIdentity()); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); + MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, added, null, null, addedNotificationCtr.getMailTemplate(), ureq.getIdentity()); MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale()); } notificationCmc.deactivate(); @@ -252,7 +256,9 @@ public class DENManageParticipantsController extends BasicController { } else { ccIdentities = null; } - MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(added, null, null, addedNotificationCtr.getMailTemplate(), ureq.getIdentity()); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); + MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, added, null, null, addedNotificationCtr.getMailTemplate(), ureq.getIdentity()); MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale()); } notificationCmc.deactivate(); diff --git a/src/main/java/de/bps/ims/qti/repository/handlers/QTITestHandlerOnyx.java b/src/main/java/de/bps/ims/qti/repository/handlers/QTITestHandlerOnyx.java index 1226c88338a..b5a129d67e3 100644 --- a/src/main/java/de/bps/ims/qti/repository/handlers/QTITestHandlerOnyx.java +++ b/src/main/java/de/bps/ims/qti/repository/handlers/QTITestHandlerOnyx.java @@ -47,6 +47,7 @@ import org.olat.repository.controllers.IAddController; import org.olat.repository.controllers.RepositoryAddCallback; import org.olat.repository.controllers.RepositoryAddController; import org.olat.repository.controllers.WizardCloseResourceController; +import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper; import org.olat.resource.references.ReferenceManager; import de.bps.onyx.plugin.OnyxModule; @@ -107,7 +108,10 @@ public class QTITestHandlerOnyx extends QTITestHandler { } public MainLayoutController createLaunchController(OLATResourceable res, String initialViewIdentifier, UserRequest ureq, WindowControl wControl) { - return (MainLayoutController) getLaunchController( res, ureq, wControl); + MainLayoutController layoutCtr = (MainLayoutController) getLaunchController( res, ureq, wControl); + //fxdiff VCRP-1: access control of learn resources + RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, layoutCtr); + return wrapper; } /** diff --git a/src/main/java/de/bps/olat/modules/cl/ChecklistManageCheckpointsController.java b/src/main/java/de/bps/olat/modules/cl/ChecklistManageCheckpointsController.java index 953eced5270..a9874debf00 100644 --- a/src/main/java/de/bps/olat/modules/cl/ChecklistManageCheckpointsController.java +++ b/src/main/java/de/bps/olat/modules/cl/ChecklistManageCheckpointsController.java @@ -119,6 +119,8 @@ public class ChecklistManageCheckpointsController extends BasicController { // collect all identities in learning groups HashSet<Identity> identitiesInGroups = new HashSet<Identity>(); identitiesInGroups.addAll(cgm.getParticipantsFromLearningGroup(null)); + //fxdiff VCRP-1,2: access control of resources + identitiesInGroups.addAll(cgm.getParticipants()); // all identities with result and/or in learning groups HashSet<Identity> identitiesAll = new HashSet<Identity>(); @@ -138,6 +140,8 @@ public class ChecklistManageCheckpointsController extends BasicController { // collect all identities in learning groups HashSet<Identity> identitiesInGroups = new HashSet<Identity>(); identitiesInGroups.addAll(cgm.getParticipantsFromLearningGroup(null)); + //fxdiff VCRP-1,2: access control of resources + identitiesInGroups.addAll(cgm.getParticipants()); allIdentities.addAll(identitiesInGroups); // collect all learning groups diff --git a/src/main/java/de/bps/olat/portal/institution/InstitutionPortletRunController.java b/src/main/java/de/bps/olat/portal/institution/InstitutionPortletRunController.java index b35029907fc..94b484719cb 100644 --- a/src/main/java/de/bps/olat/portal/institution/InstitutionPortletRunController.java +++ b/src/main/java/de/bps/olat/portal/institution/InstitutionPortletRunController.java @@ -183,7 +183,7 @@ public class InstitutionPortletRunController extends BasicController { DTab dt = dts.getDTab(ores); if (dt == null) { // does not yet exist -> create and add - dt = dts.createDTab(ores, re.getDisplayname()); + dt = dts.createDTab(ores, re, re.getDisplayname()); if (dt == null) return; Controller launchController = ControllerFactory.createLaunchController(ores, null, ureq, dt.getWindowControl(), true); dt.setController(launchController); diff --git a/src/main/java/de/bps/olat/user/ChangeEMailController.java b/src/main/java/de/bps/olat/user/ChangeEMailController.java index 95d709acbbf..21c322dde4a 100644 --- a/src/main/java/de/bps/olat/user/ChangeEMailController.java +++ b/src/main/java/de/bps/olat/user/ChangeEMailController.java @@ -45,7 +45,7 @@ public class ChangeEMailController extends DefaultController { protected static final String PACKAGE = ProfileAndHomePageEditController.class.getPackage().getName(); protected static final String CHANGE_EMAIL_ENTRY = "change.email.login"; - public static final int TIME_OUT = 3; + public static int TIME_OUT = 3; protected Translator pT; protected String emKey; diff --git a/src/main/java/de/bps/onyx/plugin/course/nodes/iq/IQEditReplaceWizard.java b/src/main/java/de/bps/onyx/plugin/course/nodes/iq/IQEditReplaceWizard.java index 90df410f333..0e3daea45d9 100644 --- a/src/main/java/de/bps/onyx/plugin/course/nodes/iq/IQEditReplaceWizard.java +++ b/src/main/java/de/bps/onyx/plugin/course/nodes/iq/IQEditReplaceWizard.java @@ -32,6 +32,8 @@ import org.olat.core.gui.control.generic.wizard.WizardController; import org.olat.core.helpers.Settings; import org.olat.core.id.Identity; import org.olat.core.logging.OLATRuntimeException; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailNotificationEditController; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerWithTemplate; @@ -147,7 +149,9 @@ public class IQEditReplaceWizard extends WizardController { recipientsCC = new ArrayList<Identity>(); recipientsCC.add(ureq.getIdentity()); } - MailerWithTemplate.getInstance().sendMailAsSeparateMails(learners, recipientsCC, null, mailCtr.getMailTemplate(), ureq.getIdentity()); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString()); + MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, learners, recipientsCC, null, mailCtr.getMailTemplate(), ureq.getIdentity()); } fireEvent(ureq, Event.DONE_EVENT); } else if (source == searchCtr && event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) { diff --git a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationMailHelper.java b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationMailHelper.java index d4113604899..d3816d10118 100644 --- a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationMailHelper.java +++ b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationMailHelper.java @@ -33,6 +33,8 @@ import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.logging.Tracing; import org.olat.core.util.Util; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; import org.olat.core.util.mail.MailerWithTemplate; @@ -105,7 +107,8 @@ public class CourseCreationMailHelper { // nothing to do } }; - return MailerWithTemplate.getInstance().sendMail(ureq.getIdentity(), null, null, template, null); + //fxdiff VCRP-16: intern mail system + return MailerWithTemplate.getInstance().sendRealMail(ureq.getIdentity(), template); } } diff --git a/src/main/java/org/olat/admin/user/SendTokenToUserForm.java b/src/main/java/org/olat/admin/user/SendTokenToUserForm.java index 33d3a0df054..8e11435b514 100644 --- a/src/main/java/org/olat/admin/user/SendTokenToUserForm.java +++ b/src/main/java/org/olat/admin/user/SendTokenToUserForm.java @@ -163,8 +163,8 @@ public class SendTokenToUserForm extends FormBasicController { // nothing to do } }; - - MailerResult result = MailerWithTemplate.getInstance().sendMail(user, null, null, mailTempl, null); + //fxdiff VCRP-16: intern mail system + MailerResult result = MailerWithTemplate.getInstance().sendRealMail(user, mailTempl); if(result.getReturnCode() == 0) { showInfo("email.sent"); } else { diff --git a/src/main/java/org/olat/admin/user/delete/BulkDeleteController.java b/src/main/java/org/olat/admin/user/delete/BulkDeleteController.java index 3cc97216a69..60859f9d370 100644 --- a/src/main/java/org/olat/admin/user/delete/BulkDeleteController.java +++ b/src/main/java/org/olat/admin/user/delete/BulkDeleteController.java @@ -151,7 +151,8 @@ public class BulkDeleteController extends BasicController { Emailer mailer = new Emailer(ureq.getLocale()); try { - mailer.sendEmail(lstAddrTO, subject, body); + //fxdiff VCRP-16: intern mail system + mailer.sendEmail(null, lstAddrTO, subject, body); } catch (AddressException e) { Tracing.createLoggerFor(BulkDeleteController.class).error("Notificatoin mail for bulk deletion could not be sent"); } catch (MessagingException e) { diff --git a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java b/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java index e1cd35ca4a0..9c9fad087e0 100644 --- a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java +++ b/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java @@ -40,6 +40,8 @@ import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.MultiUserEvent; import org.olat.core.util.mail.ContactList; import org.olat.core.util.mail.Emailer; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; /** * @@ -124,7 +126,9 @@ public class InfoMessageFrontendManagerImpl extends InfoMessageFrontendManager { if(!StringHelper.containsNonWhitespace(body)) { body = infoMessage.getMessage(); } - send = mailer.sendEmail(contacts, subject, body); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(mailFormatter.getBusinessPath()); + send = mailer.sendEmail(context, contacts, subject, body); } catch (AddressException e) { logError("Cannot send info messages", e); } catch (MessagingException e) { diff --git a/src/main/java/org/olat/commons/info/manager/MailFormatter.java b/src/main/java/org/olat/commons/info/manager/MailFormatter.java index 3514e93a9cf..786d99224e3 100644 --- a/src/main/java/org/olat/commons/info/manager/MailFormatter.java +++ b/src/main/java/org/olat/commons/info/manager/MailFormatter.java @@ -38,4 +38,6 @@ public interface MailFormatter { public String getSubject(InfoMessage msg); public String getBody(InfoMessage msg); + //fxdiff VCRP-16: intern mail system + public String getBusinessPath(); } diff --git a/src/main/java/org/olat/commons/info/ui/InfoCourseNodeResourceable.java b/src/main/java/org/olat/commons/info/ui/InfoCourseNodeResourceable.java new file mode 100644 index 00000000000..af9561e7bb4 --- /dev/null +++ b/src/main/java/org/olat/commons/info/ui/InfoCourseNodeResourceable.java @@ -0,0 +1,23 @@ +package org.olat.commons.info.ui; + +import org.olat.core.id.OLATResourceable; +import org.olat.core.util.resource.OresHelper; +import org.olat.course.CourseModule; + +public class InfoCourseNodeResourceable implements OLATResourceable { + private final Long resId; + + public InfoCourseNodeResourceable(Long resId) { + this.resId = resId; + } + + @Override + public String getResourceableTypeName() { + return OresHelper.calculateTypeName(CourseModule.class); + } + + @Override + public Long getResourceableId() { + return resId; + } +} diff --git a/src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java b/src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java new file mode 100644 index 00000000000..439ad96ba7a --- /dev/null +++ b/src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java @@ -0,0 +1,89 @@ +/** + * 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) frentix GmbH<br> + * http://www.frentix.com<br> + * <p> + */ + +package org.olat.commons.info.ui; + +import java.text.DateFormat; + +import org.olat.commons.info.model.InfoMessage; +import org.olat.core.gui.translator.Translator; +import org.olat.core.id.User; +import org.olat.core.id.UserConstants; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; + +/** + * + * Description:<br> + * Small helper class to format some datas of the InfoMessage for display. + * + * <P> + * Initial Date: 28 jul. 2010 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class InfoDisplayHelper { + + private final DateFormat formatter; + private final Translator translator; + + public InfoDisplayHelper(Translator translator) { + this.formatter = DateFormat.getDateInstance(DateFormat.MEDIUM, translator.getLocale()); + this.translator = translator; + } + + public String getAuthor(InfoMessage info) { + User user = info.getAuthor().getUser(); + String formattedName = user.getProperty(UserConstants.FIRSTNAME, null) + + " " + user.getProperty(UserConstants.LASTNAME, null); + return formattedName; + } + + + public String getInfos(InfoMessage info) { + String formattedName = getAuthor(info); + String creationDate = formatter.format(info.getCreationDate()); + String msgAddInfos = translator.translate("display.info", new String[]{formattedName, creationDate}); + return msgAddInfos; + } + + public boolean isModified(InfoMessage info) { + return info.getModifier() != null; + } + + public String getModifier(InfoMessage info) { + if(info.getModifier() == null) return "";//return empty string for velocity + + User user = info.getModifier().getUser(); + String formattedName = user.getProperty(UserConstants.FIRSTNAME, null) + + " " + user.getProperty(UserConstants.LASTNAME, null); + String creationDate = formatter.format(info.getModificationDate()); + String msgAddInfos = translator.translate("display.modifier", new String[]{formattedName, creationDate}); + return msgAddInfos; + } + + public String getMessage(InfoMessage info) { + String message = info.getMessage(); + if(StringHelper.containsNonWhitespace(message)) { + return Formatter.escWithBR(message).toString(); + } + return ""; + } +} diff --git a/src/main/java/org/olat/core/commons/persistence/DB.java b/src/main/java/org/olat/core/commons/persistence/DB.java index 6cffbb0defc..528e5c7b986 100644 --- a/src/main/java/org/olat/core/commons/persistence/DB.java +++ b/src/main/java/org/olat/core/commons/persistence/DB.java @@ -24,6 +24,7 @@ package org.olat.core.commons.persistence; import java.util.List; +import org.hibernate.Query; import org.hibernate.stat.Statistics; import org.hibernate.type.Type; import org.olat.core.id.Persistable; @@ -221,4 +222,22 @@ public interface DB { * @return True if any errors occured in the previous DB call. */ public boolean isError(); + + + // + // fxdiff + // Extensions used for native SQL queries + // + /** + * Create a named hibernate query for the given name. Optionally the database + * vendor is prepended to load database specific queries if available. Use + * this only when absolutely necessary. + * + * @param queryName The query name + * @param vendorSpecific true: prepend the database vendor name to the query + * name, e.g. mysql_queryName; false: use queryName as is + * @return the query or NULL if no such named query exists + */ + public DBQuery createNamedQuery(final String queryName, boolean vendorSpecific); + } \ No newline at end of file diff --git a/src/main/java/org/olat/core/commons/persistence/DBImpl.java b/src/main/java/org/olat/core/commons/persistence/DBImpl.java index 0d4493290e6..e9046e6b5c6 100644 --- a/src/main/java/org/olat/core/commons/persistence/DBImpl.java +++ b/src/main/java/org/olat/core/commons/persistence/DBImpl.java @@ -39,7 +39,6 @@ import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; -import javax.security.auth.DestroyFailedException; import org.hibernate.HibernateException; import org.hibernate.Session; @@ -888,4 +887,36 @@ public class DBImpl extends LogDelegator implements DB, Destroyable { } } } + + // + // fxdiff qti-statistics (praktikum MK) + // Extensions used for native SQL queries + // + String dbVendor = null; + /** + * [used by spring] + * @param dbVendor + */ + public void setDbvendor(String dbVendor) { + this.dbVendor = dbVendor; + } + + /** + * Create a named hibernate query for the given name. Optionally the database + * vendor is prepended to load database specific queries if available. Use + * this only when absolutely necessary. + * + * @param queryName The query name + * @param vendorSpecific true: prepend the database vendor name to the query + * name, e.g. mysql_queryName; false: use queryName as is + * @return the query or NULL if no such named query exists + */ + public DBQuery createNamedQuery(final String queryName, boolean vendorSpecific) { + if (queryName == null) { + throw new AssertException("queryName must not be NULL"); + } + + beginTransaction(queryName); + return getDBManager().createNamedQuery(queryName, dbVendor, vendorSpecific); + } } diff --git a/src/main/java/org/olat/core/commons/persistence/DBManager.java b/src/main/java/org/olat/core/commons/persistence/DBManager.java index 42c11362dba..127b3b64c42 100644 --- a/src/main/java/org/olat/core/commons/persistence/DBManager.java +++ b/src/main/java/org/olat/core/commons/persistence/DBManager.java @@ -28,6 +28,7 @@ import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.type.Type; +import org.olat.core.logging.AssertException; import org.olat.core.logging.DBRuntimeException; import org.olat.core.logging.Tracing; import org.olat.core.manager.BasicManager; @@ -273,6 +274,34 @@ class DBManager extends BasicManager { return dbq; } + DBQuery createNamedQuery(final String queryName, String dbVendor, boolean vendorSpecific) { + if (queryName == null) { + throw new AssertException("queryName must not be NULL"); + } + Query q= null; + DBQuery dbq = null; + if (vendorSpecific) { + String finalQueryName = vendorSpecific ? dbVendor + "_" + queryName : queryName; + q = this.getSession().getNamedQuery(finalQueryName); + if (q == null) { + // try fallback with normal query + q = this.getSession().getNamedQuery(queryName); + } + if (q == null) { + String msg = "Can not create namedQuery::" + finalQueryName; + if (vendorSpecific) { + msg += " for dbvendor::" + dbVendor + " and non db specific::" + queryName; + } + msg += ", named query does not exist"; + logError(msg, null); + } else { + + dbq = new DBQueryImpl(q); + } + } + return dbq; + } + /** * @param session */ diff --git a/src/main/java/org/olat/core/commons/persistence/_spring/databaseCorecontext.xml b/src/main/java/org/olat/core/commons/persistence/_spring/databaseCorecontext.xml index f79e4beaa4f..a4e56696fef 100644 --- a/src/main/java/org/olat/core/commons/persistence/_spring/databaseCorecontext.xml +++ b/src/main/java/org/olat/core/commons/persistence/_spring/databaseCorecontext.xml @@ -16,7 +16,8 @@ <!-- Hibernate SessionFactory --> <!-- taken from: http://www.shoesobjects.com/blog/2004/11/21/1101083542880.html --> - <bean id="sessionFactory" class="org.olat.core.commons.persistence.OLATLocalSessionFactoryBean"> + <bean id="sessionFactory" class="org.olat.core.commons.persistence.OLATLocalSessionFactoryBean" + depends-on="databaseUpgrader"> <!-- Setting datasource let Spring using the LocalDataSourceConnectionProvider. Some JUnit Tests fail if not the hibernate C3P0ConnectionProvider is used. Not using the dataSource property in the sessionFactory means setting the connection in the hibernateProperties. DataSources are still defined for the Upgrader and the Statistics feature. @@ -93,6 +94,7 @@ <bean id="database" class="org.olat.core.commons.persistence.DBImpl" destroy-method="destroy"> <property name="sessionFactory" ref="sessionFactory"/> + <property name="dbvendor" value="${db.vendor}" /> </bean> <bean id="persistenceHelper" class="org.olat.core.commons.persistence.PersistenceHelper"> diff --git a/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java b/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java index ffa47b7d30e..c339033b861 100644 --- a/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java +++ b/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java @@ -39,7 +39,7 @@ import org.olat.core.logging.AssertException; import org.olat.core.logging.LogFileParser; import org.olat.core.logging.Tracing; import org.olat.core.util.WebappHelper; -import org.olat.core.util.mail.Emailer; +import org.olat.core.util.mail.manager.MailManager; /** * Description:<br> @@ -54,7 +54,7 @@ public class ErrorFeedbackMailer implements Dispatcher { private static final ErrorFeedbackMailer INSTANCE = new ErrorFeedbackMailer(); private ErrorFeedbackMailer() { - // private since singleton + // private since singleton } protected static ErrorFeedbackMailer getInstance() { @@ -71,67 +71,43 @@ public class ErrorFeedbackMailer implements Dispatcher { String errorNr = feedback.substring(0, feedback.indexOf("\n") - 1); String username = request.getParameter("username"); try { - IdentityManager im = (IdentityManager)CoreSpringFactory.getBean("core.id.IdentityManager"); + IdentityManager im = (IdentityManager) CoreSpringFactory.getBean("core.id.IdentityManager"); Identity ident = im.findIdentityByName(username); - //if null, user may crashed befor getting a valid session, try with guest user instead - if (ident == null) ident = im.findIdentityByName("guest"); - Emailer emailer = new Emailer(ident, false); - String errorNum = parseErrorNumber(errorNr); - Collection logFileEntries = LogFileParser.getErrorToday(errorNum, false); + // if null, user may crashed befor getting a valid session, try with + // guest user instead + if (ident == null) + ident = im.findIdentityByName("guest"); + Collection<String> logFileEntries = LogFileParser.getErrorToday(errorNr, false); StringBuilder out = new StringBuilder(); if (logFileEntries != null) { - for (Iterator iter = logFileEntries.iterator(); iter.hasNext();) { - out.append((String) iter.next()); + for (Iterator<String> iter = logFileEntries.iterator(); iter.hasNext();) { + out.append(iter.next()); } } - emailer.sendEmail(WebappHelper.getMailConfig("mailSupport"), "Feedback from Error Nr.: " + errorNr, request.getParameter("textarea") - + "\n------------------------------------------\n\n --- from user: "+username+" ---" + out.toString()); - } catch (AddressException e) { + String to = WebappHelper.getMailConfig("mailSupport"); + String subject = "Feedback from Error Nr.: " + errorNr; + String body = feedback + "\n------------------------------------------\n\n --- from user: " + username + + " ---" + out.toString(); + MailManager.getInstance().sendExternMessage(ident, null, null, to, null, null, null, subject, body, null, null); + } catch (Exception e) { // error in recipient email address(es) handleException(request, e); return; - } catch (SendFailedException e) { - // error in sending message - // CAUSE: sender email address invalid - handleException(request, e); - return; - } catch (MessagingException e) { - // error in message-subject || .-body - handleException(request, e); - return; - } catch (AssertException e) { - handleException(request, e); - return; - } catch (NullPointerException e) { - handleException(request, e); - return; } - } - private String parseErrorNumber(String errorNr) { - // try with format N<nodeId>-E<errorCode> first - Pattern r1 = Pattern.compile("N[0-9]+-E[0-9]+"); - Matcher m1 = r1.matcher(errorNr); - if (m1.find()) return m1.group(); - - Pattern r2 = Pattern.compile("E[0-9]+"); - Matcher m2 = r2.matcher(errorNr); - if (m2.find()) return m2.group(); - return ""; - - } private void handleException(HttpServletRequest request, Exception e) { String feedback = request.getParameter("textarea"); String username = request.getParameter("username"); - Tracing.logError("Error sending error feedback mail to olat support (" + WebappHelper.getMailConfig("mailSupport") - + ") from: " + username + " with content: " + feedback, e, this.getClass()); + Tracing.logError("Error sending error feedback mail to olat support (" + WebappHelper.getMailConfig("mailSupport") + ") from: " + + username + " with content: " + feedback, e, this.getClass()); } /** - * @see org.olat.core.dispatcher.Dispatcher#execute(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String) + * @see org.olat.core.dispatcher.Dispatcher#execute(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse, java.lang.String) */ public void execute(HttpServletRequest request, HttpServletResponse response, String uriPrefix) { sendMail(request); diff --git a/src/main/java/org/olat/core/id/Preferences.java b/src/main/java/org/olat/core/id/Preferences.java index fbcb2273d25..8acd553e102 100644 --- a/src/main/java/org/olat/core/id/Preferences.java +++ b/src/main/java/org/olat/core/id/Preferences.java @@ -76,6 +76,20 @@ public interface Preferences extends Serializable { */ public void setInformSessionTimeout(boolean b); + /** + * @return True if the user wants to receive a real e-mail too and not only a message in + * the OLAT Inbox + */ + //fxdiff VCRP-16: intern mail system + public String getReceiveRealMail(); + + /** + * @param receiveRealMail Set if the user wants to receive a real e-mail + * and not only a message in the OLAT intern Inbox. + */ + //fxdiff VCRP-16: intern mail system + public void setReceiveRealMail(String receiveRealMail); + /** * Instant Messaging preferences * When enabled the presence messages are shown public diff --git a/src/main/java/org/olat/core/util/mail/ContactList.java b/src/main/java/org/olat/core/util/mail/ContactList.java index 634d08abbc6..58ba292443d 100644 --- a/src/main/java/org/olat/core/util/mail/ContactList.java +++ b/src/main/java/org/olat/core/util/mail/ContactList.java @@ -22,17 +22,17 @@ package org.olat.core.util.mail; import java.util.ArrayList; -import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; +import java.util.Map; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import org.olat.core.id.Identity; import org.olat.core.id.UserConstants; -import org.olat.core.logging.Tracing; +import org.olat.core.logging.LogDelegator; import org.olat.core.util.StringHelper; /** @@ -50,14 +50,13 @@ import org.olat.core.util.StringHelper; * @author patrick */ -public class ContactList { - +public class ContactList extends LogDelegator { private String name; private String description; //container for addresses contributed as strings - private Hashtable stringEmails = new Hashtable(); + private Map<String, String> stringEmails = new Hashtable<String, String>(); //container for addresses contributed as identites - private Hashtable identiEmails = new Hashtable(); + private Map<String, Identity> identiEmails = new Hashtable<String, Identity>(); private boolean emailPrioInstitutional = false; /** @@ -116,11 +115,21 @@ public class ContactList { */ public void add(Identity identity) { String email = identity.getUser().getProperty(UserConstants.EMAIL, null); + //fxdiff VCRP-5 + if (email == null) { + logError("No email available for identity::" + identity.getName() + " - can not add to contact list", null); + return; + } identiEmails.put(keyFrom(email), identity); } public void remove(Identity identity) { String email = identity.getUser().getProperty(UserConstants.EMAIL, null); + //fxdiff VCRP-5 + if (email == null) { + logError("No email available for identity::" + identity.getName() + " - can not remove from contact list", null); + return; + } identiEmails.remove(keyFrom(email)); } @@ -133,24 +142,45 @@ public class ContactList { return name; } + /** + * ContactList-name as String encoded according to + * http://www.ietf.org/rfc/rfc2047.txt + * + * @return String encoded according to RFC2047 + */ + public String getRFC2047Name() { + String rfc2047name; + // try to MIME-encode the name, if this fails, return the name un-encoded + try { + rfc2047name = javax.mail.internet.MimeUtility.encodeWord(name, "UTF-8", null); + } + catch (java.io.UnsupportedEncodingException e) { + logWarn("Error MIME-encoding name: " + e, e); + rfc2047name = name; + } + + return rfc2047name; + } + + /** * ContactList-name as String formatted according to <a href = - * "http://www.rfc.net/rfc2822.html"> RFC2822 </a> + * "http://www.ietf.org/rfc/rfc2822.txt"> RFC2822 </a> * * @return */ public String getRFC2822Name() { - return name + ":"; + return getRFC2047Name() + ":"; } /** * ContactList-name and e-mail adresses as String formatted according to - * http://www.rfc.net/rfc2822.html + * http://www.ietf.org/rfc/rfc2822.txt * * @return */ public String getRFC2822NameWithAddresses() { - return name + ":" + toString() + ";"; + return getRFC2822Name() + toString() + ";"; } /** @@ -168,30 +198,30 @@ public class ContactList { * * @return */ - public ArrayList getEmailsAsStrings() { - ArrayList ret = new ArrayList(stringEmails.values()); + //fxdiff VCRP-16: intern mail system + public List<String> getEmailsAsStrings() { + List<String> ret = new ArrayList<String>(stringEmails.values()); /* * if priority is on institutional email get all the institutional emails * first, if they are present, remove the identity from the hashtable. If * they were not present, the user email is used in the next loop. */ - Enumeration enumeration = identiEmails.elements(); + List<Identity> copy = new ArrayList<Identity>(identiEmails.values()); String addEmail = null; if (emailPrioInstitutional) { - while (enumeration.hasMoreElements()) { - Identity tmp = (Identity) enumeration.nextElement(); + for (Iterator<Identity> it=copy.iterator(); it.hasNext(); ) { + Identity tmp = it.next(); addEmail = tmp.getUser().getProperty(UserConstants.INSTITUTIONALEMAIL, null); if (addEmail != null) { ret.add(addEmail); - identiEmails.remove(tmp); + it.remove(); } } } /* * loops over the (remaining) identities, fetches the user email. */ - while (enumeration.hasMoreElements()) { - Identity tmp = (Identity) enumeration.nextElement(); + for (Identity tmp : copy){ ret.add(tmp.getUser().getProperty(UserConstants.EMAIL, null)); } return ret; @@ -215,13 +245,12 @@ public class ContactList { * * @see java.lang.Object#toString() */ + @Override public String toString() { String retVal = ""; String sep = ""; - ArrayList emails = getEmailsAsStrings(); - Iterator iter = emails.iterator(); - while (iter.hasNext()) { - retVal += sep + (String) iter.next(); + for (String email:getEmailsAsStrings()) { + retVal += sep + email; sep = ", "; } return retVal; @@ -232,10 +261,9 @@ public class ContactList { * * @param listOfIdentity List containing Identites */ - public void addAllIdentites(List listOfIdentity) { - Iterator iter = listOfIdentity.iterator(); - while (iter.hasNext()) { - add((Identity) iter.next()); + public void addAllIdentites(List<Identity> listOfIdentity) { + for (Identity identity:listOfIdentity) { + add(identity); } } @@ -250,11 +278,11 @@ public class ContactList { return InternetAddress.parse(toString()); } - Hashtable getStringEmails() { + public Map<String,String> getStringEmails() { return stringEmails; } - Hashtable getIdentiEmails() { + public Map<String,Identity> getIdentiEmails() { return identiEmails; } @@ -265,7 +293,7 @@ public class ContactList { private void setName(String nameP) { if (!StringHelper.containsNoneOfCoDouSemi(nameP)){ - Tracing.logWarn("Contact list name \"" + nameP + "\" doesn't match "+ StringHelper.ALL_WITHOUT_COMMA_2POINT_STRPNT,null,ContactList.class); + logWarn("Contact list name \"" + nameP + "\" doesn't match "+ StringHelper.ALL_WITHOUT_COMMA_2POINT_STRPNT, null); //replace bad chars with bad char in rfc compliant comments nameP = nameP.replaceAll(":","¦"); nameP = nameP.replaceAll(";","_"); diff --git a/src/main/java/org/olat/core/util/mail/ContactMessage.java b/src/main/java/org/olat/core/util/mail/ContactMessage.java index 7e4cc33f8a1..bbcb1eba3d7 100644 --- a/src/main/java/org/olat/core/util/mail/ContactMessage.java +++ b/src/main/java/org/olat/core/util/mail/ContactMessage.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; +import java.util.Map; import org.olat.core.id.Identity; @@ -98,11 +99,8 @@ public class ContactMessage { } private ContactList cleanEMailList(ContactList emailList) { - Hashtable identityEmails = emailList.getIdentiEmails(); - Enumeration enumeration = identityEmails.elements(); String value = ""; - while (enumeration.hasMoreElements()) { - Identity identity = (Identity) enumeration.nextElement(); + for (Identity identity: emailList.getIdentiEmails().values()) { List<Identity> singleIdentityList = new ArrayList<Identity>(); singleIdentityList.add(identity); MailerResult result = new MailerResult(); diff --git a/src/main/java/org/olat/core/util/mail/Emailer.java b/src/main/java/org/olat/core/util/mail/Emailer.java index ee1467d03fa..a3a8700eeb9 100644 --- a/src/main/java/org/olat/core/util/mail/Emailer.java +++ b/src/main/java/org/olat/core/util/mail/Emailer.java @@ -23,16 +23,12 @@ package org.olat.core.util.mail; import java.io.File; -import java.util.Date; import java.util.List; import java.util.Locale; import javax.mail.MessagingException; import javax.mail.SendFailedException; -import javax.mail.Message.RecipientType; import javax.mail.internet.AddressException; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; import org.olat.core.gui.translator.PackageTranslator; import org.olat.core.helpers.Settings; @@ -43,6 +39,7 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.WebappHelper; import org.olat.core.util.i18n.I18nManager; +import org.olat.core.util.mail.manager.MailManager; /** * @@ -54,6 +51,7 @@ import org.olat.core.util.i18n.I18nManager; */ public class Emailer { private String mailfrom; + private Identity mailFromIdentity; private String footer; // footer appended to the end of the mail /** @@ -63,12 +61,21 @@ public class Emailer { * @param locale locale that should be used for message localization */ public Emailer(Locale locale) { - this.mailfrom = WebappHelper.getMailConfig("mailFrom"); + this.mailfrom = WebappHelper.getMailConfig("mailReplyTo"); // initialize the mail footer with info about this OLAt installation PackageTranslator trans = new PackageTranslator(Util.getPackageName(Emailer.class), locale); footer = trans.translate("footer.no.userdata", new String[] { Settings.getServerContextPathURI() }); } + //fxdiff + public String getFooter() { + return footer; + } + + public void setFooter(String footer) { + this.footer = footer; + } + /** * Constructs an Emailer which derives its <b>mail from address </b> from the * given <code>Identity</code>. The <b>mail host </b> used to send the @@ -102,17 +109,12 @@ public class Emailer { } } this.mailfrom = myMailfrom; + //fxdiff VCRP-16: intern mail system + this.mailFromIdentity = mailFromIdentity; // initialize the mail footer with infos about this OLAT installation and the user who sent the mail User user = mailFromIdentity.getUser(); - Locale locale = I18nManager.getInstance().getLocaleOrDefault(user.getPreferences().getLanguage()); - - PackageTranslator trans = new PackageTranslator(Util.getPackageName(Emailer.class), locale); - String institution = user.getProperty(UserConstants.INSTITUTIONALNAME, null); - if (institution == null) institution = ""; - footer = trans.translate("footer.with.userdata", new String[] { user.getProperty(UserConstants.FIRSTNAME, null), user.getProperty(UserConstants.LASTNAME, null), mailFromIdentity.getName(), - institution, Settings.getServerContextPathURI() }); - + footer = MailHelper.getMailFooter(locale, mailFromIdentity); } /** @@ -133,59 +135,20 @@ public class Emailer { * @throws AddressException * @throws MessagingException */ - public boolean sendEmail(List<ContactList> listOfContactLists, String subject, String body) throws AddressException, MessagingException { - return sendEmail(listOfContactLists, subject, body, null); + //fxdiff VCRP-16: intern mail system + public boolean sendEmail(MailContext context, List<ContactList> listOfContactLists, String subject, String body) throws AddressException, MessagingException { + return sendEmail(context, listOfContactLists, subject, body, null); } - - public boolean sendEmail(List<ContactList> listOfContactLists, String subject, String body, List<File> attachments) throws AddressException, MessagingException { - /* - * if the mailhost was not set in the olat.local.properties, we assume that no - * emailing is wished. - */ - if (MailHelper.getMailhost() == null || MailHelper.getMailhost().equals("") || ((MailHelper.getMailhost() instanceof String) && ((String)MailHelper.getMailhost()).equalsIgnoreCase("disabled"))) return false; - MimeMessage msg = MailHelper.createMessage(); - msg.setFrom(new InternetAddress(this.mailfrom)); - msg.setSubject(subject, "utf-8"); - msg.setText(body + footer, "utf-8"); - msg.setSentDate(new Date()); - for (ContactList tmp : listOfContactLists) { - InternetAddress groupName[] = InternetAddress.parse(tmp.getRFC2822Name() + ";"); - InternetAddress members[] = tmp.getEmailsAsAddresses(); - msg.addRecipients(RecipientType.TO, groupName); - msg.addRecipients(RecipientType.BCC, members); - } - msg.saveChanges(); - - File[] attachmentsArray = null; - if(attachments != null && !attachments.isEmpty()) { - attachmentsArray = attachments.toArray(new File[attachments.size()]); - } - - MailerResult result = new MailerResult(); - MailHelper.sendMessage(msg.getFrom()[0], msg.getRecipients(RecipientType.TO), msg.getRecipients(RecipientType.CC), msg - .getRecipients(RecipientType.BCC), body + footer, subject, attachmentsArray, result); + //fxdiff VCRP-16: intern mail system + public boolean sendEmail(MailContext context, List<ContactList> listOfContactLists, String subject, String body, List<File> attachments) throws AddressException, MessagingException { + body += footer; + MailerResult result = MailManager.getInstance().sendMessage(context, mailFromIdentity, mailfrom, null, null, null, null, listOfContactLists, null, subject, body, attachments); return result.getReturnCode() == MailerResult.OK; } - - public boolean sendEmailCC(String cc, String subject, String body, List<File> attachments) throws AddressException, MessagingException { - if (MailHelper.getMailhost() == null || MailHelper.getMailhost().equals("") || ((MailHelper.getMailhost() instanceof String) && ((String)MailHelper.getMailhost()).equalsIgnoreCase("disabled"))) return false; - MimeMessage msg = MailHelper.createMessage(); - msg.setFrom(new InternetAddress(mailfrom)); - msg.setRecipients(RecipientType.CC, InternetAddress.parse(cc)); - msg.setSubject(subject, "utf-8"); - msg.setText(body + footer, "utf-8"); - msg.setSentDate(new Date()); - msg.saveChanges(); - MailerResult result = new MailerResult(); - - File[] attachmentsArray = null; - if(attachments != null && !attachments.isEmpty()) { - attachmentsArray = attachments.toArray(new File[attachments.size()]); - } - - MailHelper.sendMessage(msg.getFrom()[0], msg.getRecipients(RecipientType.TO), msg.getRecipients(RecipientType.CC), msg - .getRecipients(RecipientType.BCC), body + footer, subject, attachmentsArray, result); - return true; + //fxdiff VCRP-16: intern mail system + public boolean sendEmailCC(MailContext context, Identity cc, String subject, String body, List<File> attachments) throws AddressException, MessagingException { + MailerResult result = MailManager.getInstance().sendMessage(context, mailFromIdentity, mailfrom, null, null, cc, null, null, null, subject, body, attachments); + return result.getReturnCode() == MailerResult.OK; } /** @@ -198,37 +161,12 @@ public class Emailer { * @throws MessagingException * TODO:gs handle exceptions internally and may return some error codes or so to get rid of dependecy of mail/activatoin jars in olat */ + //fxdiff VCRP-16: intern mail system public boolean sendEmail(String mailto, String subject, String body) throws AddressException, SendFailedException, MessagingException { - return sendEmail(mailfrom, mailto, subject, body); - } - - private boolean sendEmail(String from, String mailto, String subject, String body) throws AddressException, SendFailedException, - MessagingException { - /* - * if the mailhost was not set in the olat.local.properties, we assume that no - * emailing is wished. - */ - if (MailHelper.getMailhost() == null || MailHelper.getMailhost().equals("") || ((MailHelper.getMailhost() instanceof String) && ((String)MailHelper.getMailhost()).equalsIgnoreCase("disabled"))) return false; - MimeMessage msg = MailHelper.createMessage(); - msg.setFrom(new InternetAddress(from)); - msg.setRecipients(RecipientType.TO, InternetAddress.parse(mailto)); - msg.setSubject(subject, "utf-8"); - msg.setText(body + footer, "utf-8"); - msg.setSentDate(new Date()); - msg.saveChanges(); - MailerResult result = new MailerResult(); - MailHelper.sendMessage(msg.getFrom()[0], msg.getRecipients(RecipientType.TO), msg.getRecipients(RecipientType.CC), msg - .getRecipients(RecipientType.BCC), body + footer, subject, null, result); - return true; - } - - static InternetAddress asInternetAddressArray(String address) { - InternetAddress ia = null; - try { - ia = new InternetAddress(address); - } catch (AddressException ae) { - throw new RuntimeException("Error in InternetAddress : " + address); - } - return ia; + //OK context + body += footer; + //TO + MailerResult result = MailManager.getInstance().sendMessage(null, mailFromIdentity, mailfrom, null, mailto, null, null, null, null, subject, body, null); + return result.getReturnCode() == MailerResult.OK; } } \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/mail/MailContextImpl.java b/src/main/java/org/olat/core/util/mail/MailContextImpl.java new file mode 100644 index 00000000000..fbde6c23f48 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/MailContextImpl.java @@ -0,0 +1,119 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + +package org.olat.core.util.mail; + +import org.olat.core.id.OLATResourceable; + + +/** + * + * Description:<br> + * A default implementation of the mail context + * + * <P> + * Initial Date: 30 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailContextImpl implements MailContext { + + private String resourseableTypeName; + private Long resourceableId; + private String resSubPath; + private String businessPath; + + public MailContextImpl() { + // + } + + public MailContextImpl(OLATResourceable ores) { + this(ores, null, null); + } + + public MailContextImpl(String businessPath) { + this(null, null, businessPath); + } + + public MailContextImpl(OLATResourceable ores, String resSubPath, String businessPath) { + setOLATResourceable(ores); + this.resSubPath = resSubPath; + this.businessPath = businessPath; + } + + @Override + public OLATResourceable getOLATResourceable() { + final Long id = resourceableId; + final String name = resourseableTypeName; + if(id == null || name == null) return null; + + return new OLATResourceable() { + @Override + public Long getResourceableId() { + return id; + } + + @Override + public String getResourceableTypeName() { + return name; + } + }; + } + + public void setOLATResourceable(OLATResourceable ores) { + if(ores != null) { + resourseableTypeName = ores.getResourceableTypeName(); + resourceableId = ores.getResourceableId(); + } + } + + @Override + public String getResSubPath() { + return resSubPath; + } + + public void setResSubPath(String resSubPath) { + this.resSubPath = resSubPath; + } + + @Override + public String getBusinessPath() { + return businessPath; + } + + public void setBusinessPath(String businessPath) { + this.businessPath = businessPath; + } + + public String getResourseableTypeName() { + return resourseableTypeName; + } + + public void setResourseableTypeName(String resourseableTypeName) { + this.resourseableTypeName = resourseableTypeName; + } + + public Long getResourceableId() { + return resourceableId; + } + + public void setResourceableId(Long resourceableId) { + this.resourceableId = resourceableId; + } +} diff --git a/src/main/java/org/olat/core/util/mail/MailHelper.java b/src/main/java/org/olat/core/util/mail/MailHelper.java index b90605f4b88..dcf49f34a9d 100644 --- a/src/main/java/org/olat/core/util/mail/MailHelper.java +++ b/src/main/java/org/olat/core/util/mail/MailHelper.java @@ -22,27 +22,16 @@ package org.olat.core.util.mail; import java.io.File; -import java.util.Date; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Properties; -import javax.activation.DataHandler; -import javax.activation.DataSource; -import javax.activation.FileDataSource; import javax.mail.Address; import javax.mail.Authenticator; -import javax.mail.BodyPart; -import javax.mail.MessagingException; -import javax.mail.Multipart; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.Message.RecipientType; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.translator.PackageTranslator; @@ -52,10 +41,13 @@ import org.olat.core.id.Identity; import org.olat.core.id.User; import org.olat.core.id.UserConstants; import org.olat.core.logging.Tracing; +import org.olat.core.util.ArrayHelper; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.WebappHelper; import org.olat.core.util.i18n.I18nModule; +import org.olat.user.UserManager; +import org.olat.user.propertyhandlers.UserPropertyHandler; /** * Description:<br> @@ -111,27 +103,8 @@ public class MailHelper { * * @return MimeMessage */ - public static MimeMessage createMessage() { - Properties p = new Properties(); - p.put("mail.smtp.host", mailhost); - p.put("mail.smtp.timeout", mailhostTimeout); - p.put("mail.smtp.connectiontimeout", mailhostTimeout); - p.put("mail.smtp.ssl.enable", sslEnabled); - p.put("mail.smtp.ssl.checkserveridentity", sslCheckCertificate); - Session mailSession; - if (smtpAuth == null) { - mailSession = javax.mail.Session.getInstance(p); - } else { - // use smtp authentication from configuration - p.put("mail.smtp.auth", "true"); - mailSession = Session.getDefaultInstance(p, smtpAuth); - } - if (Tracing.isDebugEnabled(MailHelper.class)) { - // enable mail session debugging on console - mailSession.setDebug(true); - } - return new MimeMessage(mailSession); - } +//fxdiff VCRP-16: intern mail system + //public static MimeMessage createMessage() /** * create MimeMessage from given fields, this may be used for creation of @@ -146,70 +119,17 @@ public class MailHelper { * @param result * @return */ - public static MimeMessage createMessage(Address from, Address[] recipients, Address[] recipientsCC, Address[] recipientsBCC, String body, - String subject, File[] attachments, MailerResult result) { - if (Tracing.isDebugEnabled(MailHelper.class)) { - doDebugMessage(from, recipients, recipientsCC, recipientsBCC, body, subject, attachments); - } - - MimeMessage msg = MailHelper.createMessage(); - try { - // TO, CC and BCC - msg.setFrom(from); - msg.setRecipients(RecipientType.TO, recipients); - if (recipientsCC != null) { - msg.setRecipients(RecipientType.CC, recipientsCC); - } - if (recipientsBCC != null) { - msg.setRecipients(RecipientType.BCC, recipientsBCC); - } - // message data - msg.setSubject(subject, "utf-8"); + //fxdiff VCRP-16: intern mail system + //protected static MimeMessage createMessage(Address from, Address[] recipients, Address[] recipientsCC, Address[] recipientsBCC, String body, - if (attachments != null && attachments.length > 0) { - // with attachment use multipart message - Multipart multipart = new MimeMultipart(); - // 1) add body part - BodyPart messageBodyPart = new MimeBodyPart(); - messageBodyPart.setText(body); - multipart.addBodyPart(messageBodyPart); - // 2) add attachments - for (File attachmentFile : attachments) { - // abort if attachment does not exist - if (attachmentFile == null || !attachmentFile.exists()) { - result.setReturnCode(MailerResult.ATTACHMENT_INVALID); - Tracing.logError("Tried to send mail wit attachment that does not exist::" - + (attachmentFile == null ? null : attachmentFile.getAbsolutePath()), MailHelper.class); - return msg; - } - messageBodyPart = new MimeBodyPart(); - DataSource source = new FileDataSource(attachmentFile); - messageBodyPart.setDataHandler(new DataHandler(source)); - messageBodyPart.setFileName(attachmentFile.getName()); - multipart.addBodyPart(messageBodyPart); - } - // Put parts in message - msg.setContent(multipart); - } else { - // without attachment everything is easy, just set as text - msg.setText(body, "utf-8"); - } - msg.setSentDate(new Date()); - msg.saveChanges(); - } catch (MessagingException e) { - result.setReturnCode(MailerResult.SEND_GENERAL_ERROR); - Tracing.logWarn("Could not create MimeMessage", e, MailHelper.class); - } - // - return msg; - } /** * Send an email message to the given TO, CC and BCC address. The result will * be stored in the result object. The message can contain attachments.<br> * At this point HTML mails are not supported. * - * @param from Address used as sender address. Must not be NULL + * fxdiff: change from/replyto, see FXOLAT-74 + * @param replyTo Address used as reply-to address. The real sender is a no-reply-adress (see config: mailFrom). Must not be NULL * @param recipients Address array used as sender addresses. Must not be NULL * and contain at lease one address * @param recipientsCC Address array used as CC addresses. Can be NULL @@ -218,34 +138,10 @@ public class MailHelper { * @param subject Subject text of message. Must not be NULL * @param attachments File array used as attachments. Can be NULL * @param result MailerResult object that stores the result code - */ - public static void sendMessage(Address from, Address[] recipients, Address[] recipientsCC, Address[] recipientsBCC, String body, - String subject, File[] attachments, MailerResult result) { - // - MimeMessage msg = createMessage(from, recipients, recipientsCC, recipientsBCC, body, subject, attachments, result); - sendMessage(msg, result); - } - /** - * send email with MimeMessage available - * @param msg - * @param result - */ - public static void sendMessage(MimeMessage msg, MailerResult result){ - try{ - if (mailhost==null || mailhost.length()==0 || mailhost.equalsIgnoreCase("disabled")) { - result.setReturnCode(MailerResult.MAILHOST_UNDEFINED); - Tracing.logInfo("Did not send mail, mailhost undefined", MailHelper.class); - return; - } - if (result.getReturnCode() == MailerResult.OK) { - // now send the mail - Transport.send(msg); - } - } catch (MessagingException e) { - result.setReturnCode(MailerResult.SEND_GENERAL_ERROR); - Tracing.logWarn("Could not send mail", e, MailHelper.class); - } - } + + //fxdiff VCRP-16: intern mail system + //private static void sendMessage(Address from, Address[] recipients, Address[] recipientsCC, Address[] recipientsBCC, String body, + // String subject, File[] attachments, MailerResult result) /** * @return the maximum size allowed for attachements in MB (default 5MB) @@ -282,11 +178,27 @@ public class MailHelper { } // mail sent by a system user User user = sender.getUser(); - String institution = user.getProperty(UserConstants.INSTITUTIONALNAME, null); - if (institution == null) institution = ""; - return trans.translate("footer.with.userdata", new String[] { user.getProperty(UserConstants.FIRSTNAME, null), user.getProperty(UserConstants.LASTNAME, null), sender.getName(), - institution, Settings.getServerContextPathURI() }); + // FXOLAT-356: separate context for mail footer + // username / server-url are always first [0], [1]. + UserManager um = UserManager.getInstance(); + List<UserPropertyHandler> userPropertyHandlers = um.getUserPropertyHandlersFor(MailHelper.class.getCanonicalName(), false); + ArrayList<String> uProps = new ArrayList<String>(userPropertyHandlers.size()+2); + uProps.add(sender.getName()); + uProps.add(Settings.getServerContextPathURI()); + + for (Iterator<UserPropertyHandler> iterator = userPropertyHandlers.iterator(); iterator.hasNext();) { + UserPropertyHandler handler = iterator.next(); + uProps.add(handler.getUserProperty(user, locale)); + } + // add empty strings to prevent non-replaced wildcards like "{5}" etc. in emails. + while (uProps.size() < 15){ + uProps.add(""); + } + + String[] userProps = new String[]{}; + userProps = ArrayHelper.toArray(uProps); + return trans.translate("footer.with.userdata", userProps); } public static String getTitleForFailedUsersError(Locale locale) { diff --git a/src/main/java/org/olat/core/util/mail/MailModule.java b/src/main/java/org/olat/core/util/mail/MailModule.java new file mode 100644 index 00000000000..7ff60fe8750 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/MailModule.java @@ -0,0 +1,155 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ +package org.olat.core.util.mail; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.configuration.AbstractOLATModule; +import org.olat.core.configuration.PersistedProperties; +import org.olat.core.extensions.action.GenericActionExtension; +import org.olat.core.gui.control.Event; +import org.olat.core.util.StringHelper; +import org.olat.core.util.WebappHelper; +import org.olat.core.util.event.FrameworkStartedEvent; +import org.olat.core.util.event.FrameworkStartupEventChannel; + +/** + * + * Description:<br> + * + * + * <P> + * Initial Date: 24 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http.//www.frentix.com + */ +public class MailModule extends AbstractOLATModule { + + private static final String INTERN_MAIL_SYSTEM = "internSystem"; + private static final String RECEIVE_REAL_MAIL_USER_DEFAULT_SETTING = "receiveRealMailUserDefaultSetting"; + + private boolean internSystem; + private boolean receiveRealMailUserDefaultSetting; + + private WebappHelper webappHelper; + + public MailModule() { + //make Spring happy + FrameworkStartupEventChannel.registerForStartupEvent(this); + } + + /** + * [used by Spring] + * @param webappHelper + */ + public void setWebappHelper(WebappHelper webappHelper) { + this.webappHelper = webappHelper; + } + + /** + * [used by Spring] + * @see org.olat.core.configuration.AbstractOLATModule#setPersistedProperties(org.olat.core.configuration.PersistedProperties) + */ + @Override + public void setPersistedProperties(PersistedProperties persistedProperties) { + this.moduleConfigProperties = persistedProperties; + } + + @Override + public void init() { + String internSystemValue = getStringPropertyValue(INTERN_MAIL_SYSTEM, true); + if(StringHelper.containsNonWhitespace(internSystemValue)) { + internSystem = "true".equalsIgnoreCase(internSystemValue); + } + + String receiveRealMailUserDefaultSettingValue = getStringPropertyValue(RECEIVE_REAL_MAIL_USER_DEFAULT_SETTING, true); + if(StringHelper.containsNonWhitespace(receiveRealMailUserDefaultSettingValue)) { + receiveRealMailUserDefaultSetting = "true".equalsIgnoreCase(receiveRealMailUserDefaultSettingValue); + } + } + + @Override + protected void initDefaultProperties() { + internSystem = getBooleanConfigParameter(INTERN_MAIL_SYSTEM, false); + receiveRealMailUserDefaultSetting = getBooleanConfigParameter(RECEIVE_REAL_MAIL_USER_DEFAULT_SETTING, true); + } + + @Override + protected void initFromChangedProperties() { + init(); + } + + /** + * Used the intern mail system. + * @return + */ + public boolean isInternSystem() { + return internSystem; + } + + /** + * @param internSystem + */ + public void setInterSystem(boolean internSystem) { + String internSystemStr = internSystem ? "true" : "false"; + enableExtensions(internSystem); + setStringProperty(INTERN_MAIL_SYSTEM, internSystemStr, true); + } + + private void enableExtensions(boolean enabled){ + try { + ((GenericActionExtension)CoreSpringFactory.getBean("mailAEparent")).setEnabled(enabled); + ((GenericActionExtension)CoreSpringFactory.getBean("mailAEinbox")).setEnabled(enabled); + ((GenericActionExtension)CoreSpringFactory.getBean("mailAEoutbox")).setEnabled(enabled); + } catch (Exception e) { + // do nothing when extension don't exist. + } + } + + @Override + public void event(Event event) { + if(event instanceof FrameworkStartedEvent) { + enableExtensions(isInternSystem()); + } else { + super.event(event); + } + } + + /** + * Users can receive real e-mail too. This setting is the default for + * users. They can change it in Preferences Panel. + * @return + */ + public boolean isReceiveRealMailUserDefaultSetting() { + return receiveRealMailUserDefaultSetting; + } + + public void setReceiveRealMailUserDefaultSetting(boolean realMail) { + String realMailStr = realMail ? "true" : "false"; + setStringProperty(RECEIVE_REAL_MAIL_USER_DEFAULT_SETTING, realMailStr, true); + } + + /** + * Check if the mail host is configured + * @return + */ + public boolean isMailHostEnabled() { + String mailhost = WebappHelper.getMailConfig("mailhost"); + return (StringHelper.containsNonWhitespace(mailhost) && !mailhost.equalsIgnoreCase("disabled")); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/mail/MailUIFactory.java b/src/main/java/org/olat/core/util/mail/MailUIFactory.java new file mode 100644 index 00000000000..0fbf6510c55 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/MailUIFactory.java @@ -0,0 +1,60 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + +package org.olat.core.util.mail; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.mail.ui.MailContextResolver; +import org.olat.core.util.mail.ui.MailListController; + +/** + * + * Description:<br> + * + * <P> + * Initial Date: 25 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailUIFactory { + + public static Controller createInboxController(UserRequest ureq, WindowControl wControl, MailContextResolver resolver) { + return new MailListController(ureq, wControl, false, resolver); + } + + public static Controller createOutboxController(UserRequest ureq, WindowControl wControl, MailContextResolver resolver) { + return new MailListController(ureq, wControl, true, resolver); + } + + //fxdiff :: FXOLAT-250 we need factory-methods with standard params to create inbox/outbox controllers with the <code>FactoryControllerCreator</code> + // (used for minimalHome / genericmaincontroller) + public static Controller createInboxController(UserRequest ureq, WindowControl wControl){ + MailContextResolver resolver = (MailContextResolver)CoreSpringFactory.getBean("mailBoxExtension"); + return MailUIFactory.createInboxController(ureq, wControl, resolver); + } + + public static Controller createOutboxController(UserRequest ureq, WindowControl wControl){ + MailContextResolver resolver = (MailContextResolver)CoreSpringFactory.getBean("mailBoxExtension"); + return MailUIFactory.createOutboxController(ureq, wControl, resolver); + } + +} diff --git a/src/main/java/org/olat/core/util/mail/MailerResult.java b/src/main/java/org/olat/core/util/mail/MailerResult.java index 15a5d11def8..07e0947b5df 100644 --- a/src/main/java/org/olat/core/util/mail/MailerResult.java +++ b/src/main/java/org/olat/core/util/mail/MailerResult.java @@ -69,7 +69,7 @@ public class MailerResult { * * @param failedIdentity */ - void addFailedIdentites(Identity failedIdentity) { + public void addFailedIdentites(Identity failedIdentity) { this.failedIdentites.add(failedIdentity); } @@ -78,7 +78,7 @@ public class MailerResult { * * @param returnCode */ - void setReturnCode(int returnCode) { + public void setReturnCode(int returnCode) { this.returnCode = returnCode; } diff --git a/src/main/java/org/olat/core/util/mail/MailerWithTemplate.java b/src/main/java/org/olat/core/util/mail/MailerWithTemplate.java index e2506fc3bfd..466c61060f7 100644 --- a/src/main/java/org/olat/core/util/mail/MailerWithTemplate.java +++ b/src/main/java/org/olat/core/util/mail/MailerWithTemplate.java @@ -21,18 +21,18 @@ */ package org.olat.core.util.mail; +import java.io.File; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Properties; +import java.util.UUID; import javax.mail.Address; -import javax.mail.MessagingException; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; @@ -44,8 +44,8 @@ import org.apache.velocity.runtime.RuntimeConstants; import org.olat.core.id.Identity; import org.olat.core.id.UserConstants; import org.olat.core.logging.Tracing; -import org.olat.core.util.WebappHelper; import org.olat.core.util.i18n.I18nManager; +import org.olat.core.util.mail.manager.MailManager; /** * Description:<br> @@ -104,7 +104,8 @@ public class MailerWithTemplate { public MailerResult sendMailUsingTemplateContext(Identity recipientTO, List<Identity> recipientsCC, List<Identity> recipientsBCC, MailTemplate template, Identity sender) { MailerResult result = new MailerResult(); - sendWithContext(template.getContext(), recipientTO, recipientsCC, recipientsBCC, template, sender, result); + //fxdiff VCRP-16: intern mail system + sendWithContext(template.getContext(), null, null, recipientTO, recipientsCC, recipientsBCC, template, sender, result); return result; } @@ -123,22 +124,10 @@ public class MailerWithTemplate { VelocityContext context = new VelocityContext(); template.putVariablesInMailContext(context, recipientTO); - - MimeMessage msg = createWithContext(context, recipientTO, recipientsCC, recipientsBCC, template, sender, result); - String subject=null; - String body=null; - try { - subject = msg.getSubject(); - // - //assume String because the body text is set via setText(..,"utf-8") - //in the MailHelper - //see also http://java.sun.com/j2ee/1.4/docs/api/javax/mail/internet/MimeMessage.html#getContent() - body = (String)msg.getContent(); - } catch (MessagingException e) { - result.setReturnCode(MailerResult.TEMPLATE_GENERAL_ERROR); - } catch (IOException e) { - result.setReturnCode(MailerResult.TEMPLATE_GENERAL_ERROR); - } + //fxdiff VCRP-16: intern mail system + MessageContent msg = createWithContext(context, recipientTO, recipientsCC, recipientsBCC, template, sender, result); + String subject = msg.getSubject(); + String body = msg.getBody(); return new String[]{subject, body}; } @@ -159,11 +148,25 @@ public class MailerWithTemplate { * @return MailerResult with status and list of identites that could not be * mailed to */ - public MailerResult sendMail(Identity recipientTO, List<Identity> recipientsCC, List<Identity> recipientsBCC, MailTemplate template, + //fxdiff VCRP-16: intern mail system + public MailerResult sendRealMail(Identity recipientTO, MailTemplate template) { + MailerResult result = new MailerResult(); + VelocityContext context = new VelocityContext(); + MessageContent msg = createWithContext(context, recipientTO, null, null, template, null, result); + if(result.getReturnCode() != MailerResult.OK) { + return result; + } + + MailManager.getInstance().sendExternMessage(null, null, recipientTO, null, null, null, null, msg.getSubject(), msg.getBody(), null, result); + return result; + } + + //fxdiff VCRP-16: intern mail system + public MailerResult sendMail(MailContext mCtxt, Identity recipientTO, List<Identity> recipientsCC, List<Identity> recipientsBCC, MailTemplate template, Identity sender) { List<Identity> recipientsTO = new ArrayList<Identity>(); recipientsTO.add(recipientTO); - return sendMailAsSeparateMails(recipientsTO, recipientsCC, recipientsBCC, template, sender); + return sendMailAsSeparateMails(mCtxt, recipientsTO, recipientsCC, recipientsBCC, template, sender); } /** @@ -189,6 +192,13 @@ public class MailerWithTemplate { */ public MailerResult sendMailAsSeparateMails(List<Identity> recipientsTO, List<Identity> recipientsCC, List<Identity> recipientsBCC, MailTemplate template, Identity sender) { + return sendMailAsSeparateMails(null, recipientsTO, recipientsCC, recipientsBCC, template, sender); + } + //fxdiff VCRP-16: intern mail system + public MailerResult sendMailAsSeparateMails(MailContext mCtxt, List<Identity> recipientsTO, List<Identity> recipientsCC, List<Identity> recipientsBCC, + MailTemplate template, Identity sender) { + + String metaId = UUID.randomUUID().toString().replace("-", ""); MailerResult result = new MailerResult(); if (MailHelper.getMailhost() == null) { result.setReturnCode(MailerResult.MAILHOST_UNDEFINED); @@ -200,7 +210,7 @@ public class MailerWithTemplate { // populate velocity context with variables VelocityContext context = new VelocityContext(); template.putVariablesInMailContext(context, recipient); - sendWithContext(context, recipient, null, null, template, sender, result); + sendWithContext(context, mCtxt, metaId, recipient, null, null, template, sender, result); if (!result.getFailedIdentites().contains(recipient)) { isMailSendToRecipient = true; } @@ -213,10 +223,7 @@ public class MailerWithTemplate { // populate velocity context with variables VelocityContext context = new VelocityContext(); template.putVariablesInMailContext(context, recipient); - sendWithContext(context, null, cc, null, template, sender, result); - if (!result.getFailedIdentites().contains(recipient)) { - isMailSendToRecipient = true; - } + sendWithContext(context, mCtxt, metaId, recipient, null, null, template, sender, result); } } if (recipientsBCC != null) { @@ -224,14 +231,14 @@ public class MailerWithTemplate { // populate velocity context with variables VelocityContext context = new VelocityContext(); template.putVariablesInMailContext(context, recipient); - sendWithContext(context, recipient, null, null, template, sender, result); - if (!result.getFailedIdentites().contains(recipient)) { - isMailSendToRecipient = true; - } + sendWithContext(context, mCtxt, metaId, recipient, null, null, template, sender, result); } } if(!isMailSendToRecipient) { result.setReturnCode(MailerResult.RECIPIENT_ADDRESS_ERROR); + }//only one successful to is needed to return OK + else if(isMailSendToRecipient && result.getReturnCode() == MailerResult.RECIPIENT_ADDRESS_ERROR) { + result.setReturnCode(MailerResult.OK); } return result; } @@ -248,7 +255,8 @@ public class MailerWithTemplate { * @param result * @return */ - private MimeMessage createWithContext(VelocityContext context, Identity recipientTO, List<Identity> recipientsCC, List<Identity> recipientsBCC, + //fxdiff VCRP-16: intern mail system + private MessageContent createWithContext(VelocityContext context, Identity recipientTO, List<Identity> recipientsCC, List<Identity> recipientsBCC, MailTemplate template, Identity sender, MailerResult result){ // prepare cc addresses - will stay the same for each mail Address[] addressesCC = createAddressesFromIdentities(recipientsCC, result); @@ -269,39 +277,33 @@ public class MailerWithTemplate { recLocale = I18nManager.getInstance().getLocaleOrDefault(recipientTO.getUser().getPreferences().getLanguage()); }else if(recipientsCC!=null && recipientsCC.size()>0){ recLocale = I18nManager.getInstance().getLocaleOrDefault(recipientsCC.get(0).getUser().getPreferences().getLanguage()); + }else if(recipientsBCC!=null && recipientsBCC.size()>0){ + recLocale = I18nManager.getInstance().getLocaleOrDefault(recipientsBCC.get(0).getUser().getPreferences().getLanguage()); } String subject = subjectWriter.toString(); String body = bodyWriter.toString() + MailHelper.getMailFooter(recLocale, sender) + "\n"; + + // create mime message + return new MessageContent(subject, body); + + } - // add sender to mail - Address from, to; - try { - if (sender == null) { - from = new InternetAddress(WebappHelper.getMailConfig("mailFrom")); - } else { - from = new InternetAddress(sender.getUser().getProperty(UserConstants.EMAIL, null)); - } - } catch (AddressException e) { - result.setReturnCode(MailerResult.SENDER_ADDRESS_ERROR); - return null; + private class MessageContent { + private final String subject; + private final String body; + + public MessageContent(String subject, String body) { + this.subject = subject; + this.body = body; } - Address[] toArray = new Address[1]; - if(recipientTO != null){ - try { - to = new InternetAddress(recipientTO.getUser().getProperty(UserConstants.EMAIL, null)); - } catch (AddressException e) { - result.addFailedIdentites(recipientTO); - // skip this user, go to next one - return null; - } - toArray[0] = to; - }else{ - toArray = new Address[0]; + + public String getSubject() { + return subject; + } + + public String getBody() { + return body; } - - // create mime message - return MailHelper.createMessage(from, toArray, addressesCC, addressesBCC, body, subject, template.getAttachments(), result); - } /** @@ -314,7 +316,8 @@ public class MailerWithTemplate { * @param sender * @param result */ - private void sendWithContext(VelocityContext context, Identity recipientTO, List<Identity> recipientsCC, List<Identity> recipientsBCC, + //fxdiff VCRP-16: intern mail system + private void sendWithContext(VelocityContext context, MailContext mCtxt, String metaId, Identity recipientTO, List<Identity> recipientsCC, List<Identity> recipientsBCC, MailTemplate template, Identity sender, MailerResult result) { List<Identity> identityTO = new ArrayList<Identity>(); if(recipientTO != null) identityTO.add(recipientTO); @@ -343,12 +346,49 @@ public class MailerWithTemplate { failedIdentitiesBCC.removeAll(failedIdentitiesCC); recipientsBCC.removeAll(failedIdentitiesBCC); } - MimeMessage msg = createWithContext(context, recipientTO, recipientsCC, recipientsBCC, template, sender, result); + MessageContent msg = createWithContext(context, recipientTO, recipientsCC, recipientsBCC, template, sender, result); if(msg != null && result.getReturnCode() == MailerResult.OK){ // send mail - MailHelper.sendMessage(msg, result); + List<File> attachmentList = new ArrayList<File>(); + File[] attachments = template.getAttachments(); + if(attachments != null) { + for(File attachment:attachments) { + if(attachment == null || !attachment.exists()) { + result.setReturnCode(MailerResult.ATTACHMENT_INVALID); + } else { + attachmentList.add(attachment); + } + } + } + + List<ContactList> ccList = createContactList(recipientsCC); + List<ContactList> bccList = createContactList(recipientsBCC); + MailerResult mgrResult = MailManager.getInstance().sendMessage(mCtxt, sender, null, recipientTO, null, null, ccList, bccList, + metaId, msg.getSubject(), msg.getBody(), attachmentList); + + if(mgrResult.getReturnCode() != MailerResult.OK) { + result.setReturnCode(mgrResult.getReturnCode()); + } + if(mgrResult.getFailedIdentites() != null) { + for(Identity failedIdentity:mgrResult.getFailedIdentites()) { + result.addFailedIdentites(failedIdentity); + } + } + } } + //fxdiff VCRP-16: intern mail system + private List<ContactList> createContactList(List<Identity> recipients) { + if(recipients == null || recipients.isEmpty()) { + return null; + } + + ContactList contactList = new ContactList(""); + contactList.addAllIdentites(recipients); + List<ContactList> list = new ArrayList<ContactList>(1); + list.add(contactList); + return list; + } /** * Internal Helper: merges a velocity context with a template. diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_ar.properties index 6dc8c329239..3d087698a9c 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_ar.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_ar.properties @@ -8,7 +8,7 @@ chelp.sendMail7=\u0648\u0635\u0641 \u0627\u0644\u0645\u062C\u0645\u0648\u0639\u0 chelp.sendMail8=\u0642\u0627\u0626\u0645\u0629 \u0628\u0627\u0644\u0645\u0642\u0631\u0631\u0627\u062A \u0627\u0644\u062F\u0631\u0627\u0633\u064A\u0629 \u0627\u0644\u062A\u0649 \u062A\u0633\u062A\u062E\u062F\u0645\u0647\u0627 \u0627\u0644\u0645\u062C\u0645\u0648\u0639\u0629. contact.cp.from=\u0646\u0633\u062E\u0629 \u0625\u0644\u0649 \u0627\u0644\u0645\u0631\u0633\u0644 footer.no.userdata=--- \r\n \u062A\u0645 \u0625\u0631\u0633\u0627\u0644 \u0647\u0630\u0647 \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u062A\u0644\u0642\u0627\u0626\u064A\u0627\u064B \u0639\u0628\u0631 \u0623\u0648\u0644\u0627\u062A\r\n{0} -footer.with.userdata=--- \r\n{0} {1} ({2})\r\n{3}\r\n\r\n\u062A\u0645 \u0625\u0631\u0633\u0627\u0644 \u0647\u0630\u0647 \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u062A\u0644\u0642\u0627\u0626\u064A\u0627\u064B \u0639\u0628\u0631 \u0623\u0648\u0644\u0627\u062A\r\n{4} +footer.with.userdata=--- \r\n{2} {3} ({0})\r\n{4}\r\n\r\n\u062A\u0645 \u0625\u0631\u0633\u0627\u0644 \u0647\u0630\u0647 \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u062A\u0644\u0642\u0627\u0626\u064A\u0627\u064B \u0639\u0628\u0631 \u0623\u0648\u0644\u0627\u062A\r\n{1} help.hover.mail-templ=\u0645\u0633\u0627\u0639\u062F\u0629 \u0628\u0634\u0623\u0646 \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0646\u0645\u0627\u0630\u062C \u0627\u0644\u0628\u0631\u064A\u062F mailhelper.error.attachment=\u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u0644\u0627 \u064A\u0645\u0643\u0646 \u0625\u0631\u0633\u0627\u0644\u0647\u0627\: \u0627\u0644\u0645\u0631\u0641\u0642\u0627\u062A \u063A\u064A\u0631 \u0635\u0627\u0644\u062D\u0629\u060C \u064A\u0631\u062C\u0649 \u0625\u062E\u0637\u0627\u0631 \u0627\u0644\u0645\u0633\u062A\u0644\u0645\u064A\u0646 \u064A\u062F\u0648\u064A\u0627\u064B. mailhelper.error.failedusers=\u0644\u0627 \u064A\u0645\u0643\u0646 \u0625\u0631\u0633\u0627\u0644 \u0627\u0644\u0628\u0631\u064A\u062F \u0627\u0644\u0627\u0644\u0643\u062A\u0631\u0648\u0646\u0649 \u0625\u0644\u0649 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645\u064A\u0646 \u0627\u0644\u062A\u0627\u0644\u064A\u064A\u0646 \u0648\u0644\u0630\u0627 \u064A\u0631\u062C\u0649 \u0625\u062E\u0637\u0627\u0631\u0647\u0645 \u064A\u062F\u0648\u064A\u0627\u064B\u060C \u0648\u062A\u0637\u0644\u0628 \u0645\u0646\u0647\u0645 \u0627\u0644\u062A\u062D\u0642\u0642 \u0645\u0646 \u0639\u0646\u0627\u0648\u064A\u0646 \u0627\u0644\u0628\u0631\u064A\u062F \u0627\u0644\u0627\u0644\u0643\u062A\u0631\u0648\u0646\u0649 \u0627\u0644\u062E\u0627\u0635\u0629 \u0628\u0647\u0645. diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_bg.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_bg.properties index 2ed4c21f9b3..ebfed8f2077 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_bg.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_bg.properties @@ -8,7 +8,7 @@ chelp.sendMail7=\u0421\u043F\u0438\u0441\u044A\u043A \u043D\u0430 \u043A\u0443\u chelp.sendMail8=\u0421\u043F\u0438\u0441\u044A\u043A \u043D\u0430 \u043A\u0443\u0440\u0441\u043E\u0432\u0435\u0442\u0435, \u0432 \u043A\u043E\u0438\u0442\u043E \u0435 \u0438\u0437\u043F\u043E\u043B\u0437\u0432\u0430\u043D\u0430 \u0442\u0430\u0437\u0438 \u0433\u0440\u0443\u043F\u0430. contact.cp.from=\u041A\u043E\u043F\u0438\u0435\u0442\u043E \u0435 \u0438\u0437\u043F\u0440\u0430\u0442\u0435\u043D\u043E \u043D\u0430 \u0430\u0434\u0440\u0435\u0441\u0430\u043D\u0442\u0430 footer.no.userdata=--- \r\n\u0422\u043E\u0432\u0430 \u0441\u044A\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0435 \u0438\u0437\u043F\u0440\u0430\u0442\u0435\u043D\u043E \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E \u0447\u0440\u0435\u0437 \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u0442\u0430.\r\n{0} -footer.with.userdata=--- \r\n{0} {1} ({2})\r\n{3}\r\n\r\n\u0422\u043E\u0432\u0430 \u0441\u044A\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0435 \u0438\u0437\u043F\u0440\u0430\u0442\u0435\u043D\u043E \u0447\u0440\u0435\u0437 \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u0442\u0430.\r\n{4} +footer.with.userdata=--- \r\n{2} {3} ({0})\r\n{4}\r\n\r\n\u0422\u043E\u0432\u0430 \u0441\u044A\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0435 \u0438\u0437\u043F\u0440\u0430\u0442\u0435\u043D\u043E \u0447\u0440\u0435\u0437 \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u0442\u0430.\r\n{1} help.hover.mail-templ=\u041F\u043E\u043C\u043E\u0449 \u0437\u0430 \u0438\u0437\u043F\u043E\u043B\u0437\u0432\u0430\u043D\u0435 \u043D\u0430 \u0448\u0430\u0431\u043B\u043E\u043D\u0430 \u0437\u0430 \u043F\u043E\u0449\u0430 mailhelper.error.attachment=\u041F\u043E\u0449\u0430\u0442\u0430 \u043D\u0435 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0438\u0437\u043F\u0440\u0430\u0442\u0435\u043D\u0430\: \u043D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u0438 \u043F\u0440\u0438\u0442\u0443\u0440\u043A\u0438. \u041C\u043E\u043B\u044F, \u0443\u0432\u0435\u0434\u043E\u043C\u0435\u0442\u0435 \u0432\u0430\u0448\u0438\u0442\u0435 \u043F\u043E\u043B\u0443\u0447\u0430\u0442\u0435\u043B\u0438 \u0443\u0441\u0442\u043D\u043E. mailhelper.error.failedusers=\u041F\u043E\u0449\u0430\u0442\u0430 \u043D\u0435 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0438\u0437\u043F\u0440\u0430\u0442\u0435\u043D\u0430 \u043D\u0430 \u0441\u043B\u0435\u0434\u043D\u0438\u0442\u0435 \u0445\u043E\u0440\u0430. \u041C\u043E\u043B\u044F, \u0443\u0432\u0435\u0434\u043E\u043C\u0435\u0442\u0435 \u0433\u0438 \u0443\u0441\u0442\u043D\u043E \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u0435\u0442\u0435 \u0442\u0435\u0445\u043D\u0438\u0442\u0435 \u0438-\u043C\u0435\u0439\u043B \u0430\u0434\u0440\u0435\u0441\u0438. diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_cs.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_cs.properties index 7e3876edf3a..a66329f0442 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_cs.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_cs.properties @@ -6,7 +6,7 @@ chelp.sendMail5=Jm\u00E9no skupiny chelp.sendMail6=Popis skupiny chelp.sendMail7=Seznam kurz\u016F, kter\u00E9 u\u017Eivatel pou\u017E\u00EDv\u00E1. footer.no.userdata=\n\n--- \nTato zpr\u00E1va byla posl\u00E1na z OLATu.\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\nTato zpr\u00E1va byla posl\u00E1na z OLATu.\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4}\n\nTato zpr\u00E1va byla posl\u00E1na z OLATu.\n{1} help.hover.mail-templ=N\u00E1pov\u011Bda pro pou\u017E\u00EDv\u00E1n\u00ED \u0161ablon mail\u016F mailhelper.error.attachment=E-mail nemohl b\u00FDt odesl\u00E1n\: \u0161patn\u00E1 p\u0159\u00EDloha. Informujte pros\u00EDm p\u0159\u00EDjemce ru\u010Dn\u011B. mailhelper.error.failedusers=E-mail nemohl b\u00FDt n\u00E1sleduj\u00EDc\u00EDm osob\u00E1m odesl\u00E1n\: Informujte pros\u00EDm p\u0159\u00EDjemce ru\u010Dn\u011B a zkontrolujte jejich e-mailov\u00E9 adresy. diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_da.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_da.properties index 3754fa01a5e..f70beb4daa7 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_da.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_da.properties @@ -1,6 +1,6 @@ #Mon Mar 02 09:54:08 CET 2009 footer.no.userdata=\n\n--- \nDenne besked er afsendt automatisk via OLAT.\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\nDenne besked er afsendt via OLAT.\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4}\n\nDenne besked er afsendt via OLAT.\n{1} help.hover.mail-templ=Hj\u00E6lp til brug af e-mail skabelonen mailhelper.error.attachment=E-mail kunne ikke sendes\: ugyldige vedh\u00E6ftede filer. Kontakt venligst modtagerne ad anden vej. mailhelper.error.failedusers=E-mail kunne ikke sendes til f\u00F8lgende modtagere. Kontakt venligst modtagerne ad anden vej og check deres e-mailadresser. diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_de.properties index aae572c4dbf..d7ada9f495f 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_de.properties @@ -8,7 +8,7 @@ chelp.sendMail7=Beschreibung der Gruppe chelp.sendMail8=Liste der Kurse, in denen die Gruppe verwendet wird. contact.cp.from = Kopie an Absender footer.no.userdata=\n\n--- \nDiese Nachricht wurde automatisch von der Lernplattform OLAT versandt.\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\nDiese Nachricht wurde \u00FCber die Lernplattform OLAT versandt.\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4} {5}\n\nDiese Nachricht wurde \u00FCber die Lernplattform OLAT versandt.\n{1} help.hover.mail-templ=Hilfe zur Anwendung der Mailvorlage mailhelper.error.attachment=Die E-Mail konnte nicht verschickt werden\: ung\u00FCltiges Attachment. Bitte benachrichtigen Sie die Empf\u00E4nger manuell. mailhelper.error.failedusers=Den folgenden Benutzern kann Ihre Nachricht nicht zugestellt werden. Bitte benachrichtigen Sie diese Benutzer manuell und bitten Sie diese, ihre E-Mail-Adresse zu \u00FCberpr\u00FCfen\: @@ -29,3 +29,52 @@ mailtemplateform.subject=Betreffzeile chelp.mailtempsubject=Der Betreff der Nachricht ist vorgegeben, kann aber von Ihnen nach Belieben geändert werden. mailtemplateform.continue=Weiter chelp.mail-templ.title=E-Mail-Benachrichtigung +mail.admin.title=E-Mail Postfach und Versand +mail.admin.description=Konfiguration der OLAT E-Mail Versandoptionen und des Postfachs +chelp.mail-admin.title=$:mail.admin.title +chelp.mail.module=OLAT verfügt über ein internes E-Mail Postfach System, das alle in dem System gesendeten und empfangenen E-Mails im Homebereich jedes Benutzers im persönlichen Poftfach auflistet. Das E-Mail Postfach in OLAT ist eine optionale Komponente. +chelp.mail.module.intern=Ist das OLAT Postfach ausgeschaltet, so werden alle in OLAT erstellten E-Mails ausschliesslich und an die persönliche E-Mail Adresse versandt. Das OLAT Postfach ist im Home nicht sichtbar. +chelp.mail.module.extern=Ist das OLAT Postfach eingeschaltet, so werden alle empfangenen und gesendeten E-Mails im Homebereich jedes Benutzers im persönlichen Postfach aufgelistet. +chelp.mail.module.extern.config=Jeder Benutzer kann zudem in den Systemeinstellungen konfigurieren, ob empfangene E-Mails nur intern oder auch an die persönliche E-Mail Adresse zugestellt werden soll. Als Administrator können Sie das Standardverhalten festlegen: +mail.admin.intern.enabled=OLAT Postfach aktivieren +mail.admin.default.settings=Standardeinstellung für E-Mail Versand +mail.admin.intern.only=E-Mails an das interne OLAT Postfach zustellen +mail.admin.intern.real.mail=E-Mails an das interne OLAT Postfach und die persönliche E-Mail Adresse zustellen +mail.attachments=Anhang +mail.confirm.delete.title=E-Mails l\u00F6schen +mail.confirm.delete.multi.text=Bitte bestätigen Sie, dass Sie die selektierten {0} E-Mails inklusive aller Anhänge unwiederruflich l\u00F6schen wollen: +mail.confirm.delete.single.text=Bitte bestätigen Sie, dass Sie die selektierte E-Mail inklusive aller Anhänge unwiederruflich l\u00F6schen wollen: +mail.context=Kontext +mail.from=Von +mail.from.miscellaneous=Diverse +mail.inbox=Eingang +mail.inbox.alt=E-Mail Eingang +mail.inbox.title=E-Mail Eingang +mail.outbox=Gesendet +mail.outbox.alt=Gesendete E-Mails +mail.outbox.title=Gesendete E-Mails +mail.outbox.meta=diese E-Mails sind als Massen E-Mails versendet worden. +mail.empty.box=Diese Mailbox enth\u00E4lt keine E-Mails. +mail.marked.header=\u2691 +mail.marked=Markiert +mail.notification.type=E-Mails +mail.unmarked=Unmarkiert +mail.read.header=\u26AB +mail.read=Gelesen +mail.unread=Nicht gelesen +mail.subject=Betreff +mail.body=Nachricht +mail.sendDate=Gesendet +mail.receivedDate=Empfangen +mail.recipients=An +menu.mail=E-Mail +menu.mail.alt=E-Mail Systemkonfiguration +mail.action.open=Lesen +mail.action.send.real=Weiterleiten +mail.action.send.real.success=Die Nachricht mit dem Betreff "{0}" wurde an Ihre private E-Mail Adresse weitergeleitet. +mail.action.read=Gelesen +mail.action.unread=Nicht gelesen +mail.action.mark=Markieren +mail.action.unmark=Nicht markieren +mail.action.emtpy=Wählen Sie mindestens eine E-Mail aus um eine Aktion auszulösen. + diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_en.properties index 7a4e8d70df5..1a20a4896e8 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_en.properties @@ -1,5 +1,10 @@ -#Fri Jan 21 10:21:23 CET 2011 +#Thu May 26 09:42:27 CEST 2011 +chelp.mail-admin.title=$\:mail.admin.title chelp.mail-templ.title=E-mail notification +chelp.mail.module=OLAT has an internal e-mail inbox system that lists all sent and received e-mails of each user in his personal home area. The OLAT e-mail inbox system is an optional component. +chelp.mail.module.extern=If the OLAT inbox system is enabled, all received and sent emails will be listed in the users personal inbox. +chelp.mail.module.extern.config=In addition, each user can configure in his preferences wether he wants to receive mails from OLAT to his personal e-mail address or if he prefers to read the mail within OLAT. As administrator you can define the default behavior. +chelp.mail.module.intern=If the OLAT inbox system is disabled, all OLAT e-mails will be sent exclusively to the personal e-mail address. The OLAT inbox is not visible in the home area with this configuration. chelp.mailtemplateformbody=By default any message will contain a standardized text that can then be altered according to your needs. chelp.mailtempsubject=Subjects of messages are pre-set but can be altered according to your needs. chelp.sendMail1=Here you can determine if a user shall receive an e-mail after having been registered, delisted or moved. @@ -10,8 +15,49 @@ chelp.sendMail7=Description of group chelp.sendMail8=List of courses in which this group is used. contact.cp.from=Copy sent to addresser footer.no.userdata=--- \r\nThis message has been sent automatically via the learning platform OLAT.\r\n{0} -footer.with.userdata=--- \r\n{0} {1} ({2})\r\n{3}\r\n\r\nThis message has been sent via the learning platform OLAT.\r\n{4} +footer.with.userdata=--- \r\n{2} {3} ({0})\r\n{4} {5}\r\n\r\nThis message has been sent via the learning platform OLAT.\r\n{1} help.hover.mail-templ=Help on how to use the mail template +mail.action.emtpy=Select at least one e-mail to perform this action. +mail.action.mark=Mark +mail.action.open=Read +mail.action.read=Read +mail.action.send.real=Forward +mail.action.send.real.success=The message with the subject "{0}" has been forwarded to your personal e-mail account. +mail.action.unmark=Unmark +mail.action.unread=Unread +mail.admin.default.settings=Standard settings for e-mail sending +mail.admin.description=Configuration of the OLAT e-mails and the OLAT inbox +mail.admin.intern.enabled=Enable your OLAT e-mail inbox +mail.admin.intern.only=Send e-mails to the internal OLAT inbox +mail.admin.intern.real.mail=Send e-Mails to the internal OLAT inbox and the personal e-mail address +mail.admin.title=E-mail inbox and outbox +mail.attachments=Attachment +mail.body=Message +mail.confirm.delete.multi.text=Please confirm that you want to delete the selected {0} e-mails including their attachments. This can not be undone. +mail.confirm.delete.single.text=Please confirm that you want to delete the selected e-mail including all attachments. This can not be undone. +mail.confirm.delete.title=Delete e-mails +mail.context=Context +mail.empty.box=This inbox does not contain any e-mails. +mail.from=Sender +mail.from.miscellaneous=Miscellaneous +mail.inbox=Inbox +mail.inbox.alt=E-mail inbox +mail.inbox.title=E-mail inbox +mail.marked=Marked +mail.marked.header=\u2691 +mail.notification.type=E-mails +mail.outbox=Outbox +mail.outbox.alt=E-mail outbox +mail.outbox.meta=those e-mails have been sent as mass e-mails. +mail.outbox.title=E-mail outbox +mail.read=Read +mail.read.header=\u26AB +mail.receivedDate=Received +mail.recipients=Receiver +mail.sendDate=Sent +mail.subject=Subject +mail.unmarked=Unmarked +mail.unread=Unread mailhelper.error.attachment=Mail could not be sent\: invalid attachments. Please notify your recipients manually. mailhelper.error.failedusers=Your e-mail cannot be sent to the following users. Please notify them manually and ask them to check their e-mail address\: mailhelper.error.failedusers.title=Disabled recipients' addresses @@ -28,3 +74,5 @@ mailtemplateform.error.emptyfield=This field is mandatory. mailtemplateform.error.velocity=The \# character is not allowed here. mailtemplateform.sendMailSwitchElem=Send e-mail mailtemplateform.subject=Mail subject +menu.mail=E-mail +menu.mail.alt=E-mail system configuration diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_es.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_es.properties index 2d0695977fe..f7719a8fc0d 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_es.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_es.properties @@ -8,7 +8,7 @@ chelp.sendMail7=Lista de cursos donde el grupo es usado. chelp.sendMail8=Lista de curso en los que este grupo es usado. contact.cp.from=Copia enviada al emisor footer.no.userdata=\n\n--- \nEste mensaje ha sido generado autom\u00E1ticamente mediante la plataforma de aprendizaje OLAT.\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\nEste mensaje ha sido generado mediante la plataforma de aprendizaje OLAT.\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4}\n\nEste mensaje ha sido generado mediante la plataforma de aprendizaje OLAT.\n{1} help.hover.mail-templ=Ayuda para el uso de la plantilla del correo mailhelper.error.attachment=El correo no pod\u00EDa ser enviado\: ap\u00E9ndice inv\u00E1lidos. Por favor notificar los recipientes. mailhelper.error.failedusers=El correo no se pod\u00EDa enviar a la gente siguiente. Por favor notificar los recipientes y comprobar los direcciones de correo. diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_fa.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_fa.properties index 7b26ab963a2..e8df4af6eb5 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_fa.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_fa.properties @@ -1,3 +1,3 @@ #Mon Mar 02 09:54:12 CET 2009 footer.no.userdata=\n\n--- \nThis message has been sent automatically via OLAT.\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\nThis message has been sent via OLAT.\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4}\n\nThis message has been sent via OLAT.\n{1} diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_fr.properties index ad4f14c3c9b..e4ce496c2ed 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_fr.properties @@ -10,7 +10,7 @@ chelp.sendMail7=Liste des cours qui utilisent le groupe. chelp.sendMail8=Liste des cours utilisant ce groupe. contact.cp.from=Copie \u00E0 l'exp\u00E9diteur footer.no.userdata=--- \r\nCe message a \u00E9t\u00E9 envoy\u00E9 automatiquement via la plateforme d'apprentissage OLAT.\r\n{0} -footer.with.userdata=--- \r\n{0} {1} ({2})\r\n{3}\r\n\r\nCe message a \u00E9t\u00E9 envoy\u00E9 via la plateforme d'apprentissage OLAT.\r\n{4} +footer.with.userdata=--- \r\n{2} {3} ({0})\r\n{4} {5}\r\n\r\nCe message a \u00E9t\u00E9 envoy\u00E9 via la plateforme d'apprentissage OLAT.\r\n{1} help.hover.mail-templ=Aide pour l'utilisation de l'e-mail mod\u00E8le mailhelper.error.attachment=L'e-mail n'a pas pu \u00EAtre envoy\u00E9\: fichiers attach\u00E9s non valables. Veuillez contacter le destinataire manuellement. mailhelper.error.failedusers=Les personnes suivantes n'ont pas re\u00E7u votre e-mail. Veuillez contacter ces personnes manuellement et v\u00E9rifiez leurs adresses e-mail\: diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_it.properties index d0105e5e08e..208c8d859d9 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_it.properties @@ -10,7 +10,7 @@ chelp.sendMail7=lista dei corsi in cui viene utlizzato il gruppo. chelp.sendMail8=Lista dei corsi in cui viene utilizzato il gruppo. contact.cp.from=Copia al mittente footer.no.userdata=\n\n--- \nQuesto messaggio \u00E8 stato inviato automaticamente dalla piattaforma didattica OLAT.\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\nQuesto messaggio \u00E8 stato inviato attraverso la piattaforma didattica OLAT.\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4} {5}\n\nQuesto messaggio \u00E8 stato inviato attraverso la piattaforma didattica OLAT.\n{1} help.hover.mail-templ=Aiuto per l'utilizzo del modello mail mailhelper.error.attachment=Il messaggio non \u00E8 stato inviato\: allegato non valido. Contatti i destinatari manualmente, p.f. mailhelper.error.failedusers=Non \u00E8 stato possibile inviare il messaggio alle persone seguenti. Contatti queste persone manualmente, p.f., e controlli i loro indirizzi e-mail\: diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_jp.properties index 57eee0bbabd..e32c599f03a 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_jp.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_jp.properties @@ -10,7 +10,7 @@ chelp.sendMail7=\u3053\u306E\u30B0\u30EB\u30FC\u30D7\u304C\u4F7F\u7528\u3055\u30 chelp.sendMail8=\u3053\u306E\u30B0\u30EB\u30FC\u30D7\u304C\u4F7F\u7528\u3055\u308C\u308B\u30B3\u30FC\u30B9\u4E00\u89A7\u3067\u3059\u3002 contact.cp.from=\u767A\u4FE1\u8005\u306B\u30B3\u30D4\u30FC\u3092\u9001\u4FE1\u3059\u308B footer.no.userdata=\r\n--- \r\n\u3053\u308C\u306F\u3001OLAT\u7D4C\u7531\u3067\u81EA\u52D5\u7684\u306B\u9001\u4FE1\u3055\u308C\u305F\u30E1\u30C3\u30BB\u30FC\u30B8\u3067\u3059\u3002\r\n{0} -footer.with.userdata=\r\n--- \r\n{0} {1} ({2})\r\n{3}\r\n\r\n\u3053\u308C\u306F\u3001OLAT\u7D4C\u7531\u3067\u9001\u4FE1\u3055\u308C\u305F\u30E1\u30C3\u30BB\u30FC\u30B8\u3067\u3059\u3002\r\n{4} +footer.with.userdata=\r\n--- \r\n{2} {3} ({0})\r\n{4}\r\n\r\n\u3053\u308C\u306F\u3001OLAT\u7D4C\u7531\u3067\u9001\u4FE1\u3055\u308C\u305F\u30E1\u30C3\u30BB\u30FC\u30B8\u3067\u3059\u3002\r\n{1} help.hover.mail-templ=\u30E1\u30FC\u30EB\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u4F7F\u7528\u306B\u95A2\u3059\u308B\u30D8\u30EB\u30D7 mailhelper.error.attachment=\u30E1\u30FC\u30EB\u306F\u9001\u4FE1\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F\: \u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB\u304C\u7121\u52B9\u3067\u3059\u3002\u3042\u306A\u305F\u306E\u53D7\u4FE1\u8005\u306B\u76F4\u63A5\u77E5\u3089\u305B\u3066\u304F\u3060\u3055\u3044\u3002 mailhelper.error.failedusers=\u4EE5\u4E0B\u306E\u30E6\u30FC\u30B6\u306B\u30E1\u30FC\u30EB\u3092\u9001\u4FE1\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u53D7\u4FE1\u8005\u306B\u76F4\u63A5\u77E5\u3089\u305B\u305F\u5F8C\u3001\u53D7\u4FE1\u8005\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002 diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_lt.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_lt.properties index 66fb9dbf2e5..30fea196f34 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_lt.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_lt.properties @@ -4,7 +4,7 @@ chelp.sendMail5=Grup\u0117s pavadinimas chelp.sendMail6=Grup\u0117s apib\u016Bdinimas chelp.sendMail7=Kurs\u0173 s\u0105ra\u0161as, kuriame \u0161i grup\u0117 yra panaudota. footer.no.userdata=\n\n--- \n\u0160is prane\u0161imas automati\u0161kai buvo i\u0161si\u0173stas per OLAT.\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\n\u0160is prane\u0161imas buvo i\u0161si\u0173stas per OLAT.\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4} {5}\n\n\u0160is prane\u0161imas buvo i\u0161si\u0173stas per OLAT.\n{1} help.hover.mail-templ=Pagalba d\u0117l pa\u0161to \u0161ablono vartojimo mailhelper.error.failedusers.user={0} {1} naudojamas el. pa\u0161to adresas {2} ir prisijungimas {3} mailnotification.title=El. pa\u0161to prane\u0161imas diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_nl_NL.properties index d4085b0dbad..5810405d642 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_nl_NL.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_nl_NL.properties @@ -10,7 +10,7 @@ chelp.sendMail7=Groepsbeschrijving chelp.sendMail8=Lijst van cursussen waarbinnen deze groep wordt gebruikt. contact.cp.from=Kopie aan afzender verzonden footer.no.userdata=---\r\nDit bericht werd automatisch verstuurd via OLAT.\r\n{0} -footer.with.userdata=\r\n---\r\n{0} {1} ({2}\r\n{3}\r\nDit bericht werd via OLAT verstuurd.\r\n{4} +footer.with.userdata=\r\n---\r\n{2} {3} ({0}\r\n{4}\r\nDit bericht werd via OLAT verstuurd.\r\n{1} help.hover.mail-templ=Hulp voor het gebruik van het e-mailsjabloon mailhelper.error.attachment=Uw e-mail is niet verzonden\: ongeldige bijlagen. Breng uw ontvangers op een andere manier op de hoogte. mailhelper.error.failedusers=Uw e-mail is niet verzonden naar de volgende contactpersonen. Breng hen op een andere manier op de hoogte en kijk hun e-mailadressen na. diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pl.properties index afe4cfc2576..2de9ac4dba3 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pl.properties @@ -10,7 +10,7 @@ chelp.sendMail7=Zestawienie kurs\u00F3w, w kt\u00F3rych wykorzystywana jest ta g chelp.sendMail8=Lista kurs\u00F3w, w kt\u00F3rych wykorzystywana jest ta grupa. contact.cp.from=Kopia wys\u0142ana do nadawcy footer.no.userdata=\n\n--- \n Wiadomo\u015B\u0107 zosta\u0142a automatycznie wys\u0142ana z systemu OLAT\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\n Wiadomo\u015B\u0107 zosta\u0142a wys\u0142ana z systemu OLAT\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4}\n\n Wiadomo\u015B\u0107 zosta\u0142a wys\u0142ana z systemu OLAT\n{1} help.hover.mail-templ=Pomoc dla szablonu u\u017Cycia poczty mailhelper.error.attachment=Wiadomo\u015B\u0107 nie mog\u0142a zosta\u0107 wys\u0142ana\: nieprawid\u0142owy za\u0142\u0105cznik. Powiadom adresat\u00F3w tej wiadomo\u015Bci w inny spos\u00F3b... mailhelper.error.failedusers=Wiadomo\u015B\u0107 nie mog\u0142a zosta\u0107 wys\u0142ana do nast\u0119puj\u0105cych os\u00F3b. Powiadom adresat\u00F3w tej wiadomo\u015Bci w inny spos\u00F3b... diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pt_BR.properties index 6b5a01133b7..dcca4f126f5 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pt_BR.properties @@ -10,7 +10,7 @@ chelp.sendMail7=Listas de cursos nos quais este grupo \u00E9 usado. chelp.sendMail8=Lista de cursos em que esse grupo \u00E9 utilizado contact.cp.from=C\u00F3pia enviada ao endere\u00E7o footer.no.userdata=\n\n--- \nEsta mensagem foi enviada automaticamente via OLAT.\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\nEsta mensagem foi enviada via OLAT.\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4}\n\nEsta mensagem foi enviada via OLAT.\n{1} help.hover.mail-templ=Ajuda para o uso do modelo de e-mail mailhelper.error.attachment=O e-mail n\u00E3o p\u00F4de ser enviado\:anexa\u00E7\u00E3o inv\u00E1lida. Favor notificar os receptores manualmente. mailhelper.error.failedusers=O e-mail n\u00E3o p\u00F4de ser enviado para as seguintes pessoas. Favor notificar aquelas pessoas manualmente e checar seus endere\u00E7os de e-mail. diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pt_PT.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pt_PT.properties index 0480b3dfcc3..a2d7402cc1d 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pt_PT.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_pt_PT.properties @@ -6,7 +6,7 @@ chelp.sendMail5=Nome do grupo chelp.sendMail6=Descri\u00E7\u00E3o do grupo chelp.sendMail7=Listas de cursos nos quais este grupo \u00E9 usado. footer.no.userdata=\n\n--- \nEsta mensagem foi enviada automaticamente via OLAT.\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\nEsta mensagem foi enviada via OLAT.\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4}\n\nEsta mensagem foi enviada via OLAT.\n{1} help.hover.mail-templ=Ajuda para o uso do modelo de e-mail mailhelper.error.attachment=O e-mail n\u00E3o p\u00F4de ser enviado\:anexa\u00E7\u00E3o inv\u00E1lida. Favor notificar os receptores manualmente. mailhelper.error.failedusers=O e-mail n\u00E3o p\u00F4de ser enviado para as seguintes pessoas. Favor notificar aquelas pessoas manualmente e checar seus endere\u00E7os de e-mail. diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_ru.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_ru.properties index 31698b200b4..0b21445d897 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_ru.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_ru.properties @@ -2,7 +2,7 @@ chelp.mail-templ.title=$\:mailnotification.title contact.cp.from=\u041F\u043E\u0441\u043B\u0430\u0442\u044C \u043A\u043E\u043F\u0438\u044E \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u0435\u043B\u044E footer.no.userdata=\n\n--- \n\u042D\u0442\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0431\u044B\u043B\u043E \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u043E\u0442\u043E\u0441\u043B\u0430\u043D\u043E \u043E\u0431\u0443\u0447\u0430\u044E\u0449\u0435\u0439 \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u043E\u0439 OLAT.\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\n\u042D\u0442\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0431\u044B\u043B\u043E \u043E\u0442\u043E\u0441\u043B\u0430\u043D\u043E \u043E\u0431\u0443\u0447\u0430\u044E\u0449\u0435\u0439 \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u043E\u0439 OLAT.\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4}\n\n\u042D\u0442\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0431\u044B\u043B\u043E \u043E\u0442\u043E\u0441\u043B\u0430\u043D\u043E \u043E\u0431\u0443\u0447\u0430\u044E\u0449\u0435\u0439 \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u043E\u0439 OLAT.\n{1} help.hover.mail-templ=\u041F\u043E\u043C\u043E\u0449\u044C \u043A \u043F\u0440\u0438\u043C\u0435\u043D\u0435\u043D\u0438\u044E mail-\u0448\u0430\u0431\u043B\u043E\u043D\u0430 mailhelper.error.attachment=Email \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u0431\u044B\u043B\u043E \u043E\u0442\u043E\u0441\u043B\u0430\u0442\u044C\: \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043D\u0435\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u043E. \u041F\u043E\u0436\u0430\u0439\u043B\u0443\u0441\u0442\u0430, \u043E\u043F\u043E\u0432\u0435\u0441\u0442\u0438\u0442\u0435 \u043F\u043E\u043B\u0443\u0447\u0430\u0442\u0435\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u044F \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430 \u0441\u0432\u044F\u0437\u0438. mailhelper.error.failedusers=\u0421\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u043C \u043F\u043E\u043B\u0443\u0447\u0430\u0442\u0435\u043B\u044F\u043C \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u0431\u044B\u043B\u043E \u0434\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435. \u041F\u043E\u0436\u0430\u0439\u043B\u0443\u0441\u0442\u0430, \u043E\u043F\u043E\u0432\u0435\u0441\u0442\u0438\u0442\u0435 \u0434\u0430\u043D\u043D\u044B\u0445 \u043F\u043E\u043B\u0443\u0447\u0430\u0442\u0435\u043B\u0435\u0439 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u044F \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430 \u0441\u0432\u044F\u0437\u0438 \u0438 \u043F\u0435\u0440\u0435\u043F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 \u0438\u0445 email-\u0430\u0434\u0440\u0435\u0441\: diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_zh_CN.properties index 914b9e190d2..419b2456268 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_zh_CN.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_zh_CN.properties @@ -10,7 +10,7 @@ chelp.sendMail7=\u672C\u7FA4\u7EC4\u6B63\u5728\u4F7F\u7528\u7684\u5B66\u7A0B\u52 chelp.sendMail8=\u672C\u7FA4\u7EC4\u6B63\u5728\u4F7F\u7528\u7684\u5B66\u7A0B\u5217\u8868\u3002 contact.cp.from=\u53D1\u9001\u7ED9\u53D1\u4EF6\u4EBA\u7684\u590D\u4EF6 footer.no.userdata=\n\n--- \n\u8BE5\u6D88\u606F\u5DF2\u7ECF\u901A\u8FC7OLAT\u81EA\u52A8\u53D1\u9001.\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\n\u8BE5\u6D88\u606F\u5DF2\u7ECF\u901A\u8FC7 OLAT\u53D1\u9001.\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4}\n\n\u8BE5\u6D88\u606F\u5DF2\u7ECF\u901A\u8FC7 OLAT\u53D1\u9001.\n{1} help.hover.mail-templ=\u6709\u5173\u90AE\u4EF6\u6A21\u7248\u7684\u4F7F\u7528\u5E2E\u52A9 mailhelper.error.attachment=\u90AE\u4EF6\u4E0D\u80FD\u88AB\u53D1\u9001\uFF1A\u65E0\u6548\u9644\u4EF6.\u8BF7\u4EBA\u5DE5\u901A\u77E5\u90AE\u4EF6\u63A5\u53D7\u8005. mailhelper.error.failedusers=\u4F60\u7684\u7535\u5B50\u90AE\u4EF6\u4E0D\u80FD\u88AB\u53D1\u9001\u7ED9\u4E0B\u9762\u7684\u7528\u6237\u3002\u8BF7\u4EBA\u5DE5\u901A\u77E5\u4ED6\u4EEC\u5E76\u8981\u6C42\u5176\u68C0\u67E5\u7535\u5B50\u90AE\u4EF6\u5730\u5740 diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_zh_TW.properties index 0a9bd33aab0..da681398857 100644 --- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_zh_TW.properties +++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_zh_TW.properties @@ -8,7 +8,7 @@ chelp.sendMail7=\u4F7F\u7528\u9019\u500B\u7FA4\u7D44\u7684\u8AB2\u7A0B\u6E05\u55 chelp.sendMail8=\u9019\u500B\u7FA4\u7D44\u88AB\u4F7F\u7528\u5230\u7684\u8AB2\u7A0B\u6E05\u55AE contact.cp.from=\u8907\u88FD\u5BC4\u4EF6\u4EBA\u81F3\u901A\u8A0A\u9304 footer.no.userdata=\n\n--- \n\u672C\u4FE1\u4EF6\u7531 OLAT \u81EA\u52D5\u5BC4\u9001\u3002\n{0} -footer.with.userdata=\n\n--- \n{0} {1} ({2})\n{3}\n\n\u672C\u4FE1\u4EF6\u7531 OLAT \u5BC4\u9001\u3002\n{4} +footer.with.userdata=\n\n--- \n{2} {3} ({0})\n{4}\n\n\u672C\u4FE1\u4EF6\u7531 OLAT \u5BC4\u9001\u3002\n{1} help.hover.mail-templ=\u6709\u95DC\u90F5\u4EF6\u7BC4\u672C\u4F7F\u7528\u8AAA\u660E mailhelper.error.attachment=\u90F5\u4EF6\u7121\u6CD5\u767C\u9001\uFF1A \u7121\u6548\u7684\u9644\u4EF6\u3002\u8ACB\u624B\u52D5\u901A\u77E5\u60A8\u7684\u6536\u4EF6\u4EBA\u3002 mailhelper.error.failedusers=\u60A8\u7684\u96FB\u5B50\u90F5\u4EF6\u7121\u6CD5\u767C\u9001\u7D66\u4E0B\u5217\u7684\u4F7F\u7528\u8005\u3002\u8ACB\u624B\u52D5\u901A\u77E5\u4ED6\u5011\u4E26\u8981\u6C42\u4ED6\u5011\u6AA2\u67E5\u4ED6\u5011\u7684\u96FB\u5B50\u90F5\u4EF6\u5730\u5740\u3002 diff --git a/src/main/java/org/olat/core/util/mail/_spring/mailContext.xml b/src/main/java/org/olat/core/util/mail/_spring/mailContext.xml new file mode 100644 index 00000000000..6f5206bbcda --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/_spring/mailContext.xml @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + + <context:property-placeholder location="classpath:serviceconfig/olat.properties, classpath:olat.local.properties" /> + + <!-- MAIL CONFIGURATION --> + <!-- ========================= --> + + <bean id="mailModule" class="org.olat.core.util.mail.MailModule" depends-on="org.olat.core.util.WebappHelper,coordinatorManager,org.olat.core.util.event.FrameworkStartupEventChannel"> + <property name="persistedProperties"> + <bean class="org.olat.core.configuration.PersistedProperties" scope="prototype" init-method="init" destroy-method="destroy" + depends-on="coordinatorManager,org.olat.core.util.WebappHelper"> + <constructor-arg index="0" ref="coordinatorManager"/> + <constructor-arg index="1" ref="mailModule" /> + </bean> + </property> + <property name="webappHelper" ref="org.olat.core.util.WebappHelper"/> + </bean> + + <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> + <property name="targetObject" ref="mailModule" /> + <property name="targetMethod" value="init" /> + <property name="arguments"> + <value> + internSystem=${mail.intern} + receiveRealMailUserDefaultSetting=${mail.receiveRealMailUserDefaultSetting} + </value> + </property> + </bean> + + <!-- Mail admin. panel --> + <bean class="org.olat.core.extensions.action.GenericActionExtension" id="sysadmin.menupoint.syscfg.mailcfg" init-method="initExtensionPoints"> + <property name="actionController"> + <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> + <property name="className" value="org.olat.core.util.mail.ui.MailAdminController"/> + </bean> + </property> + <property name="navigationKey" value="mail" /> + <property name="i18nActionKey" value="menu.mail"/> + <property name="i18nDescriptionKey" value="menu.mail.alt"/> + <property name="translationPackage" value="org.olat.core.util.mail"/> + <property name="extensionPoints"> + <list> + <value>org.olat.admin.SystemAdminMainController</value> + </list> + </property> + <property name="parentTreeNodeIdentifier" value="sysconfigParent" /> + <property name="order" value="780" /> + </bean> + + <bean id="mailManager" class="org.olat.core.util.mail.manager.MailManager"> + <constructor-arg index="0" ref="mailModule" /> + <property name="dbInstance" ref="database"/> + <property name="notificationsManager" ref="org.olat.core.util.notifications.NotificationsManager"/> + </bean> + + <bean id="mailDBMappings" class="org.olat.core.commons.persistence.AdditionalDBMappings"> + <property name="xmlFiles"> + <list> + <value>org/olat/core/util/mail/model/DBMail.hbm.xml</value> + <value>org/olat/core/util/mail/model/DBMailAttachment.hbm.xml</value> + <value>org/olat/core/util/mail/model/DBMailRecipient.hbm.xml</value> + </list> + </property> + </bean> + + <bean id="org.olat.core.util.mail.manager.MailNotificationsHandler" class="org.olat.core.util.mail.manager.MailNotificationsHandler"> + <property name="mailModule" ref="mailModule"/> + </bean> + + + <!-- the email-parent-menu --> + <bean class="org.olat.core.util.mail.ui.MailActionExtension" name="mailAEparent" init-method="initExtensionPoints"> + <property name="order" value="108" /> + <property name="navigationKey" value="Mail" /> + <property name="securityCallbackClassName" value="org.olat.core.extensions.security.UserOnlyExtensionSecurityCallback" /> + <property name="nodeIdentifierIfParent" value="homeEmailParent" /> + <property name="translationPackage" value="org.olat.home" /> + <property name="i18nActionKey" value="menu.mail" /> + <property name="i18nDescriptionKey" value="menu.mail.alt" /> + <property name="extensionPoints"> + <list> + <value>org.olat.home.HomeMainController</value> + </list> + </property> + </bean> + + <!-- The name of this extension is used by the NotificationUIFactory, don't change it --> + <bean class="org.olat.core.extensions.action.GenericActionExtension" name="mailAEinbox" init-method="initExtensionPoints" > + <property name="order" value="401" /> + <property name="navigationKey" value="Inbox" /> + <property name="actionController"> + <bean class=" org.olat.core.gui.control.creator.FactoryControllerCreator" scope="prototype"> + <property name="factoryName" value="org.olat.core.util.mail.MailUIFactory"/> + <property name="factoryMethod" value="createInboxController"/> + </bean> + </property> + <property name="securityCallbackClassName" value="org.olat.core.extensions.security.UserOnlyExtensionSecurityCallback" /> + <property name="i18nActionKey" value="mail.inbox"/> + <property name="i18nDescriptionKey" value="mail.inbox.alt"/> + <property name="parentTreeNodeIdentifier" value="homeEmailParent" /> + <property name="extensionPoints"> + <list> + <value>org.olat.home.HomeMainController</value> + </list> + </property> + </bean> + + + <bean class="org.olat.core.extensions.action.GenericActionExtension" name="mailAEoutbox" init-method="initExtensionPoints" > + <property name="order" value="402" /> + <property name="navigationKey" value="Outbox" /> + <property name="actionController"> + <bean class=" org.olat.core.gui.control.creator.FactoryControllerCreator" scope="prototype"> + <property name="factoryName" value="org.olat.core.util.mail.MailUIFactory"/> + <property name="factoryMethod" value="createOutboxController"/> + </bean> + </property> + <property name="securityCallbackClassName" value="org.olat.core.extensions.security.UserOnlyExtensionSecurityCallback" /> + <property name="i18nActionKey" value="mail.outbox"/> + <property name="i18nDescriptionKey" value="mail.outbox.alt"/> + <property name="parentTreeNodeIdentifier" value="homeEmailParent" /> + <property name="extensionPoints"> + <list> + <value>org.olat.home.HomeMainController</value> + </list> + </property> + </bean> + + +</beans> diff --git a/src/main/java/org/olat/core/util/mail/manager/MailManager.java b/src/main/java/org/olat/core/util/mail/manager/MailManager.java new file mode 100644 index 00000000000..123700d74b4 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/manager/MailManager.java @@ -0,0 +1,1202 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + +package org.olat.core.util.mail.manager; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Properties; + +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.activation.FileDataSource; +import javax.mail.Address; +import javax.mail.Authenticator; +import javax.mail.BodyPart; +import javax.mail.Message.RecipientType; +import javax.mail.MessagingException; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; +import javax.mail.util.ByteArrayDataSource; + +import org.olat.core.commons.persistence.DB; +import org.olat.core.commons.persistence.DBQuery; +import org.olat.core.commons.persistence.PersistentObject; +import org.olat.core.helpers.Settings; +import org.olat.core.id.Identity; +import org.olat.core.id.OLATResourceable; +import org.olat.core.id.UserConstants; +import org.olat.core.manager.BasicManager; +import org.olat.core.util.StringHelper; +import org.olat.core.util.WebappHelper; +import org.olat.core.util.mail.ContactList; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailModule; +import org.olat.core.util.mail.MailerResult; +import org.olat.core.util.mail.MailerSMTPAuthenticator; +import org.olat.core.util.mail.model.DBMail; +import org.olat.core.util.mail.model.DBMailAttachment; +import org.olat.core.util.mail.model.DBMailAttachmentData; +import org.olat.core.util.mail.model.DBMailImpl; +import org.olat.core.util.mail.model.DBMailRecipient; +import org.olat.core.util.notifications.NotificationsManager; +import org.olat.core.util.notifications.Publisher; +import org.olat.core.util.notifications.PublisherData; +import org.olat.core.util.notifications.Subscriber; +import org.olat.core.util.notifications.SubscriptionContext; + +/** + * + * Description:<br> + * Manager which send e-mails, make the triage between mails which are + * really send by POP, or only saved in the intern mail system (a.k.a on + * the database). + * + * <P> + * Initial Date: 24 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailManager extends BasicManager { + + private final MailModule mailModule; + private DB dbInstance; + private NotificationsManager notificationsManager; + + private static MailManager INSTANCE; + + public MailManager(MailModule mailModule) { + INSTANCE = this; + this.mailModule = mailModule; + } + + public static MailManager getInstance() { + return INSTANCE; + } + + /** + * [used by Spring] + * + * @param dbInstance + */ + public void setDbInstance(DB dbInstance) { + this.dbInstance = dbInstance; + } + + /** + * [used by Spring] + * @param notificationsManager + */ + public void setNotificationsManager(NotificationsManager notificationsManager) { + this.notificationsManager = notificationsManager; + } + + public SubscriptionContext getSubscriptionContext() { + return new SubscriptionContext("Inbox", 0l, ""); + } + + public PublisherData getPublisherData() { + String data = ""; + String businessPath = "[Inbox:0]"; + PublisherData publisherData = new PublisherData("Inbox", data, businessPath); + return publisherData; + } + + public Subscriber getSubscriber(Identity identity) { + SubscriptionContext context = getSubscriptionContext(); + if(context == null) return null; + Publisher publisher = notificationsManager.getPublisher(context); + if(publisher == null) { + return null; + } + return notificationsManager.getSubscriber(identity, publisher); + } + + public void subscribe(Identity identity) { + PublisherData data = getPublisherData(); + SubscriptionContext context = getSubscriptionContext(); + if(context != null) { + notificationsManager.subscribe(identity, context, data); + } + } + + public DBMail getMessageByKey(Long key) { + StringBuilder sb = new StringBuilder(); + sb.append("select mail from ").append(DBMailImpl.class.getName()).append(" mail") + .append(" left join fetch mail.recipients recipients") + .append(" where mail.key=:mailKey"); + + DBQuery query = dbInstance.createQuery(sb.toString()); + query.setLong("mailKey", key); + + List<DBMailImpl> mails = query.list(); + if(mails.isEmpty()) return null; + DBMailImpl mail = mails.get(0); + return mail; + } + + public List<DBMailAttachment> getAttachments(DBMail mail) { + StringBuilder sb = new StringBuilder(); + sb.append("select attachment from ").append(DBMailAttachment.class.getName()).append(" attachment") + .append(" inner join attachment.mail mail") + .append(" where mail.key=:mailKey"); + + DBQuery query = dbInstance.createQuery(sb.toString()); + query.setLong("mailKey", mail.getKey()); + + List<DBMailAttachment> attachments = query.list(); + return attachments; + } + + public DBMailAttachmentData getAttachmentWithData(Long key) { + StringBuilder sb = new StringBuilder(); + sb.append("select attachment from ").append(DBMailAttachmentData.class.getName()).append(" attachment") + .append(" where attachment.key=:attachmentKey"); + + DBQuery query = dbInstance.createQuery(sb.toString()); + query.setLong("attachmentKey", key); + + List<DBMailAttachmentData> mails = query.list(); + if(mails.isEmpty()) return null; + return mails.get(0); + } + + public boolean hasNewMail(Identity identity) { + StringBuilder sb = new StringBuilder(); + sb.append("select count(mail) from ").append(DBMailImpl.class.getName()).append(" mail") + .append(" inner join mail.recipients recipient") + .append(" inner join recipient.recipient recipientIdentity") + .append(" where recipientIdentity.key=:recipientKey and recipient.read=false and recipient.deleted=false"); + + DBQuery query = dbInstance.createQuery(sb.toString()); + query.setLong("recipientKey", identity.getKey()); + + List<Number> mails = query.list(); + if(mails.isEmpty()) return false; + return mails.get(0).intValue() > 0; + } + + /** + * + * @param mail + * @param read cannot be null + * @param identity + * @return true if the read flag has been changed + */ + public boolean setRead(DBMail mail, Boolean read, Identity identity) { + if(mail == null || read == null || identity == null) throw new NullPointerException(); + + boolean changed = false; + for(DBMailRecipient recipient:mail.getRecipients()) { + if(recipient == null) continue; + if(recipient.getRecipient() != null && recipient.getRecipient().equalsByPersistableKey(identity)) { + if(!read.equals(recipient.getRead())) { + recipient.setRead(read); + dbInstance.updateObject(recipient); + changed |= true; + } + } + } + return changed; + } + + public DBMail toggleRead(DBMail mail, Identity identity) { + Boolean read = null; + for(DBMailRecipient recipient:mail.getRecipients()) { + if(recipient == null) continue; + if(recipient.getRecipient() != null && recipient.getRecipient().equalsByPersistableKey(identity)) { + if(read == null) { + read = recipient.getRead() == null ? Boolean.FALSE : recipient.getRead(); + } + recipient.setRead(read.booleanValue() ? Boolean.FALSE : Boolean.TRUE); + dbInstance.updateObject(recipient); + } + } + return mail; + } + + /** + * @param mail + * @param marked cannot be null + * @param identity + * @return true if the marked flag has been changed + */ + public boolean setMarked(DBMail mail, Boolean marked, Identity identity) { + if(mail == null || marked == null || identity == null) throw new NullPointerException(); + + boolean changed = false; + for(DBMailRecipient recipient:mail.getRecipients()) { + if(recipient == null) continue; + if(recipient != null && recipient.getRecipient() != null && recipient.getRecipient().equalsByPersistableKey(identity)) { + if(marked == null) { + marked = Boolean.FALSE; + } + if(!marked.equals(recipient.getMarked())) { + recipient.setMarked(marked.booleanValue()); + dbInstance.updateObject(recipient); + changed |= true; + } + } + } + return changed; + } + + public DBMail toggleMarked(DBMail mail, Identity identity) { + Boolean marked = null; + for(DBMailRecipient recipient:mail.getRecipients()) { + if(recipient == null) continue; + if(recipient != null && recipient.getRecipient() != null && recipient.getRecipient().equalsByPersistableKey(identity)) { + if(marked == null) { + marked = recipient.getMarked() == null ? Boolean.FALSE : recipient.getMarked(); + } + recipient.setMarked(marked.booleanValue() ? Boolean.FALSE : Boolean.TRUE); + dbInstance.updateObject(recipient); + } + } + return mail; + } + + /** + * Set the mail as deleted for a user + * @param mail + * @param identity + */ + public void delete(DBMail mail, Identity identity, boolean deleteMetaMail) { + if(StringHelper.containsNonWhitespace(mail.getMetaId()) && deleteMetaMail) { + List<DBMail> mails = getEmailsByMetaId(mail.getMetaId()); + for(DBMail childMail:mails) { + deleteMail(childMail, identity, false); + } + } else { + deleteMail(mail, identity, false); + } + } + + private void deleteMail(DBMail mail, Identity identity, boolean forceRemoveRecipient) { + boolean delete = true; + List<DBMailRecipient> updates = new ArrayList<DBMailRecipient>(); + if(mail.getFrom() != null && mail.getFrom().getRecipient() != null) { + if(identity.equalsByPersistableKey(mail.getFrom().getRecipient())) { + DBMailRecipient from = mail.getFrom(); + from.setDeleted(Boolean.TRUE); + if(forceRemoveRecipient) { + from.setRecipient(null); + } + updates.add(from); + } + if(mail.getFrom().getDeleted() != null) { + delete &= mail.getFrom().getDeleted().booleanValue(); + } + } + + for(DBMailRecipient recipient:mail.getRecipients()) { + if(recipient == null) continue; + if(recipient.getRecipient() != null && recipient.getRecipient().equalsByPersistableKey(identity)) { + recipient.setDeleted(Boolean.TRUE); + if(forceRemoveRecipient) { + recipient.setRecipient(null); + } + updates.add(recipient); + } + if(recipient.getDeleted() != null) { + delete &= recipient.getDeleted().booleanValue(); + } + } + + if(delete) { + //all marked as deleted -> delete the mail + List<DBMailAttachment> attachments = getAttachments(mail); + for(DBMailAttachment attachment: attachments) { + mail = attachment.getMail();//reload from the hibernate session + dbInstance.deleteObject(attachment); + } + dbInstance.deleteObject(mail); + } else { + for(DBMailRecipient update:updates) { + dbInstance.updateObject(update); + } + } + } + + /** + * Load all mails with the identity as from, mail which are not deleted + * for this user. Recipients are loaded. + * @param from + * @param firstResult + * @param maxResults + * @return + */ + public List<DBMail> getOutbox(Identity from, int firstResult, int maxResults) { + StringBuilder sb = new StringBuilder(); + sb.append("select mail from ").append(DBMailImpl.class.getName()).append(" mail") + .append(" inner join fetch mail.from fromRecipient") + .append(" inner join fromRecipient.recipient fromRecipientIdentity") + .append(" inner join fetch mail.recipients recipient") + .append(" inner join recipient.recipient recipientIdentity") + .append(" where fromRecipientIdentity.key=:fromKey and fromRecipient.deleted=false and recipientIdentity.key!=:fromKey") + .append(" order by mail.creationDate desc"); + + DBQuery query = dbInstance.createQuery(sb.toString()); + if(maxResults > 0) { + query.setMaxResults(maxResults); + } + if(firstResult >= 0) { + query.setFirstResult(firstResult); + } + query.setLong("fromKey", from.getKey()); + + List<DBMail> mails = query.list(); + return mails; + } + + public List<DBMail> getEmailsByMetaId(String metaId) { + if(!StringHelper.containsNonWhitespace(metaId)) return Collections.emptyList(); + + StringBuilder sb = new StringBuilder(); + sb.append("select mail from ").append(DBMailImpl.class.getName()).append(" mail") + .append(" inner join fetch mail.from fromRecipient") + .append(" inner join fromRecipient.recipient fromRecipientIdentity") + .append(" where mail.metaId=:metaId"); + + DBQuery query = dbInstance.createQuery(sb.toString()); + query.setString("metaId", metaId); + List<DBMail> mails = query.list(); + return mails; + } + + /** + * Load all mails with the identity as recipient, only mails which are not deleted + * for this user. Recipients are NOT loaded if not explicitly wanted! + * @param identity + * @param unreadOnly + * @param fetchRecipients + * @param from + * @param firstResult + * @param maxResults + * @return + */ + public List<DBMail> getInbox(Identity identity, Boolean unreadOnly, Boolean fetchRecipients, Date from, int firstResult, int maxResults) { + StringBuilder sb = new StringBuilder(); + String fetchOption = (fetchRecipients != null && fetchRecipients.booleanValue()) ? "fetch" : ""; + sb.append("select mail from ").append(DBMailImpl.class.getName()).append(" mail") + .append(" inner join ").append(fetchOption).append(" mail.recipients recipient") + .append(" inner join ").append(fetchOption).append(" recipient.recipient recipientIdentity") + .append(" where recipientIdentity.key=:recipientKey and recipient.deleted=false"); + if(unreadOnly != null && unreadOnly.booleanValue()) { + sb.append(" and recipient.read=false"); + } + if(from != null) { + sb.append(" and mail.creationDate>=:from"); + } + + sb.append(" order by mail.creationDate desc"); + + DBQuery query = dbInstance.createQuery(sb.toString()); + if(maxResults > 0) { + query.setMaxResults(maxResults); + } + if(firstResult >= 0) { + query.setFirstResult(firstResult); + } + query.setLong("recipientKey", identity.getKey()); + if(from != null) { + query.setDate("from", from); + } + + List<DBMail> mails = query.list(); + return mails; + } + + public MailerResult sendMessage(MailContext context, Identity fromId, String from, Identity toId, String to, + Identity cc, List<ContactList> ccLists, List<ContactList> bccLists, + String metaId, String subject, String body, List<File> attachments) { + + MailerResult result = new MailerResult(); + if(mailModule.isInternSystem()) { + saveDBMessage(context, fromId, from, toId, to, cc, ccLists, bccLists, metaId, subject, body, attachments, result); + } else { + sendExternMessage(fromId, from, toId, to, cc, ccLists, bccLists, subject, body, attachments, result); + } + return result; + } + + + public MailerResult forwardToRealInbox(Identity identity, DBMail mail, MailerResult result) { + + if(result == null) { + result = new MailerResult(); + } + + List<DBMailAttachment> attachments = getAttachments(mail); + + try { + Address from = createAddress(WebappHelper.getMailConfig("mailFrom")); + Address to = createAddress(identity, result, true); + MimeMessage message = createForwardMimeMessage(from, to, mail.getSubject(), mail.getBody(), attachments, result); + if(message != null) { + sendMessage(message, result); + } + } catch (AddressException e) { + logError("mailFrom is not configured", e); + } + return result; + } + + + /** + * Send the message via e-mail, always. + * @param from + * @param to + * @param cc + * @param contactLists + * @param listAsBcc + * @param subject + * @param body + * @param attachments + * @return + */ + public MailerResult sendExternMessage(Identity fromId, String from, Identity toId, String to, Identity cc, List<ContactList> ccLists, List<ContactList> bccLists, + String subject, String body, List<File> attachments, MailerResult result) { + + if(result == null) { + result = new MailerResult(); + } + MimeMessage mail = createMimeMessage(fromId, from, toId, to, cc, ccLists, bccLists, subject, body, attachments, result); + if(mail != null) { + sendMessage(mail, result); + } + return result; + } + + private boolean wantRealMailToo(Identity id) { + if(id == null) return false; + String want = id.getUser().getPreferences().getReceiveRealMail(); + if(want != null) { + return "true".equals(want); + } + return mailModule.isReceiveRealMailUserDefaultSetting(); + } + + protected DBMail saveDBMessage(MailContext context, Identity fromId, String from, Identity toId, String to, + Identity cc, List<ContactList> ccLists, List<ContactList> bccLists, + String metaId, String subject, String body, List<File> attachments, MailerResult result) { + + try { + DBMailImpl mail = new DBMailImpl(); + if(result == null) { + result = new MailerResult(); + } + + boolean makeRealMail = makeRealMail(toId, ccLists, bccLists); + Address fromAddress = null; + List<Address> toAddress = new ArrayList<Address>(); + List<Address> ccAddress = new ArrayList<Address>(); + List<Address> bccAddress = new ArrayList<Address>(); + + if(fromId != null) { + DBMailRecipient fromRecipient = new DBMailRecipient(); + fromRecipient.setRecipient(fromId); + if(StringHelper.containsNonWhitespace(from)) { + fromRecipient.setEmailAddress(from); + fromAddress = createFromAddress(from, result); + } else { + fromAddress = createFromAddress(fromId, result); + } + fromRecipient.setVisible(Boolean.TRUE); + fromRecipient.setMarked(Boolean.FALSE); + fromRecipient.setDeleted(Boolean.FALSE); + mail.setFrom(fromRecipient); + } else { + if(!StringHelper.containsNonWhitespace(from)) { + from = WebappHelper.getMailConfig("mailFrom"); + } + DBMailRecipient fromRecipient = new DBMailRecipient(); + fromRecipient.setEmailAddress(from); + fromRecipient.setVisible(Boolean.TRUE); + fromRecipient.setMarked(Boolean.FALSE); + fromRecipient.setDeleted(Boolean.TRUE);//marked as delted as nobody can read it + mail.setFrom(fromRecipient); + fromAddress = createFromAddress(from, result); + } + + if(result.getReturnCode() != MailerResult.OK) { + return null; + } + + mail.setMetaId(metaId); + if(subject != null && subject.length() > 500) { + logWarn("Cut a too long subkect in name. Size: " + subject.length(), null); + subject = subject.substring(0, 500); + } + mail.setSubject(subject); + if(body != null && body.length() > 16777210) { + logWarn("Cut a too long body in mail. Size: " + body.length(), null); + body = body.substring(0, 16000000); + } + mail.setBody(body); + mail.setLastModified(new Date()); + + if(context != null) { + OLATResourceable ores = context.getOLATResourceable(); + if(ores != null) { + String resName = ores.getResourceableTypeName(); + if(resName != null && resName.length() > 50) { + logWarn("Cut a too long resourceable type name in mail context: " + resName, null); + resName = resName.substring(0, 49); + } + mail.getContext().setResName(ores.getResourceableTypeName()); + mail.getContext().setResId(ores.getResourceableId()); + } + + String resSubPath = context.getResSubPath(); + if(resSubPath != null && resSubPath.length() > 2000) { + logWarn("Cut a too long resSubPath in mail context: " + resSubPath, null); + resSubPath = resSubPath.substring(0, 2000); + } + mail.getContext().setResSubPath(resSubPath); + + String businessPath = context.getBusinessPath(); + if(businessPath != null && businessPath.length() > 2000) { + logWarn("Cut a too long resSubPath in mail context: " + businessPath, null); + businessPath = businessPath.substring(0, 2000); + } + mail.getContext().setBusinessPath(businessPath); + } + + //add to + DBMailRecipient recipientTo = null; + if(toId != null) { + recipientTo = new DBMailRecipient(); + if(toId instanceof PersistentObject) { + recipientTo.setRecipient(toId); + } else { + to = toId.getUser().getProperty(UserConstants.EMAIL, null); + } + if(StringHelper.containsNonWhitespace(to)) { + recipientTo.setEmailAddress(to); + } + recipientTo.setVisible(Boolean.TRUE); + recipientTo.setDeleted(Boolean.FALSE); + recipientTo.setMarked(Boolean.FALSE); + recipientTo.setRead(Boolean.FALSE); + } else if (StringHelper.containsNonWhitespace(to)) { + recipientTo = new DBMailRecipient(); + recipientTo.setEmailAddress(to); + recipientTo.setVisible(Boolean.TRUE); + recipientTo.setDeleted(Boolean.TRUE); + recipientTo.setMarked(Boolean.FALSE); + recipientTo.setRead(Boolean.FALSE); + } + + if(recipientTo != null) { + mail.getRecipients().add(recipientTo); + createAddress(toAddress, recipientTo, true, result, true); + } + if(makeRealMail && StringHelper.containsNonWhitespace(to)) { + createAddress(toAddress, to, result); + } + + if(cc != null) { + DBMailRecipient recipient = new DBMailRecipient(); + if(cc instanceof PersistentObject) { + recipient.setRecipient(cc); + } else { + recipient.setEmailAddress(cc.getUser().getProperty(UserConstants.EMAIL, null)); + } + recipient.setVisible(Boolean.TRUE); + recipient.setDeleted(Boolean.FALSE); + recipient.setMarked(Boolean.FALSE); + recipient.setRead(Boolean.FALSE); + mail.getRecipients().add(recipient); + createAddress(ccAddress, recipient, false, result, true); + } + + //add cc recipients + appendRecipients(mail, ccLists, toAddress, ccAddress, true, makeRealMail, result); + + //add bcc recipients + appendRecipients(mail, bccLists, toAddress, bccAddress, false, makeRealMail, result); + + dbInstance.saveObject(mail); + + //save attachments + if(attachments != null && !attachments.isEmpty()) { + for(File attachment:attachments) { + DBMailAttachmentData data = new DBMailAttachmentData(); + data.setSize(attachment.length()); + data.setName(attachment.getName()); + data.setMimetype(WebappHelper.getMimeType(attachment.getName())); + data.setMail(mail); + + try { + byte[] datas = new byte[(int)attachment.length()]; + FileInputStream fis = new FileInputStream(attachment); + fis.read(datas); + data.setDatas(datas); + dbInstance.saveObject(data); + } catch (FileNotFoundException e) { + logError("File attachment not found: " + attachment, e); + } catch (IOException e) { + logError("Error with file attachment: " + attachment, e); + } + } + } + + if(makeRealMail) { + sendRealMessage(fromAddress, toAddress, ccAddress, bccAddress, subject, body, attachments, result); + } + + //update subscription + for(DBMailRecipient recipient:mail.getRecipients()) { + if(recipient.getRecipient() != null) { + subscribe(recipient.getRecipient()); + } + } + + SubscriptionContext subContext = getSubscriptionContext(); + Publisher publisher = NotificationsManager.getInstance().getPublisher(subContext); + if(publisher != null && publisher.getKey() != null) { + publisher.setLatestNewsDate(new Date()); + notificationsManager.updatePublisher(publisher); + } + return mail; + } catch (AddressException e) { + logError("Cannot send e-mail: ", e); + result.setReturnCode(MailerResult.RECIPIENT_ADDRESS_ERROR); + return null; + } + } + + private void appendRecipients(DBMailImpl mail, List<ContactList> ccLists, List<Address> toAddress, List<Address> ccAddress, + boolean visible, boolean makeRealMail, MailerResult result) throws AddressException { + + //append cc/bcc recipients + if(ccLists != null && !ccLists.isEmpty()) { + for(ContactList contactList:ccLists) { + if(makeRealMail && StringHelper.containsNonWhitespace(contactList.getName())) { + Address[] groupAddress = InternetAddress.parse(contactList.getRFC2822Name() + ";"); + if(groupAddress != null && groupAddress.length > 0) { + for(Address groupAdd:groupAddress) { + toAddress.add(groupAdd); + } + } + } + + for(String email:contactList.getStringEmails().values()) { + DBMailRecipient recipient = new DBMailRecipient(); + recipient.setEmailAddress(email); + recipient.setGroup(contactList.getName()); + recipient.setVisible(visible); + recipient.setDeleted(Boolean.FALSE); + recipient.setMarked(Boolean.FALSE); + recipient.setRead(Boolean.FALSE); + mail.getRecipients().add(recipient); + + if(makeRealMail) { + createAddress(ccAddress, recipient, false, result, false); + } + } + + for(Identity identityEmail:contactList.getIdentiEmails().values()) { + DBMailRecipient recipient = new DBMailRecipient(); + if(identityEmail instanceof PersistentObject) { + recipient.setRecipient(identityEmail); + } else { + recipient.setEmailAddress(identityEmail.getUser().getProperty(UserConstants.EMAIL, null)); + } + recipient.setGroup(contactList.getName()); + recipient.setVisible(visible); + recipient.setDeleted(Boolean.FALSE); + recipient.setMarked(Boolean.FALSE); + recipient.setRead(Boolean.FALSE); + mail.getRecipients().add(recipient); + + if(makeRealMail) { + createAddress(ccAddress, recipient, false, result, false); + } + } + } + } + } + + private boolean makeRealMail(Identity toId, List<ContactList> ccLists, List<ContactList> bccLists) { + //need real mail to??? + boolean makeRealMail = false; + // can occur on self-registration + if (toId == null && ccLists == null && bccLists == null) return true; + + if(toId != null) { + makeRealMail |= wantRealMailToo(toId); + } + + //add bcc recipients + if(bccLists != null && !bccLists.isEmpty()) { + for(ContactList contactList:bccLists) { + for(Identity identityEmail:contactList.getIdentiEmails().values()) { + makeRealMail |= wantRealMailToo(identityEmail); + } + + if(!contactList.getStringEmails().isEmpty()) { + makeRealMail |= true; + } + } + } + + //add bcc recipients + if(ccLists != null && !ccLists.isEmpty()) { + for(ContactList contactList:ccLists) { + for(Identity identityEmail:contactList.getIdentiEmails().values()) { + makeRealMail |= wantRealMailToo(identityEmail); + } + + if(!contactList.getStringEmails().isEmpty()) { + makeRealMail |= true; + } + } + } + + return makeRealMail; + } + + private MimeMessage createMimeMessage(Identity fromId, String mailFrom, Identity toId, String to, Identity ccId, + List<ContactList> ccLists, List<ContactList> bccLists, + String subject, String body, List<File> attachments, MailerResult result) { + try { + Address from; + if(StringHelper.containsNonWhitespace(mailFrom)) { + from = createFromAddress(mailFrom, result); + } else if (fromId != null) { + from = createFromAddress(fromId, result); + } else { + // fxdiff: change from/replyto, see FXOLAT-74 . if no from is set, use default sysadmin-address (adminemail). + from = createAddress(WebappHelper.getMailConfig("mailReplyTo")); + } + + List<Address> toList = new ArrayList<Address>(); + if(StringHelper.containsNonWhitespace(to)) { + Address[] toAddresses = InternetAddress.parse(to); + for(Address toAddress:toAddresses) { + toList.add(toAddress); + } + } else if (toId != null) { + Address toAddress = createAddress(toId, result, true); + if(toAddress != null) { + toList.add(toAddress); + } + } + + List<Address> ccList = new ArrayList<Address>(); + if(ccId != null) { + Address ccAddress = createAddress(ccId, result, true); + ccList.add(ccAddress); + } + + //add cc contact list + if(ccLists != null) { + for (ContactList contactList : ccLists) { + if(StringHelper.containsNonWhitespace(contactList.getName())) { + Address[] groupNames = InternetAddress.parse(contactList.getRFC2822Name() + ";"); + for(Address groupName:groupNames) { + toList.add(groupName); + } + } + + Address[] members = contactList.getEmailsAsAddresses(); + for(Address member:members) { + ccList.add(member); + } + } + } + + //add bcc contact lists + List<Address> bccList = new ArrayList<Address>(); + if(bccLists != null) { + for (ContactList contactList : bccLists) { + if(StringHelper.containsNonWhitespace(contactList.getName())) { + Address[] groupNames = InternetAddress.parse(contactList.getRFC2822Name() + ";"); + for(Address groupName:groupNames) { + toList.add(groupName); + } + } + + Address[] members = contactList.getEmailsAsAddresses(); + for(Address member:members) { + bccList.add(member); + } + } + } + + Address[] tos = toList.toArray(new Address[toList.size()]); + Address[] ccs = ccList.toArray(new Address[ccList.size()]); + Address[] bccs = bccList.toArray(new Address[bccList.size()]); + return createMimeMessage(from, tos, ccs, bccs, subject, body, attachments, result); + } catch (MessagingException e) { + logError("", e); + return null; + } + } + + private Address createAddress(String address) throws AddressException { + return new InternetAddress(address); + } + + private Address createAddressWithName(String address, String name) throws UnsupportedEncodingException, AddressException { + InternetAddress add = new InternetAddress(address, name); + try { + add.validate(); + } catch (AddressException e) { + throw e; + } + return add; + } + + private Address createFromAddress(String address, MailerResult result) throws AddressException { + try { + Address add = new InternetAddress(address); + return add; + } catch (AddressException e) { + result.setReturnCode(MailerResult.SENDER_ADDRESS_ERROR); + throw e; + } + } + + private boolean createAddress(List<Address> addressList, String address, MailerResult result) throws AddressException { + Address add = createAddress(address); + if(add != null) { + addressList.add(add); + } + return true; + } + + private boolean createAddress(List<Address> addressList, DBMailRecipient recipient, boolean force, MailerResult result, boolean error) { + String emailAddress = recipient.getEmailAddress(); + if(recipient.getRecipient() == null) { + try { + Address address = createAddress(emailAddress); + if(address != null) { + addressList.add(address); + return true; + } else { + if(error) { + result.setReturnCode(MailerResult.RECIPIENT_ADDRESS_ERROR); + } + } + } catch (AddressException e) { + if(error) { + result.setReturnCode(MailerResult.RECIPIENT_ADDRESS_ERROR); + } + } + } else { + if(force || wantRealMailToo(recipient.getRecipient())) { + if(!StringHelper.containsNonWhitespace(emailAddress)) { + emailAddress = recipient.getRecipient().getUser().getProperty(UserConstants.EMAIL, null); + } + try { + Address address = createAddress(emailAddress); + if(address != null) { + addressList.add(address); + return true; + } else { + result.addFailedIdentites(recipient.getRecipient()); + if(error) { + result.setReturnCode(MailerResult.RECIPIENT_ADDRESS_ERROR); + } + } + } catch (AddressException e) { + result.addFailedIdentites(recipient.getRecipient()); + if(error) { + result.setReturnCode(MailerResult.RECIPIENT_ADDRESS_ERROR); + } + } + } + } + return false; + } + + private Address createAddress(Identity recipient, MailerResult result, boolean error) { + if(recipient != null) { + String emailAddress = recipient.getUser().getProperty(UserConstants.EMAIL, null); + Address address; + try { + address = createAddress(emailAddress); + if(address == null) { + result.addFailedIdentites(recipient); + if(error) { + result.setReturnCode(MailerResult.RECIPIENT_ADDRESS_ERROR); + } + } + return address; + } catch (AddressException e) { + result.addFailedIdentites(recipient); + if(error) { + result.setReturnCode(MailerResult.RECIPIENT_ADDRESS_ERROR); + } + } + } + return null; + } + + private Address createFromAddress(Identity recipient, MailerResult result) { + if(recipient != null) { + String emailAddress = recipient.getUser().getProperty(UserConstants.EMAIL, null); + String name = recipient.getUser().getProperty(UserConstants.FIRSTNAME, null) + " " + recipient.getUser().getProperty(UserConstants.LASTNAME, null); + Address address; + try { + address = createAddressWithName(emailAddress, name); + if(address == null) { + result.addFailedIdentites(recipient); + result.setReturnCode(MailerResult.SENDER_ADDRESS_ERROR); + } + return address; + } catch (AddressException e) { + result.addFailedIdentites(recipient); + result.setReturnCode(MailerResult.SENDER_ADDRESS_ERROR); + } catch (UnsupportedEncodingException e) { + result.addFailedIdentites(recipient); + result.setReturnCode(MailerResult.SENDER_ADDRESS_ERROR); + } + } + return null; + } + + private void sendRealMessage(Address from, List<Address> toList, List<Address> ccList, List<Address> bccList, String subject, String body, + List<File> attachments, MailerResult result) { + + Address[] tos = null; + if(toList != null && !toList.isEmpty()) { + tos = new Address[toList.size()]; + tos = toList.toArray(tos); + } + + Address[] ccs = null; + if(ccList != null && !ccList.isEmpty()) { + ccs = new Address[ccList.size()]; + ccs = ccList.toArray(ccs); + } + + Address[] bccs = null; + if(bccList != null && !bccList.isEmpty()) { + bccs = new Address[bccList.size()]; + bccs = bccList.toArray(bccs); + } + + MimeMessage msg = createMimeMessage(from, tos, ccs, bccs, subject, body, attachments, result); + sendMessage(msg, result); + } + + private MimeMessage createForwardMimeMessage(Address from, Address to, String subject, String body, + List<DBMailAttachment> attachments, MailerResult result) { + + try { + Address convertedFrom = getRawEmailFromAddress(from); + MimeMessage msg = createMessage(convertedFrom); + msg.setFrom(from); + msg.setSubject(subject, "utf-8"); + + if(to != null) { + msg.addRecipient(RecipientType.TO, to); + } + + if (attachments != null && !attachments.isEmpty()) { + // with attachment use multipart message + Multipart multipart = new MimeMultipart(); + // 1) add body part + BodyPart messageBodyPart = new MimeBodyPart(); + messageBodyPart.setText(body); + multipart.addBodyPart(messageBodyPart); + // 2) add attachments + for (DBMailAttachment attachment : attachments) { + // abort if attachment does not exist + if (attachment == null || attachment.getSize() <= 0) { + result.setReturnCode(MailerResult.ATTACHMENT_INVALID); + logError("Tried to send mail wit attachment that does not exist::" + + (attachment == null ? null : attachment.getName()), null); + return msg; + } + messageBodyPart = new MimeBodyPart(); + + DBMailAttachmentData data = getAttachmentWithData(attachment.getKey()); + DataSource source = new ByteArrayDataSource(data.getDatas(), attachment.getMimetype()); + messageBodyPart.setDataHandler(new DataHandler(source)); + messageBodyPart.setFileName(attachment.getName()); + multipart.addBodyPart(messageBodyPart); + } + // Put parts in message + msg.setContent(multipart); + } else { + // without attachment everything is easy, just set as text + msg.setText(body, "utf-8"); + } + msg.setSentDate(new Date()); + msg.saveChanges(); + return msg; + } catch (MessagingException e) { + logError("", e); + return null; + } + } + + /** + * + * @param bounceAdress must be a raw email, without anything else (no "bla bli <bla@bli.ch>" !) + * @return + */ + public MimeMessage createMessage(Address bounceAdress) { + String mailhost = WebappHelper.getMailConfig("mailhost"); + String mailhostTimeout = WebappHelper.getMailConfig("mailTimeout"); + boolean sslEnabled = Boolean.parseBoolean(WebappHelper.getMailConfig("sslEnabled")); + boolean sslCheckCertificate = Boolean.parseBoolean(WebappHelper.getMailConfig("sslCheckCertificate")); + + Authenticator smtpAuth; + if (WebappHelper.isMailHostAuthenticationEnabled()) { + String smtpUser = WebappHelper.getMailConfig("smtpUser"); + String smtpPwd = WebappHelper.getMailConfig("smtpPwd"); + smtpAuth = new MailerSMTPAuthenticator(smtpUser, smtpPwd); + } else { + smtpAuth = null; + } + + Properties p = new Properties(); + p.put("mail.smtp.from", bounceAdress.toString()); + p.put("mail.smtp.host", mailhost); + p.put("mail.smtp.timeout", mailhostTimeout); + p.put("mail.smtp.connectiontimeout", mailhostTimeout); + p.put("mail.smtp.ssl.enable", sslEnabled); + p.put("mail.smtp.ssl.checkserveridentity", sslCheckCertificate); + Session mailSession; + if (smtpAuth == null) { + mailSession = javax.mail.Session.getInstance(p); + } else { + // use smtp authentication from configuration + p.put("mail.smtp.auth", "true"); + mailSession = Session.getDefaultInstance(p, smtpAuth); + } + if (isLogDebugEnabled()) { + // enable mail session debugging on console + mailSession.setDebug(true); + } + return new MimeMessage(mailSession); + } + + // converts an address "bla bli <bla@bli.ch>" => "bla@bli.ch" + private InternetAddress getRawEmailFromAddress(Address address) throws AddressException{ + InternetAddress fromAddress = new InternetAddress(address.toString()); + String fromPlainAddress = fromAddress.getAddress(); + return new InternetAddress(fromPlainAddress); + } + + public MimeMessage createMimeMessage(Address from, Address[] tos, Address[] ccs, Address[] bccs, String subject, String body, + List<File> attachments, MailerResult result) { + + try { + // see FXOLAT-74: send all mails as <fromemail> (in config) to have a valid reverse lookup and therefore pass spam protection. + // following doesn't work correctly, therefore add bounce-address in message already + Address convertedFrom = getRawEmailFromAddress(from); + MimeMessage msg = createMessage(convertedFrom); + String uri = Settings.createServerURI(); + Address viewableFrom = createAddressWithName(WebappHelper.getMailConfig("mailFrom"), "OLAT @ " + uri); + msg.setFrom(viewableFrom); + msg.setSubject(subject, "utf-8"); + // reply to can only be an address without name (at least for postfix!), see FXOLAT-312 + msg.setReplyTo(new Address[] { convertedFrom }); + + if(tos != null && tos.length > 0) { + msg.addRecipients(RecipientType.TO, tos); + } + + if(ccs != null && ccs.length > 0) { + msg.addRecipients(RecipientType.CC, ccs); + } + + if(bccs != null && bccs.length > 0) { + msg.addRecipients(RecipientType.BCC, bccs); + } + + if (attachments != null && !attachments.isEmpty()) { + // with attachment use multipart message + Multipart multipart = new MimeMultipart(); + // 1) add body part + BodyPart messageBodyPart = new MimeBodyPart(); + messageBodyPart.setText(body); + multipart.addBodyPart(messageBodyPart); + // 2) add attachments + for (File attachmentFile : attachments) { + // abort if attachment does not exist + if (attachmentFile == null || !attachmentFile.exists()) { + result.setReturnCode(MailerResult.ATTACHMENT_INVALID); + logError("Tried to send mail wit attachment that does not exist::" + + (attachmentFile == null ? null : attachmentFile.getAbsolutePath()), null); + return msg; + } + messageBodyPart = new MimeBodyPart(); + DataSource source = new FileDataSource(attachmentFile); + messageBodyPart.setDataHandler(new DataHandler(source)); + messageBodyPart.setFileName(attachmentFile.getName()); + multipart.addBodyPart(messageBodyPart); + } + // Put parts in message + msg.setContent(multipart); + } else { + // without attachment everything is easy, just set as text + msg.setText(body, "utf-8"); + } + msg.setSentDate(new Date()); + msg.saveChanges(); + return msg; + } catch (MessagingException e) { + result.setReturnCode(MailerResult.SEND_GENERAL_ERROR); + logError("", e); + return null; + } catch (UnsupportedEncodingException e) { + result.setReturnCode(MailerResult.SENDER_ADDRESS_ERROR); + logError("", e); + return null; + } + } + + public void sendMessage(MimeMessage msg, MailerResult result){ + try{ + if(Settings.isJUnitTest()) { + //we want not send really e-mails + } else if (mailModule.isMailHostEnabled() && result.getReturnCode() == MailerResult.OK) { + // now send the mail + Transport.send(msg); + } else { + result.setReturnCode(MailerResult.MAILHOST_UNDEFINED); + } + } catch (MessagingException e) { + result.setReturnCode(MailerResult.SEND_GENERAL_ERROR); + logWarn("Could not send mail", e); + } + } + +} diff --git a/src/main/java/org/olat/core/util/mail/manager/MailNotificationsHandler.java b/src/main/java/org/olat/core/util/mail/manager/MailNotificationsHandler.java new file mode 100644 index 00000000000..1d7437b9c1a --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/manager/MailNotificationsHandler.java @@ -0,0 +1,126 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + +package org.olat.core.util.mail.manager; + +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.olat.core.gui.translator.Translator; +import org.olat.core.logging.LogDelegator; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; +import org.olat.core.util.mail.MailModule; +import org.olat.core.util.mail.model.DBMail; +import org.olat.core.util.notifications.NotificationHelper; +import org.olat.core.util.notifications.NotificationsHandler; +import org.olat.core.util.notifications.NotificationsManager; +import org.olat.core.util.notifications.Publisher; +import org.olat.core.util.notifications.Subscriber; +import org.olat.core.util.notifications.SubscriptionInfo; +import org.olat.core.util.notifications.items.SubscriptionListItem; +import org.olat.core.util.notifications.items.TitleItem; + +/** + * + * Description:<br> + * + * + * <P> + * Initial Date: 24 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailNotificationsHandler extends LogDelegator implements NotificationsHandler { + + private MailModule mailModule; + + public MailNotificationsHandler() { + // + } + + /** + * [user by Spring] + * @param mailModule + */ + public void setMailModule(MailModule mailModule) { + this.mailModule = mailModule; + } + + + + @Override + public SubscriptionInfo createSubscriptionInfo(Subscriber subscriber, Locale locale, Date compareDate) { + if(!mailModule.isInternSystem()) { + return NotificationsManager.getInstance().getNoSubscriptionInfo(); + } + + String realMail = subscriber.getIdentity().getUser().getPreferences().getReceiveRealMail(); + if("true".equals(realMail)) { + //receive real e-mails + return NotificationsManager.getInstance().getNoSubscriptionInfo(); + } else if (!StringHelper.containsNonWhitespace(realMail) && mailModule.isReceiveRealMailUserDefaultSetting()) { + //user has no settings, check the default setting + return NotificationsManager.getInstance().getNoSubscriptionInfo(); + } + + SubscriptionInfo si = null; + Publisher p = subscriber.getPublisher(); + Date latestNews = p.getLatestNewsDate(); + + // do not try to create a subscription info if state is deleted - results in + // exceptions, course + // can't be loaded when already deleted + if (NotificationsManager.getInstance().isPublisherValid(p) && compareDate.before(latestNews)) { + try { + List<DBMail> inbox = MailManager.getInstance().getInbox(subscriber.getIdentity(), Boolean.TRUE, Boolean.FALSE, compareDate, 0, 0); + if(!inbox.isEmpty()) { + Translator translator = Util.createPackageTranslator(MailModule.class, locale); + si = new SubscriptionInfo(subscriber.getKey(), p.getType(), new TitleItem(translator.translate("mail.notification.type"), "o_co_icon"), null); + for (DBMail mail : inbox) { + String subject = mail.getSubject(); + String businessPath = "[Inbox:" + mail.getKey() + "]"; + String urlToSend = NotificationHelper.getURLFromBusinessPathString(p, businessPath); + SubscriptionListItem subListItem = new SubscriptionListItem(subject, urlToSend, mail.getCreationDate(), "o_co_icon"); + si.addSubscriptionListItem(subListItem); + } + } + } catch(Exception ex) { + logError("", ex); + } + } + + if( si == null) { + si = NotificationsManager.getInstance().getNoSubscriptionInfo(); + } + return si; + } + + @Override + public String createTitleInfo(Subscriber subscriber, Locale locale) { + Translator translator = Util.createPackageTranslator(MailModule.class, locale); + return translator.translate("mail.notification.type"); + } + + @Override + public String getType() { + return "Inbox"; + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/mail/model/DBMail.hbm.xml b/src/main/java/org/olat/core/util/mail/model/DBMail.hbm.xml new file mode 100644 index 00000000000..d97fdd2c354 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/model/DBMail.hbm.xml @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> +<hibernate-mapping default-lazy="false"> + + <class name="org.olat.core.util.mail.model.DBMailImpl" mutable="false" table="o_mail"> + <id name="key" column="mail_id" type="long" unsaved-value="null"> + <generator class="hilo"/> + </id> + + <property name="creationDate" column="creationdate" type="timestamp" /> + <property name="lastModified" column="lastmodified" type="timestamp" /> + + <property name="subject" column="subject" type="string" length="512" not-null="false"/> + <property name="body" column="body" type="string" length="16777210" not-null="false"/> + <property name="metaId" column="meta_mail_id" type="string" length="64" not-null="false"/> + + <component name="context"> + <property name="resName" column="resname" type="string" length="50" not-null="false"/> + <property name="resId" column="resid" type="long" not-null="false"/> + <property name="resSubPath" column="ressubpath" type="string" length="2048" not-null="false"/> + <property name="businessPath" column="businesspath" type="string" length="2048" not-null="false"/> + </component> + + <many-to-one name="from" column="fk_from_id" class="org.olat.core.util.mail.model.DBMailRecipient" fetch="join" unique="false" cascade="all"/> + + <list name="recipients" table="o_mail_to_recipient" cascade="all,delete-orphan" lazy="true" inverse="false"> + <key column="fk_mail_id" not-null="true" /> + <list-index column="pos"/> + <many-to-many column="fk_recipient_id" class="org.olat.core.util.mail.model.DBMailRecipient"/> + </list> + </class> + +</hibernate-mapping> \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/mail/model/DBMail.java b/src/main/java/org/olat/core/util/mail/model/DBMail.java new file mode 100644 index 00000000000..c045e906983 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/model/DBMail.java @@ -0,0 +1,54 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + +package org.olat.core.util.mail.model; + +import java.util.Date; +import java.util.List; + +import org.olat.core.id.CreateInfo; +import org.olat.core.id.ModifiedInfo; +import org.olat.core.id.Persistable; + +/** + * + * Description:<br> + * + * + * <P> + * Initial Date: 28 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public interface DBMail extends CreateInfo, ModifiedInfo, Persistable { + + public DBMailRecipient getFrom(); + + public String getSubject(); + + public String getBody(); + + public Date getLastModified(); + + public String getMetaId(); + + public List<DBMailRecipient> getRecipients(); + + public DBMailContext getContext(); +} diff --git a/src/main/java/org/olat/core/util/mail/model/DBMailAttachment.hbm.xml b/src/main/java/org/olat/core/util/mail/model/DBMailAttachment.hbm.xml new file mode 100644 index 00000000000..49a26127fcf --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/model/DBMailAttachment.hbm.xml @@ -0,0 +1,30 @@ +<?xml version="1.0"?> +<!DOCTYPE hibernate-mapping PUBLIC + "-//Hibernate/Hibernate Mapping DTD//EN" + "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> +<hibernate-mapping default-lazy="false"> + + <class name="org.olat.core.util.mail.model.DBMailAttachment" table="o_mail_attachment"> + <id name="key" column="attachment_id" type="long" unsaved-value="null"> + <generator class="hilo"/> + </id> + <property name="creationDate" column="creationdate" type="timestamp" /> + <property name="size" column="datas_size" type="long"/> + <property name="mimetype" column="mimetype" type="string" not-null="false" length="255"/> + <property name="name" column="datas_name" type="string" not-null="false" length="255"/> + <many-to-one name="mail" column="fk_att_mail_id" class="org.olat.core.util.mail.model.DBMailImpl" fetch="join" unique="false" cascade="none"/> + </class> + + <class name="org.olat.core.util.mail.model.DBMailAttachmentData" table="o_mail_attachment"> + <id name="key" column="attachment_id" type="long" unsaved-value="null"> + <generator class="hilo"/> + </id> + <property name="creationDate" column="creationdate" type="timestamp" /> + <property name="datas" column="datas" type="binary" length="16777215"/> + <property name="size" column="datas_size" type="long"/> + <property name="mimetype" column="mimetype" type="string" not-null="false" length="255"/> + <property name="name" column="datas_name" type="string" not-null="false" length="255"/> + <many-to-one name="mail" column="fk_att_mail_id" class="org.olat.core.util.mail.model.DBMailImpl" fetch="join" unique="false" cascade="none"/> + </class> + +</hibernate-mapping> diff --git a/src/main/java/org/olat/core/util/mail/model/DBMailAttachment.java b/src/main/java/org/olat/core/util/mail/model/DBMailAttachment.java new file mode 100644 index 00000000000..6420eeacc55 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/model/DBMailAttachment.java @@ -0,0 +1,85 @@ +/** + * <p> + * Copyright (c) frentix GmbH<br> + * http://www.frentix.com<br> + */ +package org.olat.core.util.mail.model; + +import org.olat.core.commons.persistence.PersistentObject; +import org.olat.core.gui.util.CSSHelper; + +/** + * + * Description:<br> + * + * <P> + * Initial Date: 8 sept. 2010 <br> + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class DBMailAttachment extends PersistentObject { + + private static final long serialVersionUID = -1713863670528439651L; + + private Long size; + private String name; + private String mimetype; + private DBMailImpl mail; + + public DBMailAttachment() { + // + } + + public DBMailImpl getMail() { + return mail; + } + + public void setMail(DBMailImpl mail) { + this.mail = mail; + } + + public Long getSize() { + return size; + } + + public void setSize(Long size) { + this.size = size; + } + + public String getCssClass() { + return CSSHelper.createFiletypeIconCssClassFor(name); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getMimetype() { + return mimetype; + } + + public void setMimetype(String mimetype) { + this.mimetype = mimetype; + } + + @Override + public int hashCode() { + return getKey() == null ? 2951 : getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof DBMailAttachment) { + DBMailAttachment attachment = (DBMailAttachment)obj; + return getKey() != null && getKey().equals(attachment.getKey()); + } + return false; + } +} diff --git a/src/main/java/org/olat/core/util/mail/model/DBMailAttachmentData.java b/src/main/java/org/olat/core/util/mail/model/DBMailAttachmentData.java new file mode 100644 index 00000000000..2aa57362cc4 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/model/DBMailAttachmentData.java @@ -0,0 +1,89 @@ +/** + * <p> + * Copyright (c) frentix GmbH<br> + * http://www.frentix.com<br> + */ +package org.olat.core.util.mail.model; + +import org.olat.core.commons.persistence.PersistentObject; + +/** + * + * Description:<br> + * + * <P> + * Initial Date: 8 sept. 2010 <br> + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class DBMailAttachmentData extends PersistentObject { + + private static final long serialVersionUID = -3741636430048220733L; + + private Long size; + private String name; + private String mimetype; + private byte[] datas; + private DBMailImpl mail; + + public DBMailAttachmentData() { + // + } + + public DBMailImpl getMail() { + return mail; + } + + public void setMail(DBMailImpl mail) { + this.mail = mail; + } + + public byte[] getDatas() { + return datas; + } + + public void setDatas(byte[] datas) { + this.datas = datas; + } + + public Long getSize() { + return size; + } + + public void setSize(Long size) { + this.size = size; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getMimetype() { + return mimetype; + } + + public void setMimetype(String mimetype) { + this.mimetype = mimetype; + } + + @Override + public int hashCode() { + return getKey() == null ? 921536 : getKey().intValue(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof DBMailAttachmentData) { + DBMailAttachmentData data = (DBMailAttachmentData)obj; + return getKey() != null && getKey().equals(data.getKey()); + } + return false; + } +} diff --git a/src/main/java/org/olat/core/util/mail/model/DBMailContext.java b/src/main/java/org/olat/core/util/mail/model/DBMailContext.java new file mode 100644 index 00000000000..d583caf6747 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/model/DBMailContext.java @@ -0,0 +1,94 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + + +package org.olat.core.util.mail.model; + +import org.olat.core.id.OLATResourceable; +import org.olat.core.util.mail.MailContext; + +/** + * + * Description:<br> + * + * + * <P> + * Initial Date: 30 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class DBMailContext implements MailContext { + + private String resName; + private Long resId; + private String businessPath; + private String resSubPath; + + + public OLATResourceable getOLATResourceable() { + final Long id = resId; + final String name = resName; + + if(id == null || name == null) return null; + + return new OLATResourceable() { + @Override + public Long getResourceableId() { + return id; + } + + @Override + public String getResourceableTypeName() { + return name; + } + }; + } + + public String getResSubPath() { + return resSubPath; + } + + public void setResSubPath(String resSubPath) { + this.resSubPath = resSubPath; + } + + public String getBusinessPath() { + return businessPath; + } + + public void setBusinessPath(String businessPath) { + this.businessPath = businessPath; + } + + public String getResName() { + return resName; + } + + public void setResName(String resName) { + this.resName = resName; + } + + public Long getResId() { + return resId; + } + + public void setResId(Long resId) { + this.resId = resId; + } +} diff --git a/src/main/java/org/olat/core/util/mail/model/DBMailImpl.java b/src/main/java/org/olat/core/util/mail/model/DBMailImpl.java new file mode 100644 index 00000000000..3d70935224d --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/model/DBMailImpl.java @@ -0,0 +1,138 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + +package org.olat.core.util.mail.model; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.olat.core.commons.persistence.PersistentObject; + +/** + * + * Description:<br> + * + * + * <P> + * Initial Date: 28 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class DBMailImpl extends PersistentObject implements DBMail { + + private static final long serialVersionUID = 6407865711769961684L; + + private String subject; + private String body; + private Date lastModified; + private String metaId; + + private DBMailRecipient from; + private List<DBMailRecipient> recipients; + private DBMailContext context; + + + + @Override + public DBMailRecipient getFrom() { + return from; + } + + public void setFrom(DBMailRecipient from) { + this.from = from; + } + + @Override + public String getMetaId() { + return metaId; + } + + public void setMetaId(String metaId) { + this.metaId = metaId; + } + + @Override + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + @Override + public Date getLastModified() { + return lastModified; + } + + @Override + public void setLastModified(Date lastModified) { + this.lastModified = lastModified; + } + + public List<DBMailRecipient> getRecipients() { + if(recipients == null) { + recipients = new ArrayList<DBMailRecipient>(); + } + return recipients; + } + + public void setRecipients(List<DBMailRecipient> recipients) { + this.recipients = recipients; + } + + + + public DBMailContext getContext() { + if(context == null) { + context = new DBMailContext(); + } + return context; + } + + public void setContext(DBMailContext context) { + this.context = context; + } + + @Override + public int hashCode() { + return getKey() == null ? 2991 : getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof DBMailImpl) { + DBMailImpl mail = (DBMailImpl)obj; + return getKey() != null && getKey().equals(mail.getKey()); + } + return false; + } +} diff --git a/src/main/java/org/olat/core/util/mail/model/DBMailRecipient.hbm.xml b/src/main/java/org/olat/core/util/mail/model/DBMailRecipient.hbm.xml new file mode 100644 index 00000000000..14a7d437994 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/model/DBMailRecipient.hbm.xml @@ -0,0 +1,23 @@ +<?xml version="1.0"?> +<!DOCTYPE hibernate-mapping PUBLIC + "-//Hibernate/Hibernate Mapping DTD//EN" + "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> +<hibernate-mapping default-lazy="false"> + + <class name="org.olat.core.util.mail.model.DBMailRecipient" table="o_mail_recipient"> + <!-- the default columns --> + <id name="key" column="recipient_id" type="long" unsaved-value="null"> + <generator class="hilo"/> + </id> + <property name="creationDate" column="creationdate" type="timestamp" /> + <property name="deleted" column="deleted" type="boolean" /> + <property name="visible" column="recipientvisible" type="boolean" /> + <property name="read" column="mailread" type="boolean" /> + <property name="marked" column="mailmarked" type="boolean" /> + <property name="group" column="recipientgroup" type="string" length="255"/> + <property name="emailAddress" column="email" type="string" length="255"/> + + <many-to-one name="recipient" column="fk_recipient_id" class="org.olat.basesecurity.IdentityImpl" fetch="join" unique="false" cascade="none"/> + </class> + +</hibernate-mapping> diff --git a/src/main/java/org/olat/core/util/mail/model/DBMailRecipient.java b/src/main/java/org/olat/core/util/mail/model/DBMailRecipient.java new file mode 100644 index 00000000000..feebbf28054 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/model/DBMailRecipient.java @@ -0,0 +1,127 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + +package org.olat.core.util.mail.model; + +import org.olat.core.commons.persistence.PersistentObject; +import org.olat.core.id.Identity; + +/** + * + * Description:<br> + * + * + * <P> + * Initial Date: 24 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class DBMailRecipient extends PersistentObject { + + private static final long serialVersionUID = -6793421633217512631L; + + private Identity recipient; + private String emailAddress; + private Boolean deleted; + private Boolean visible; + private Boolean read; + private Boolean marked; + private String group; + + public DBMailRecipient() { + //make Hibernate happy + } + + public DBMailRecipient(Identity recipient) { + this.recipient = recipient; + } + + public Identity getRecipient() { + return recipient; + } + + public void setRecipient(Identity recipient) { + this.recipient = recipient; + } + + public String getEmailAddress() { + return emailAddress; + } + + public void setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + } + + public Boolean getDeleted() { + return deleted; + } + + public void setDeleted(Boolean deleted) { + this.deleted = deleted; + } + + public Boolean getVisible() { + return visible; + } + + public void setVisible(Boolean visible) { + this.visible = visible; + } + + public Boolean getRead() { + return read; + } + + public void setRead(Boolean read) { + this.read = read; + } + + public Boolean getMarked() { + return marked; + } + + public void setMarked(Boolean marked) { + this.marked = marked; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + @Override + public int hashCode() { + return getKey() == null ? 2981 : getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof DBMailRecipient) { + DBMailRecipient recipient = (DBMailRecipient)obj; + return getKey() != null && getKey().equals(recipient.getKey()); + } + return false; + } +} diff --git a/src/main/java/org/olat/core/util/mail/ui/BooleanCSSCellRenderer.java b/src/main/java/org/olat/core/util/mail/ui/BooleanCSSCellRenderer.java new file mode 100644 index 00000000000..39f4a221519 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/BooleanCSSCellRenderer.java @@ -0,0 +1,71 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ +package org.olat.core.util.mail.ui; + +import org.olat.core.gui.components.table.CustomCssCellRenderer; +import org.olat.core.gui.translator.Translator; + +/** + * + * Description:<br> + * + * <P> + * Initial Date: 25 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class BooleanCSSCellRenderer extends CustomCssCellRenderer { + + private String trueCss; + private String falseCss; + private String trueHoverText; + private String falseHoverText; + + private final Translator translator; + + public BooleanCSSCellRenderer(Translator translator, String trueCss, String falseCss, + String trueHoverText, String falseHoverText) { + this.trueCss = trueCss; + this.falseCss = falseCss; + this.trueHoverText = trueHoverText; + this.falseHoverText = falseHoverText; + this.translator = translator; + } + + @Override + protected String getCssClass(Object val) { + if(val instanceof Boolean) { + return ((Boolean)val).booleanValue() ? trueCss : falseCss; + } + return ""; + } + + @Override + protected String getCellValue(Object val) { + return ""; + } + + @Override + protected String getHoverText(Object val) { + if(val instanceof Boolean) { + return ((Boolean)val).booleanValue() ? translator.translate(trueHoverText) : translator.translate(falseHoverText); + } + return ""; + } +} diff --git a/src/main/java/org/olat/core/util/mail/ui/MailActionExtension.java b/src/main/java/org/olat/core/util/mail/ui/MailActionExtension.java new file mode 100644 index 00000000000..cc3cf468faf --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/MailActionExtension.java @@ -0,0 +1,53 @@ +/** + * 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) 2008 frentix GmbH, Switzerland<br> + * <p> + */ +package org.olat.core.util.mail.ui; + +import org.olat.core.extensions.action.GenericActionExtension; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.tree.GenericTreeNode; + +/** + * + * Description:<br> + * MailActionExtension is used in MinimalHomeController (Home-menu). it returns + * a MailTreeNode which displays an iconDecorator if user has unread e-mails in + * his inbox + * + * <P> + * Initial Date: 13.09.2011 <br> + * + * @author Sergio Trentini, sergio.trentini@frentix.com, www.frentix.com + */ +public class MailActionExtension extends GenericActionExtension { + + @Override + public GenericTreeNode createMenuNode(UserRequest ureq) { + GenericTreeNode node = new MailTreeNode(ureq.getIdentity()); + node.setAltText(getDescription(ureq.getLocale())); + node.setTitle(getActionText(ureq.getLocale())); + node.setIconCssClass(getIconCssClass()); + node.setCssClass(getCssClass()); + + node.setUserObject(this); + + return node; + } + +} diff --git a/src/main/java/org/olat/core/util/mail/ui/MailAdminController.java b/src/main/java/org/olat/core/util/mail/ui/MailAdminController.java new file mode 100644 index 00000000000..fb943b6586c --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/MailAdminController.java @@ -0,0 +1,143 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ +package org.olat.core.util.mail.ui; + +import org.olat.core.CoreSpringFactory; +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.MultipleSelectionElement; +import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +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.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.Util; +import org.olat.core.util.mail.MailModule; +import org.olat.core.util.mail.MailUIFactory; + +/** + * + * Description:<br> + * Small administration to set on/off the intern mail system + * + * <P> + * Initial Date: 14 avr. 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailAdminController extends FormBasicController { + + private MultipleSelectionElement enabled; + private SingleSelection userDefaultSettingEl; + + private String[] values = {""}; + private String[] keys = {"on"}; + + + private String[] userSettingValues ; + private String[] userSettingKeys = {"intern.only","send.copy"}; + + public MailAdminController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl, null, Util.createPackageTranslator(MailModule.class, ureq.getLocale())); + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + this.setFormTitle("mail.admin.title"); + this.setFormDescription("mail.admin.description"); + this.setFormContextHelp(MailUIFactory.class.getPackage().getName(), "mail-admin.html", "chelp.mail-admin.title"); + + boolean internEnabled = isEnabled(); + enabled = uifactory.addCheckboxesHorizontal("mail.admin.intern.enabled", formLayout, keys, values, null); + enabled.select(keys[0], internEnabled); + enabled.addActionListener(this, FormEvent.ONCHANGE); + + boolean realMailSetting = isUserDefaultSetting(); + userSettingValues = new String[] { + translate("mail.admin.intern.only"), + translate("mail.admin.intern.real.mail") + }; + userDefaultSettingEl = uifactory.addRadiosVertical("mail-system", "mail.admin.default.settings", formLayout, userSettingKeys, userSettingValues); + if(realMailSetting) { + userDefaultSettingEl.select(userSettingKeys[1], true); + } else { + userDefaultSettingEl.select(userSettingKeys[0], true); + } + userDefaultSettingEl.setEnabled(internEnabled); + + final FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator()); + buttonGroupLayout.setRootForm(mainForm); + formLayout.add(buttonGroupLayout); + + uifactory.addFormSubmitButton("save", formLayout); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + boolean on = !enabled.getSelectedKeys().isEmpty(); + setEnabled(on); + + if(userDefaultSettingEl.isOneSelected()) { + boolean realMailSetting = userDefaultSettingEl.getSelected() == 1; + setUserDefaultSetting(realMailSetting); + } + userDefaultSettingEl.setEnabled(on); + + getWindowControl().setInfo("saved"); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(source == enabled) { + boolean on = !enabled.getSelectedKeys().isEmpty(); + userDefaultSettingEl.setEnabled(on); + } + super.formInnerEvent(ureq, source, event); + } + + private boolean isEnabled() { + MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule"); + return config.isInternSystem(); + } + + private void setEnabled(boolean enabled) { + MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule"); + config.setInterSystem(enabled); + } + + + private boolean isUserDefaultSetting() { + MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule"); + return config.isReceiveRealMailUserDefaultSetting(); + } + + private void setUserDefaultSetting(boolean enabled) { + MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule"); + config.setReceiveRealMailUserDefaultSetting(enabled); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/mail/ui/MailAttachmentMapper.java b/src/main/java/org/olat/core/util/mail/ui/MailAttachmentMapper.java new file mode 100644 index 00000000000..ba8fccfe3c6 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/MailAttachmentMapper.java @@ -0,0 +1,144 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + +package org.olat.core.util.mail.ui; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.olat.core.dispatcher.mapper.Mapper; +import org.olat.core.gui.media.ForbiddenMediaResource; +import org.olat.core.gui.media.MediaResource; +import org.olat.core.gui.media.NotFoundMediaResource; +import org.olat.core.util.StringHelper; +import org.olat.core.util.WebappHelper; +import org.olat.core.util.mail.manager.MailManager; +import org.olat.core.util.mail.model.DBMail; +import org.olat.core.util.mail.model.DBMailAttachmentData; + +/** + * + * Description:<br> + * TODO: srosse Class Description for MailAttachmentMapper + * + * <P> + * Initial Date: 28 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailAttachmentMapper implements Mapper { + + public static final String ATTACHMENT_CONTEXT = "/attachments/"; + + private final DBMail mail; + private final MailManager mailManager; + + public MailAttachmentMapper(DBMail mail, MailManager mailManager) { + this.mail = mail; + this.mailManager = mailManager; + } + + @Override + public MediaResource handle(String relPath, HttpServletRequest request) { + if(relPath != null && relPath.indexOf(ATTACHMENT_CONTEXT) >= 0) { + int startIndex = relPath.indexOf(ATTACHMENT_CONTEXT); + int endIndex = relPath.indexOf("/", startIndex + ATTACHMENT_CONTEXT.length()); + if(startIndex >= 0 && endIndex > startIndex) { + String attachmentKey = relPath.substring(startIndex + ATTACHMENT_CONTEXT.length(), endIndex); + try { + Long key = new Long(attachmentKey); + + boolean rightMail = true; + /*for(DBMailAttachment attachment:mail.getAttachments()) { + if(key.equals(attachment.getKey())) { + rightMail = true; + break; + } + }*/ + + if(rightMail) { + DBMailAttachmentData datas = mailManager.getAttachmentWithData(key); + BytesMediaResource resource = new BytesMediaResource(datas); + return resource; + } else { + //only show the attachment of the selected e-mail + return new ForbiddenMediaResource(relPath); + } + } catch(NumberFormatException e) { + return new NotFoundMediaResource(relPath); + } + } + } + return new NotFoundMediaResource(relPath); + } + + public class BytesMediaResource implements MediaResource { + + private final DBMailAttachmentData datas; + + public BytesMediaResource(DBMailAttachmentData datas) { + this.datas = datas; + } + + @Override + public String getContentType() { + if(StringHelper.containsNonWhitespace(datas.getMimetype())) { + return datas.getMimetype(); + } + if(StringHelper.containsNonWhitespace(datas.getName())) { + String mimeType = WebappHelper.getMimeType(datas.getName()); + if(StringHelper.containsNonWhitespace(mimeType)) { + return mimeType; + } + } + return "application/octet-stream"; + } + + @Override + public Long getSize() { + if(datas.getDatas() == null) return 0l; + return new Long(datas.getDatas().length); + } + + @Override + public InputStream getInputStream() { + return new ByteArrayInputStream(datas.getDatas()); + } + + @Override + public Long getLastModified() { + return null; + } + + @Override + public void prepare(HttpServletResponse hres) { + String fileName = datas.getName(); + hres.setHeader("Content-Disposition","filename=\"" + StringHelper.urlEncodeISO88591(fileName) + "\""); + hres.setHeader("Content-Description",StringHelper.urlEncodeISO88591(fileName)); + } + + @Override + public void release() { + // + } + } +} diff --git a/src/main/java/org/olat/core/util/mail/ui/MailContextCellRenderer.java b/src/main/java/org/olat/core/util/mail/ui/MailContextCellRenderer.java new file mode 100644 index 00000000000..3f4645140a4 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/MailContextCellRenderer.java @@ -0,0 +1,76 @@ +/** + * 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) frentix GmbH<br> + * http://www.frentix.com<br> + * <p> + */ +package org.olat.core.util.mail.ui; + +import java.util.Locale; +import java.util.UUID; + +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.table.CustomCellRenderer; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.render.RenderResult; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; +import org.olat.core.util.mail.ui.MailDataModel.ContextPair; + +/** + * + * Description:<br> + * Render a list of resources / with link + * + * <P> + * Initial Date: 7 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailContextCellRenderer implements CustomCellRenderer { + + private final Translator translator; + private VelocityContainer container; + private final Controller listeningController; + + public MailContextCellRenderer(Controller listeningController, VelocityContainer container, Translator translator) { + this.listeningController = listeningController; + this.container = container; + this.translator = translator; + } + + @Override + public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) { + if(val instanceof ContextPair) { + ContextPair context = (ContextPair)val; + if(renderer == null) { + sb.append(context.getName()); + } else { + Link link = LinkFactory.createLink("bp_" + UUID.randomUUID().toString(), container, listeningController); + link.setCustomDisplayText(context.getName()); + link.setUserObject(context.getBusinessPath()); + + URLBuilder ubu = renderer.getUrlBuilder().createCopyFor(link); + RenderResult renderResult = new RenderResult(); + link.getHTMLRendererSingleton().render(renderer, sb, link, ubu, translator, renderResult, null); + } + } + } +} diff --git a/src/main/java/org/olat/core/util/mail/ui/MailContextResolver.java b/src/main/java/org/olat/core/util/mail/ui/MailContextResolver.java new file mode 100644 index 00000000000..1f9f26e05e5 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/MailContextResolver.java @@ -0,0 +1,23 @@ +package org.olat.core.util.mail.ui; + +import java.util.Locale; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.WindowControl; + +/** + * + * Description:<br> + * TODO: srosse Class Description for MailContextResolver + * + * <P> + * Initial Date: 30 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public interface MailContextResolver { + + public String getName(String businessPath, Locale locale); + + public void open(UserRequest ureq, WindowControl wControl, String url); + +} diff --git a/src/main/java/org/olat/core/util/mail/ui/MailContextShortName.java b/src/main/java/org/olat/core/util/mail/ui/MailContextShortName.java new file mode 100644 index 00000000000..34ccc59e101 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/MailContextShortName.java @@ -0,0 +1,59 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + + +package org.olat.core.util.mail.ui; + +import org.olat.core.gui.ShortName; + +/** + * + * Description:<br> + * + * <P> + * Initial Date: 30 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailContextShortName implements ShortName { + private String businessPath; + private String contextName; + + public MailContextShortName(String contextName) { + this(contextName, null); + } + + public MailContextShortName(String contextName, String businessPath) { + this.contextName = contextName; + this.businessPath = businessPath; + } + + @Override + public String getShortName() { + return contextName; + } + + public String getBusinessPath() { + return businessPath; + } + + public String getContextName() { + return contextName; + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/mail/ui/MailController.java b/src/main/java/org/olat/core/util/mail/ui/MailController.java new file mode 100644 index 00000000000..249e9ed456f --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/MailController.java @@ -0,0 +1,188 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + +package org.olat.core.util.mail.ui; + +import java.text.DateFormat; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +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.FormLink; +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.id.Identity; +import org.olat.core.id.User; +import org.olat.core.id.UserConstants; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; +import org.olat.core.util.mail.MailModule; +import org.olat.core.util.mail.manager.MailManager; +import org.olat.core.util.mail.model.DBMail; +import org.olat.core.util.mail.model.DBMailAttachment; +import org.olat.core.util.mail.model.DBMailRecipient; + +/** + * + * Description:<br> + * + * <P> + * Initial Date: 24 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailController extends FormBasicController { + + private FormLink backLink; + + private String mapperBaseURI; + private final boolean back; + private final DBMail mail; + private final List<DBMailAttachment> attachments; + private final MailManager mailManager; + + public MailController(UserRequest ureq, WindowControl wControl, DBMail mail, boolean back) { + super(ureq, wControl, LAYOUT_VERTICAL); + setTranslator(Util.createPackageTranslator(MailModule.class, ureq.getLocale())); + this.mail = mail; + this.back = back; + mailManager = MailManager.getInstance(); + attachments = MailManager.getInstance().getAttachments(mail); + if(!attachments.isEmpty()) { + mapperBaseURI = registerMapper(new MailAttachmentMapper(mail, mailManager)); + } + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer mainLayout, Controller listener, UserRequest ureq) { + setTranslator(Util.createPackageTranslator(MailModule.class, ureq.getLocale())); + String page = Util.getPackageVelocityRoot(MailModule.class) + "/mail.html"; + FormLayoutContainer vcLayout = FormLayoutContainer.createCustomFormLayout("wrapper", getTranslator(), page); + vcLayout.setRootForm(mainForm); + mainLayout.add(vcLayout); + + if(back) { + backLink = uifactory.addFormLink("back", vcLayout, Link.LINK_BACK); + vcLayout.add("back", backLink); + } + + FormLayoutContainer formLayout = FormLayoutContainer.createDefaultFormLayout("mainCmp", getTranslator()); + formLayout.setRootForm(mainForm); + vcLayout.add("mainCmp", formLayout); + + uifactory.addStaticTextElement("subject", "mail.subject", mail.getSubject(), formLayout); + + String from = getFullName(mail.getFrom()); + uifactory.addStaticTextElement("from", "mail.from", from, formLayout); + + String recipients = getRecipients(); + uifactory.addStaticTextElement("recipients", "mail.recipients", recipients, formLayout); + + String date = DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale()).format(mail.getCreationDate()); + uifactory.addStaticTextElement("date", "mail.sendDate", date, formLayout); + + uifactory.addSpacerElement("spacer2", formLayout, false); + uifactory.addStaticTextElement("body", "mail.body", formattedBody(), formLayout); + + if(!attachments.isEmpty()) { + uifactory.addSpacerElement("spacer3", formLayout, false); + String attachmentsPage = Util.getPackageVelocityRoot(MailModule.class) + "/attachments.html"; + FormLayoutContainer container = FormLayoutContainer.createCustomFormLayout("attachments", getTranslator(), attachmentsPage); + container.setLabel("mail.attachments", null); + container.setRootForm(mainForm); + container.contextPut("attachments", attachments); + container.contextPut("mapperBaseURI", mapperBaseURI); + formLayout.add(container); + } + } + + private String getRecipients() { + StringBuilder sb = new StringBuilder(); + Set<String> groups = new HashSet<String>(); + for(DBMailRecipient recipient:mail.getRecipients()) { + if(recipient == null) continue; + String group = recipient.getGroup(); + if(StringHelper.containsNonWhitespace(group) && !groups.contains(group)) { + if(sb.length() > 0) sb.append(", "); + sb.append(group); + groups.add(group); + } + } + return sb.toString(); + } + + private String getFullName(DBMailRecipient recipient) { + if(recipient == null) return ""; + return getFullName(recipient.getRecipient()); + } + + private String getFullName(Identity identity) { + StringBuilder sb = new StringBuilder(); + if(identity != null) { + User user = identity.getUser(); + sb.append(user.getProperty(UserConstants.LASTNAME, null)) + .append(" ") + .append(user.getProperty(UserConstants.FIRSTNAME, null)); + } + return sb.toString(); + } + + private String formattedBody() { + String body = mail.getBody(); + if(!StringHelper.containsNonWhitespace(body)) return ""; + + if(body.indexOf("<") >= 0 && body.indexOf("/>") >= 0) { + //html + return body; + } + + body = body.replace("\n\r", "<br />");//if windows + body = body.replace("\n", "<br />"); + return body; + } + + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(source == backLink) { + fireEvent(ureq, Event.BACK_EVENT); + } else { + super.formInnerEvent(ureq, source, event); + } + } +} diff --git a/src/main/java/org/olat/core/util/mail/ui/MailDataModel.java b/src/main/java/org/olat/core/util/mail/ui/MailDataModel.java new file mode 100644 index 00000000000..e92a86f454b --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/MailDataModel.java @@ -0,0 +1,243 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + +package org.olat.core.util.mail.ui; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.olat.core.gui.components.table.TableDataModelWithMarkableRows; +import org.olat.core.gui.translator.Translator; +import org.olat.core.id.Identity; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; +import org.olat.core.util.mail.model.DBMail; +import org.olat.core.util.mail.model.DBMailRecipient; + +/** + * + * Description:<br> + * + * + * <P> + * Initial Date: 28 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailDataModel implements TableDataModelWithMarkableRows { + + private boolean outbox; + private List<DBMail> mails; + private List<DBMail> filteredMails; + private final Identity identity; + private final Formatter formatter; + private final Translator translator; + private final Map<String,String> bpToContexts; + + public MailDataModel(List<DBMail> mails, Map<String,String> bpToContexts, Identity identity, + Translator translator, Formatter formatter, boolean outbox) { + this.mails = mails; + this.bpToContexts = bpToContexts; + this.identity = identity; + this.formatter = formatter; + this.translator = translator; + this.outbox = outbox; + } + + @Override + public int getColumnCount() { + return 2; + } + + @Override + public int getRowCount() { + return filteredMails == null ? mails.size() : filteredMails.size(); + } + + @Override + public Object getValueAt(int row, int col) { + DBMail mail = filteredMails == null ? mails.get(row) : filteredMails.get(row); + Columns[] cols = Columns.values(); + if(col < cols.length) { + switch(cols[col]) { + case read: { + for(DBMailRecipient recipient:mail.getRecipients()) { + if(recipient != null && recipient.getRecipient() != null && recipient.getRecipient().equalsByPersistableKey(identity)) { + return recipient.getRead(); + } + } + return Boolean.FALSE; + } + case marked: { + for(DBMailRecipient recipient:mail.getRecipients()) { + if(recipient != null && recipient.getRecipient() != null && recipient.getRecipient().equalsByPersistableKey(identity)) { + return recipient.getMarked(); + } + } + return Boolean.FALSE; + } + case context: { + String businessPath = mail.getContext().getBusinessPath(); + if(StringHelper.containsNonWhitespace(businessPath)) { + String contextName = bpToContexts.get(businessPath); + if(StringHelper.containsNonWhitespace(businessPath) && StringHelper.containsNonWhitespace(contextName)) { + return new ContextPair(contextName, businessPath); + } + } + return null; + } + case subject: return mail.getSubject(); + case receivedDate: + case sendDate: { + return mail.getCreationDate(); + } + case from: { + DBMailRecipient from = mail.getFrom(); + if(from != null ) { + if(from.getRecipient() != null) { + return from.getRecipient(); + } else if (StringHelper.containsNonWhitespace(from.getGroup())) { + return from.getGroup(); + } else if (StringHelper.containsNonWhitespace(from.getEmailAddress())) { + return from.getEmailAddress(); + } + } + return "-"; + } + case recipients: { + if(StringHelper.containsNonWhitespace(mail.getMetaId())) { + return translator.translate("mail.from.miscellaneous"); + } + + StringBuilder sb = new StringBuilder(); + Set<String> groupSet = new HashSet<String>(); + for(DBMailRecipient recipient:mail.getRecipients()) { + if(recipient != null && recipient.getGroup() != null) { + String group = recipient.getGroup(); + if(!groupSet.contains(group)) { + if(sb.length() > 0) sb.append(", "); + sb.append(group); + groupSet.add(group); + } + } + } + return sb.toString(); + } + } + } + return mail; + } + + @Override + public DBMail getObject(int row) { + return filteredMails == null ? mails.get(row) : filteredMails.get(row); + } + + @Override + public void setObjects(List objects) { + mails = objects; + filteredMails = null; + } + + /** + * @see org.olat.core.gui.components.table.TableDataModelWithMarkableRows#getRowCssClass(int) + */ + @Override + public String getRowCssClass(int row) { + if(outbox) return null; + + DBMail mail = filteredMails == null ? mails.get(row) : filteredMails.get(row); + for(DBMailRecipient recipient:mail.getRecipients()) { + if(recipient != null && recipient.getRecipient() != null && recipient.getRecipient().equalsByPersistableKey(identity)) { + if (!recipient.getRead()) { + return "b_marked"; + } + } + } + return null; + } + + public void replace(DBMail mail) { + int index = mails.indexOf(mail); + if(index >= 0 && index < mails.size()) { + mails.set(index, mail); + } + } + + public void filter(MailContextShortName filter) { + if(filter == null || !StringHelper.containsNonWhitespace(filter.getBusinessPath())) { + filteredMails = null; + } else { + filteredMails = new ArrayList<DBMail>(); + for(DBMail mail:mails) { + if(filter.getBusinessPath().equals(mail.getContext().getBusinessPath())) { + filteredMails.add(mail); + } + } + } + } + + @Override + public Object createCopyWithEmptyList() { + return new MailDataModel(Collections.<DBMail>emptyList(), bpToContexts, identity, translator, formatter, outbox); + } + + public enum Columns { + read("mail.read.header"), + marked("mail.marked.header"), + context("mail.context"), + subject("mail.subject"), + sendDate("mail.sendDate"), + receivedDate("mail.receivedDate"), + from("mail.from"), + recipients("mail.recipients"); + + + private final String i18nKey; + + private Columns(String i18nKey) { + this.i18nKey = i18nKey; + } + + public String i18nKey() { + return i18nKey; + } + } + + public class ContextPair { + private final String name; + private final String businessPath; + + public ContextPair(String name, String businessPath) { + this.name = name; + this.businessPath = businessPath; + } + + public String getName() { + return name; + } + public String getBusinessPath() { + return businessPath; + } + } +} diff --git a/src/main/java/org/olat/core/util/mail/ui/MailFromCellRenderer.java b/src/main/java/org/olat/core/util/mail/ui/MailFromCellRenderer.java new file mode 100644 index 00000000000..e11ac751672 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/MailFromCellRenderer.java @@ -0,0 +1,82 @@ +/** + * 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) frentix GmbH<br> + * http://www.frentix.com<br> + * <p> + */ +package org.olat.core.util.mail.ui; + +import java.util.Locale; +import java.util.UUID; + +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.table.CustomCellRenderer; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.render.RenderResult; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; +import org.olat.core.id.Identity; +import org.olat.core.id.User; +import org.olat.core.id.UserConstants; + +/** + * + * Description:<br> + * Render the from with link to visit card or group name or email + * + * <P> + * Initial Date: 7 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailFromCellRenderer implements CustomCellRenderer { + + private final Translator translator; + private VelocityContainer container; + private final Controller listeningController; + + public MailFromCellRenderer(Controller listeningController, VelocityContainer container, Translator translator) { + this.listeningController = listeningController; + this.container = container; + this.translator = translator; + } + + @Override + public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) { + if(val instanceof Identity) { + Identity identity = (Identity)val; + User user = identity.getUser(); + String fullName = user.getProperty(UserConstants.LASTNAME, null) + " " + user.getProperty(UserConstants.FIRSTNAME, null); + + if(renderer == null) { + sb.append(fullName); + } else { + Link link = LinkFactory.createLink("bp_" + UUID.randomUUID().toString(), container, listeningController); + link.setCustomDisplayText(fullName); + link.setUserObject("[Identity:" + identity.getKey() + "]"); + URLBuilder ubu = renderer.getUrlBuilder().createCopyFor(link); + RenderResult renderResult = new RenderResult(); + link.getHTMLRendererSingleton().render(renderer, sb, link, ubu, translator, renderResult, null); + } + } else if (val instanceof String) { + sb.append("<span>").append((String)val).append("</span>"); + } + } +} diff --git a/src/main/java/org/olat/core/util/mail/ui/MailListController.java b/src/main/java/org/olat/core/util/mail/ui/MailListController.java new file mode 100644 index 00000000000..7965d84bab5 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/MailListController.java @@ -0,0 +1,447 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ + +package org.olat.core.util.mail.ui; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.olat.core.gui.ShortName; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.table.ColumnDescriptor; +import org.olat.core.gui.components.table.CustomCellRenderer; +import org.olat.core.gui.components.table.CustomRenderColumnDescriptor; +import org.olat.core.gui.components.table.DefaultColumnDescriptor; +import org.olat.core.gui.components.table.StaticColumnDescriptor; +import org.olat.core.gui.components.table.Table; +import org.olat.core.gui.components.table.TableController; +import org.olat.core.gui.components.table.TableEvent; +import org.olat.core.gui.components.table.TableGuiConfiguration; +import org.olat.core.gui.components.table.TableMultiSelectEvent; +import org.olat.core.gui.components.velocity.VelocityContainer; +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.control.controller.BasicController; +import org.olat.core.gui.control.generic.dtabs.Activateable; +import org.olat.core.gui.control.generic.dtabs.Activateable2; +import org.olat.core.gui.control.generic.modal.DialogBoxController; +import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.id.OLATResourceable; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; +import org.olat.core.util.mail.MailHelper; +import org.olat.core.util.mail.MailModule; +import org.olat.core.util.mail.MailerResult; +import org.olat.core.util.mail.manager.MailManager; +import org.olat.core.util.mail.model.DBMail; +import org.olat.core.util.mail.model.DBMailImpl; +import org.olat.core.util.mail.model.DBMailRecipient; +import org.olat.core.util.mail.ui.MailDataModel.Columns; +import org.olat.core.util.resource.OresHelper; + + +/** + * + * Description:<br> + * Represent a list of mails. + * + * <P> + * Initial Date: 24 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailListController extends BasicController implements Activateable, Activateable2 { + + private static final String CMD_READ_TOGGLE = "creadt"; + private static final String CMD_READ = "cread"; + private static final String CMD_DELETE = "cdelselected"; + private static final String CMD_MARK_TOGGLE = "cmark"; + private static final String CMD_PROFILE = "cprofile"; + private static final String CMD_SEND_REAL_MAIL = "cfwd"; + private static final String CMD_MARK_READ = "creadselected"; + private static final String CMD_MARK_UNREAD = "cunreadselected"; + private static final String CMD_MARK_MARKED = "cmarkselected"; + private static final String CMD_MARK_UNMARKED = "cunmarkselected"; + private static final String MAIN_CMP = "mainCmp"; + + private Link backLink; + private final VelocityContainer mainVC; + private MailController mailCtr; + private MailListController metaMailCtr; + private final TableController tableCtr; + private final VelocityContainer tableVC; + private DialogBoxController deleteConfirmationBox; + + + private final boolean outbox; + private final String metaId; + private final MailManager mailManager; + private final MailContextResolver contextResolver; + + public MailListController(UserRequest ureq, WindowControl wControl, boolean outbox, MailContextResolver resolver) { + this(ureq, wControl, null, outbox, resolver); + } + + private MailListController(UserRequest ureq, WindowControl wControl, String metaId, boolean outbox, MailContextResolver resolver) { + super(ureq, wControl); + setBasePackage(MailModule.class); + this.outbox = outbox; + this.metaId = metaId; + this.contextResolver = resolver; + + mailManager = MailManager.getInstance(); + + TableGuiConfiguration tableConfig = new TableGuiConfiguration(); + tableConfig.setDownloadOffered(true); + tableConfig.setPreferencesOffered(true, "MailBox"); + tableConfig.setTableEmptyMessage(translate("mail.empty.box")); + tableConfig.setMultiSelect(true); + + mainVC = createVelocityContainer("mails"); + tableVC = createVelocityContainer("mailsTable"); + + String context = translate("mail.context"); + tableCtr = new TableController(tableConfig, ureq, wControl, Collections.<ShortName>emptyList(), null, context , null, false, getTranslator()); + + //only for outbox + if(outbox) { + //context / recipients / subject / sendDate + tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Columns.context.i18nKey(), Columns.context.ordinal(), null, + getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new MailContextCellRenderer(this, tableVC, getTranslator()))); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Columns.recipients.i18nKey(), Columns.recipients.ordinal(), null, getLocale())); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Columns.subject.i18nKey(), Columns.subject.ordinal(), CMD_READ, getLocale())); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Columns.sendDate.i18nKey(), Columns.sendDate.ordinal(), null, getLocale())); + } else { + //read / marked / context / from / subject / receivedDate + CustomCellRenderer readRenderer = new BooleanCSSCellRenderer(getTranslator(), "b_mail_read", "b_mail_unread", "mail.read", "mail.unread"); + tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Columns.read.i18nKey(), Columns.read.ordinal(), CMD_READ_TOGGLE, + getLocale(), ColumnDescriptor.ALIGNMENT_CENTER, readRenderer)); + CustomCellRenderer markRenderer = new BooleanCSSCellRenderer(getTranslator(), "b_mail_marked", "b_mail_unmarked", "mail.marked", "mail.unmarked"); + tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Columns.marked.i18nKey(), Columns.marked.ordinal(), CMD_MARK_TOGGLE, + getLocale(), ColumnDescriptor.ALIGNMENT_CENTER, markRenderer)); + tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Columns.context.i18nKey(), Columns.context.ordinal(), null, + getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new MailContextCellRenderer(this, tableVC, getTranslator()))); + tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Columns.from.i18nKey(), Columns.from.ordinal(), null, + getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new MailFromCellRenderer(this, tableVC, getTranslator()))); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Columns.subject.i18nKey(), Columns.subject.ordinal(), CMD_READ, getLocale())); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Columns.receivedDate.i18nKey(), Columns.receivedDate.ordinal(), null, getLocale())); + } + + tableCtr.addColumnDescriptor(new StaticColumnDescriptor(CMD_READ, "mail.action.open", translate("mail.action.open"))); + + // only for inbox + if (!outbox) { + tableCtr.addMultiSelectAction("mail.action.read", CMD_MARK_READ); + tableCtr.addMultiSelectAction("mail.action.unread", CMD_MARK_UNREAD); + tableCtr.addMultiSelectAction("mail.action.mark", CMD_MARK_MARKED); + tableCtr.addMultiSelectAction("mail.action.unmark", CMD_MARK_UNMARKED); + } + tableCtr.addMultiSelectAction("mail.action.send.real", CMD_SEND_REAL_MAIL); + tableCtr.addMultiSelectAction("delete", CMD_DELETE); + + reloadModel(); + + int dateSort = outbox ? 4 : 6; + tableCtr.setSortColumn(dateSort, false); + + listenTo(tableCtr); + + tableVC.put("tableCmp", tableCtr.getInitialComponent()); + if(outbox) { + if(StringHelper.containsNonWhitespace(metaId)) { + tableVC.contextPut("title", translate("mail.outbox.title")); + tableVC.contextPut("description", translate("mail.outbox.meta")); + + } else { + tableVC.contextPut("title", translate("mail.outbox.title")); + } + } else { + tableVC.contextPut("title", translate("mail.inbox.title")); + } + + mainVC.put(MAIN_CMP, tableVC); + if(StringHelper.containsNonWhitespace(metaId)) { + backLink = LinkFactory.createLinkBack(mainVC, this); + mainVC.put("back", backLink); + } + + putInitialPanel(mainVC); + } + + private void replaceInModel(DBMail mail) { + MailDataModel dataModel = (MailDataModel)tableCtr.getTableDataModel(); + dataModel.replace(mail); + tableCtr.modelChanged(); + } + + private void reloadModel() { + List<DBMail> mails; + if(outbox) { + if(StringHelper.containsNonWhitespace(metaId)) { + mails = MailManager.getInstance().getEmailsByMetaId(metaId); + } else { + mails = MailManager.getInstance().getOutbox(getIdentity(), 0, 0); + } + + //strip meta emails + Set<String> metaIds = new HashSet<String>(); + for(Iterator<DBMail> it=mails.iterator(); it.hasNext(); ) { + DBMail mail = it.next(); + if(StringHelper.containsNonWhitespace(mail.getMetaId())) { + if(metaIds.contains(mail.getMetaId())) { + it.remove(); + } else { + metaIds.add(mail.getMetaId()); + } + } + } + } else { + mails = MailManager.getInstance().getInbox(getIdentity(), null, Boolean.TRUE, null, 0, 0); + } + + //extract contexts + Map<String, String> bpToContexts = new HashMap<String, String>(); + for(DBMail mail:mails) { + String businessPath = mail.getContext().getBusinessPath(); + if(StringHelper.containsNonWhitespace(businessPath) && !bpToContexts.containsKey(businessPath)) { + String contextName = contextResolver.getName(businessPath, getLocale()); + if(StringHelper.containsNonWhitespace(contextName)) { + bpToContexts.put(businessPath, contextName); + } + } + } + + if(!bpToContexts.isEmpty()) { + List<ShortName> filters = new ArrayList<ShortName>(); + ShortName allContextFilter = new MailContextShortName("-"); + filters.add(allContextFilter); + for(Map.Entry<String, String> entry:bpToContexts.entrySet()) { + String businessPath = entry.getKey(); + String contextName = entry.getValue(); + filters.add(new MailContextShortName(contextName, businessPath)); + } + tableCtr.setFilters(filters, allContextFilter); + } + + Formatter formatter = Formatter.getInstance(getLocale()); + MailDataModel dataModel = new MailDataModel(mails, bpToContexts, getIdentity(), getTranslator(), formatter, outbox); + tableCtr.setTableDataModel(dataModel); + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + if(source == backLink) { + if(mailCtr != null) { + backFromMail(); + } else { + fireEvent(ureq, event); + } + } else if (source instanceof Link && source.getComponentName().startsWith("bp_")) { + String businessPath = (String)((Link)source).getUserObject(); + if(StringHelper.containsNonWhitespace(businessPath)) { + contextResolver.open(ureq, getWindowControl(), businessPath); + } + } + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(source == tableCtr) { + if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) { + TableEvent te = (TableEvent) event; + String actionid = te.getActionId(); + int rowid = te.getRowId(); + DBMail mail = (DBMail)tableCtr.getTableDataModel().getObject(rowid); + if(CMD_READ.equals(actionid)) { + if(outbox && StringHelper.containsNonWhitespace(mail.getMetaId()) && !mail.getMetaId().equals(metaId)) { + selectMetaMail(ureq, mail.getMetaId()); + } else { + selectMail(ureq, mail.getKey()); + } + } else if (CMD_PROFILE.equals(actionid)) { + DBMailRecipient from = mail.getFrom(); + if(from != null&& from.getRecipient() != null) { + contextResolver.open(ureq, getWindowControl(), "[Identity:" + from.getRecipient().getKey() + "]"); + } + } else if (CMD_MARK_TOGGLE.equals(actionid)) { + mail = mailManager.toggleMarked(mail, getIdentity()); + replaceInModel(mail); + } else if (CMD_READ_TOGGLE.equals(actionid)) { + mail = mailManager.toggleRead(mail, getIdentity()); + replaceInModel(mail); + } + } else if (event.getCommand().equals(Table.COMMAND_MULTISELECT)) { + // Multiselect events + TableMultiSelectEvent tmse = (TableMultiSelectEvent) event; + BitSet selectedMails = tmse.getSelection(); + if(selectedMails.isEmpty()){ + tableVC.setDirty(true); + showWarning("mail.action.emtpy"); + return; + } + String actionid = tmse.getAction(); + if (CMD_DELETE.equals(actionid)) { + String title = translate("mail.confirm.delete.title"); + int selected = selectedMails.cardinality(); + String text; + if (selected == 1) { + text = translate("mail.confirm.delete.single.text"); + } else { + text = translate("mail.confirm.delete.multi.text", selected + ""); + } + deleteConfirmationBox = activateYesNoDialog(ureq, title, text, deleteConfirmationBox); + deleteConfirmationBox.setUserObject(selectedMails); + } else if (CMD_SEND_REAL_MAIL.equals(actionid)) { + for (int i=selectedMails.nextSetBit(0); i >= 0; i=selectedMails.nextSetBit(i+1)) { + DBMail mail = (DBMail) tableCtr.getTableDataModel().getObject(i); + MailerResult result = forwardToMyRealMail(mail); + if(result.getReturnCode() != MailerResult.OK) { + MailHelper.printErrorsAndWarnings(result, getWindowControl(), getLocale()); + } else { + this.showInfo("mail.action.send.real.success", mail.getSubject()); + } + } + reloadModel(); + } else if (CMD_MARK_MARKED.equals(actionid) || CMD_MARK_UNMARKED.equals(actionid)) { + for (int i=selectedMails.nextSetBit(0); i >= 0; i=selectedMails.nextSetBit(i+1)) { + DBMailImpl mail = (DBMailImpl) tableCtr.getTableDataModel().getObject(i); + mailManager.setMarked(mail, CMD_MARK_MARKED.equals(actionid), getIdentity()); + } + reloadModel(); + } else if (CMD_MARK_READ.equals(actionid) || CMD_MARK_UNREAD.equals(actionid)) { + for (int i=selectedMails.nextSetBit(0); i >= 0; i=selectedMails.nextSetBit(i+1)) { + DBMailImpl mail = (DBMailImpl) tableCtr.getTableDataModel().getObject(i); + mailManager.setRead(mail, CMD_MARK_READ.equals(actionid), getIdentity()); + } + reloadModel(); + } + + } else if (TableController.EVENT_FILTER_SELECTED == event) { + MailDataModel dataModel = (MailDataModel)tableCtr.getTableDataModel(); + MailContextShortName filter = (MailContextShortName)tableCtr.getActiveFilter(); + dataModel.filter(filter); + } else if (TableController.EVENT_NOFILTER_SELECTED == event) { + MailDataModel dataModel = (MailDataModel)tableCtr.getTableDataModel(); + dataModel.filter(null); + } + + } else if (source == mailCtr) { + backFromMail(); + + } else if (source == metaMailCtr) { + removeAsListenerAndDispose(metaMailCtr); + metaMailCtr = null; + mainVC.put(MAIN_CMP, tableVC); + + } else if (source == deleteConfirmationBox) { + if(DialogBoxUIFactory.isYesEvent(event)) { + BitSet deleteMails = (BitSet)deleteConfirmationBox.getUserObject(); + for (int i=deleteMails.nextSetBit(0); i >= 0; i=deleteMails.nextSetBit(i+1)) { + DBMailImpl mail = (DBMailImpl) tableCtr.getTableDataModel().getObject(i); + boolean deleteMetaMail = outbox && !StringHelper.containsNonWhitespace(metaId); + mailManager.delete(mail, getIdentity(), deleteMetaMail); + // Do not remove from model to prevent concurrent modification + // exception, instead just reload model afterwards + } + reloadModel(); + } + } else { + super.event(ureq, source, event); + } + } + + @Override + protected void doDispose() { + // + } + + @Override + public void activate(UserRequest ureq, String viewIdentifier) { + if(!StringHelper.containsNonWhitespace(viewIdentifier) || "0".equals(viewIdentifier)) return; + + try { + Long mailKey = Long.parseLong(viewIdentifier); + selectMail(ureq, mailKey); + } catch(NumberFormatException e) { + //not a key + logWarn("Cannot activate with this identifier: " + viewIdentifier, e); + } + } + + + + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) return; + + ContextEntry entry = entries.get(0); + String type = entry.getOLATResourceable().getResourceableTypeName(); + if(DBMail.class.getSimpleName().equals(type)) { + selectMail(ureq, entry.getOLATResourceable().getResourceableId()); + } + } + + private void backFromMail() { + removeAsListenerAndDispose(mailCtr); + mailCtr = null; + mainVC.put(MAIN_CMP, tableVC); + } + + private MailerResult forwardToMyRealMail(DBMail mail) { + return mailManager.forwardToRealInbox(getIdentity(), mail, null); + } + + private void selectMetaMail(UserRequest ureq, String metaID) { + metaMailCtr = new MailListController(ureq, getWindowControl(), metaID, outbox, contextResolver); + listenTo(metaMailCtr); + mainVC.put(MAIN_CMP, metaMailCtr.getInitialComponent()); + } + + private void selectMail(UserRequest ureq, Long mailKey) { + DBMail mail = mailManager.getMessageByKey(mailKey); + selectMail(ureq, mail); + } + + private void selectMail(UserRequest ureq, DBMail mail) { + removeAsListenerAndDispose(mailCtr); + boolean back = !StringHelper.containsNonWhitespace(mail.getMetaId()) || !outbox; + OLATResourceable ores = OresHelper.createOLATResourceableInstance(DBMail.class, mail.getKey()); + WindowControl bwControl = addToHistory(ureq, ores, null); + mailCtr = new MailController(ureq, bwControl, mail, back); + listenTo(mailCtr); + mainVC.put(MAIN_CMP, mailCtr.getInitialComponent()); + + if(mailManager.setRead(mail, Boolean.TRUE, getIdentity())) { + reloadModel(); + } + } +} diff --git a/src/main/java/org/olat/core/util/mail/ui/MailTreeNode.java b/src/main/java/org/olat/core/util/mail/ui/MailTreeNode.java new file mode 100644 index 00000000000..e86022c23d5 --- /dev/null +++ b/src/main/java/org/olat/core/util/mail/ui/MailTreeNode.java @@ -0,0 +1,57 @@ +/** +* 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) 2008 frentix GmbH, Switzerland<br> +* <p> +*/ +package org.olat.core.util.mail.ui; + +import org.olat.core.gui.components.tree.GenericTreeNode; +import org.olat.core.id.Identity; +import org.olat.core.util.mail.manager.MailManager; + +/** + * + * Description:<br> + * overwrites <code>getIconDecorator1CssClass()</code> to display a special icon + * if the user has unread mails in his inbox. + * + * <P> + * Initial Date: 24 mars 2011 <br> + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * @author strentini, sergio.trentini@frentix.com + * + */ +public class MailTreeNode extends GenericTreeNode { + + private static final long serialVersionUID = -2579792704194953641L; + + private final Identity identity; + + public MailTreeNode(Identity identity) { + this.identity = identity; + } + + + @Override + public String getIconDecorator1CssClass() { + if(MailManager.getInstance().hasNewMail(identity)) { + return "b_mail_new"; + } + return null; + } +} diff --git a/src/main/java/org/olat/core/util/notifications/ContextualSubscriptionController.java b/src/main/java/org/olat/core/util/notifications/ContextualSubscriptionController.java index 0d16e43596d..30e3d076ec2 100644 --- a/src/main/java/org/olat/core/util/notifications/ContextualSubscriptionController.java +++ b/src/main/java/org/olat/core/util/notifications/ContextualSubscriptionController.java @@ -61,7 +61,7 @@ public class ContextualSubscriptionController extends BasicController { myContent = createVelocityContainer("consubs"); if (subscriptionContext == null) { - setInitialComponent(new Panel("empty:nosubscription")); + putInitialPanel(new Panel("empty:nosubscription")); return; } diff --git a/src/main/java/org/olat/core/util/notifications/NotificationsManager.java b/src/main/java/org/olat/core/util/notifications/NotificationsManager.java index 377a7b624aa..3cac0e943e4 100644 --- a/src/main/java/org/olat/core/util/notifications/NotificationsManager.java +++ b/src/main/java/org/olat/core/util/notifications/NotificationsManager.java @@ -232,6 +232,16 @@ public abstract class NotificationsManager extends BasicManager { */ public abstract SubscriptionItem createSubscriptionItem(Subscriber subscriber, Locale locale, String mimeTypeTitle, String mimeTypeContent, Date lowerDateBoundary); + /** + * Create a subscription item from info without reloading all the subscription + * @param subsInfo + * @param subscriber + * @param locale + * @param mimeTypeTitle + * @param mimeTypeContent + * @return + */ + public abstract SubscriptionItem createSubscriptionItem(SubscriptionInfo subsInfo, Subscriber subscriber, Locale locale, String mimeTypeTitle, String mimeTypeContent); public abstract SubscriptionInfo getNoSubscriptionInfo(); diff --git a/src/main/java/org/olat/core/util/notifications/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/util/notifications/_i18n/LocalStrings_de.properties index 6fdf1b08298..1a1ee8c8915 100644 --- a/src/main/java/org/olat/core/util/notifications/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/util/notifications/_i18n/LocalStrings_de.properties @@ -1,7 +1,7 @@ #Mon Mar 02 09:54:04 CET 2009 actions.title=\u00C4nderungen chelp.del=<i>$org.olat.notifications\:subs.deleted</i> -chelp.home=<i>$org.olat.home\:menu.root</i> +chelp.home=<i>$org.olat.home\:main.menu.title.title</i> chelp.home-notifications.title=Abonnements und Benachrichtigungen chelp.notif=<i>$org.olat.home\:menu.notifications</i> chelp.notif1=OLAT bietet Ihnen die M\u00F6glichkeit, \u00FCber \u00C4nderungen in abonnierbaren Objekten informiert zu werden. diff --git a/src/main/java/org/olat/core/util/notifications/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/util/notifications/_i18n/LocalStrings_en.properties index 07a434df246..0395615b800 100644 --- a/src/main/java/org/olat/core/util/notifications/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/util/notifications/_i18n/LocalStrings_en.properties @@ -1,7 +1,7 @@ #Fri Jan 21 10:25:59 CET 2011 actions.title=Modifications chelp.del=<i>$org.olat.notifications\:subs.deleted</i> -chelp.home=<i>$org.olat.home\:menu.root</i> +chelp.home=<i>$org.olat.home\:main.menu.title.title</i> chelp.home-notifications.title=Subscriptions and notifications chelp.notif=<i>$org.olat.home\:menu.notifications</i> chelp.notif1=OLAT can assist you in getting information on modifications regarding subscribed objects. diff --git a/src/main/java/org/olat/core/util/notifications/items/SubscriptionListItem.java b/src/main/java/org/olat/core/util/notifications/items/SubscriptionListItem.java index 013c8afa106..e73df7e8633 100644 --- a/src/main/java/org/olat/core/util/notifications/items/SubscriptionListItem.java +++ b/src/main/java/org/olat/core/util/notifications/items/SubscriptionListItem.java @@ -68,15 +68,15 @@ public class SubscriptionListItem { public String getDescription() { return description; } - - public String getIconCssClass() { - return iconCssClass; - } public String getDescriptionTooltip() { return descriptionTooltip; } + public String getIconCssClass() { + return iconCssClass; + } + /** * compose list item representation depending on mimeType * @param mimeType @@ -121,7 +121,9 @@ public class SubscriptionListItem { sb.append(link); sb.append("\">"); } - sb.append(description.trim()); + if (StringHelper.containsNonWhitespace(description)) { + sb.append(description.trim()); + } if (StringHelper.containsNonWhitespace(link)) sb.append("</a>"); sb.append(" ").append(datePart.trim()); sb.append("</li>"); diff --git a/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java b/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java index 245552a20a0..2b9e4b5a4de 100644 --- a/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java +++ b/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java @@ -36,6 +36,8 @@ import org.olat.core.logging.Tracing; import org.olat.core.manager.BasicManager; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.coordinate.SyncerExecutor; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; @@ -166,7 +168,9 @@ public class EnrollmentManager extends BasicManager { // 3. Send notification mail MailTemplate mailTemplate = BGMailHelper.createRemoveMyselfMailTemplate(enrolledGroup, identity); MailerWithTemplate mailer = MailerWithTemplate.getInstance(); - MailerResult mailerResult = mailer.sendMail(identity, null, null, mailTemplate, null); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString()); + MailerResult mailerResult = mailer.sendMail(context, identity, null, null, mailTemplate, null); MailHelper.printErrorsAndWarnings(mailerResult, wControl, trans.getLocale()); } @@ -189,7 +193,9 @@ public class EnrollmentManager extends BasicManager { // 3. Send notification mail MailTemplate mailTemplate = BGMailHelper.createRemoveWaitinglistMailTemplate(enrolledWaitingListGroup, identity); MailerWithTemplate mailer = MailerWithTemplate.getInstance(); - MailerResult mailerResult = mailer.sendMail(identity, null, null, mailTemplate, null); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString()); + MailerResult mailerResult = mailer.sendMail(context, identity, null, null, mailTemplate, null); MailHelper.printErrorsAndWarnings(mailerResult, wControl, trans.getLocale()); } @@ -332,7 +338,9 @@ public class EnrollmentManager extends BasicManager { // 4. Send notification mail MailTemplate mailTemplate = BGMailHelper.createAddMyselfMailTemplate(group, identity); MailerWithTemplate mailer = MailerWithTemplate.getInstance(); - MailerResult mailerResult = mailer.sendMail(identity, null, null, mailTemplate, null); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString()); + MailerResult mailerResult = mailer.sendMail(context, identity, null, null, mailTemplate, null); MailHelper.printErrorsAndWarnings(mailerResult, wControl, trans.getLocale()); @@ -368,7 +376,9 @@ public class EnrollmentManager extends BasicManager { // 4. Send notification mail MailTemplate mailTemplate = BGMailHelper.createAddWaitinglistMailTemplate(group, identity); MailerWithTemplate mailer = MailerWithTemplate.getInstance(); - MailerResult mailerResult = mailer.sendMail(identity, null, null, mailTemplate, null); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString()); + MailerResult mailerResult = mailer.sendMail(context, identity, null, null, mailTemplate, null); MailHelper.printErrorsAndWarnings(mailerResult, wControl, trans.getLocale()); return true; diff --git a/src/main/java/org/olat/course/nodes/info/SendMailFormatterForCourse.java b/src/main/java/org/olat/course/nodes/info/SendMailFormatterForCourse.java index 537dc8c7dc5..9937865906f 100644 --- a/src/main/java/org/olat/course/nodes/info/SendMailFormatterForCourse.java +++ b/src/main/java/org/olat/course/nodes/info/SendMailFormatterForCourse.java @@ -54,6 +54,12 @@ public class SendMailFormatterForCourse implements MailFormatter { this.translator = translator; this.businessPath = businessPath; } + + @Override + //fxdiff VCRP-16: intern mail system + public String getBusinessPath() { + return businessPath; + } @Override public String getSubject(InfoMessage msg) { diff --git a/src/main/java/org/olat/course/nodes/info/_chelp/ced-info-config.html b/src/main/java/org/olat/course/nodes/info/_chelp/ced-info-config.html index a7ccf06a05a..e591d81326c 100644 --- a/src/main/java/org/olat/course/nodes/info/_chelp/ced-info-config.html +++ b/src/main/java/org/olat/course/nodes/info/_chelp/ced-info-config.html @@ -1,4 +1,4 @@ -<br/>$r.translate("chelp.ced-info-config1") +<br/>$r.translate("chelp.ced-info-config1") $r.translate("chelp.ced-info-config2") <br/><br/> <b>$r.translate("chelp.ced-info-config2.label"):</b> $r.translate("chelp.ced-info-config2")<br/> <b>$r.translate("chelp.ced-info-config3.label"):</b> $r.translate("chelp.ced-info-config3") \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/iq/IQEditReplaceWizard.java b/src/main/java/org/olat/course/nodes/iq/IQEditReplaceWizard.java index 355359c66b3..4d3b6bf4494 100644 --- a/src/main/java/org/olat/course/nodes/iq/IQEditReplaceWizard.java +++ b/src/main/java/org/olat/course/nodes/iq/IQEditReplaceWizard.java @@ -32,6 +32,8 @@ import org.olat.core.gui.control.generic.wizard.WizardController; import org.olat.core.helpers.Settings; import org.olat.core.id.Identity; import org.olat.core.logging.OLATRuntimeException; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailNotificationEditController; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerWithTemplate; @@ -136,7 +138,9 @@ public class IQEditReplaceWizard extends WizardController { recipientsCC = new ArrayList<Identity>(); recipientsCC.add(ureq.getIdentity()); } - MailerWithTemplate.getInstance().sendMailAsSeparateMails(learners, recipientsCC, null, mailCtr.getMailTemplate(), ureq.getIdentity()); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); + MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, learners, recipientsCC, null, mailCtr.getMailTemplate(), ureq.getIdentity()); } fireEvent(ureq, Event.DONE_EVENT); } else if (source == searchCtr && event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) { diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectGroupController.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectGroupController.java index ed3d8e66218..6035a1949bd 100644 --- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectGroupController.java +++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectGroupController.java @@ -38,6 +38,8 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.id.Identity; import org.olat.core.logging.activity.ActionType; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; @@ -159,7 +161,9 @@ public class ProjectGroupController extends BasicController { } else { ccIdentities = null; } - MailerResult mailerResult = mailer.sendMailAsSeparateMails(identitiesMoveEvent.getMovedIdentities(), ccIdentities, null, mailTemplate, null); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); + MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, identitiesMoveEvent.getMovedIdentities(), ccIdentities, null, mailTemplate, null); MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), urequest.getLocale()); } fireEvent(urequest, Event.CHANGED_EVENT ); diff --git a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerMailerImpl.java b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerMailerImpl.java index 5f4e0510c5d..dd45fb0c348 100644 --- a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerMailerImpl.java +++ b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerMailerImpl.java @@ -35,6 +35,8 @@ import org.olat.core.id.UserConstants; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.Formatter; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; import org.olat.core.util.mail.MailerWithTemplate; @@ -176,7 +178,9 @@ public class ProjectBrokerMailerImpl implements ProjectBrokerMailer { // als Workaround wurde die Methode sendMailAsSeparateMails verwendet List<Identity> enrolledIdentityList = new ArrayList<Identity>(); enrolledIdentityList.add(enrolledIdentity); - MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(enrolledIdentityList, null, null, enrolledMailTemplate, null); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(project.getProjectBroker(), null, null); + MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, enrolledIdentityList, null, null, enrolledMailTemplate, null); log.audit("ProjectBroker: sendEmail to identity.name=" + enrolledIdentity.getName() + " , mailerResult.returnCode=" + mailerResult.getReturnCode()); return mailerResult; } @@ -190,7 +194,9 @@ public class ProjectBrokerMailerImpl implements ProjectBrokerMailer { if (identityNames.length()>0) identityNames.append(","); identityNames.append(identity.getName()); } - MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(projectManagerList, null, null, enrolledMailTemplate, null); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(project.getProjectBroker(), null, null); + MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, projectManagerList, null, null, enrolledMailTemplate, null); log.audit("ProjectBroker: sendEmailToGroup: identities=" + identityNames.toString() + " , mailerResult.returnCode=" + mailerResult.getReturnCode()); return mailerResult; } @@ -204,7 +210,9 @@ public class ProjectBrokerMailerImpl implements ProjectBrokerMailer { if (identityNames.length()>0) identityNames.append(","); identityNames.append(identity.getName()); } - MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(projectManagerList, null, null, enrolledMailTemplate, null); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(project.getProjectBroker(), null, null); + MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, projectManagerList, null, null, enrolledMailTemplate, null); log.audit("ProjectBroker: sendEmailToGroup: identities=" + identityNames.toString() + " , mailerResult.returnCode=" + mailerResult.getReturnCode()); return mailerResult; } diff --git a/src/main/java/org/olat/course/nodes/ta/DropboxController.java b/src/main/java/org/olat/course/nodes/ta/DropboxController.java index 36deb9ab490..bc358ed2d00 100644 --- a/src/main/java/org/olat/course/nodes/ta/DropboxController.java +++ b/src/main/java/org/olat/course/nodes/ta/DropboxController.java @@ -54,6 +54,8 @@ import org.olat.core.id.Identity; import org.olat.core.id.UserConstants; import org.olat.core.util.FileUtils; import org.olat.core.util.Formatter; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; @@ -275,7 +277,9 @@ public class DropboxController extends BasicController { } }; - MailerResult result = MailerWithTemplate.getInstance().sendMail(ureq.getIdentity(), null, null, mailTempl, null); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); + MailerResult result = MailerWithTemplate.getInstance().sendMail(context, ureq.getIdentity(), null, null, mailTempl, null); if(result.getFailedIdentites().size() > 0) { List<Identity> disabledIdentities = new ArrayList<Identity>(); disabledIdentities = result.getFailedIdentites(); diff --git a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java index 836eb90de27..f2654e1e246 100644 --- a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java +++ b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java @@ -54,6 +54,8 @@ import org.olat.core.id.UserConstants; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.i18n.I18nManager; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; import org.olat.core.util.mail.MailerWithTemplate; @@ -284,8 +286,9 @@ public class DropboxScoringViewController extends BasicController { // nothing to do } }; - - MailerResult result = MailerWithTemplate.getInstance().sendMail(student, null, null, mailTempl, null); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); + MailerResult result = MailerWithTemplate.getInstance().sendMail(context, student, null, null, mailTempl, null); if(result.getReturnCode() > 0) { am.appendToUserNodeLog(node, coach, student, "MAIL SEND FAILED TO:" + toMail + "; MailReturnCode: " + result.getReturnCode()); diff --git a/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java b/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java index 90aa425880e..12aa166a88f 100644 --- a/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java +++ b/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java @@ -54,6 +54,8 @@ import org.olat.core.id.UserConstants; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.Util; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailNotificationEditController; import org.olat.core.util.mail.MailTemplate; @@ -533,7 +535,9 @@ public class TACourseNodeEditController extends ActivateableTabbableDefaultContr } else { ccIdentities = null; } - MailerResult mailerResult = mailer.sendMailAsSeparateMails(recipients, ccIdentities, null, mailTemplate, sender); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); + MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, recipients, ccIdentities, null, mailTemplate, sender); MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale()); } } diff --git a/src/main/java/org/olat/group/BusinessGroupManagerImpl.java b/src/main/java/org/olat/group/BusinessGroupManagerImpl.java index fc126309206..49e8e8f4050 100644 --- a/src/main/java/org/olat/group/BusinessGroupManagerImpl.java +++ b/src/main/java/org/olat/group/BusinessGroupManagerImpl.java @@ -68,6 +68,8 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.coordinate.SyncerCallback; import org.olat.core.util.coordinate.SyncerExecutor; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; @@ -630,9 +632,9 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr MailTemplate mailTemplate = BGMailHelper.createDeleteGroupMailTemplate(businessGroupTodelete, ureq.getIdentity()); if (mailTemplate != null) { //fxdiff VCRP-16: intern mail system - //TODO SR MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString()); - //TODO SR MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, users, null, null, mailTemplate, null); - //TODO SR MailHelper.printErrorsAndWarnings(mailerResult, wControl, ureq.getLocale()); + MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString()); + MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, users, null, null, mailTemplate, null); + MailHelper.printErrorsAndWarnings(mailerResult, wControl, ureq.getLocale()); } } @@ -1643,8 +1645,8 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr if (mailTemplate != null) { MailerWithTemplate mailer = MailerWithTemplate.getInstance(); //fxdiff VCRP-16: intern mail system - //TODO SR MailContext context = new MailContextImpl("[BusinessGroup:" + group.getKey() + "]"); - //TODO SR MailerResult mailerResult = mailer.sendMail(context, firstWaitingListIdentity, null, null, mailTemplate, null); + MailContext context = new MailContextImpl("[BusinessGroup:" + group.getKey() + "]"); + MailerResult mailerResult = mailer.sendMail(context, firstWaitingListIdentity, null, null, mailTemplate, null); // Does not report errors to current screen because this is the identity who triggered the transfer Tracing.logWarn("Could not send WaitinglistTransferMail for identity=" + firstWaitingListIdentity.getName() , BusinessGroupManagerImpl.class); } diff --git a/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java b/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java index 6568683f765..edd4282d3c9 100644 --- a/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java +++ b/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java @@ -64,6 +64,8 @@ import org.olat.core.util.Util; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.coordinate.LockResult; import org.olat.core.util.event.GenericEventListener; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; @@ -363,9 +365,9 @@ public class BusinessGroupEditController extends BasicController implements Cont MailTemplate mailTemplate = identitiesMoveEvent.getMailTemplate(); if (mailTemplate != null) { //fxdiff VCRP-16: intern mail system - //TODO SR MailContext context = new MailContextImpl(currBusinessGroup, null, getWindowControl().getBusinessControl().getAsString()); - //TODO SR MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, identitiesMoveEvent.getMovedIdentities(), null, null, mailTemplate, null); - //TODO SR MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale()); + MailContext context = new MailContextImpl(currBusinessGroup, null, getWindowControl().getBusinessControl().getAsString()); + MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, identitiesMoveEvent.getMovedIdentities(), null, null, mailTemplate, null); + MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale()); } fireEvent(ureq, Event.CHANGED_EVENT ); } diff --git a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties index b23ad9d2396..c5cb3e907a4 100644 --- a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties @@ -1,4 +1,4 @@ -#Sat Jan 22 16:31:11 CET 2011 +#Mon May 16 17:34:39 CEST 2011 areachoice.no.areas.admin=No learning areas found. Please create a learning area within your group management. areachoice.no.areas.owner=No learning areas found. New learning areas can only be created by users who have access to the entire group management. chelp.area1=Provided that learning groups have already been created in the course, these will appear in the tab. @@ -98,6 +98,7 @@ chelp.tools.right6=All members of a $org.olat.group.ui\:RightGroup have the righ chelp.tools.right8=You can put a calendar at the disposal of your $org.olat.group.ui\:RightGroup to record joint events. Furthermore you can determine the calendar's write access, that is, who will have the right to record data. chelp.tools.right9=You can put a Wiki at the disposal of your $org.olat.group.ui\:RightGroup chelp.tools.title=Configuration of collaborative tools +chkBox.open=Publish group in group area for booking chkBox.show.owners=Members can see owners chkBox.show.partips=Members can see participants chkBox.show.waitingList=Members can see waiting list @@ -108,8 +109,10 @@ fieldset.legend.details=Details fieldset.legend.displaymembers=Display members fieldset.legend.groupowners=Owners fieldset.legend.grouppartips=Participants +fieldset.legend.open=Visibility fieldset.legend.rights=Assigned rights fieldset.legend.waitinggroup=Waiting list +group.edit.tab.accesscontrol=Publishing and booking configuration group.edit.tab.areas=Learning areas group.edit.tab.collabtools=Tools group.edit.tab.details=Description diff --git a/src/main/java/org/olat/home/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/home/_i18n/LocalStrings_de.properties index 00e6be2d6f1..a16ad6b3490 100644 --- a/src/main/java/org/olat/home/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/home/_i18n/LocalStrings_de.properties @@ -46,12 +46,16 @@ menu.guestinfo=Informationen menu.guestinfo.alt=Informationen \u00FCber die OLAT-Bedienung menu.guestwelcome=Willkommen menu.guestwelcome.alt=Willkommen bei OLAT +menu.mail=E-Mails +menu.mail.alt=Mailbereich menu.mysettings=Einstellungen menu.mysettings.alt=Meine OLAT-Einstellungen menu.note=Notizen menu.note.alt=Meine Notizen menu.notifications=Abonnements menu.notifications.alt=Meine Abonnements f\u00FCr Benachrichtigungen verwalten +menu.orders=Buchungen +menu.orders.alt=Meine Buchungen menu.otherusers=Andere Benutzer menu.otherusers.alt=Visitenkarte anderer Benutzer menu.portfolio=ePortfolio diff --git a/src/main/java/org/olat/home/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/home/_i18n/LocalStrings_en.properties index bb6c7300888..049e792ff66 100644 --- a/src/main/java/org/olat/home/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/home/_i18n/LocalStrings_en.properties @@ -46,12 +46,16 @@ menu.guestinfo=Information menu.guestinfo.alt=Information on how to use OLAT menu.guestwelcome=Welcome menu.guestwelcome.alt=Welcome to OLAT +menu.mail=E-mails +menu.mail.alt=Mail area menu.mysettings=Settings menu.mysettings.alt=My personal OLAT settings menu.note=Notes menu.note.alt=My notes menu.notifications=Subscriptions menu.notifications.alt=Administer my notifications and subsriptions +menu.orders=Bookings +menu.orders.alt=My bookings menu.otherusers=Other users menu.otherusers.alt=Visiting card of other users menu.portfolio=ePortfolio diff --git a/src/main/java/org/olat/modules/co/ContactForm.java b/src/main/java/org/olat/modules/co/ContactForm.java index 24c7a1bafbe..6c58ac57150 100644 --- a/src/main/java/org/olat/modules/co/ContactForm.java +++ b/src/main/java/org/olat/modules/co/ContactForm.java @@ -196,9 +196,8 @@ class ContactForm extends FormBasicController { /** * @return */ - protected String getEmailFrom() { - String ccMail = emailFrom.getUser().getProperty(UserConstants.EMAIL, null); - return ccMail; + protected Identity getEmailFrom() { + return emailFrom; } /** diff --git a/src/main/java/org/olat/modules/co/ContactFormController.java b/src/main/java/org/olat/modules/co/ContactFormController.java index 7f3f57a7ee5..8ab7b4aa967 100644 --- a/src/main/java/org/olat/modules/co/ContactFormController.java +++ b/src/main/java/org/olat/modules/co/ContactFormController.java @@ -52,6 +52,8 @@ import org.olat.core.util.WebappHelper; import org.olat.core.util.mail.ContactList; import org.olat.core.util.mail.ContactMessage; import org.olat.core.util.mail.Emailer; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailLoggingAction; @@ -207,10 +209,12 @@ public class ContactFormController extends BasicController { // boolean success = false; try { - List<File> attachments = cntctForm.getAttachments(); - success = emailer.sendEmail(cntctForm.getEmailToContactLists(), cntctForm.getSubject(), cntctForm.getBody(), attachments); + List<File> attachments = cntctForm.getAttachments(); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); + success = emailer.sendEmail(context, cntctForm.getEmailToContactLists(), cntctForm.getSubject(), cntctForm.getBody(), attachments); if(cntctForm.isTcpFrom()) { - success = emailer.sendEmailCC(cntctForm.getEmailFrom(), cntctForm.getSubject(), cntctForm.getBody(), attachments); + success = emailer.sendEmailCC(context, cntctForm.getEmailFrom(), cntctForm.getSubject(), cntctForm.getBody(), attachments); } } catch (AddressException e) { //error in recipient email address(es) diff --git a/src/main/java/org/olat/notifications/NotificationNewsController.java b/src/main/java/org/olat/notifications/NotificationNewsController.java index 2374f5a8ae7..758d548d6f2 100644 --- a/src/main/java/org/olat/notifications/NotificationNewsController.java +++ b/src/main/java/org/olat/notifications/NotificationNewsController.java @@ -25,7 +25,6 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.StringTokenizer; @@ -119,7 +118,7 @@ class NotificationNewsController extends BasicController implements Activateable newsVC.contextPut("subs", subs); subsInfoMap = NotificationHelper.getSubscriptionMap(getLocale(), true, compareDate, subs); - NotificationSubscriptionAndNewsFormatter subsFormatter = new NotificationSubscriptionAndNewsFormatter(compareDate, getTranslator(), subsInfoMap); + NotificationSubscriptionAndNewsFormatter subsFormatter = new NotificationSubscriptionAndNewsFormatter(getTranslator(), subsInfoMap); newsVC.contextPut("subsFormatter", subsFormatter); return subs; } diff --git a/src/main/java/org/olat/notifications/NotificationSubscriptionAndNewsFormatter.java b/src/main/java/org/olat/notifications/NotificationSubscriptionAndNewsFormatter.java index 4b9265f8465..9dee854f08d 100644 --- a/src/main/java/org/olat/notifications/NotificationSubscriptionAndNewsFormatter.java +++ b/src/main/java/org/olat/notifications/NotificationSubscriptionAndNewsFormatter.java @@ -20,7 +20,6 @@ */ package org.olat.notifications; -import java.util.Date; import java.util.Map; import org.olat.ControllerFactory; @@ -41,12 +40,11 @@ import org.olat.core.util.notifications.SubscriptionItem; * @author gnaegi */ public class NotificationSubscriptionAndNewsFormatter { - private Date compareDate; + private Translator translator; private Map<Subscriber, SubscriptionInfo> subsInfoMap; - NotificationSubscriptionAndNewsFormatter(Date compareDate, Translator translator, Map<Subscriber, SubscriptionInfo> subsInfoMap) { - this.compareDate = compareDate; + NotificationSubscriptionAndNewsFormatter(Translator translator, Map<Subscriber, SubscriptionInfo> subsInfoMap) { this.translator = translator; this.subsInfoMap = subsInfoMap; } @@ -103,11 +101,9 @@ public class NotificationSubscriptionAndNewsFormatter { } public SubscriptionItem getSubscriptionItem(Subscriber sub) { + SubscriptionInfo subsInfo = subsInfoMap.get(sub); NotificationsManager notiMgr = NotificationsManager.getInstance(); - SubscriptionItem subscrItem = notiMgr.createSubscriptionItem(sub, translator.getLocale(), SubscriptionInfo.MIME_HTML, SubscriptionInfo.MIME_HTML, compareDate); + SubscriptionItem subscrItem = notiMgr.createSubscriptionItem(subsInfo, sub, translator.getLocale(), SubscriptionInfo.MIME_HTML, SubscriptionInfo.MIME_HTML); return subscrItem; } - - - -} +} \ No newline at end of file diff --git a/src/main/java/org/olat/notifications/NotificationsManagerImpl.java b/src/main/java/org/olat/notifications/NotificationsManagerImpl.java index 863e0831b37..7f85dad2f13 100644 --- a/src/main/java/org/olat/notifications/NotificationsManagerImpl.java +++ b/src/main/java/org/olat/notifications/NotificationsManagerImpl.java @@ -484,13 +484,24 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us // nothing to do } }; - - MailerResult result = MailerWithTemplate.getInstance().sendMail(to, null, null, mailTempl, null); - if (result.getReturnCode() > 0) { - log.warn("Could not send email to identity " + to.getName() + ". (returncode="+result.getReturnCode()+", to="+to+")"); + + MailerResult result = null; + try { + // fxdiff VCRP-16: intern mail system + result = MailerWithTemplate.getInstance().sendRealMail(to, mailTempl); + } catch (Exception e) { + // FXOLAT-294 :: sending the mail will throw nullpointer exception if To-Identity has no + // valid email-address!, catch it... + } + if (result == null || result.getReturnCode() > 0) { + if(result!=null) + log.warn("Could not send email to identity " + to.getName() + ". (returncode=" + result.getReturnCode() + ", to=" + to + ")"); + else + log.warn("Could not send email to identity " + to.getName() + ". (returncode = null) , to=" + to + ")"); return false; + } else { + return true; } - return true; } /** @@ -518,6 +529,12 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us private Publisher findOrCreatePublisher(final SubscriptionContext scontext, final PublisherData pdata) { final OLATResourceable ores = OresHelper.createOLATResourceableInstance(scontext.getResName() + "_" + scontext.getSubidentifier(),scontext.getResId()); //o_clusterOK by:cg + //fxdiff VCRP-16:prevent nested doInSync + Publisher pub = getPublisher(scontext.getResName(), scontext.getResId(), scontext.getSubidentifier()); + if(pub != null) { + return pub; + } + Publisher publisher = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(ores, new SyncerCallback<Publisher>(){ public Publisher execute() { Publisher p = getPublisher(scontext.getResName(), scontext.getResId(), scontext.getSubidentifier()); @@ -977,23 +994,13 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us SubscriptionItem si = null; Publisher pub = subscriber.getPublisher(); NotificationsHandler notifHandler = getNotificationsHandler(pub); + if (isLogDebugEnabled()) logDebug("create subscription with handler: " + notifHandler.getClass().getName()); // do not create subscription item when deleted if (isPublisherValid(pub)) { if (isLogDebugEnabled()) logDebug("NotifHandler: " + notifHandler.getClass().getName() + " compareDate: " + latestEmailed.toString() + " now: " + new Date().toString(), null); SubscriptionInfo subsInfo = notifHandler.createSubscriptionInfo(subscriber, locale, latestEmailed); if (subsInfo.hasNews()) { - String title = getFormatedTitle(subsInfo, subscriber, locale, mimeTypeTitle); - - String itemLink = null; - if(subsInfo.getCustomUrl() != null) { - itemLink = subsInfo.getCustomUrl(); - } - if(itemLink == null && pub.getBusinessPath() != null) { - itemLink = NotificationHelper.getURLFromBusinessPathString(pub, pub.getBusinessPath()); - } - - String description = subsInfo.getSpecificInfo(mimeTypeContent, locale); - si = new SubscriptionItem(title, itemLink, description); + si = createSubscriptionItem(subsInfo, subscriber, locale, mimeTypeTitle, mimeTypeContent); } } return si; @@ -1003,6 +1010,23 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us } } + @Override + public SubscriptionItem createSubscriptionItem(SubscriptionInfo subsInfo, Subscriber subscriber, Locale locale, String mimeTypeTitle, String mimeTypeContent) { + Publisher pub = subscriber.getPublisher(); + String title = getFormatedTitle(subsInfo, subscriber, locale, mimeTypeTitle); + + String itemLink = null; + if(subsInfo.getCustomUrl() != null) { + itemLink = subsInfo.getCustomUrl(); + } + if(itemLink == null && pub.getBusinessPath() != null) { + itemLink = NotificationHelper.getURLFromBusinessPathString(pub, pub.getBusinessPath()); + } + + String description = subsInfo.getSpecificInfo(mimeTypeContent, locale); + return new SubscriptionItem(title, itemLink, description); + } + /** * format the type-title and title-details * @param subscriber diff --git a/src/main/java/org/olat/notifications/NotificationsPortletRunController.java b/src/main/java/org/olat/notifications/NotificationsPortletRunController.java index 3640ff3a13a..31b76b6aeec 100644 --- a/src/main/java/org/olat/notifications/NotificationsPortletRunController.java +++ b/src/main/java/org/olat/notifications/NotificationsPortletRunController.java @@ -59,8 +59,6 @@ import org.olat.core.gui.translator.Translator; import org.olat.core.id.OLATResourceable; import org.olat.core.id.context.BusinessControl; import org.olat.core.id.context.BusinessControlFactory; -import org.olat.core.logging.OLog; -import org.olat.core.logging.Tracing; import org.olat.core.util.event.GenericEventListener; import org.olat.core.util.event.PersistsEvent; import org.olat.core.util.notifications.NotificationHelper; @@ -81,7 +79,6 @@ import org.olat.group.BusinessGroupManagerImpl; * @author gnaegi */ public class NotificationsPortletRunController extends AbstractPortletRunController implements GenericEventListener { - private OLog log = Tracing.createLoggerFor(NotificationsPortletRunController.class); private static final String CMD_LAUNCH = "cmd.launch"; @@ -178,32 +175,21 @@ public class NotificationsPortletRunController extends AbstractPortletRunControl */ protected void reloadModel(SortingCriteria sortingCriteria) { if (sortingCriteria.getSortingType() == SortingCriteria.AUTO_SORTING) { - notificationsList = man.getValidSubscribers(identity); - // calc subscriptioninfo for all subscriptions and, if only those with news are to be shown, remove the other ones - for (Iterator<Subscriber> it_subs = notificationsList.iterator(); it_subs.hasNext();) { - Subscriber subscriber = it_subs.next(); - Publisher pub = subscriber.getPublisher(); - try { - NotificationsHandler notifHandler = man.getNotificationsHandler(pub); - if(notifHandler == null) { - it_subs.remove(); - } else { - SubscriptionInfo subsInfo = notifHandler.createSubscriptionInfo(subscriber, locale, compareDate); - if (!subsInfo.hasNews()) { - it_subs.remove(); - } + Map<Subscriber,SubscriptionInfo> subscriptionMap = NotificationHelper.getSubscriptionMap(getIdentity(), getLocale(), true, compareDate); + + notificationsList = new ArrayList<Subscriber>(); + for (Iterator<Map.Entry<Subscriber, SubscriptionInfo>> it_subs = subscriptionMap.entrySet().iterator(); it_subs.hasNext();) { + Map.Entry<Subscriber, SubscriptionInfo> sInfo = it_subs.next(); + Subscriber subscrer = sInfo.getKey(); + SubscriptionInfo infos = sInfo.getValue(); + if(infos.hasNews()) { + notificationsList.add(subscrer); } - } catch(Exception e) { - log.error("Cannot load publisher:" + pub, e); } - } - - notificationsList = getSortedList(notificationsList, sortingCriteria ); - List<PortletEntry> entries = convertNotificationToPortletEntryList(notificationsList); - - Map subscriptionMap = NotificationHelper.getSubscriptionMap(getIdentity(), getLocale(), true, compareDate); - notificationListModel = new NotificationsPortletTableDataModel(entries, locale, subscriptionMap); - tableCtr.setTableDataModel(notificationListModel); + notificationsList = getSortedList(notificationsList, sortingCriteria ); + List<PortletEntry> entries = convertNotificationToPortletEntryList(notificationsList); + notificationListModel = new NotificationsPortletTableDataModel(entries, locale, subscriptionMap); + tableCtr.setTableDataModel(notificationListModel); } else { reloadModel(this.getPersistentManuallySortedItems()); } diff --git a/src/main/java/org/olat/portfolio/ui/structel/EPShareListController.java b/src/main/java/org/olat/portfolio/ui/structel/EPShareListController.java index 69324838cab..3c477837bcd 100644 --- a/src/main/java/org/olat/portfolio/ui/structel/EPShareListController.java +++ b/src/main/java/org/olat/portfolio/ui/structel/EPShareListController.java @@ -66,6 +66,8 @@ 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.Emailer; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailHelper; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupManager; @@ -309,7 +311,9 @@ public class EPShareListController extends FormBasicController { String last = getIdentity().getUser().getProperty(UserConstants.LASTNAME, null); String sender = first + " " + last; String[] bodyArgs = new String[]{busLink, sender}; - success = mailer.sendEmail(clList, translate("map.share.invitation.mail.subject"), translate("map.share.invitation.mail.body", bodyArgs)); + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(map.getOlatResource(), null, getWindowControl().getBusinessControl().getAsString()); + success = mailer.sendEmail(context, clList, translate("map.share.invitation.mail.subject"), translate("map.share.invitation.mail.body", bodyArgs)); } catch (AddressException e) { logError("Error on sending invitation mail to contactlist, invalid address.", e); } catch (MessagingException e) { diff --git a/src/main/java/org/olat/registration/RegistrationController.java b/src/main/java/org/olat/registration/RegistrationController.java index 7c57b8b1ae8..0e8194e68a3 100644 --- a/src/main/java/org/olat/registration/RegistrationController.java +++ b/src/main/java/org/olat/registration/RegistrationController.java @@ -50,7 +50,9 @@ import org.olat.core.logging.OLATRuntimeException; import org.olat.core.util.Util; import org.olat.core.util.WebappHelper; import org.olat.core.util.i18n.I18nManager; -import org.olat.core.util.mail.Emailer; +import org.olat.core.util.i18n.I18nModule; +import org.olat.core.util.mail.MailerResult; +import org.olat.core.util.mail.manager.MailManager; import org.olat.dispatcher.LocaleNegotiator; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; @@ -228,7 +230,7 @@ public class RegistrationController extends BasicController { String ip = ureq.getHttpReq().getRemoteAddr(); String body = null; String today = DateFormat.getDateInstance(DateFormat.LONG, ureq.getLocale()).format(new Date()); - Emailer mailer = new Emailer(ureq.getLocale()); + MailManager mailM = MailManager.getInstance(); //TODO eMail Vorlagen String serverpath = Settings.getServerContextPathURI(); boolean isMailSent = false; @@ -241,7 +243,8 @@ public class RegistrationController extends BasicController { + SEPARATOR + getTranslator().translate("reg.wherefrom", new String [] { serverpath, today, ip }); try { - if (mailer.sendEmail(email, translate("reg.subject"), body)) isMailSent = true; + MailerResult result = mailM.sendExternMessage(null, null, null, email, null, null, null, translate("reg.subject"), body, null, null); + if (MailerResult.OK == result.getReturnCode()) isMailSent = true; } catch (Exception e) { // nothing to do, emailSent flag is false, errors will be reported to user } @@ -252,7 +255,8 @@ public class RegistrationController extends BasicController { body = translate("login.body", identity.getName()) + SEPARATOR + getTranslator().translate("reg.wherefrom", new String[] { serverpath, today, ip }); try { - isMailSent = mailer.sendEmail(email, translate("login.subject"), body); + MailerResult result = mailM.sendExternMessage(null, null, null, email, null, null, null, translate("login.subject"), body, null, null); + if (MailerResult.OK == result.getReturnCode()) isMailSent = true; } catch (Exception e) { // nothing to do, emailSent flag is false, errors will be reported to user } diff --git a/src/main/java/org/olat/registration/RegistrationManager.java b/src/main/java/org/olat/registration/RegistrationManager.java index 8d95844d323..fba0e313c3b 100644 --- a/src/main/java/org/olat/registration/RegistrationManager.java +++ b/src/main/java/org/olat/registration/RegistrationManager.java @@ -28,6 +28,7 @@ import java.util.Locale; import javax.mail.Address; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; import org.hibernate.Hibernate; import org.olat.basesecurity.AuthHelper; @@ -45,8 +46,8 @@ import org.olat.core.util.Encoder; import org.olat.core.util.Util; import org.olat.core.util.WebappHelper; import org.olat.core.util.i18n.I18nModule; -import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailerResult; +import org.olat.core.util.mail.manager.MailManager; import org.olat.properties.Property; import org.olat.properties.PropertyManager; @@ -58,7 +59,7 @@ import org.olat.properties.PropertyManager; public class RegistrationManager extends BasicManager { public final String PW_CHANGE = "PW_CHANGE"; - protected final String REGISTRATION = "REGISTRATION"; + public final String REGISTRATION = "REGISTRATION";//fxdiff FXOLAT-113: business path in DMZ public static final String EMAIL_CHANGE = "EMAIL_CHANGE"; protected static final int REG_WORKFLOW_STEPS = 5; protected static final int PWCHANGE_WORKFLOW_STEPS = 4; @@ -101,7 +102,8 @@ public class RegistrationManager extends BasicManager { Address from; Address[] to; try { - from = new InternetAddress(WebappHelper.getMailConfig("mailFrom")); + // fxdiff: change from/replyto, see FXOLAT-74 + from = new InternetAddress(WebappHelper.getMailConfig("mailReplyTo")); to = new Address[] { new InternetAddress(notificationMailAddress)}; } catch (AddressException e) { Tracing.logError("Could not send registration notification message, bad mail address", e, RegistrationManager.class); @@ -116,7 +118,9 @@ public class RegistrationManager extends BasicManager { String subject = trans.translate("reg.notiEmail.subject", userParams); String body = trans.translate("reg.notiEmail.body", userParams); - MailHelper.sendMessage(from, to , null, null, body, subject, null, result); + //fxdiff VCRP-16: intern mail system + MimeMessage msg = MailManager.getInstance().createMimeMessage(from, to, null, null, body, subject, null, result); + MailManager.getInstance().sendMessage(msg, result); if (result.getReturnCode() != MailerResult.OK ) { Tracing.logError("Could not send registration notification message, MailerResult was ::" + result.getReturnCode(), RegistrationManager.class); } diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties index 3d02a52c9c6..99d01574fb9 100644 --- a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties @@ -377,6 +377,7 @@ tab.log=Logfiles tab.public=Allgemein tab.glossary.flexions=Morphologischer Dienst tab.glossary.register=Alphabetisches Register +tab.glossary.edit=Schreibberechtigung tab.sharedfolder=Ressourcenordner table.header.ac=AC table.header.access=Zugriff* diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties index 79710067b8b..502bfcd4986 100644 --- a/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties @@ -354,6 +354,7 @@ tab.calendar=Calendar tab.chat=Course chat tab.efficencystatement=Evidence of achievement tab.glossary=Glossary +tab.glossary.edit=Write permissions tab.glossary.flexions=Morphologic service tab.glossary.register=Alphabetical index tab.layout=Layout diff --git a/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java b/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java index d596a2157c7..321c00aa563 100644 --- a/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java +++ b/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java @@ -51,6 +51,8 @@ import org.olat.core.gui.translator.PackageTranslator; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.id.UserConstants; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailNotificationEditController; import org.olat.core.util.mail.MailTemplate; @@ -190,7 +192,9 @@ public class WizardCloseCourseController extends WizardController implements Wiz } else { ccIdentities = null; } - MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(ownerList, ccIdentities, null, + //fxdiff VCRP-16: intern mail system + MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString()); + MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, ownerList, ccIdentities, null, mailNotificationCtr.getMailTemplate(), ureq.getIdentity()); StringBuilder errorMessage = new StringBuilder(); StringBuilder warningMessage = new StringBuilder(); diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_7_1_1.java b/src/main/java/org/olat/upgrade/OLATUpgrade_7_1_1.java index 82d54dc1be5..988f82a9ca9 100644 --- a/src/main/java/org/olat/upgrade/OLATUpgrade_7_1_1.java +++ b/src/main/java/org/olat/upgrade/OLATUpgrade_7_1_1.java @@ -25,6 +25,10 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; +import org.olat.basesecurity.BaseSecurity; +import org.olat.basesecurity.BaseSecurityManager; +import org.olat.basesecurity.Constants; +import org.olat.basesecurity.SecurityGroup; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.commons.persistence.DBQuery; @@ -33,6 +37,10 @@ import org.olat.core.commons.services.commentAndRating.CommentAndRatingService; import org.olat.core.commons.services.commentAndRating.UserCommentsManager; import org.olat.core.commons.services.commentAndRating.model.UserComment; import org.olat.core.id.Identity; +import org.olat.group.BusinessGroup; +import org.olat.group.context.BGContext; +import org.olat.group.context.BGContextManager; +import org.olat.group.context.BGContextManagerImpl; import org.olat.portfolio.PortfolioModule; import org.olat.portfolio.manager.EPFrontendManager; import org.olat.portfolio.model.artefacts.AbstractArtefact; @@ -42,6 +50,7 @@ import org.olat.portfolio.model.structel.EPStructuredMap; import org.olat.portfolio.model.structel.EPStructuredMapTemplate; import org.olat.portfolio.model.structel.ElementType; import org.olat.portfolio.model.structel.PortfolioStructure; +import org.olat.repository.RepositoryEntry; /** * Description:<br> @@ -59,12 +68,15 @@ public class OLATUpgrade_7_1_1 extends OLATUpgrade { private static final String TASK_CLEANUP_TEMPLATES = "Cleanup template maps on db directly"; private static final String TASK_CHECK_AND_FIX_TEMPLATEMAPS = "Check templates and fix portfolio-task child elements"; + private static final String MIGRATE_SECURITY_GROUP = "Migrate repository entry security groups"; + private static final int REPO_ENTRIES_BATCH_SIZE = 20; private static final String VERSION = "OLAT_7.1.1"; private boolean portfolioCourseNodeEnabled; private EPFrontendManager ePFMgr; private CommentAndRatingService commentAndRatingService; private PortfolioModule epfModule; + public OLATUpgrade_7_1_1(PortfolioModule epfModule) { super(); this.epfModule = epfModule; @@ -97,6 +109,8 @@ public class OLATUpgrade_7_1_1 extends OLATUpgrade { // remove invalid references on db fixInvalidTemplateMaps(upgradeManager, uhd); + + migrateSecurityGroups(upgradeManager, uhd); // uhd.setInstallationComplete(true); upgradeManager.setUpgradesHistory(uhd, VERSION); @@ -378,6 +392,128 @@ public class OLATUpgrade_7_1_1 extends OLATUpgrade { } + //fxdiff VCRP-1: access control repository entry + private void migrateSecurityGroups(UpgradeManager upgradeManager, UpgradeHistoryData uhd) { + if (!uhd.getBooleanDataValue(MIGRATE_SECURITY_GROUP)) { + log.audit("+-----------------------------------------------------------------------------+"); + log.audit("+... Migrate the repository entry security groups from business groups ...+"); + log.audit("+-----------------------------------------------------------------------------+"); + + int counter = 0; + List<RepositoryEntry> entries; + do { + entries = queryEntries(counter); + for(RepositoryEntry entry:entries) { + createRepoEntrySecurityGroups(entry); + migrateRepoEntrySecurityGroups(entry); + } + counter += entries.size(); + log.audit("Processed entries: " + entries.size()); + } while(entries.size() == REPO_ENTRIES_BATCH_SIZE); + + log.audit("+... Migration processed " + counter + " repository entries ...+"); + + uhd.setBooleanDataValue(MIGRATE_SECURITY_GROUP, true); + upgradeManager.setUpgradesHistory(uhd, VERSION); + } + } + + private void createRepoEntrySecurityGroups(RepositoryEntry entry) { + BaseSecurity securityManager = BaseSecurityManager.getInstance(); + + boolean save = false; + if(entry.getTutorGroup() == null) { + // security group for tutors / coaches + SecurityGroup tutorGroup = securityManager.createAndPersistSecurityGroup(); + // member of this group may modify member's membership + securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_ACCESS, entry.getOlatResource()); + // members of this group are always tutors also + securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_TUTOR); + entry.setTutorGroup(tutorGroup); + + securityManager.createAndPersistPolicy(entry.getTutorGroup(), Constants.PERMISSION_COACH, entry.getOlatResource()); + + DBFactory.getInstance().commit(); + save = true; + } + + if(entry.getParticipantGroup() == null) { + // security group for participants + SecurityGroup participantGroup = securityManager.createAndPersistSecurityGroup(); + // member of this group may modify member's membership + securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_ACCESS, entry.getOlatResource()); + // members of this group are always participants also + securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_PARTICIPANT); + entry.setParticipantGroup(participantGroup); + + securityManager.createAndPersistPolicy(entry.getParticipantGroup(), Constants.PERMISSION_PARTI, entry.getOlatResource()); + + DBFactory.getInstance().commit(); + save = true; + } + + if(save) { + DBFactory.getInstance().updateObject(entry); + } + } + + private void migrateRepoEntrySecurityGroups(RepositoryEntry entry) { + BaseSecurity securityManager = BaseSecurityManager.getInstance(); + BGContextManager contextManager = BGContextManagerImpl.getInstance(); + + List<BGContext> contexts = contextManager.findBGContextsForResource(entry.getOlatResource(), true, true); + for(BGContext context:contexts) { + List<BusinessGroup> groups = contextManager.getGroupsOfBGContext(context); + for(BusinessGroup group:groups) { + //migrate tutors + if(group.getOwnerGroup() != null) { + int count = 0; + List<Identity> owners = securityManager.getIdentitiesOfSecurityGroup(group.getOwnerGroup()); + SecurityGroup tutorGroup = entry.getTutorGroup(); + for(Identity owner:owners) { + if(securityManager.isIdentityInSecurityGroup(owner, tutorGroup)) { + continue; + } + securityManager.addIdentityToSecurityGroup(owner, tutorGroup); + if(count++ % 20 == 0) { + DBFactory.getInstance().intermediateCommit(); + } + } + DBFactory.getInstance().intermediateCommit(); + } + + //migrate participants + if(group.getPartipiciantGroup() != null) { + int count = 0; + List<Identity> participants = securityManager.getIdentitiesOfSecurityGroup(group.getPartipiciantGroup()); + SecurityGroup participantGroup = entry.getParticipantGroup(); + for(Identity participant:participants) { + if(securityManager.isIdentityInSecurityGroup(participant, participantGroup)) { + continue; + } + securityManager.addIdentityToSecurityGroup(participant, participantGroup); + if(count++ % 20 == 0) { + DBFactory.getInstance().intermediateCommit(); + } + } + + DBFactory.getInstance().intermediateCommit(); + } + } + } + } + + public List<RepositoryEntry> queryEntries(int firstResult) { + StringBuilder sb = new StringBuilder(); + sb.append("select v from ").append(RepositoryEntry.class.getName()).append(" v inner join fetch v.olatResource as res order by v.key asc"); + DBQuery dbquery = DBFactory.getInstance().createQuery(sb.toString()); + dbquery.setFirstResult(firstResult); + dbquery.setMaxResults(REPO_ENTRIES_BATCH_SIZE); + return dbquery.list(); + } + + + @Override public String getVersion() { return VERSION; diff --git a/src/main/java/org/olat/user/ChangePasswordController.java b/src/main/java/org/olat/user/ChangePasswordController.java index c4a160849e0..38fffe60ca8 100644 --- a/src/main/java/org/olat/user/ChangePasswordController.java +++ b/src/main/java/org/olat/user/ChangePasswordController.java @@ -135,6 +135,8 @@ public class ChangePasswordController extends BasicController implements Support String newPwd = chPwdForm.getNewPasswordValue(); if(OLATAuthManager.changePassword(ureq.getIdentity(), provenIdent, newPwd)) { //TODO: verify that we are NOT in a transaction (changepwd should be commited immediately) + // fxdiff: we need this event for the afterlogin-controller + fireEvent(ureq, Event.DONE_EVENT); getLogger().audit("Changed password for identity."+provenIdent.getName()); showInfo("password.successful"); } else { diff --git a/src/main/java/org/olat/user/MailBoxExtension.java b/src/main/java/org/olat/user/MailBoxExtension.java new file mode 100644 index 00000000000..ea0134b68c7 --- /dev/null +++ b/src/main/java/org/olat/user/MailBoxExtension.java @@ -0,0 +1,159 @@ +/** + * 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) frentix GmbH<br> + * http://www.frentix.com<br> + * <p> + */ +package org.olat.user; + +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import org.olat.NewControllerFactory; +import org.olat.admin.user.delete.service.UserDeletionManager; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.id.Identity; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.BusinessControlFactory; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.ContextEntryControllerCreator; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.manager.BasicManager; +import org.olat.core.util.StringHelper; +import org.olat.core.util.mail.manager.MailManager; +import org.olat.core.util.mail.model.DBMail; +import org.olat.core.util.mail.ui.MailContextResolver; +import org.olat.group.BusinessGroup; +import org.olat.group.BusinessGroupManagerImpl; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryManager; + +import org.olat.home.HomeSite; + +/** + * + * Description:<br> + * The MailBoxExtensio for + * + * <P> + * Initial Date: 25 mars 2011 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class MailBoxExtension extends BasicManager implements MailContextResolver, UserDataDeletable { + + private static final OLog log = Tracing.createLoggerFor(MailBoxExtension.class); + + private MailManager mailManager; + + public MailBoxExtension(UserDeletionManager userDeletionManager) { + userDeletionManager.registerDeletableUserData(this); + } + + public void init() { + NewControllerFactory.getInstance().addContextEntryControllerCreator("Inbox", new ContextEntryControllerCreator(){ + @Override + public Controller createController(ContextEntry ce, UserRequest ureq, WindowControl wControl) { + return null; + } + + @Override + public String getTabName(ContextEntry ce) { + // opens in home-tab + return null; + } + + @Override + public String getSiteClassName(ContextEntry ce) { + return HomeSite.class.getName(); + } + + @Override + public boolean validateContextEntryAndShowError(ContextEntry ce, UserRequest ureq, WindowControl wControl) { + return true; + } + }); + } + + /** + * [used by Spring] + * @param mailManager + */ + public void setMailManager(MailManager mailManager) { + this.mailManager = mailManager; + } + + + @Override + public void deleteUserData(Identity identity, String newDeletedUserName) { + //set as deleted all recpient + logInfo("Delete intern messages"); + + List<DBMail> inbox = mailManager.getInbox(identity, null, false, null, 0, 0); + for(DBMail inMail:inbox) { + mailManager.delete(inMail, identity, true); + } + + List<DBMail> outbox = mailManager.getOutbox(identity, 0, 0); + for(DBMail outMail:outbox) { + mailManager.delete(outMail, identity, true); + } + + logInfo("Delete " + inbox.size() + " messages in INBOX and " + outbox.size() + " in OUTBOX"); + } + + @Override + public String getName(String businessPath, Locale locale) { + if(!StringHelper.containsNonWhitespace(businessPath)) return null; + + try { + List<ContextEntry> entries = BusinessControlFactory.getInstance().createCEListFromString(businessPath); + Collections.reverse(entries); + + for(ContextEntry entry:entries) { + String resourceTypeName = entry.getOLATResourceable().getResourceableTypeName(); + Long resourceId = entry.getOLATResourceable().getResourceableId(); + if("BusinessGroup".equals(resourceTypeName)) { + BusinessGroup group = BusinessGroupManagerImpl.getInstance().loadBusinessGroup(resourceId, false); + if(group == null) { + return null; + } + return group.getName(); + } else if ("RepositoryEntry".equals(resourceTypeName)) { + RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(resourceId); + if(re == null) { + return null; + } + return re.getDisplayname(); + } + } + } catch (Exception e) { + log.error("", e); + } + return null; + } + + @Override + public void open(UserRequest ureq, WindowControl wControl, String businessPath) { + BusinessControl bc = BusinessControlFactory.getInstance().createFromString(businessPath); + WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, wControl); + NewControllerFactory.getInstance().launch(ureq, bwControl); + } +} diff --git a/src/main/java/org/olat/user/PreferencesFormController.java b/src/main/java/org/olat/user/PreferencesFormController.java index 44791c5a591..e412ccc492c 100644 --- a/src/main/java/org/olat/user/PreferencesFormController.java +++ b/src/main/java/org/olat/user/PreferencesFormController.java @@ -27,6 +27,7 @@ import java.util.Map; import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurityManager; +import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -41,10 +42,12 @@ import org.olat.core.gui.control.WindowBackOffice; import org.olat.core.gui.control.WindowControl; import org.olat.core.id.Identity; import org.olat.core.id.Preferences; +import org.olat.core.id.UserConstants; import org.olat.core.util.ArrayHelper; import org.olat.core.util.StringHelper; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; +import org.olat.core.util.mail.MailModule; import org.olat.core.util.notifications.NotificationsManager; /** @@ -64,7 +67,8 @@ import org.olat.core.util.notifications.NotificationsManager; public class PreferencesFormController extends FormBasicController { private static final String[] cssFontsizeKeys = new String[] { "80", "90", "100", "110", "120", "140" }; private Identity tobeChangedIdentity; - private SingleSelection language, fontsize, charset, notificationInterval; + private SingleSelection language, fontsize, charset, notificationInterval, mailSystem; + private static final String[] mailIntern = new String[]{"intern.only","send.copy"}; /** * Constructor for the user preferences form @@ -104,6 +108,11 @@ public class PreferencesFormController extends FormBasicController { // set window dirty to force full page refresh wbo.getWindow().setDirty(true); } + //fxdiff VCRP-16: intern mail system + if(mailSystem != null && mailSystem.isOneSelected()) { + String val = mailSystem.isSelected(1) ? "true" : "false"; + prefs.setReceiveRealMail(val); + } if (um.updateUserFromIdentity(tobeChangedIdentity)) { // Language change needs logout / login @@ -180,6 +189,26 @@ public class PreferencesFormController extends FormBasicController { notificationInterval = uifactory.addDropdownSingleselect("form.notification", formLayout, intervalKeys, intervalValues, null); notificationInterval.select(prefs.getNotificationInterval(), true); } + //fxdiff VCRP-16: intern mail system + MailModule mailModule = (MailModule)CoreSpringFactory.getBean("mailModule"); + if(mailModule.isInternSystem()) { + String userEmail = tobeChangedIdentity.getUser().getProperty(UserConstants.EMAIL, getLocale()); + String[] mailInternLabels = new String[] { translate("mail." + mailIntern[0], userEmail), translate("mail." + mailIntern[1], userEmail) }; + mailSystem = uifactory.addRadiosVertical("mail-system", "mail.system", formLayout, mailIntern, mailInternLabels); + + String mailPrefs = prefs.getReceiveRealMail(); + if(StringHelper.containsNonWhitespace(mailPrefs)) { + if("true".equals(mailPrefs)) { + mailSystem.select(mailIntern[1], true); + } else { + mailSystem.select(mailIntern[0], true); + } + } else if(mailModule.isReceiveRealMailUserDefaultSetting()) { + mailSystem.select(mailIntern[1], true); + } else { + mailSystem.select(mailIntern[0], true); + } + } // Text encoding Map<String, Charset> charsets = Charset.availableCharsets(); diff --git a/src/main/java/org/olat/user/PreferencesImpl.java b/src/main/java/org/olat/user/PreferencesImpl.java index b82ae996c41..1a4c1948654 100644 --- a/src/main/java/org/olat/user/PreferencesImpl.java +++ b/src/main/java/org/olat/user/PreferencesImpl.java @@ -39,6 +39,7 @@ public class PreferencesImpl implements Preferences{ private String fontsize; private String notificationInterval; boolean informSessionTimeout; + private String receiveRealMail; private boolean presenceMessagesPublic; /** @@ -103,7 +104,7 @@ public class PreferencesImpl implements Preferences{ // Always return a valid notification interval NotificationsManager notiMgr = NotificationsManager.getInstance(); if (notificationInterval == null || notificationInterval.isEmpty() - || !notiMgr.getEnabledNotificationIntervals().contains(notificationInterval)) { + || notiMgr == null || !notiMgr.getEnabledNotificationIntervals().contains(notificationInterval)) { notificationInterval = notiMgr.getDefaultNotificationInterval(); } return notificationInterval; @@ -122,6 +123,23 @@ public class PreferencesImpl implements Preferences{ public void setInformSessionTimeout(boolean b) { informSessionTimeout = b; } + + /** + * @see org.olat.core.id.Preferences#isReceiveRealMail() + */ + //fxdiff VCRP-16: intern mail system + @Override + public String getReceiveRealMail() { + return receiveRealMail; + } + + /** + * @see org.olat.core.id.Preferences#setReceiveRealMail(boolean) + */ + @Override + public void setReceiveRealMail(String receiveRealMail) { + this.receiveRealMail = receiveRealMail; + } /** * @see org.olat.user.Preferences#getPresenceMessagesPublic() diff --git a/src/main/java/org/olat/user/UserImpl.hbm.xml b/src/main/java/org/olat/user/UserImpl.hbm.xml index e59b9ad0bf8..7ace2e77abe 100644 --- a/src/main/java/org/olat/user/UserImpl.hbm.xml +++ b/src/main/java/org/olat/user/UserImpl.hbm.xml @@ -25,8 +25,10 @@ <column name="presencemessagespublic" unique="false" not-null="false"/> </property> <property name="informSessionTimeout"> - <column name="informsessiontimeout" not-null="true"/> - </property> + <column name="informsessiontimeout" unique="false" not-null="false" length="16"/> + </property> + + <property name="receiveRealMail" column="receiverealmail" unique="false" not-null="false" length="16" type="string"/> </component> <map name="properties" table="o_userproperty" cascade="all,delete-orphan" fetch="join"> diff --git a/src/main/java/org/olat/user/UserManager.java b/src/main/java/org/olat/user/UserManager.java index 379fb066229..d9d27a58475 100644 --- a/src/main/java/org/olat/user/UserManager.java +++ b/src/main/java/org/olat/user/UserManager.java @@ -176,8 +176,7 @@ public abstract class UserManager extends BasicManager { return userNameAndPasswordSyntaxChecker.syntaxCheckOlatLogin(login); } - // only package scope, used by user impl - UserPropertiesConfig getUserPropertiesConfig() { + public UserPropertiesConfig getUserPropertiesConfig() { return userPropertiesConfig; } @@ -210,6 +209,9 @@ public abstract class UserManager extends BasicManager { public boolean isUserViewReadOnly(String usageIdentifyer, UserPropertyHandler propertyHandler) { return userPropertiesConfig.isUserViewReadOnly(usageIdentifyer, propertyHandler); } + + // fxdiff: check also for emails in change-workflow + public abstract boolean isEmailInUse(String email); /** * Spring setter diff --git a/src/main/java/org/olat/user/UserManagerImpl.java b/src/main/java/org/olat/user/UserManagerImpl.java index 36e08358260..6383150d297 100644 --- a/src/main/java/org/olat/user/UserManagerImpl.java +++ b/src/main/java/org/olat/user/UserManagerImpl.java @@ -92,6 +92,28 @@ public class UserManagerImpl extends UserManager { DBFactory.getInstance().saveObject(user); return user; } + + // fxdiff: check also for emails in change-workflow + public boolean isEmailInUse(String email) { + DB db = DBFactory.getInstance(); + String[] emailProperties = {UserConstants.EMAIL, UserConstants.INSTITUTIONALEMAIL}; + for(String emailProperty:emailProperties) { + StringBuilder sb = new StringBuilder(); + sb.append("select count(user) from org.olat.core.id.User user where ") + .append("user.properties['") + .append(emailProperty) + .append("']=:email_value"); + + String query = sb.toString(); + DBQuery dbq = db.createQuery(query); + dbq.setString("email_value", email); + Number countEmail = (Number)dbq.uniqueResult(); + if(countEmail.intValue() > 0) { + return true; + } + } + return false; + } /** * @see org.olat.user.UserManager#findIdentityByEmail(java.lang.String) diff --git a/src/main/java/org/olat/user/_chelp/home-prefs.html b/src/main/java/org/olat/user/_chelp/home-prefs.html index 95ac281fd17..e0f0ad7e6be 100644 --- a/src/main/java/org/olat/user/_chelp/home-prefs.html +++ b/src/main/java/org/olat/user/_chelp/home-prefs.html @@ -5,5 +5,6 @@ $r.translate("chelp.prefs5") <br/><br/> <b>$r.translate("form.fontsize"):</b> $r.translate("chelp.prefs6") $r.translate("chelp.prefs7") <br/><br/> <b>$r.translate("form.notification"):</b> $r.translate("chelp.prefs15") $r.translate("chelp.prefs16") <br/><br/> + <b>$r.translate("mail.system"):</b> $r.translate("chelp.mail.system") <br/><br/> <b>$r.translate("form.charset"):</b> $r.translate("chelp.prefs8") $r.translate("chelp.prefs9") <br/><br/> $r.translate("chelp.prefs10") $r.translate("chelp.prefs11") diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties index 0461dfe54bd..3aef0d99ab7 100644 --- a/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties @@ -20,7 +20,7 @@ chelp.contact=<b>$org.olat.user\:menu.contact</b> chelp.fName=<i>$org.olat.user.propertyhandlers\:form.name.firstName</i> chelp.fNameF=<b>$org.olat.user.propertyhandlers\:form.name.firstName\:</b> chelp.folder=<b>$org.olat.user\:menu.folder</b> -chelp.home=<i>$org.olat.home\:menu.root</i> +chelp.home=<i>$org.olat.home\:main.menu.title</i> chelp.home-imsettings.title=Instant-Messaging: Konfiguration chelp.home-imsettings-roster.title=Instant-Messaging: Statusanzeige in der Kontaktliste chelp.home-prefs-ajax.title=AJAX-Einstellungen @@ -196,6 +196,10 @@ success.change.email = Die E-Mail-Adresse wurde erfolgreich von {0} auf {1} ge\u error.change.email.time = Dieser Aktivierungs-Link hat eine G\u00fcltigkeitsdauer von {0} Stunden und ist somit nicht mehr g\u00fcltig. email.change.form.info = Ihre neue E-Mail-Adresse <b>{0}</b> wurde noch nicht aktiviert. Bitte folgen Sie den Anweisungen in der Ihnen zugestellten E-Mail zur Aktivierung der neuen E-Mail-Adresse. email.change.reminder = Sie haben die \u00c4nderung Ihrer in OLAT hinterlegten E-Mail-Adresse beantragt, die neue Adresse jedoch noch nicht aktiviert. Weitere Informationen zu diesem Vorgang finden Sie in der kontextsensitiven Hilfe im Bereich "Home" \u2192 "Meine Einstellungen". +mail.system=E-Mail Versand +mail.intern.only=E-Mails an das interne OLAT Postfach zustellen +mail.send.copy=E-Mails an das interne OLAT Postfach und die Adresse {0} zustellen +chelp.mail.system= Hier k�nnen Sie einstellen, ob Ihre pers�nlichen E-Mails and Ihre konfigurierte E-Mail Adresse verschickt oder nur in dem Posteingang innerhalb des OLAT Systems angezeigt werden sollen. Bitte beachten Sie, dass die Benachrichtigungen �ber Neuigkeiten innerhalb des System in jedem Fall per E-Mail an Ihre konfigurierte Mailadresse versendet werden. In dieser Benachrichtigungsemail finden Sie denn auch einen Hinweis �ber allf�llige neue E-Mails innerhalb des OLAT Postfachs falls Sie die Option "$:mail.intern.only" gew�hlt haben.. runonce.profile.intro=Bitte pr\u00FCfen Sie, ob Ihr Profil auf dem aktuellsten Stand ist und dr\u00FCcken Sie danach "Speichern". runonce.changepw.intro=Bitte \u00E4ndern Sie Ihr Passwort. pwdav.title=WebDAV Zugang diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties index 5ab26377a2c..b3a8328a531 100644 --- a/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties @@ -27,7 +27,7 @@ chelp.contact=<b>$org.olat.user\:menu.contact</b> chelp.fName=<i>$org.olat.user.propertyhandlers\:form.name.firstName</i> chelp.fNameF=<b>$org.olat.user.propertyhandlers\:form.name.firstName\:</b> chelp.folder=<b>$org.olat.user\:menu.folder</b> -chelp.home=<i>$org.olat.home\:menu.root</i> +chelp.home=<i>$org.olat.home\:main.menu.title</i> chelp.home-imsettings-roster.title=Instant Messaging\: status display in contact list chelp.home-imsettings.title=Instant Messaging\: configuration chelp.home-picture.hover=Help to upload an image to your user profile @@ -50,6 +50,7 @@ chelp.instMail=<i>$org.olat.user.propertyhandlers\:form.name.institutionalEmail< chelp.lName=<i>$org.olat.user.propertyhandlers\:form.name.lastName</i> chelp.lNameF=<b>$org.olat.user.propertyhandlers\:form.name.lastName\:</b> chelp.large=<i>«$org.olat.user\:form.fontsize.large»</i> +chelp.mail.system=Here you can configure if you e-mails sent within the OLAT system should be delivered to you personal e-mail address or to the OLAT e-mail inbox in your home area. Please note that notification e-mails will be sent to your e-mail address in any case. In this notification e-mail you will find information about new internal e-mails if you selected the option "$\:mail.intern.only". chelp.nname=<i>$org.olat.user.propertyhandlers\:form.name.lastName</i> chelp.normal=<i>«$org.olat.user\:form.fontsize.normal»</i> chelp.onl1=Here you can determine if your $\:chelp.uname, $\:chelp.vname, and $\:chelp.nname on the online user list should be visible to all other OLAT users. @@ -151,6 +152,9 @@ interval.monthly=Monthly interval.never=Never interval.two-hourly=Every two hours interval.weekly=Weekly +mail.intern.only=Send e-mails to the OLAT internal inbox +mail.send.copy=Send e-mails to the OLAT internal inbox and the address {0} +mail.system=E-mail delivery menu.calendar=Calendar menu.calendar.alt=Personal calendar of selected user menu.contact=Contact diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties index 4b56b98c384..7eff19e9595 100644 --- a/src/main/resources/serviceconfig/olat.properties +++ b/src/main/resources/serviceconfig/olat.properties @@ -98,15 +98,22 @@ smtp.host=localhost # if required by your local SMTP you may need to provide credentials smtp.user= smtp.pwd= -# enable SSL if you smtp server supports it +# enable SSL if your smtp server supports it smtp.sslEnabled=false smtp.sslCheckCertificate=false -# set this email to a mail address in your domain -adminemail=webmaster@myolat.com -# set this email to a mail address in your domain -supportemail=support@myolat.com +# system mails will be sent from this address (from local domain with valid reverse dns): +fromemail=no-reply@openolat.org +# set this email to a mail address in your domain (used as reply-to address) +adminemail=webmaster@openolat.org +# set this email to a mail address in your domain (for RS-reports) +supportemail=support@openolat.org + # maximum size for email attachements (in MB) mail.attachment.maxsize=5 +# if mail intern is enabled you must make sure, that your mysql-db accepts large packets to also save the attachments: +# set "max_allowed_packet = 134217728" in my.cnf/my.ini see FXOLAT-154 +mail.intern=false +mail.receiveRealMailUserDefaultSetting=true ######################################################################## # User registration, login and deletion settings diff --git a/src/test/java/org/olat/core/test/OlatcoreTestCaseWithMocking.java b/src/test/java/org/olat/core/test/OlatcoreTestCaseWithMocking.java index 30ea7586a45..6dcb8191b37 100644 --- a/src/test/java/org/olat/core/test/OlatcoreTestCaseWithMocking.java +++ b/src/test/java/org/olat/core/test/OlatcoreTestCaseWithMocking.java @@ -38,6 +38,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; "classpath*:/org/olat/core/test/_spring/webapphelperMock.xml", "classpath*:/org/olat/core/util/i18n/_spring/i18nCorecontext.xml", "classpath*:/org/olat/core/test/_spring/coordinatorMock.xml", + //fxdiff VCRP-16: intern mail system + "classpath*:/org/olat/core/test/_spring/mailModuleMock.xml", "classpath*:/org/olat/core/util/i18n/devtools/_spring/devtoolsCorecontext.xml", "classpath*:/org/olat/core/util/_spring/utilCorecontext.xml"}) diff --git a/src/test/java/org/olat/core/test/_spring/coordinatorMock.xml b/src/test/java/org/olat/core/test/_spring/coordinatorMock.xml index 22cb8c1f303..89fc4eca12a 100644 --- a/src/test/java/org/olat/core/test/_spring/coordinatorMock.xml +++ b/src/test/java/org/olat/core/test/_spring/coordinatorMock.xml @@ -13,4 +13,9 @@ <bean id="coordinatorManager" class="org.olat.test.CoordinatorManagerMock" /> +<bean class="org.olat.core.util.event.FrameworkStartupEventChannel"> + <constructor-arg type="String" value="${node.id}" /> + <property name="coordinatorManager" ref="coordinatorManager" /> +</bean> + </beans> \ No newline at end of file diff --git a/src/test/java/org/olat/core/test/_spring/mailModuleMock.xml b/src/test/java/org/olat/core/test/_spring/mailModuleMock.xml new file mode 100644 index 00000000000..fadedcadabb --- /dev/null +++ b/src/test/java/org/olat/core/test/_spring/mailModuleMock.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + +<context:property-placeholder location="classpath:serviceconfig/olat.properties, classpath:olat.local.properties" /> +<context:annotation-config /> + + <bean id="mailModule" class="org.olat.core.util.mail.MailModule" depends-on="org.olat.core.util.WebappHelper,coordinatorManager,org.olat.core.util.event.FrameworkStartupEventChannel"> + <property name="persistedProperties"> + <bean class="org.olat.core.configuration.PersistedProperties" scope="prototype" init-method="init" destroy-method="destroy" + depends-on="coordinatorManager,org.olat.core.util.WebappHelper"> + <constructor-arg index="0" ref="coordinatorManager"/> + <constructor-arg index="1" ref="mailModule" /> + </bean> + </property> + <property name="webappHelper" ref="org.olat.core.util.WebappHelper"/> + </bean> + + <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> + <property name="targetObject" ref="mailModule" /> + <property name="targetMethod" value="init" /> + <property name="arguments"> + <value> + internSystem=false + receiveRealMailUserDefaultSetting=true + </value> + </property> + </bean> + + <bean id="mailManager" class="org.olat.core.util.mail.manager.MailManager"> + <constructor-arg index="0" ref="mailModule" /> + </bean> + +</beans> \ No newline at end of file diff --git a/src/test/java/org/olat/core/util/mail/MailTest.java b/src/test/java/org/olat/core/util/mail/MailTest.java index eddbd88e3e8..ed640f47f42 100644 --- a/src/test/java/org/olat/core/util/mail/MailTest.java +++ b/src/test/java/org/olat/core/util/mail/MailTest.java @@ -466,6 +466,16 @@ class TestUser implements User { public void setLanguage(String l) {} public void setPresenceMessagesPublic(boolean b) {} + + @Override + public String getReceiveRealMail() { + return "false"; + } + + @Override + public void setReceiveRealMail(String receiveRealMail) { + // + } }); } diff --git a/src/test/java/org/olat/course/nodes/en/EnrollmentManagerTest.java b/src/test/java/org/olat/course/nodes/en/EnrollmentManagerTest.java index 67c95fb03c2..4be6eecab1f 100644 --- a/src/test/java/org/olat/course/nodes/en/EnrollmentManagerTest.java +++ b/src/test/java/org/olat/course/nodes/en/EnrollmentManagerTest.java @@ -33,6 +33,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.ArrayList; +import java.util.List; import java.util.Locale; import org.apache.log4j.Logger; @@ -54,6 +55,7 @@ import org.olat.core.id.IdentityEnvironment; import org.olat.core.id.OLATResourceable; import org.olat.core.id.User; import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; import org.olat.core.util.Encoder; import org.olat.core.util.Util; import org.olat.core.util.resource.OresHelper; @@ -252,7 +254,50 @@ public class EnrollmentManagerTest extends OlatTestCase implements WindowControl public DTabs getDTabs(){return null;}; public WindowControlInfo getWindowControlInfo(){return null;}; public void makeFlat(){}; - public BusinessControl getBusinessControl() {return null;} + public BusinessControl getBusinessControl() { + + BusinessControl control = new BusinessControl() { + + @Override + public String getAsString() { + return null; + } + + @Override + public List<ContextEntry> getEntries() { + return null; + } + + @Override + public ContextEntry popLauncherContextEntry() { + return null; + } + + @Override + public ContextEntry getCurrentContextEntry() { + return null; + } + + @Override + public void setCurrentContextEntry(ContextEntry cw) { + // + } + + @Override + public void dropLauncherEntries() { + // + } + + @Override + public boolean hasContextEntry() { + return false; + } + + }; + + return control; + + } public WindowBackOffice getWindowBackOffice() { // TODO Auto-generated method stub -- GitLab