+ Start a Discussion
Greg RohmanGreg Rohman 

Incorrect "UserOrGroupId" in share object for criteria-based sharing on custom object

Hello.

 

I have a custom object, called "Deal__c", that has it's default sharing access set to private. I have a number of criteria-based sharing rules on that object, and they are properly sharing the records to the appropriate groups specified in the criteria sharing rules.

 

My problem lies when I query the "Deal__Share" object to programmatically obtain the groups that have been shared to via criteria sharing. In the code sample below, I'm querying the Deal__Share object for all of the sharing rules applied to a specific record. I'm using Workbench for this testing, but I'm getting identical results when querying through Apex:

 

SELECT AccessLevel,Id,ParentId,RowCause,UserOrGroupId FROM Deal__Share WHERE ParentId='<deal_id_here>'

This particular record has four shares returned: two are manual shares, and two criteria-based. For the two manual shares, the UserOrGroupId shows the correct user/group that has been shared to. But, for the two that are criteria-based, it's not showing the correct Id for the groups that have been shared via criteria sharing. In fact, I don't know what IDs it's returning, because when I attempt to view those Ids from within Salesforce, I'm returned an "Insufficient Priveleges" page. I'm logged in as the system administrator, so priveleges shouldn't be an issue.

 

Any insight or help is greatly appreciated. Thank you.

 

-Greg

 

 

 

sfdcfoxsfdcfox

Examine the "key prefix" (the first three characters). Groups will be "00G...", and you can't view those directly. Instead, you would query for them (select ... from group ...) or you can view them in Setup (Setup > Manage Users > Public Groups and/or Setup > My Personal Information > My Groups). Note that you may not have access to a group, if the group is (a) private, and (b) not owned by you; this scenario can only be remedied by logging in as the user that owns the group. You cannot access private groups even as an administrator otherwise.

Greg RohmanGreg Rohman

Hi sfdcfox, and thanks for the reply.

 

I'm not sure I'm understanding, though. What do you mean that I can't view them directly and that I should query for them from the Group object? Do you mean groups shared via criteria-based sharing only? In my scenario, I own all of the public groups that would be shared via criteria sharing.

 

I do see the "00G" prefix on the 2 groups that are criteria-shared, but I also see it on another group that was shared manually. I can obtain the group members for the manually shared group (by querying the Deal__Share object for the UserOrGroupId, then by querying the GroupMember object) , but not the members of the groups shared via criteria sharing.

 

Thanks.

 

-Greg

 

sfdcfoxsfdcfox

That's odd. You should be able to query group members for criteria sharing entries the same as any other.

Greg RohmanGreg Rohman

I've managed to find a solution to this, but I don't quite understand why and was hoping if someone could shed some light. Below is my solution (not bulkified yet, just POC) for obtaining the list of users that have access to a custom object record due to criteria based sharing:

 

		// First, determine the users that have access to the deal. This is accomplished by
		// looking at the Title_Deal__Share object for the deal to see what public groups have
		// been shared through criteria-based sharing. Then, get the user for each person in
		// the group. 
		List<Title_Deal__Share> listShares = new List<Title_Deal__Share>();
		listShares = [SELECT Id,UserOrGroupId FROM Title_Deal__Share WHERE ParentId=:currentDeal.Id AND IsDeleted=false AND RowCause='Rule'];

		// Convert the list of shares to just a list of userorgroupids
		List<Id> listShareIds = new List<Id>();
		for (Title_Deal__Share s : listShares) {
			listShareIds.add(s.UserOrGroupId);			
		}

		// retrieve the list of group members that belong to each of thse groups.
		// Odd behavior here - need to query UserOrGroupId instead of GroupId.
		List<GroupMember> listGroupMembers = new List<GroupMember>();
		listGroupMembers = [SELECT Id,GroupId,UserOrGroupId FROM GroupMember WHERE GroupId IN :listShareIds];

		// Convert the list of groupmembers to just a list of group IDs
		List<Id> listGroupIds = new List<Id>();
		for (GroupMember g : listGroupMembers) {
			listGroupIds.add(g.UserOrGroupId);			
		}

		// Now, need to requery GroupMember with the UserOrGroupId as the ID, to get the user Ids
		List<GroupMember> newGroupMemberList = new List<GroupMember>();
		newGroupMemberList = [SELECT Id,GroupId,UserOrGroupId FROM GroupMember WHERE GroupId IN :listGroupIds];
		List<Id> listUserIds = new List<Id>();
		for (GroupMember g : newGroupMemberList) {
			listUserIds.add(g.UserOrGroupId);
		}

		// Finally, get the list of users.
		List<User> commUsers = new List<User>();
		commUsers = [SELECT Id,FirstName,LastName FROM User WHERE Id IN :listUserIds];

 Specifically, I don't understand why I first have to query the GroupMember object twice. If anyone has experienced this, has an explanation, or a simpler way of doing it, it would be appreciated.

 

