Sunday, May 27, 2018

Apex Record Sharing

Apex Sharing


Individual records can be shared with Users or Groups by creating records in share object related to the object. These records can be inserted in share object from trigger or controller.

We will need to create records in share object when object's default OWD settings are restricted like Private, Public Read Only etc. This will open up record level access to new users / groups.

Fields to be set while using Apex sharing: ParentId, UserOrGroupId, AccessLevel, RowCause

These fields must be set when creating records in Share object :

  • ParentId
  • UserOrGroupId
  • AccessLevel
  • RowCause


ParentId The Id of the record being shared. This field cannot be updated.

UserOrGroupId The Id of the User to whom you are granting access. May also be a
Public Group Id. When sharing to a role, you cannot assign Role Id to UserOrGroupId field
directly. It should instead be a matching Group Id from Group table. This field cannot be
updated.

RowCause (aka Sharing Reasons) The reason why the user or group is being granted access.
The reason determines the type of sharing, which in turn controls who can alter the
sharing record. This field cannot be updated.

AccessLevel The level of access that the specified User or Group has been granted.
Valid values for Apex managed sharing are: Edit, Read.

This field must be set to an access level that is higher than the organizations default
access level for the parent object. For more information, see Access Levels.

AccessLevel is the only updateable field in Share object record.

Contact object has a custom field named Make_Public__c.

If a new contact record is either being created or updated and if this custom checkbox field is set to true, share the contact record with Group named Organization.

trigger ContactMakePublicTrigger on Contact (after insert, after update) {

  // get the id for the group for everyone in the org
  ID groupId = [select id from Group where Type = 'Organization'].id;
  // inserting new records
  if (Trigger.isInsert) {

    List<ContactShare> sharesToCreate = new List<ContactShare>();

    for (Contact contact : Trigger.new) {
      if (contact.Make_Public__c == true) {
        // create the new share for group
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        cs.UserOrGroupId =  groupId;
        sharesToCreate.add(cs);
      }
    }

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  // updating existing records
  } else if (Trigger.isUpdate) {

    List<ContactShare> sharesToCreate = new List<ContactShare>();
    List<ID> shareIdsToDelete = new List<ID>();

    for (Contact contact : Trigger.new) {

      // if the record was public but is now private -- delete the existing share
      if (Trigger.oldMap.get(contact.id).Make_Public__c == true &&
  contact.Make_Public__c == false) {
        shareIdsToDelete.add(contact.id);

      // if the record was private but now is public -- create the new share for the group
      } else if (Trigger.oldMap.get(contact.id).Make_Public__c == false &&
  contact.Make_Public__c == true) {

        // create the new share with read/write access
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        cs.UserOrGroupId =  groupId;
        sharesToCreate.add(cs);
      }
    }

    // do the DML to delete shares
    if (!shareIdsToDelete.isEmpty())
      delete [select id from ContactShare where ContactId IN :shareIdsToDelete
and RowCause = 'Manual'];
    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  }

}

Salesforce Lightning components interview questions

Salesforce Lightning components interview questions 1 Lightning vs ui namespace for components ? It is recommended that you use t...