Retrieve rules prohibiting management

Background

Weekly, we will ask some users to ask for help, why you canโ€™t do X in form Y. Due to complex business rules, we often have to pay attention to the code itself to find out why this particular action is not available at that time. Are there any proven strategies to solve this problem?

How to collect all the information from the GUI, business rules and / or security, which causes the button to turn off?

Example

The user cannot delete a dimension from the dimension overview form because

GUI

  • there are no dimensions in the form.
  • Several dimensions are selected in the form.

Business rules

  • The selected measurement was used in the calculation.
  • The selected dimension is related to (what we call) the product.

Security

  • The current user is not in the group of analysts responsible for this particular dimension.
  • The current user is not an analyst.

Edit

Regarding valid comments that we have already done the calculation in order to decide whether the control should be disabled.

We use a home brew ACL for security processing. These are the steps to decide whether to disable a control.

  • The global ACL is retrieved (currently from the database). If a Write ACE present in the ACL for the dimension property, this means that the current user has the right to change the dimension.
  • The dimension business object receives a copy of this global ACL. A business object puts its business rules on top of the received ACL. If the business rules indicate that the measurement should not be written, it adds the Deny Write ACE to the ACL.
    Note that a business object can make protection more restrictive. If global security dictates, it is impossible to do, it is impossible.
  • Communication with the business object ACL and the GUI is done through what we call our GuiMap object. This object retrieves a copy of the ACL from the business object and allows the developer to add function pointers that return Boolean to add Gui rules on top of the ACL of the business objects.

Now, in order to determine whether a button should be turned on, GuiMap evaluates each function passed to it in combination with the protection determined by the ACL of the business object, and in extreme conditions with user safety.

  • If the user does not have rights, the result is always disabled.
  • else, if business rules say it should be disabled, it is disabled.
  • else, if any Gui rule says that it should be disabled, it is disabled.

So, in fact, each layer is built on top of the previous one to determine the final result. It doesn't seem like there will be one calculation to determine if a button or something else needs to be activated.

The beauty, if you like, is this: since the ACL sends the copies, the copies attach to the master and get notified when their main ACL is updated. It allows us

  • Let each control refresh if users log out on any screen.
  • Let each control be updated when a business object that requires it changes.

This works well for us, except that itโ€™s hard to understand why something is disabled.

+7
user-interface design-patterns
source share
4 answers

If you understand correctly, you have two separate problems:

1) Checks at each level simply return a boolean indicating enabled / disabled, and do not return a reason.

You will need to modify it so that each check also returns a reason; for example, you can return a tuple (enabled, reason) , where access is the logical value that you have now, and explain the reason it is disabled (for example, as a string).

Depending on the environment in which you work, changing the type of return of all access checks may not be possible; if you want to avoid this, you can tell the reason "out of range", for example. insert it into the global (or rather, local) variable a la errno on UNIX or GetLastError on Windows. Of course, this is not that elegant, and, of course, they will frown on many: - (

Alternatively, you can modify your checks to throw exceptions (with a descriptive message) instead of returning a boolean value. Again, in many environments this will be frowned upon ...

2) Your business layer adds entries to the object access control lists. When you check access later, you know which entry denied access, but you no longer know why this entry was added.

Th enable this, you can add a reason field in the ACE. When the business layer adds ACE, it establishes a reason for describing the reason for the denial of access. The access control check then reads the reason and passes it to the GUI layer, as described above.

+2
source share

I would always explicitly disable the control and let the user know the reason either with a hover tip or a dialog when pressed (if your graphical interface allows you to listen to events on disabled controls).

+1
source share

If it is not explained in the documentation and is not displayed in the graphical interface, I see no alternative to learning the code. I did this a thousand times, so I'm really interested in any alternative posted here :)

Perhaps we could write the reason for the logs each time the button is disabled / enabled. For example:

  • Button A is disabled because the user does not have ABC security privileges
  • Button B is on because all the necessary information is now available
+1
source share

Lieven, I personally recommend you the solution given by oefe .

.

However, since you are not satisfied, I am adding a different approach below. This will only work if the visualization process of the graphical user interface is idempotent (i.e., it does not change the state of the system and can be called several times without affecting the system).

  • Using a decorator pattern creates shell rules that can original business rules. the wrapper rule will execute the original rule as well as add a reason if access is denied.
  • Use strategic template to get an instance of the rules. Depending on the parameter, the strategy should be to use the original business rule or a wrapped business rule.
  • On the client screen, when you turn off the control button, asynchronously call the same process that was used to originally built the screen. However, this time add additional parameters, i.e. control identifier and reason pointer you want to know the reason why it is disabled.
  • When a parameter parameter causes a real use strategy that uses a wrapper . These wrappers add reasons to ACE. In the end, for this control, restoring the cause requires a management identifier and returning it.
  • When the client receives the reason as an asynchronous response, display it.

Disadvantages:

  • Screen initiation should be idempotent
  • More wrappers for rules
  • Learn more about how an instance rules (using a strategy)
  • If the rules are not idempotent or cannot be used in a wrapper, you will be required to create a parallel hierarchy of rules.

<strong> Benefits:

  • Reasons are not populated by default
  • When the user asks for a reason, only then additional processing is performed.

.

Update:

As an alternative to a rough, but more simplified approach, you can gradually increase one module over time, reorganize existing rules and make them sensitive to control the indicator parameter id and reason. If a reason pointer parameter is present, the rules themselves must fill in the reason.

+1
source share

All Articles