diff --git a/config/alfresco/messages/bootstrap-spaces.properties b/config/alfresco/messages/bootstrap-spaces.properties index dc4d4601ab..15188af254 100644 --- a/config/alfresco/messages/bootstrap-spaces.properties +++ b/config/alfresco/messages/bootstrap-spaces.properties @@ -27,6 +27,12 @@ spaces.templates.content.description=Presentation templates spaces.templates.email.name=Email Templates spaces.templates.email.description=Email templates +spaces.invite_templates.email.name=Email Invite Templates +spaces.invite_templates.email.description=Email Invite templates + +spaces.notify_templates.email.name=Email Notify Templates +spaces.notify_templates.email.description=Email Notify templates + spaces.templates.rss.name=RSS Templates spaces.templates.rss.description=RSS templates diff --git a/config/alfresco/messages/invitation-service.properties b/config/alfresco/messages/invitation-service.properties index 5c16d9dc91..ca4bea46a5 100644 --- a/config/alfresco/messages/invitation-service.properties +++ b/config/alfresco/messages/invitation-service.properties @@ -9,4 +9,5 @@ invitation.invite.already_member "The user , {0} is already a member of {1} and invitation.cancel.not_site_manager "Current user, {0}, cannot cancel invitation: {1} because they are not a Site Manager for site: {2} invitation.invite.not_site_manager "Current user, {0}, is not a Site Manager for site: {1} invitation.invite.unable_generate_id "Unable to generate a user name for invitee, which doesn't already belong to someone else firstName:{0} lastName:{1} email:{2}" -invitation.invite.already_finished "Invitation, {0} has already been accepted, cancelled or rejected" \ No newline at end of file +invitation.invite.already_finished "Invitation, {0} has already been accepted, cancelled or rejected" +invitation.invite.authentication_chain "Authentication chain does not allow creation of new accounts" \ No newline at end of file diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index 5bfc5c4c94..93a1a303a2 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -74,6 +74,12 @@ patch.emailTemplatesFolder.description=Ensures the existence of the 'Email Templ patch.emailTemplatesFolder.result.exists=The email templates folder already exists: {0} patch.emailTemplatesFolder.result.created=The email templates folder was successfully created: {0} +patch.emailInviteAndNotifyTemplatesFolder.description=Ensures the existence of the 'Email Invite Templates' and 'Email Notify Templates' folders. +patch.emailNotifyTemplatesFolder.result.exists=The Email Notify Templates folder already exists: {0} +patch.emailNotifyTemplatesFolder.result.created=The Email Notify Templates folder was successfully created: {0} +patch.emailInviteTemplatesFolder.result.exists=The Email Invite Templates folder already exists: {0} +patch.emailInviteTemplatesFolder.result.created=The Email Invite Templates folder was successfully created: {0} + patch.emailTemplatesContent.description=Loads the email templates into the Email Templates folder. patch.emailTemplatesContent.result=Imported the Email Templates into the default folder. diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 63c770e875..13eccd77fa 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -320,6 +320,20 @@ + + patch.emailInviteAndNotifyTemplatesFolder + patch.emailInviteAndNotif yTemplatesFolder.description + 0 + 4006 + 4007 + + + + + + + + diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index 1ada6cea2b..0318cc73fd 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -19,4 +19,4 @@ version.build=@build-number@ # Schema number -version.schema=4006 +version.schema=4007 diff --git a/source/java/org/alfresco/repo/admin/patch/impl/EmailTemplatesInviteAndNotifyFoldersPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/EmailTemplatesInviteAndNotifyFoldersPatch.java new file mode 100755 index 0000000000..fd5860bc23 --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/impl/EmailTemplatesInviteAndNotifyFoldersPatch.java @@ -0,0 +1,294 @@ +/* +* Copyright (C) 2005-2010 Alfresco Software Limited. +* +* This file is part of Alfresco +* +* Alfresco is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* Alfresco is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with Alfresco. If not, see . +*/ + +package org.alfresco.repo.admin.patch.impl; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.model.ApplicationModel; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.importer.ImporterBootstrap; +import org.alfresco.service.cmr.admin.PatchException; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.QName; +import org.springframework.context.MessageSource; + +/** + * Ensures that the invite email templates and notify email templates folders are present. + *

+ * This uses the bootstrap importer to get the paths to look for. If not present, + * the required structures are created. + *

