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. Commented Sep 10, 2022 at 1:06
  • 1
    Hey @LetMeCodeYou, done! Commented Sep 27, 2022 at 8:17

1 Answer 1

7

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

4
  • 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 :) Commented Apr 12, 2021 at 15:04
  • PROFILES CAN NOW BE UPDATED using the FieldPermissions object I don't know when this changed, but it's PHENOMENAL AND GAME-CHANGING Try it out for yourself! Commented Aug 15 at 19:16
  • 1] run a query like this, to get the ID for the "Standard User" Profile's FLS for Account.AccountNumber: SELECT Id, Field, PermissionsEdit, Parent.Profile.Name FROM FieldPermissions WHERE SObjectType = 'Account' AND Parent.Profile.Name = 'Standard User' AND Field = 'Account.AccountNumber' Commented Aug 15 at 19:16
  • 2] update the PermissionsEdit and/or PermissionsRead fields for the record whose ID was returned in step [1]. you're done! Commented Aug 15 at 19:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .