4

I've been testing out a component where one can programmatically create a field in the user object. It's being used to allow a user to check a few boxes that'll filter components in pages (using the lightning page component filtering) that is unique to that user.

With this test I've met an annoying problem. If I manually create the field, it's all good because we get to decide the field level access. But when I create it programmatically it comes with zero access to any users even my own (sys admin).

The way I'm creating the field is:

global with sharing class FieldGen {
        //@future(callout = true)
        global static void makeCreateUserFieldCallout(String intendedName){
            String objectapiname = 'User';
        
        /* assertFieldName just makes name acceptable for the API name of the field. */
        String fieldapiname = TogglerCtrlApex.assertFieldName(intendedName, true);
        String fieldlabel = TogglerCtrlApex.assertFieldName(intendedName, false);
        String fielddescription = 'Field created for topic visibility toggler component!';
        
        try{
            HttpRequest requestinside = new HttpRequest();
            requestinside.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
            requestinside.setHeader('Content-Type', 'application/json');
            requestinside.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm()+'/services/data/v26.0/tooling/sobjects/CustomField/');
            requestinside.setMethod('POST');
            String fieldDef = '{"Metadata" : ';
            String metadef = '"type" : "Checkbox","description" : "'+fielddescription+'","defaultValue":"true", "inlineHelpText" : "","precision" : null,"label" : "'+fieldlabel+'","required" : false';
            fieldDef += '{'+metadef+'},';
            fieldDef += '"FullName" : "'+objectapiname+'.'+fieldapiname+'"}';
            system.debug(fieldDef);
            requestinside.setBody(fieldDef);
            Http http = new Http();
            HTTPResponse res = http.send(requestinside);
            System.debug(res.getBody());
        }
        catch(Exception e){
            System.debug(e.getMessage());
        }
    }
}

Basically using the API to create a field in the User Object. Unfortunatelly it doesn't give access though =/

I've been experimenting with the MetadataService class to try to add field permissions to a permission set when the field is created. This isn't working though and the documentation for this class is very slim. This is what I have so far:

public with sharing class MetadataServiceExamples
{
    @future(callout = true)
    public static void testPerm()
    {
        /* Find the Quick Toggler Permission Set! */
        MetadataService.MetadataPort service = createService();
        String[] permissionSetNames = new String[] {'Quick_Visibility_Toggler_Permissions'};
        List<MetadataService.PermissionSet> perm = 
            (List<MetadataService.PermissionSet>) service.readMetadata('PermissionSet', permissionSetNames).getRecords();
        MetadataService.PermissionSet quickPerm = perm.get(0);
        System.debug('Test: ' + quickPerm.fieldPermissions);
        MetadataService.PermissionSetFieldPermissions fieldSec = new MetadataService.PermissionSetFieldPermissions();
        fieldSec.field='User.TestFieldA__c';
        fieldSec.editable=true;
        fieldSec.readable=true;
        quickPerm.fieldPermissions.add(fieldSec);// = new MetadataService.PermissionSetFieldPermissions[] {fieldSec} ;
        System.debug('Test: ' + quickPerm.fieldPermissions);
        List<MetadataService.SaveResult> results =
            service.updateMetadata(
                new MetadataService.Metadata[] { quickPerm });
        System.debug('Results: ' + results);
        //handleSaveResults(results[0]);
    }
}

It seems I can't access and change the permission set though. WIth that being said, does anyone know of a way I could either add CRUD permissions for the new field to a permission set or a profile programmatically right after the field is created?

EDIT:

Based on the best answer I just added this method to the class and it adds permissions to a permission set:

@AuraEnabled
    public static void addToPermissionSet(String fieldName){
        String fieldAPIName = assertFieldName(fieldName, true); /* this just makes sure theres's an __c in the input. */
        /* Get Id of permission Set and build API name of field. */
        PermissionSet ps = [SELECT Id,Name FROM PermissionSet WHERE Name = 'Example' LIMIT 1];
        String fullAPIName = 'User.'+fieldAPIName; /* Example: User.TestMe__c */
        System.debug('FullAPI:' + fullAPIName);
        
        FieldPermissions newPerm = new FieldPermissions();
        newPerm.Field = fullAPIName;
        newPerm.ParentId = ps.Id;
        newPerm.PermissionsEdit = true;
        newPerm.PermissionsRead = true;
        newPerm.SobjectType = 'User';
        Insert newPerm; 
    }
2
  • Hey Victor, can I know how your complete code looks like now? I want to know if you go with Metadata service or the above REST. Thanks. Sep 10 at 1:06
  • 1
    Hey @LetMeCodeYou, done! Sep 27 at 8:17

1 Answer 1

5

You can Provide Field Permission to permission set by creating FieldPermissions record like this

FieldPermissions fp= new FieldPermissions();
fp.Field='Case.AccountId';//the name of new field
fp.ParentId='0PS0o000001WP6AGAW';// id of permission set 
fp.PermissionsEdit=true;//
fp.PermissionsRead=true;
fp.SobjectType='Case';
Insert fp; 

though this only works for permission set here is the link for object https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_fieldpermissions.htm

1
  • This is incredibly helpful! Let me test it out and I'll mark it as answered if it works, thank you so much even for the reply, I did not know this obj existed :) Apr 12, 2021 at 15:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.