using System;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
namespace PracticeGateway.Plugin
{
public class DisassociateEntitiesPostOperationUpdate : PluginBase
{
public DisassociateEntitiesPostOperationUpdate(string unsecure, string secure)
: base(typeof(DisassociateEntitiesPostOperationUpdate))
{
}
protected override void ExecuteCdsPlugin(ILocalPluginContext localContext)
{
if (localContext == null)
throw new InvalidPluginExecutionException(nameof(localContext));
ITracingService tracingService = localContext.TracingService;
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService currentUserService = localContext.CurrentUserService;
try
{
tracingService.Trace("=== Starting DisassociateEntitiesPostOperationUpdate ===");
if (context.MessageName != "Disassociate")
throw new InvalidPluginExecutionException($"Unexpected message: {context.MessageName}");
Utils.Utils utils = new Utils.Utils(currentUserService, tracingService);
if (!utils.ValidateContactAssignmentRelationship(context, tracingService, out EntityReference contactRef, out EntityReference assignmentRef))
{
return;
}
Guid contactId = contactRef.Id;
Guid removedAssignmentId = assignmentRef.Id;
tracingService.Trace($"Processing disassociation of contact {contactId} from assignment {removedAssignmentId}");
Entity removedAssignment = currentUserService.Retrieve("tt_assignment", removedAssignmentId, new ColumnSet("tt_name"));
string removedAssignmentName = removedAssignment.GetAttributeValue<string>("tt_name");
tracingService.Trace($"Removed assignment name: {removedAssignmentName}");
// Load assignment configuration from JSON
var config = utils.GetAssignmentConfiguration(currentUserService, tracingService);
if (config == null || !config.ContainsKey(removedAssignmentName))
{
tracingService.Trace($"No configuration found for assignment '{removedAssignmentName}'");
return;
}
// Get web roles associated with the removed assignment
List<string> removedRoles = utils.GetWebRolesForAssignment(config, removedAssignmentName, tracingService);
if (removedRoles.Count == 0)
{
tracingService.Trace($"No web roles configured for removed assignment '{removedAssignmentName}'");
return;
}
// Retrieve remaining assignments for the contact
QueryExpression remainingAssignmentsQuery = new QueryExpression("tt_contact_tt_assignment")
{
ColumnSet = new ColumnSet("tt_assignmentid"),
Criteria = new FilterExpression
{
Conditions = { new ConditionExpression("contactid", ConditionOperator.Equal, contactId) }
}
};
EntityCollection remainingAssignments = currentUserService.RetrieveMultiple(remainingAssignmentsQuery);
tracingService.Trace($"Found {remainingAssignments.Entities.Count} remaining assignments for contact.");
// Build a set of web roles that should be kept
HashSet<string> rolesToKeep = new HashSet<string>();
foreach (var assignmentEntity in remainingAssignments.Entities)
{
Guid assignmentId = assignmentEntity.GetAttributeValue<Guid>("tt_assignmentid");
Entity assignment = currentUserService.Retrieve("tt_assignment", assignmentId, new ColumnSet("tt_name"));
string assignmentName = assignment.GetAttributeValue<string>("tt_name");
// Get web roles for each remaining assignment
List<string> roles = utils.GetWebRolesForAssignment(config, assignmentName, tracingService);
foreach (var role in roles)
{
rolesToKeep.Add(role);
}
}
// Remove web roles that are no longer needed
foreach (string roleName in removedRoles)
{
if (rolesToKeep.Contains(roleName))
{
tracingService.Trace($"Web role '{roleName}' is still required by another assignment. Skipping disassociation.");
continue;
}
Entity webRole = utils.GetWebRoleByName(currentUserService, roleName);
if (webRole == null)
{
tracingService.Trace($"Web role '{roleName}' not found.");
continue;
}
currentUserService.Disassociate(
"contact",
contactId,
new Relationship("adx_webrole_contact"),
new EntityReferenceCollection { new EntityReference("adx_webrole", webRole.Id) }
);
tracingService.Trace($"Successfully disassociated contact from web role '{roleName}'.");
}
tracingService.Trace("=== Finished DisassociateEntitiesPostOperationUpdate ===");
}
catch (Exception ex)
{
tracingService.Trace($"Error in DisassociateEntitiesPostOperationUpdate: {ex}");
throw new InvalidPluginExecutionException("Plugin execution failed.", ex);
}
}
}
}