CiviCRM Community Forums (archive)

*

News:

Have a question about CiviCRM?
Get it answered quickly at the new
CiviCRM Stack Exchange Q+A site

This forum was archived on 25 November 2017. Learn more.
How to get involved.
What to do if you think you've found a bug.



  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion (Moderator: Donald Lobo) »
  • Development Advice for Fine Grained ACLs based on Case Type
Pages: [1]

Author Topic: Development Advice for Fine Grained ACLs based on Case Type  (Read 810 times)

murray.grant

  • I’m new here
  • *
  • Posts: 1
  • Karma: 0
  • CiviCRM version: 4.3.3
  • CMS version: Drupal 7
  • MySQL version: 5.5
  • PHP version: 5.3.10
Development Advice for Fine Grained ACLs based on Case Type
July 10, 2013, 07:28:48 pm
Hello,

I'm a developer working on some customisations to CiviCRM Cases. Specificly, restricting access to cases based on case type and group membership. The details are below, but I'll put some questions up front:

  • Does this functionality exist in CiviCRM somewhere, or in a 3rd party module / extensions / add-on? That is, am I re-inventing the wheel?
  • Does the way I'm going to approach this (outline below) as a developer make sense? That is, am I approaching the implementation in a reasonable way? My usual platform of development is C# .NET and ASP MVC, so while I'm pretty confident in what concepts I want to accomplish, I'm less certain about how best to implement them in the world of CiviCRM.



OK, my context and the problem I'm trying to solve:

We're managing cases for a variety of government programs. Individuals and family's come in looking for various forms government assistance. These are divided into a few general categories and some official programs; eg: General Assistance, Program ABC, Program  XYZ, etc. These programs map directly to Civi case types, with a variety of custom fields to capture all the information we need to report back to the government. Civi is working fine for this.

Now, there are case managers who work particular case types. That is, Helpful Harry works on Program ABC, while Adam Admin can work any case type. We want case managers to be restricted in what cases they can create, view and edit based on case type. Case managers can search for and see listings of all cases, however. And, if they've been assigned to any case (in the Roles tab), they can view and edit it. As far as I can tell, this isn't directly supported by CiviCRM. (This forum post seems to be talking about something similar: topic=27718.0 (sorry, apparently I'm not allowed to post "external" links)).

Just repeating my first question: have I missed the functionality in Civi somewhere (I confess to not fully understanding how the ACLs work) or is there some 3rd party module available which can cover this off?


Now, assuming I'll need to implement this myself, here's my plan:
  • Configure users / groups and roles such that there's a link between a user and a case type.
  • Based on the current user, and their associated case types, query the database and get a list of cases they can view and edit.
  • Hide page elements and deny access to pages based on this list.


The config:
  • Create a bunch of Drupal groups to map to the Civi case types. These will be subdivided into view / edit level access. Eg: Program ABC View, Program ABC Edit, Program XYZ View, Program XYZ Edit, etc.
  • Place Drupal users into groups based on what case types they are allowed to view / edit.
  • Make a lookup table which maps from the Drupal groups to Civi case types. Normally I'd make database tables and admin pages for this, but, in the interests of saving time, I'll hard code it as a PHP associative array.
  • Give all users the access all cases and activities permission via the Drupal groups. This grants them access to view and manage all cases.
  • Now I need to remove / revoke access based on my requirements.


There are two parts to enforcing the read and edit permissions:
  • Hard page level access (that is, if the user tries to browse to a case they should not be able to view, or edit a case they should not edit, they get an appropriate "access denied" error).
  • Removal of links / buttons / actions which a user cannot access (that is, users should not see "Manage Case" links if they cannot view the case. They should not see any edit links on the Case Summary page if they are not allowed to edit the case).


For the hard access denied errors:
  • hook_civicrm_validateForm to reject any edits a user is not allowed to make. I'd need to implement this for Cases, Activities, Relationships, Roles and probably other form types I've missed.
  • hook_civicrm_pageRun to reject any page views a user is not allowed to make. Again, I'd need to cover off similar pages as above. I did a simple proof of concept using CRM_Core_Error::statusBounce(), and it worked well enough (if a little ugly).

Based on my experience with Civi when removing / moving page elements, I've found Javascript in template extra files works pretty well (and, most importantly, gives the least pain when upgrading Civi versions). This will boil down to:
  • A list of jQuery selectors on each page to remove elements. One for read level, one for edit level. This gets a bit more complex for search / lists of cases, but a function to extract case id from elements should work here.
  • Getting a list of case ids the user is NOT allowed to view / edit into that Javascript. This can be via AJAX or via smarty templates (leaning toward the latter for simplicity at the moment).
  • I'm a bit worried about dumping a list of every case id a user cannot access on case search / list pages, as this will grow as they enter more data. The simplest solution to this I've come up with so far is to first check for open cases, and then if there's any left over in our search list, AJAX callback and check the remaining ones (assuming there won't be very many of these). I'm open to solutions which don't have that extra level of complexity though.

Restricting what cases a user can create I've already implemented by hooking hook_civicrm_buildForm and removing elements from the case_type_id form element. This is working well enough, but I need to validate on create as well in hook_civicrm_validateForm. I'll also migrate this to be part of the edit level permission.


Underlying all this would be database query(s) and PHP code yielding a list of case ids a user can view / edit. I'm thinking of writing that as a custom API (based on the wiki page How+to+migrate+or+write+an+api (sorry, I'm not allowed to post an "external" link)). That allows me to a) keep that code in one place and b) consume it via PHP, Smarty, AJAX, other hooks or wherever else I might need it.

This list of allowed case ids involves checking:
  • If the user is listed on the case roles. This should be a SQL query against the civicrm_relationship table based on contact id.
  • Figuring out what groups a user belongs to, mapping that via my PHP lookup table to a list of case types. From there, a SQL query against the civicrm_case table based on case_type_id will get what I need.
And some other assumptions:
  • For simplicity's sake, I'll assume if a user can edit a case they can also view it. Making edit a true sub-set of view should make removing page elements easier.
  • Removing page elements requires a set difference (SQL EXCEPT clause) to get the list of cases the user is not allowed to access. Again, that's pretty easy in SQL or PHP.
  • And I can add some nice functions to the API which build on top of the the basic list of case ids as I need, eg: userHasReadAccessTo($caseId), getReadDenyListCases($userId).




One loose end I have is that I've been asked to apply the same restrictions to Activities attached to Contacts rather than cases. I don't think this is actually possible (at least based on case types) as there's no case involved. My thought is to say "not technically possible" to this, at least for now.



Repeating my second question: does all this make sense? Does this approach seem reasonable to more seasoned Civi developers? Am I missing something really important which might make my life much easier (or worse, is there a gotcha which will come back to bite me)?


And a final question: Is this useful functionality for other people? If so, where should I post the final code?

Regards
Murray Grant

jaapjansma

  • I post frequently
  • ***
  • Posts: 247
  • Karma: 9
    • CiviCoop
  • CiviCRM version: 4.4.2
  • CMS version: Drupal 7
  • MySQL version: 5
  • PHP version: 5.4
Re: Development Advice for Fine Grained ACLs based on Case Type
September 16, 2014, 02:27:03 am
Murray,

Did you develop the above future and if so were do I found the code? This is really useful for us at the moment.

Jaap
Developer at Edeveloper / CiviCoop

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion (Moderator: Donald Lobo) »
  • Development Advice for Fine Grained ACLs based on Case Type

This forum was archived on 2017-11-26.