Thanks.

 

-Greg

HareHare
I Shared a record to user and group using apex and vf page

for this i created one job custom object
here is my code
-------------------------------------------------------------------------------------------------
RecordShareingtogroupp
-------------------------------------------------------------------------
vf page
--------------------------------------------------------------------------
<apex:page controller="RecordShareingtogrouppcpn">
<apex:form >
  <apex:pageBlock >
      <apex:selectList value="{!SelectedJobval}" size="1">
      <apex:actionSupport event="onchange" reRender="opt1" />
             <apex:selectOptions value="{!Jobs}">
             </apex:selectOptions>
      </apex:selectList>
   <apex:selectList value="{!SelectedGroupeval }" size="1" >
   <apex:actionSupport event="onchange" reRender="opt1" />
           <apex:selectOptions value="{!Groups}">
           </apex:selectOptions>
   </apex:selectList>
  
  <apex:commandLink value="Share" action="{!shareWithGroup}"  id="opt1"/>
 
   </apex:pageBlock>
   </apex:form>
</apex:page>
------------------------------------------------------------------------------------------------------
apex page
----------------------------------------------------------------------------------------------------------
public class RecordShareingtogrouppcpn {

    Public String SelectedJobval {get;set;}
    public String SelectedGroupeval { get;set;}
    public List<Job__C> jobList { get;set;}
    public List<Group> userroleList { get;set;}
    public List<SelectOption> getJobs() {
 
  List<SelectOption> jobSelectOption=new List<SelectOption>();
 
   for(job__c jo:[select id,name from Job__c])
   {
   jobSelectOption.add(new SelectOption(jo.id,jo.name));
   }
 
  
  return jobSelectOption;
  }
  public List<SelectOption> getGroups() {
 
  List<SelectOption> GroupSelectOption=new List<SelectOption>();
 
   for(Group gp:[select id,name from Group ])
   {
   if(gp.name != null && !String.isEmpty(gp.name))
   GroupSelectOption.add(new SelectOption(gp.id,gp.name));
   }
 
  
  return GroupSelectOption;
  }
 
  
  public PageReference shareWithGroup(){
 
  system.debug('shareWithRole');
 
  jobList =[ select id,name from job__c where id=:SelectedJobval];
  system.debug('jobList value'+jobList );
 
  userroleList =[select id,name from Group where id=:SelectedGroupeval ];
  system.debug('userroleList '+userroleList );
               Job__Share jobShr  = new Job__Share(); 
               jobShr.ParentId = jobList[0].id;
               system.debug('jobShr.ParentId '+jobShr.ParentId );
               jobShr.UserOrGroupId = userroleList [0].id;
               system.debug('jobShr.UserOrGroupId'+jobShr.UserOrGroupId);
               jobShr.AccessLevel = 'Read';
               jobShr.RowCause = Schema.Job__Share.RowCause.Manual;
              
             Database.SaveResult sr = Database.insert(jobShr,false);
               system.debug('sr  value'+sr );          
 
 
             
             if(sr.isSuccess())
            {
               system.debug('sr.isSuccess() value:'+sr.isSuccess());
                  system.debug('if sr.isSuccess() block');
               PageReference nextpage = new PageReference('/apex/CustomTeam?id='+jobList[0].id);
             
                return nextpage;
               }
           else {
                  system.debug('inner else sr.isSuccess() block');
                     Database.Error err = sr.getErrors()[0];
                     system.debug('err value '+ err );
                     if(err.getStatusCode() == StatusCode.FIELD_FILTER_VALIDATION_EXCEPTION  &&   err.getMessage().contains('AccessLevel')){
                      system.debug(' err.getStatusCode()  value'+err.getStatusCode() );

                      system.debug(' iner if sr.isSuccess() block');
                      PageReference nextpage = new PageReference('/apex/CustomTeam?id='+jobList[0].id);
                return nextpage;
            }
             else
             {
                      system.debug('outer else sr.isSuccess() block');
               PageReference nextpage = new PageReference('/apex/failure?id='+jobList[0].id);
                    return nextpage;
               }
             }
  }
 
}
----------------------------------------------------------------------------------------------------
RecordshareToUserApex
-----------------------------------------------------------------------------------------------
vf page
----------------------------------------------------------------------------------------------------
<apex:page standardController="Job__c"   extensions="RecordshareToUserApexCon">
    <apex:form >
      <apex:pageBlock >
     
                <apex:selectList size="1" value="{!jobst }" multiselect="false">
                    <apex:selectOptions value="{!Job}"> </apex:selectOptions> 
                     <apex:actionSupport event="onchange" reRender="table,opt1" />
                </apex:selectList>
    
                <apex:selectList size="1" value="{!selectedVal}" multiselect="false">
                <apex:actionSupport event="onchange" reRender="table,opt1" />
                    <apex:selectOptions value="{!Value}">
                    </apex:selectOptions>
                </apex:selectList>
               
                <apex:outputText id="opt12" value="{!selectedVal}"></apex:outputText>
               
               <apex:commandLink action="{!manualShareRead}" value="Share" id="opt1">
                </apex:commandLink>
       </apex:pageBlock>
           
     </apex:form>
