Would you please help me with implementing the solution where you derive from XPObjectSpaceProviderThreadSafe?
I already implemented my own XPObjectSpaceProviderThreadSafe and everything works in that class but I don't know how to handle the property change properly in order to not get the validation exception.
This is how my property looks like (nothing special there):
public class Auditing
{
[Persistent("AuditingState")]
public AuditingState AuditingState
{
get
{
return _AuditingState;
}
set
{
SetPropertyValue("AuditingState", ref _AuditingState, value);
}
}
AuditingState _AuditingState = null;
}
Lets just say that AuditingState has a property called IsProtected, and if IsProtected is true then the user has no write permission for the Auditing. What do I have to do in order to not get the validation exception but still be able to see the property change in the LookupPropertyEditor so that the whole issue is transparent for the user?
I created a sample project to demonstrate my setup.
We are working on your issue and will answer you as soon as possible. We apologize for the delay.
Hi Bernd.
I have reviewed your project, but it is still unclear what scenario you are trying to implement. Please describe the scenario that leads to a security validation error you wish to avoid.
The scenario is as follows:
That means that he cannot save the Auditing if he sets the State reference to the "closed" state (which is created in the Updater and has IsProtected = true).
So in order to get the validation exception please log in with the user TestUser. Then create an Auditing object and set the State to "closed". Then press save.
>>>he cannot save the Auditing if he sets the State reference to the "closed" state
It seems that such a security rule makes no sense. If a user should be able to change this property, you must grant the write permission for this property to him. For example:
SecuritySystemTypePermissionObject permission1 = GetTypePermission(typeof(BusinessObjects.Auditing), true, true, true, true, false); permission1.ObjectPermissions.Add(GetObjectPermission("Not(AuditingState.IsProtected)", false, false, false, false, true)); SecuritySystemMemberPermissionsObject memberPermission = ObjectSpace.CreateObject<SecuritySystemMemberPermissionsObject>(); memberPermission.AllowWrite = true; memberPermission.Members = "AuditingState"; permission1.MemberPermissions.Add(memberPermission);
Well the real business case is the following:
Objects of type Auditing can be created and modified by the user UNTIL they are set to the closed state. That means the object is ARCHIVED and can no longer be changed, not even the State.
Imagine something like a juristic case or something along the line. When it is closed it is closed and noone may alter it in any way. But in order to close the case the user has to be able to close it in the first place. This is my problem.
I learned that this is not possible with the integrated security. Now there are two possiblities:
At the end of that thread I asked help for the implementation and this thread here was created…
I thought the second way would be the better one because then the security would reflect the business case and I could really work with the security in the code. Can you help me with the implementation or do you have another suggestion?
Thank you for the clarification. We are looking for a solution and will get back once we get any result.
Hi Bernd.
We have researched your scenario and concluded that it cannot be implemented as is with the current implementation of the security system. We will take it into account when implementing the Security - Provide an easy way to create additional objects or modify protected properties in code (preferably within the same transaction) request. Currently, you can switch the Auditing object to the "closed" state via an action that modifies the database directly. For example:
public class CloseAuditController : ViewController { public CloseAuditController() { TargetObjectType = typeof(Auditing); SimpleAction action = new SimpleAction(this, "CloseAudit", PredefinedCategory.Edit); action.SelectionDependencyType = SelectionDependencyType.RequireMultipleObjects; action.Execute += action_Execute; } void action_Execute(object sender, SimpleActionExecuteEventArgs e) { ObjectSpace.CommitChanges(); XPObjectSpaceProvider provider = new XPObjectSpaceProvider(Application.ConnectionString, null); using (IObjectSpace os = provider.CreateObjectSpace()) { AuditingState closedState = os.FindObject<AuditingState>(CriteriaOperator.Parse("IsProtected")); if (closedState == null) return; foreach (Auditing obj in e.SelectedObjects) { Auditing auditing = os.GetObject<Auditing>(obj); auditing.AuditingState = closedState; } os.CommitChanges(); } //ObjectSpace.Refresh(); View.Close(); } }
I implemented the action in the way you proposed and it solved the issue. Thank you for your help!
You are welcome, Bernd.