Here's a small Apex Trigger that demonstrates how to programmatically create sharing rules for objects with a private sharing model. It came in handy on a project about a year ago so I thought I'd post it.
So the scenario is that the object has a private sharing model (Contacts in this case) so that only the record owner and users higher in the role hierarchy have access to it. I added a checkbox to the Contact object called "Make Public" that when set to TRUE, creates a sharing record for a specific group (e.g., All Internal Users). When set to FALSE, it deletes all manual sharing rules for the record. You can modify this to add multiple groups or even make it operate on the reverse (public by default and then remove the sharing rules).
ContactMakePublicTrigger
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 & amp ; & amp ; 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 & amp ; & amp ; 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 ;
}
}
TestContactMakePublicTrigger
@ isTest
private class TestContactMakePublicTrigger {
// test that newly inserted records marked as pubic=true have corresponding shares created
static testMethod void testAddShares () {
Set < ID > ids = new Set < ID > ();
List < Contact > contacts = new List < Contact > ();
for ( Integer i = 0 ; i < 50 ; i ++ )
contacts . add ( new Contact ( FirstName = ' First ' , LastName = ' Name ' + i ,
Email = ' email ' + i + ' @email.com ' , Make_Public__c = true ));
insert contacts ;
// get a set of all new created ids
for ( Contact c : contacts )
ids . add ( c . id );
// assert that 50 shares were created
List < ContactShare > shares = [ select id from ContactShare where
ContactId IN : ids and RowCause = ' Manual ' ];
System . assertEquals ( shares . size (), 50 );
}
// insert records and switch them from public = true to public = false
static testMethod void testUpdateContacts () {
Set < ID > ids = new Set < ID > ();
List < Contact > contacts = new List < Contact > ();
for ( Integer i = 0 ; i < 50 ; i ++ )
contacts . add ( new Contact ( FirstName = ' First ' , LastName = ' Name ' + i ,
Email = ' email ' + i + ' @email.com ' , Make_Public__c = false ));
insert contacts ;
for ( Contact c : contacts )
ids . add ( c . id );
update contacts ;
// assert that 0 shares exist
List < ContactShare > shares = [ select id from ContactShare where
ContactId IN : ids and RowCause = ' Manual ' ];
System . assertEquals ( shares . size (), 0 );
for ( Contact c : contacts )
c . Make_Public__c = true ;
update contacts ;
// assert that 50 shares were created
shares = [ select id from ContactShare where ContactId IN : ids and RowCause = ' Manual ' ];
System . assertEquals ( shares . size (), 50 );
for ( Contact c : contacts )
c . Make_Public__c = false ;
update contacts ;
// assert that 0 shares exist
shares = [ select id from ContactShare where ContactId IN : ids and RowCause = ' Manual ' ];
System . assertEquals ( shares . size (), 0 );
}
}
One thing to remember. When transferring accounts and their related data, all existing sharing rules will be removed. Any relevant sharing rules are then applied to the records based upon the new owners. You may need to manually share these accounts and opportunities to grant access to certain users and/or groups.