Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/XrmMockupShared/Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ private void InitializeDB()
new CloseIncidentRequestHandler(this, db, metadata, security),
new AddMembersTeamRequestHandler(this, db, metadata, security),
new RemoveMembersTeamRequestHandler(this, db, metadata, security),
new SendEmailRequestHandler(this, db, metadata, security),
#if !(XRM_MOCKUP_2011 || XRM_MOCKUP_2013)
new IsValidStateTransitionRequestHandler(this, db, metadata, security),
new CalculateRollupFieldRequestHandler(this, db, metadata, security),
Expand Down
8 changes: 4 additions & 4 deletions src/XrmMockupShared/Database/DbAttributeTypeMap.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;
using System;
using System.Collections.Generic;
using System.Text;

namespace DG.Tools.XrmMockup.Database
{
Expand All @@ -27,7 +27,7 @@ internal static class DbAttributeTypeHelper
{ AttributeTypeCode.Money, typeof(decimal) },
{ AttributeTypeCode.Owner, typeof(DbRow) },
{ AttributeTypeCode.Customer, typeof(DbRow) },
{ AttributeTypeCode.PartyList, typeof(DbRow[]) },
{ AttributeTypeCode.PartyList, typeof(EntityCollection) },
{ AttributeTypeCode.String, typeof(string) },
{ AttributeTypeCode.Uniqueidentifier, typeof(Guid) },
{ AttributeTypeCode.Virtual, typeof(DbRow[]) }
Expand All @@ -37,7 +37,7 @@ public static bool IsValidType(AttributeMetadata attrMetadata, object value) {
if (value == null) return true;
_metadataTypeMap.TryGetValue(attrMetadata.AttributeType.Value, out Type expectedType);
if (expectedType == null) {
throw new NotImplementedException($"Attribute of type '{attrMetadata.AttributeType.Value}' is not implemeted in XrmMockup yet.");
throw new NotImplementedException($"Attribute of type '{attrMetadata.AttributeType.Value}' is not implemented in XrmMockup yet.");
}
if (expectedType.Name == "DbRow[]" && attrMetadata.AttributeType.Value == AttributeTypeCode.Virtual)
return true;
Expand Down
140 changes: 140 additions & 0 deletions src/XrmMockupShared/Requests/SendEmailRequestHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using DG.Tools.XrmMockup.Database;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using System;
using System.ServiceModel;

namespace DG.Tools.XrmMockup
{
internal class SendEmailRequestHandler : RequestHandler
{
const int EMAIL_STATE_COMPLETED = 1;
const int EMAIL_STATUS_DRAFT = 1;
const int EMAIL_STATUS_PENDING_SEND = 6;
const int EMAIL_STATUS_SENT = 3;

public SendEmailRequestHandler(Core core, XrmDb db, MetadataSkeleton metadata, Security security) : base(core, db, metadata, security, "SendEmail") { }

internal override void CheckSecurity(OrganizationRequest orgRequest, EntityReference userRef)
{
var request = MakeRequest<SendEmailRequest>(orgRequest);
if (request.EmailId == Guid.Empty)
{
throw new FaultException("Required field 'EmailId' is missing");
}

var emailRef = new EntityReference("email", request.EmailId);

if (!security.HasPermission(emailRef, AccessRights.ReadAccess, userRef))
{
throw new FaultException($"Principal user (Id={userRef.Id}) is missing Read privilege for email (Id={emailRef.Id})");
}

if (!security.HasPermission(emailRef, AccessRights.WriteAccess, userRef))
{
throw new FaultException($"Principal user (Id={userRef.Id}) is missing Write privilege for email (Id={emailRef.Id})");
}

var email = db.GetEntityOrNull(emailRef) ?? throw new FaultException($"email with Id = {request.EmailId} does not exist");

if (email.Contains("regardingobjectid"))
{
var regardingObject = email.GetAttributeValue<EntityReference>("regardingobjectid");

if (!security.HasPermission(regardingObject, AccessRights.ReadAccess, userRef))
{
throw new FaultException($"Principal user (Id={userRef.Id}) is missing Read privilege for {regardingObject.LogicalName} (Id={regardingObject.Id})");
}
}

// Remaining security checks have been omitted to reduce complexity
}

internal override OrganizationResponse Execute(OrganizationRequest orgRequest, EntityReference userRef)
{
var request = MakeRequest<SendEmailRequest>(orgRequest);

var email = db.GetEntity(new EntityReference("email", request.EmailId));

if (email.GetAttributeValue<OptionSetValue>("statuscode").Value != EMAIL_STATUS_DRAFT)
{
throw new FaultException("Email must be in Draft status to send");
}

if (email.GetAttributeValue<bool>("directioncode") is false)
{
throw new FaultException("Cannot send incoming email messages");
}

if (email.Contains("from"))
{
var from = email.GetAttributeValue<EntityCollection>("from");
if (from.Entities.Count != 1)
{
throw new FaultException("The email must have one and only one sender");
}

var activityParty = from.Entities[0];
if (activityParty.Contains("partyid"))
{
var partyRef = activityParty.GetAttributeValue<EntityReference>("partyid");
if (db.GetEntityOrNull(partyRef) is null)
{
throw new FaultException($"{partyRef.LogicalName} with Id = {partyRef.Id} does not exist");
}
}
else
{
throw new FaultException("Sender cannot be unresolved");
}
}
else
{
throw new FaultException("The email must have a sender");
}

if (email.Contains("to"))
{
var to = email.GetAttributeValue<EntityCollection>("to");
if (to.Entities.Count is 0)
{
throw new FaultException("The email must have at least one recipient before it can be sent");
}

foreach (Entity activityParty in to.Entities)
{
if (activityParty.Contains("partyid"))
{
var partyRef = activityParty.GetAttributeValue<EntityReference>("partyid");
if (db.GetEntityOrNull(partyRef) is null)
{
throw new FaultException($"{partyRef.LogicalName} with Id = {partyRef.Id} does not exist");
}
}
else if (!activityParty.Contains("addressused"))
{
throw new FaultException("Invalid ActivityParty");
}
}
}
else
{
throw new FaultException("The email must have at least one recipient before it can be sent");
}


email["statecode"] = new OptionSetValue(EMAIL_STATE_COMPLETED);
email["statuscode"] = new OptionSetValue(request.IssueSend ? EMAIL_STATUS_PENDING_SEND : EMAIL_STATUS_SENT);

db.Update(email);

return new SendEmailResponse
{
Results = new ParameterCollection
{
{ "Subject", email.Contains("subject") ? email.GetAttributeValue<string>("subject") : null }
}
};
}
}
}
1 change: 1 addition & 0 deletions src/XrmMockupShared/XrmMockupShared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Database\DbTable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MockupServiceAsync2.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MockupServiceAsync.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Requests\SendEmailRequestHandler.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Serialization\DbDTO.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Serialization\OptionSetCollectionDTO.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Serialization\EntityReferenceDTO.cs" />
Expand Down
1 change: 1 addition & 0 deletions tests/SharedTests/SharedTests.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<Compile Include="$(MSBuildThisFileDirectory)TestCWAAccountOptional.cs" />
<Compile Include="$(MSBuildThisFileDirectory)TestDefaultBusinessUnitTeamsMembers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)TestPriorityAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)TestSendEmail.cs" />
<Compile Include="..\SharedTests\TestZipSnapshot.cs" />
<Compile Include="$(MSBuildThisFileDirectory)TestTableReset.cs" />
<Compile Include="$(MSBuildThisFileDirectory)TestPrivileges\TestPrivilegesAppendToOnUpdate.cs" />
Expand Down
Loading