This post will explain how you can implement a plug-in that will allow the
normal users without prvDeleteActivity (Delete
privilege for the Activity table) to
- end a recurring appointment series, update recurrence information, or
- convert an existing appointment to a recurring appointment.
In most of the Dynamics 365/Power Apps + Dataverse implementations, it is a
common practice not to give the Delete privilege to the normal user
security role to prevent users from accidentally deleting data. Leaving
the Delete privilege empty for all tables works fine for
most of the actions, but some out-of-the-box actions require
the Delete privilege to be successfully performed.
Problem Statement
If the user wants to
end a recurring appointment series
before the original end date specified during the creation of the series, the
user can click on the "End Series" button on the recurring appointment
form. That action will call the DeleteOpenInstancesRequest
which deletes all the “open” and “scheduled” future instances of the specified
series from the date specified in the series end date. If the user does not
have the prvDeleteActivity, the user will get the
following Insufficient Permissions error.
You do not have {0} permission to access {1} records. Contact your Microsoft Dynamics 365 administrator for help.
If you decipher the error message by
opening the Network tab in the browser Developer Tools, you will see that the error is due to the current user missing
prvDeleteActivity privilege.
The same error happens when the user tries to convert an existing appointment to a recurring appointment by clicking on the "Recurrence" button on the appointment form. That action will call the
AddRecurrenceRequest which creates a recurring appointment series and deletes the existing single
Appointment. That is why the user will require
the
prvDeleteActivity to delete the existing single Appointment.
Solution
In order to let the user perform those actions without
giving prvDeleteActivity in the user's security role, you
can implement a plug-in to delete the Appointments with an elevated user
account or temporarily assign a security role
with prvDeleteActivity while performing the action.
Solution for Ending a Recurring Appointment Series
The solution for this scenario is simple. The plug-in just needs to retrieve
the appointments with the same SeriesId which are starting on or
after the SeriesEndDate parameter and delete those appointments with
SYSTEM user before the system does. If there is no future appointment
after SeriesEndDate, the system will not try to delete in the
current user's context and it will not show any error due to the lack
of prvDeleteActivity privilege.
The plug-in will only run for RecurringAppointmentMaster table and
the DeleteOpenInstances message. Since the future appointments need
to be deleted before the actual operation, the plug-in will be registered in
the Pre-operation (stage 20). Two main important parameters are
the GUID of the target recurring appointment and the series end date
parameter entered by the user.
DeleteFutureAppointments method will query the appointments with
SeriesId same as the recurring appointment GUID and the
ScheduledStart on or after the SeriesEndDate parameter. Then,
it will loop through each appointment and delete as the SYSTEM user.
Solution for Updating Recurrence Information of the Recurring Appointment
The plug-in for this scenario is also similar to the previous one. The
plug-in needs to be registered for the Update message instead and
delete all the future instances of the original series before the actual
operation.
Solution for Ending a Recurring Appointment Series
The solution for this scenario is a bit more complex than the previous
ones. When the user tries to convert an existing appointment to a
recurring appointment, AddRecurrenceRequest will delete the original
appointment by GUID, so that even if the plug-in delete the appointment in
the Pre-operation with SYSTEM user, the system will throw
the following error because the appointment has already deleted when the
main operation tried to delete the appointment by GUID.
The requested record was not found or you do not have sufficient permissions to view it.
The workaround solution is to share the Delete permission for the
Appointment with the user. However, sharing the permission does not work if
the user has no privilege at any level for the particular action. It will
only work if the user has minimum User level Delete privilege
for the Activity table. So the second step is to temporarily assign
the security role
with User level Delete privilege before
the main operation and remove it afterwards.
The plug-in will run for RecurringAppointmentMaster table
as well and for the AddRecurrence message. The user will be
assigned an elevated security role in
the Pre-validation (stage 10) because making changes to the
security roles of the user after validation
in Pre-operation (stage 20) will not make any changes and
the system will throw the same Insufficient Permissions error.
In Post-operation (stage 40), the security role assigned in
the previous step will be removed.
In the ElevateDeleteAppointmentPermission method, the delete
permission for that particular row is granted to the user first.
Then, check if the user has the delete privilege to the activity at all and
if the user does not any enough privilege, temporarily assign the role with
DeleteActivityRoleName (security role which has User level
Delete privilege for Activity table) in the same
Business Unit as the user.
After the main operation, the plug-in step
in Post-operation (stage 40) will check if the user has a
role with DeleteActivityRoleName (which may be assigned to
the user in Pre-validation step) and remove the role from
the user if there any.
Summary
Some of the actions related to the recurring appointment will require the Delete privilege for the Activity table but if there is a business requirement not to grant the Delete privilege to the normal users, it can still be achieved by implementing the plug-in as above.
In my opinion, such OOB request action as deleting the future appointments in ending a recurring appointment series or deleting the original appointment in conversion to recurring appointment should automatically be handled by the elevated SYSTEM account instead of deleting with the initiating user's context. If you agree with me, please vote on my ideas in
Dynamics 365 Application Ideas or
Power Apps Ideas (or both).
You can download the above sample code snippet from my GitHub repository via
this link.
Comments
Post a Comment