Skip to content

Commit

Permalink
Merge pull request #234 from delegateas/75_Implement_SendEmailRequest
Browse files Browse the repository at this point in the history
Implemented SendEmailRequestHandler
  • Loading branch information
mkholt authored Sep 10, 2024
2 parents f5715d2 + 42d1260 commit 231deb7
Show file tree
Hide file tree
Showing 6 changed files with 508 additions and 4 deletions.
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

0 comments on commit 231deb7

Please sign in to comment.