</apex:page>
-----------------------------------------------------------------------------------------------------------------------
apex page
-----------------------------------------------------------------------------------------------------------------------
public class RecordshareToUserApexCon
{   
         List<user> con1= new List<user>(); 
         public job__c j {get;set;}
         Public List<string> usertselect{get;set;}
         public string jobst { get;set;}
         public string val{ get;set;}
         public user gp {get;set;}
         public boolean nojb{get;set;}
         public String selectedVal{get;set;}
         public List<job__C> joblist = new List<job__C>();
        
         public RecordshareToUserApexCon () {

          }
         public RecordshareToUserApexCon (ApexPages.StandardController controller) {
          }
       
   

           public List<SelectOption> getJob(){  
       
             List<SelectOption> option = new List<SelectOption>();
             
            for(job__c j: [Select id,name From  job__c]){
             
                     option.add(new SelectOption(j.name,j.name));
                     system.debug('option value is '+option);
                    
                 }
                 return option;     
           }
             public List<SelectOption> getValue(){  
            
                 List<SelectOption> option = new List<SelectOption>();
                     
                for(user gp: [Select id,name From  user  ])
                 {
                 
                     option.add(new SelectOption(gp.name,gp.name));
                     system.debug('option value is '+option);
                    
                 }
                 return option;     
             }
                
       public PageReference manualShareRead() {
             
                 
                   joblist = [select id from job__C where name=:jobst];
                   con1 = [select id from user where name=:selectedVal];
                   system.debug('PGList value is'+con1);
                   system.debug('PGList value is'+joblist);
                   Job__Share jobShr  = new Job__Share(); 
                   jobShr.ParentId = joblist[0].id;
                   jobShr.UserOrGroupId = con1[0].id;
                   jobShr.AccessLevel = 'Read';
                   jobShr.RowCause = Schema.Job__Share.RowCause.Manual;
                  
                 Database.SaveResult sr = Database.insert(jobShr,false);
                  system.debug('sr value is'+sr);
          
                 if(sr.isSuccess()){
                   system.debug('sr.isSuccess() value:'+sr.isSuccess());
                      system.debug('if sr.isSuccess() block');
                   PageReference nextpage = new PageReference('/apex/CustomTeam?id='+joblist[0].id);
                 
                    return nextpage;
                   }
               else {
                      system.debug('inner else sr.isSuccess() block');
                         Database.Error err = sr.getErrors()[0];
                         if(err.getStatusCode() == StatusCode.FIELD_FILTER_VALIDATION_EXCEPTION  && 
                         err.getMessage().contains('AccessLevel')){
                          system.debug(' iner if sr.isSuccess() block');
                          PageReference nextpage = new PageReference('/apex/CustomTeam?id='+joblist[0].id);
                    return nextpage;
                }
                 else{
                          system.debug('outer else sr.isSuccess() block');
                   PageReference nextpage = new PageReference('/apex/RecordShareFailure?id='+joblist[0].id);
                        return nextpage;
                   }
                 }
                
                
           
         
         }
  
  
       
     }
-------------------------------------------------------------------
this is working code let me know any clarifications on this

thanks,
hareesh.