+ * + * @author valerysh + * + */ +public class EmailTemplatesInviteAndNotifyFoldersPatch extends AbstractPatch { + + public static final String PROPERTY_COMPANY_HOME_CHILDNAME = "spaces.company_home.childname"; + public static final String PROPERTY_DICTIONARY_CHILDNAME = "spaces.dictionary.childname"; + public static final String PROPERTY_EMAIL_TEMPLATES_FOLDER_CHILDNAME = "spaces.templates.email.childname"; + public static final String PROPERTY_EMAIL_NOTIFY_TEMPLATES_FOLDER_CHILDNAME = "spaces.templates.email.notify.childname"; + public static final String PROPERTY_EMAIL_INVITE_TEMPLATES_FOLDER_CHILDNAME = "spaces.templates.email.invite1.childname"; + private static final String PROPERTY_EMAIL_NOTIFY_TEMPLATES_FOLDER_NAME = "spaces.notify_templates.email.name"; + private static final String PROPERTY_EMAIL_NOTIFY_TEMPLATES_FOLDER_DESCRIPTION = "spaces.notify_templates.email.description"; + private static final String PROPERTY_EMAIL_INVITE_TEMPLATES_FOLDER_NAME = "spaces.invite_templates.email.name"; + private static final String PROPERTY_EMAIL_INVITE_TEMPLATES_FOLDER_DESCRIPTION = "spaces.invite_templates.email.description"; + + private static final String NOTIFY_TEMPLATE_NAME = "notify_user_email.ftl"; + private static final String INVITE_TEMPLATE_NAME = "invite_user_email.ftl"; + + private static final String MSG_EMAIL_INVITE_TEMPLATES_FOLDER_EXISTS = "patch.emailInviteTemplatesFolder.result.exists"; + private static final String MSG_EMAIL_INVITE_TEMPLATES_FOLDER_CREATED = "patch.emailInviteTemplatesFolder.result.created"; + private static final String MSG_EMAIL_NOTIFY_TEMPLATES_FOLDER_EXISTS = "patch.emailNotifyTemplatesFolder.result.exists"; + private static final String MSG_EMAIL_NOTIFY_TEMPLATES_FOLDER_CREATED = "patch.emailNotifyTemplatesFolder.result.created"; + + private static final String PROPERTY_ICON = "space-icon-default"; + + private ImporterBootstrap importerBootstrap; + private MessageSource messageSource; + + protected NodeRef emailNotifyTemplatesFolderNodeRef; + protected NodeRef emailInviteTemplatesFolderNodeRef; + + protected Properties configuration; + protected NodeRef emailTemplatesFolderNodeRef; + + private String emaiemailTemplatesFolderXPath; + + public void setImporterBootstrap(ImporterBootstrap importerBootstrap) + { + this.importerBootstrap = importerBootstrap; + } + + public void setMessageSource(MessageSource messageSource) + { + this.messageSource = messageSource; + } + + /** + * Ensure that required common properties have been set + */ + protected void checkCommonProperties() throws Exception + { + checkPropertyNotNull(importerBootstrap, "importerBootstrap"); + checkPropertyNotNull(messageSource, "messageSource"); + } + + /** + * Extracts pertinent references and properties that are common to execution + * of this and derived patches. + */ + protected void setUp() throws Exception + { + // get the node store that we must work against + StoreRef storeRef = importerBootstrap.getStoreRef(); + if (storeRef == null) + { + throw new PatchException("Bootstrap store has not been set"); + } + NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef); + + this.configuration = importerBootstrap.getConfiguration(); + + // get the association names that form the path + String companyHomeChildName = configuration.getProperty(PROPERTY_COMPANY_HOME_CHILDNAME); + if (companyHomeChildName == null || companyHomeChildName.length() == 0) + { + throw new PatchException("Bootstrap property '" + PROPERTY_COMPANY_HOME_CHILDNAME + "' is not present"); + } + String dictionaryChildName = configuration.getProperty(PROPERTY_DICTIONARY_CHILDNAME); + if (dictionaryChildName == null || dictionaryChildName.length() == 0) + { + throw new PatchException("Bootstrap property '" + PROPERTY_DICTIONARY_CHILDNAME + "' is not present"); + } + String emailTemplatesChildName = configuration.getProperty(PROPERTY_EMAIL_TEMPLATES_FOLDER_CHILDNAME); + if (emailTemplatesChildName == null || emailTemplatesChildName.length() == 0) + { + throw new PatchException("Bootstrap property '" + PROPERTY_EMAIL_TEMPLATES_FOLDER_CHILDNAME + "' is not present"); + } + + String emailNotifyTemplatesChildName = configuration.getProperty(PROPERTY_EMAIL_NOTIFY_TEMPLATES_FOLDER_CHILDNAME); + if (emailNotifyTemplatesChildName == null || emailNotifyTemplatesChildName.length() == 0) + { + throw new PatchException("Bootstrap property '" + PROPERTY_EMAIL_NOTIFY_TEMPLATES_FOLDER_CHILDNAME + "' is not present"); + } + + String emailInviteTemplatesChildName = configuration.getProperty(PROPERTY_EMAIL_INVITE_TEMPLATES_FOLDER_CHILDNAME); + if (emailInviteTemplatesChildName == null || emailInviteTemplatesChildName.length() == 0) + { + throw new PatchException("Bootstrap property '" + PROPERTY_EMAIL_INVITE_TEMPLATES_FOLDER_CHILDNAME + "' is not present"); + } + + StringBuilder sb = new StringBuilder(); + sb.append("/").append(companyHomeChildName) + .append("/").append(dictionaryChildName) + .append("/").append(emailTemplatesChildName); + emaiemailTemplatesFolderXPath = sb.toString(); + + // get the email templates node + List nodeRefs = searchService.selectNodes(storeRootNodeRef, emaiemailTemplatesFolderXPath, null, namespaceService, false); + if (nodeRefs.size() == 0) + { + throw new PatchException("XPath didn't return any results: \n" + + " root: " + storeRootNodeRef + "\n" + + " xpath: " + emaiemailTemplatesFolderXPath); + } + else if (nodeRefs.size() > 1) + { + throw new PatchException("XPath returned too many results: \n" + + " root: " + storeRootNodeRef + "\n" + + " xpath: " + emaiemailTemplatesFolderXPath + "\n" + + " results: " + nodeRefs); + } + this.emailTemplatesFolderNodeRef = nodeRefs.get(0); + + emailNotifyTemplatesFolderNodeRef = searchFolder(emailNotifyTemplatesChildName); + emailInviteTemplatesFolderNodeRef = searchFolder(emailInviteTemplatesChildName); + } + + @Override + protected String applyInternal() throws Exception + { + // common properties must be set before we can continue + checkCommonProperties(); + if (messageSource == null) + { + throw new PatchException("'messageSource' property has not been set"); + } + + setUp(); + + // create the folder if needed - output a message to describe the result + StringBuffer msg = new StringBuffer(); + if (emailNotifyTemplatesFolderNodeRef == null) + { + emailNotifyTemplatesFolderNodeRef = createFolderAndMoveTemplate(PROPERTY_EMAIL_NOTIFY_TEMPLATES_FOLDER_CHILDNAME, + PROPERTY_EMAIL_NOTIFY_TEMPLATES_FOLDER_NAME, + PROPERTY_EMAIL_NOTIFY_TEMPLATES_FOLDER_DESCRIPTION, + NOTIFY_TEMPLATE_NAME); + msg.append(I18NUtil.getMessage(MSG_EMAIL_NOTIFY_TEMPLATES_FOLDER_CREATED, emailNotifyTemplatesFolderNodeRef)); + } + else + { + msg.append(I18NUtil.getMessage(MSG_EMAIL_NOTIFY_TEMPLATES_FOLDER_EXISTS, emailNotifyTemplatesFolderNodeRef)); + } + msg.append("; "); + if (emailInviteTemplatesFolderNodeRef == null) + { + emailInviteTemplatesFolderNodeRef = createFolderAndMoveTemplate(PROPERTY_EMAIL_INVITE_TEMPLATES_FOLDER_CHILDNAME, + PROPERTY_EMAIL_INVITE_TEMPLATES_FOLDER_NAME, + PROPERTY_EMAIL_INVITE_TEMPLATES_FOLDER_DESCRIPTION, + INVITE_TEMPLATE_NAME); + msg.append(I18NUtil.getMessage(MSG_EMAIL_INVITE_TEMPLATES_FOLDER_CREATED, emailNotifyTemplatesFolderNodeRef)); + } + else + { + msg.append(I18NUtil.getMessage(MSG_EMAIL_INVITE_TEMPLATES_FOLDER_EXISTS, emailNotifyTemplatesFolderNodeRef)); + } + + return msg.toString(); + } + + private NodeRef searchFolder(String xpath) + { + List nodeRefs = searchService.selectNodes(emailTemplatesFolderNodeRef, xpath, null, namespaceService, false); + if (nodeRefs.size() > 1) + { + throw new PatchException("XPath returned too many results: \n" + + " email templates node: " + emailTemplatesFolderNodeRef + "\n" + + " xpath: " + xpath + "\n" + + " results: " + nodeRefs); + } + else if (nodeRefs.size() == 0) + { + // the node does not exist + return null; + } + else + { + return nodeRefs.get(0); + } + } + + private NodeRef createFolderAndMoveTemplate(String folderChildName, String folderName, String folderDescription, String templateName) + { + // get required properties + String emailTemplatesChildName = configuration.getProperty(folderChildName); + if (emailTemplatesChildName == null) + { + throw new PatchException("Bootstrap property '" + folderChildName + "' is not present"); + } + + String emailTemplatesName = messageSource.getMessage( + folderName, + null, + I18NUtil.getLocale()); + if (emailTemplatesName == null || emailTemplatesName.length() == 0) + { + throw new PatchException("Bootstrap property '" + folderName + "' is not present"); + } + + String emailTemplatesDescription = messageSource.getMessage( + folderDescription, + null, + I18NUtil.getLocale()); + if (emailTemplatesDescription == null || emailTemplatesDescription.length() == 0) + { + throw new PatchException("Bootstrap property '" + folderDescription + "' is not present"); + } + + Map properties = new HashMap(7); + properties.put(ContentModel.PROP_NAME, emailTemplatesName); + properties.put(ContentModel.PROP_TITLE, emailTemplatesName); + properties.put(ContentModel.PROP_DESCRIPTION, emailTemplatesDescription); + properties.put(ApplicationModel.PROP_ICON, PROPERTY_ICON); + + // create the node + ChildAssociationRef childAssocRef = nodeService.createNode( + emailTemplatesFolderNodeRef, + ContentModel.ASSOC_CONTAINS, + QName.resolveToQName(namespaceService, emailTemplatesChildName), + ContentModel.TYPE_FOLDER, + properties); + NodeRef createdFolderNodeRef = childAssocRef.getChildRef(); + + // add the required aspects + nodeService.addAspect(createdFolderNodeRef, ApplicationModel.ASPECT_UIFACETS, null); + + //move template + String xpath = emaiemailTemplatesFolderXPath + "/cm:" + templateName; + List templateNodeRef = searchService.selectNodes(emailTemplatesFolderNodeRef, xpath, null, namespaceService, false); + if (templateNodeRef != null) + { + nodeService.moveNode(templateNodeRef.get(0), createdFolderNodeRef, ContentModel.ASSOC_CHILDREN, + nodeService.getPrimaryParent(templateNodeRef.get(0)).getQName()); + } + + return createdFolderNodeRef; + } +} diff --git a/source/java/org/alfresco/repo/invitation/InvitationServiceImpl.java b/source/java/org/alfresco/repo/invitation/InvitationServiceImpl.java index 7770a6177c..5e4b669085 100644 --- a/source/java/org/alfresco/repo/invitation/InvitationServiceImpl.java +++ b/source/java/org/alfresco/repo/invitation/InvitationServiceImpl.java @@ -1098,6 +1098,7 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli // get the inviter user name (the name of user web script is executed // under) String inviterUserName = this.authenticationService.getCurrentUserName(); + boolean created = false; checkManagerRole(inviterUserName, resourceType, siteShortName); @@ -1164,10 +1165,16 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli if (inviteeUserName == null) { + // This shouldn't normally happen. Due to the fix for ETHREEOH-3268, the link to invite external users + // should be disabled when the authentication chain does not allow it. + if (!authenticationService.isAuthenticationCreationAllowed()) + { + throw new InvitationException("invitation.invite.authentication_chain"); + } // else there are no existing people who have the given invitee // email address so create new person inviteeUserName = createInviteePerson(inviteeFirstName, inviteeLastName, inviteeEmail); - + created = true; if (logger.isDebugEnabled()) { logger.debug("not explictly passed username - created new person, inviteeUserName=" @@ -1211,19 +1218,14 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli // user name, then local reference to invitee password will be "null" // final String initeeUserNameFinal = inviteeUserName; - String inviteePassword = AuthenticationUtil.runAs(new RunAsWork() + + String inviteePassword = created ? AuthenticationUtil.runAs(new RunAsWork() { public String doWork() { - if (!InvitationServiceImpl.this.authenticationService.authenticationExists(initeeUserNameFinal)) - { - if (logger.isDebugEnabled()) - logger.debug("Invitee user account does not exist, creating disabled account."); - return createInviteeDisabledAccount(initeeUserNameFinal); - } - return null; + return createInviteeDisabledAccount(initeeUserNameFinal); } - }, AuthenticationUtil.getSystemUserName()); + }, AuthenticationUtil.getSystemUserName()) : null; // create a ticket for the invite - this is used String inviteTicket = GUID.generate();