mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
Merged HEAD (5.2) to 5.2.N (5.2.1)
126436 jkaabimofrad: Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2) 121917 jkaabimofrad: RA-778: Added support for QuickShare service to email users notifying them that a content has been shared with them. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@126782 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -27,16 +27,23 @@ package org.alfresco.repo.quickshare;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.events.types.ActivityEvent;
|
||||
import org.alfresco.events.types.Event;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.QuickShareModel;
|
||||
import org.alfresco.repo.Client;
|
||||
import org.alfresco.repo.Client.ClientType;
|
||||
import org.alfresco.repo.action.executer.MailActionExecuter;
|
||||
import org.alfresco.repo.copy.CopyBehaviourCallback;
|
||||
import org.alfresco.repo.copy.CopyDetails;
|
||||
import org.alfresco.repo.copy.CopyServicePolicies;
|
||||
@@ -54,8 +61,11 @@ import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.repo.tenant.TenantUtil;
|
||||
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
|
||||
import org.alfresco.repo.thumbnail.ThumbnailDefinition;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.preference.PreferenceService;
|
||||
import org.alfresco.service.cmr.quickshare.InvalidSharedIdException;
|
||||
import org.alfresco.service.cmr.quickshare.QuickShareDTO;
|
||||
import org.alfresco.service.cmr.quickshare.QuickShareDisabledException;
|
||||
@@ -73,11 +83,16 @@ import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.EqualsHelper;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.safehaus.uuid.UUID;
|
||||
import org.safehaus.uuid.UUIDGenerator;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* QuickShare Service implementation.
|
||||
@@ -85,16 +100,20 @@ import org.safehaus.uuid.UUIDGenerator;
|
||||
* In addition to the quick share service, this class also provides a BeforeDeleteNodePolicy and
|
||||
* OnCopyNodePolicy for content with the QuickShare aspect.
|
||||
*
|
||||
* @author Alex Miller, janv
|
||||
* @author Alex Miller, janv, Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class QuickShareServiceImpl implements QuickShareService, NodeServicePolicies.BeforeDeleteNodePolicy, CopyServicePolicies.OnCopyNodePolicy
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(QuickShareServiceImpl.class);
|
||||
|
||||
static final String ATTR_KEY_SHAREDIDS_ROOT = ".sharedIds";
|
||||
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
private static final String FTL_SHARED_NODE_URL = "shared_node_url";
|
||||
private static final String FTL_SHARED_NODE_NAME = "shared_node_name";
|
||||
private static final String FTL_SENDER_MESSAGE = "sender_message";
|
||||
private static final String FTL_SENDER_FIRST_NAME = "sender_first_name";
|
||||
private static final String FTL_SENDER_LAST_NAME = "sender_last_name";
|
||||
private static final String DEFAULT_EMAIL_SUBJECT = "quickshare.notifier.email.subject";
|
||||
|
||||
private AttributeService attributeService;
|
||||
private DictionaryService dictionaryService;
|
||||
@@ -105,28 +124,15 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
|
||||
private TenantService tenantService;
|
||||
private ThumbnailService thumbnailService;
|
||||
private EventPublisher eventPublisher;
|
||||
|
||||
private ActionService actionService;
|
||||
private PreferenceService preferenceService;
|
||||
/** Component to determine which behaviours are active and which not */
|
||||
private BehaviourFilter behaviourFilter;
|
||||
|
||||
/**
|
||||
* Spring configuration
|
||||
*
|
||||
* @param behaviourFilter the behaviourFilter to set
|
||||
*/
|
||||
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
|
||||
{
|
||||
this.behaviourFilter = behaviourFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable this service.
|
||||
*/
|
||||
public void setEnabled(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
|
||||
private boolean enabled;
|
||||
private String defaultEmailSender;
|
||||
private Map<String, String> templateRegistry;
|
||||
|
||||
/**
|
||||
* Set the attribute service
|
||||
*/
|
||||
@@ -198,12 +204,82 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
|
||||
{
|
||||
this.eventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the actionService
|
||||
*/
|
||||
public void setActionService(ActionService actionService)
|
||||
{
|
||||
this.actionService = actionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the preferenceService
|
||||
*/
|
||||
public void setPreferenceService(PreferenceService preferenceService)
|
||||
{
|
||||
this.preferenceService = preferenceService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring configuration
|
||||
*
|
||||
* @param behaviourFilter the behaviourFilter to set
|
||||
*/
|
||||
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
|
||||
{
|
||||
this.behaviourFilter = behaviourFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable this service.
|
||||
*/
|
||||
public void setEnabled(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default email sender
|
||||
*/
|
||||
public void setDefaultEmailSender(String defaultEmailSender)
|
||||
{
|
||||
this.defaultEmailSender = defaultEmailSender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the templates
|
||||
*/
|
||||
public void setTemplateRegistry(Map<String, String> templateRegistry)
|
||||
{
|
||||
this.templateRegistry = templateRegistry;
|
||||
}
|
||||
|
||||
private void checkMandatoryProperties()
|
||||
{
|
||||
PropertyCheck.mandatory(this, "attributeService", attributeService);
|
||||
PropertyCheck.mandatory(this, "dictionaryService", dictionaryService);
|
||||
PropertyCheck.mandatory(this, "nodeService", nodeService);
|
||||
PropertyCheck.mandatory(this, "permissionService", permissionService);
|
||||
PropertyCheck.mandatory(this, "personService", personService);
|
||||
PropertyCheck.mandatory(this, "policyComponent", policyComponent);
|
||||
PropertyCheck.mandatory(this, "tenantService", tenantService);
|
||||
PropertyCheck.mandatory(this, "thumbnailService", thumbnailService);
|
||||
PropertyCheck.mandatory(this, "eventPublisher", eventPublisher);
|
||||
PropertyCheck.mandatory(this, "actionService", actionService);
|
||||
PropertyCheck.mandatory(this, "preferenceService", preferenceService);
|
||||
PropertyCheck.mandatory(this, "behaviourFilter", behaviourFilter);
|
||||
PropertyCheck.mandatory(this, "defaultEmailSender", defaultEmailSender);
|
||||
PropertyCheck.mandatory(this, "templateRegistry", templateRegistry);
|
||||
}
|
||||
|
||||
/**
|
||||
* The initialise method. Register our policies.
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
checkMandatoryProperties();
|
||||
|
||||
// Register interest in the beforeDeleteNode policy - note: currently for content only !!
|
||||
policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
|
||||
@@ -321,7 +397,7 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
|
||||
@Override
|
||||
public Map<String, Object> getMetaData(NodeRef nodeRef)
|
||||
{
|
||||
// TODO This functionality MUST be available when quickshare is also disabled, therefor refactor it out from the quickshare package to a more common package.
|
||||
// TODO This functionality MUST be available when quickshare is also disabled, therefor refactor it out from the quickshare package to a more common package.
|
||||
|
||||
Map<QName, Serializable> nodeProps = nodeService.getProperties(nodeRef);
|
||||
ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
|
||||
@@ -404,9 +480,9 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
|
||||
}
|
||||
else
|
||||
{
|
||||
QName type = nodeService.getType(nodeRef);
|
||||
boolean sharable = isSharable(type);
|
||||
metadata.put("sharable", sharable);
|
||||
QName type = nodeService.getType(nodeRef);
|
||||
boolean sharable = isSharable(type);
|
||||
metadata.put("sharable", sharable);
|
||||
}
|
||||
|
||||
Map<String, Object> model = new HashMap<String, Object>(2);
|
||||
@@ -439,8 +515,8 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
|
||||
@Override
|
||||
public Map<String, Object> getMetaData(String sharedId)
|
||||
{
|
||||
checkEnabled();
|
||||
|
||||
checkEnabled();
|
||||
|
||||
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(sharedId);
|
||||
final String tenantDomain = pair.getFirst();
|
||||
final NodeRef nodeRef = pair.getSecond();
|
||||
@@ -483,24 +559,24 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
|
||||
String sharedId = (String)nodeService.getProperty(beforeDeleteNodeRef, QuickShareModel.PROP_QSHARE_SHAREDID);
|
||||
if (sharedId != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(sharedId);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
final String tenantDomain = pair.getFirst();
|
||||
final NodeRef nodeRef = pair.getSecond();
|
||||
|
||||
// note: deleted nodeRef might not match, eg. for upload new version -> checkin -> delete working copy
|
||||
if (nodeRef.equals(beforeDeleteNodeRef))
|
||||
{
|
||||
removeSharedId(sharedId);
|
||||
}
|
||||
}
|
||||
catch (InvalidSharedIdException ex)
|
||||
{
|
||||
logger.warn("Couldn't find shareId, " + sharedId + ", attributes for node " + beforeDeleteNodeRef);
|
||||
}
|
||||
try
|
||||
{
|
||||
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(sharedId);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
final String tenantDomain = pair.getFirst();
|
||||
final NodeRef nodeRef = pair.getSecond();
|
||||
|
||||
// note: deleted nodeRef might not match, eg. for upload new version -> checkin -> delete working copy
|
||||
if (nodeRef.equals(beforeDeleteNodeRef))
|
||||
{
|
||||
removeSharedId(sharedId);
|
||||
}
|
||||
}
|
||||
catch (InvalidSharedIdException ex)
|
||||
{
|
||||
logger.warn("Couldn't find shareId, " + sharedId + ", attributes for node " + beforeDeleteNodeRef);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -569,7 +645,7 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
|
||||
|
||||
private boolean isSharable(QName type)
|
||||
{
|
||||
return type.equals(ContentModel.TYPE_CONTENT) || dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT);
|
||||
return type.equals(ContentModel.TYPE_CONTENT) || dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT);
|
||||
}
|
||||
// Prevent copying of Quick share properties on node copy.
|
||||
@Override
|
||||
@@ -603,4 +679,263 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEmailNotification(final QuickShareEmailRequest emailRequest)
|
||||
{
|
||||
ParameterCheck.mandatory("emailRequest", emailRequest);
|
||||
emailRequest.validate();
|
||||
|
||||
if (!templateRegistry.containsKey(emailRequest.getTemplateId()))
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Invalid template. Couldn't find a template with id:" + emailRequest.getTemplateId());
|
||||
}
|
||||
|
||||
// Set the details of the person sending the email
|
||||
final String authenticatedUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
final NodeRef senderNodeRef = personService.getPerson(authenticatedUser, false);
|
||||
final Map<QName, Serializable> senderProps = nodeService.getProperties(senderNodeRef);
|
||||
final String senderFirstName = (String) senderProps.get(ContentModel.PROP_FIRSTNAME);
|
||||
final String senderLastName = (String) senderProps.get(ContentModel.PROP_LASTNAME);
|
||||
final String senderEmail = (String) senderProps.get(ContentModel.PROP_EMAIL);
|
||||
final String senderFullName = ((senderFirstName != null ? senderFirstName + " " : "") + (senderLastName != null ? senderLastName : "")).trim();
|
||||
|
||||
// Set the default model information
|
||||
Map<String, Serializable> templateModel = new HashMap<>(5);
|
||||
templateModel.put(FTL_SENDER_FIRST_NAME, senderFirstName);
|
||||
templateModel.put(FTL_SENDER_LAST_NAME, senderLastName);
|
||||
templateModel.put(FTL_SHARED_NODE_URL, emailRequest.getSharedNodeURL());
|
||||
templateModel.put(FTL_SHARED_NODE_NAME, emailRequest.getSharedNodeName());
|
||||
templateModel.put(FTL_SENDER_MESSAGE, emailRequest.getSenderMessage());
|
||||
|
||||
// Email sender
|
||||
// By default the current-user's email address will not be used to send this mail.
|
||||
// However, current-user's first and lastname will be used as the personal name.
|
||||
final String from = (!emailRequest.isSendFromDefaultEmail() && senderEmail != null) ? senderEmail : this.defaultEmailSender;
|
||||
|
||||
// Set the email details
|
||||
Map<String, Serializable> actionParams = new HashMap<>();
|
||||
actionParams.put(MailActionExecuter.PARAM_FROM, from);
|
||||
actionParams.put(MailActionExecuter.PARAM_FROM_PERSONAL_NAME, senderFullName);
|
||||
actionParams.put(MailActionExecuter.PARAM_SUBJECT, DEFAULT_EMAIL_SUBJECT);
|
||||
actionParams.put(MailActionExecuter.PARAM_SUBJECT_PARAMS, new Object[] { senderFirstName, senderLastName, emailRequest.getSharedNodeName() });
|
||||
actionParams.put(MailActionExecuter.PARAM_IGNORE_SEND_FAILURE, emailRequest.isIgnoreSendFailure());
|
||||
// Pick the template
|
||||
actionParams.put(MailActionExecuter.PARAM_TEMPLATE, templateRegistry.get(emailRequest.getTemplateId()));
|
||||
actionParams.put(MailActionExecuter.PARAM_TEMPLATE_MODEL, (Serializable) templateModel);
|
||||
actionParams.put(MailActionExecuter.PARAM_LOCALE, getDefaultIfNull(getEmailCreatorLocale(authenticatedUser), emailRequest.getLocale()));
|
||||
|
||||
for (String to : emailRequest.getToEmails())
|
||||
{
|
||||
Map<String, Serializable> params = new HashMap<>(actionParams);
|
||||
params.put(MailActionExecuter.PARAM_TO, to);
|
||||
Action mailAction = actionService.createAction(MailActionExecuter.NAME, params);
|
||||
actionService.executeAction(mailAction, null, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T getDefaultIfNull(T defaultValue, T newValue)
|
||||
{
|
||||
return (newValue == null) ? defaultValue : newValue;
|
||||
}
|
||||
|
||||
private Locale getEmailCreatorLocale(String userId)
|
||||
{
|
||||
String localeString = (String) preferenceService.getPreference(userId, "locale");
|
||||
return I18NUtil.parseLocale(localeString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an email request to send a quick share link.
|
||||
*/
|
||||
public static class QuickShareEmailRequest
|
||||
{
|
||||
/**
|
||||
* Whether to send an email from the default email address or use the current-user's email (if not null).
|
||||
* The default is true.
|
||||
*/
|
||||
private boolean sendFromDefaultEmail = true;
|
||||
|
||||
/**
|
||||
* Optional Locale for subject and body text
|
||||
*/
|
||||
private Locale locale;
|
||||
|
||||
/**
|
||||
* The email addresses (1 or many) of the recipients.
|
||||
*/
|
||||
private Set<String> toEmails;
|
||||
|
||||
/**
|
||||
* The template id. If not provided, a default template will be used.
|
||||
*/
|
||||
private String templateId = "default";
|
||||
|
||||
/**
|
||||
* The shared content URL.
|
||||
*/
|
||||
private String sharedNodeURL;
|
||||
|
||||
/**
|
||||
* The shared content name.
|
||||
*/
|
||||
private String sharedNodeName;
|
||||
/**
|
||||
* Optional message from the sender.
|
||||
*/
|
||||
private String senderMessage;
|
||||
|
||||
/**
|
||||
* Whether to ignore throwing exception or not. The default is false.
|
||||
*/
|
||||
private boolean ignoreSendFailure = false;
|
||||
|
||||
public void validate()
|
||||
{
|
||||
ParameterCheck.mandatoryCollection("toEmails", toEmails);
|
||||
ParameterCheck.mandatoryString("templateId", templateId);
|
||||
ParameterCheck.mandatoryString("sharedNodeURL", sharedNodeURL);
|
||||
ParameterCheck.mandatoryString("sharedNodeName", sharedNodeName);
|
||||
ParameterCheck.mandatoryString("senderMessage", senderMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#sendFromDefaultEmail}
|
||||
*/
|
||||
public boolean isSendFromDefaultEmail()
|
||||
{
|
||||
return sendFromDefaultEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#sendFromDefaultEmail}
|
||||
*/
|
||||
public void setSendFromDefaultEmail(Boolean sendFromDefaultEmail)
|
||||
{
|
||||
if (sendFromDefaultEmail != null)
|
||||
{
|
||||
this.sendFromDefaultEmail = sendFromDefaultEmail;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#locale}
|
||||
*/
|
||||
public Locale getLocale()
|
||||
{
|
||||
return this.locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#locale}
|
||||
*/
|
||||
public void setLocale(Locale locale)
|
||||
{
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#toEmails}
|
||||
*/
|
||||
public Set<String> getToEmails()
|
||||
{
|
||||
return this.toEmails;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#toEmails}
|
||||
*/
|
||||
public void setToEmails(Collection<String> toEmails)
|
||||
{
|
||||
if (toEmails != null)
|
||||
{
|
||||
this.toEmails = Collections.unmodifiableSet(new HashSet<>(toEmails));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#templateId}
|
||||
*/
|
||||
public String getTemplateId()
|
||||
{
|
||||
return templateId;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#templateId}
|
||||
*/
|
||||
public void setTemplateId(String templateId)
|
||||
{
|
||||
if (templateId != null)
|
||||
{
|
||||
this.templateId = templateId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#sharedNodeURL}
|
||||
*/
|
||||
public String getSharedNodeURL()
|
||||
{
|
||||
return sharedNodeURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#sharedNodeURL}
|
||||
*/
|
||||
public void setSharedNodeURL(String sharedNodeURL)
|
||||
{
|
||||
this.sharedNodeURL = sharedNodeURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#sharedNodeName}
|
||||
*/
|
||||
public String getSharedNodeName()
|
||||
{
|
||||
return sharedNodeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#sharedNodeName}
|
||||
*/
|
||||
public void setSharedNodeName(String sharedNodeName)
|
||||
{
|
||||
this.sharedNodeName = sharedNodeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#senderMessage}
|
||||
*/
|
||||
public String getSenderMessage()
|
||||
{
|
||||
return senderMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#senderMessage}
|
||||
*/
|
||||
public void setSenderMessage(String senderMessage)
|
||||
{
|
||||
this.senderMessage = senderMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#ignoreSendFailure}
|
||||
*/
|
||||
public boolean isIgnoreSendFailure()
|
||||
{
|
||||
return ignoreSendFailure;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link QuickShareEmailRequest#ignoreSendFailure}
|
||||
*/
|
||||
public void setIgnoreSendFailure(Boolean ignoreSendFailure)
|
||||
{
|
||||
if (ignoreSendFailure != null)
|
||||
{
|
||||
this.ignoreSendFailure = ignoreSendFailure;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user