I am using meta-data api to create custom fields in java class. Now I want to set field level security for different profiles. First is it possible to set this with meta-dat api, If yes than how can I set this , can anyone provide me some sort of code.
3 Answers
Update
Since this was posted there are now simpler ways to accomplish this. Refer to Greg's answer for specifics.
Original Answer
Yes, it's possible, but it's not particularly easy. Unlike creating fields which you can utilize the "CRUD" based metadata api calls, profiles require using retrieve and deploy calls. This means you'll have to deal with zipping and unzipping the data for the deploy/retrieve calls, constructing the xml for the package manifest to do the retrieve call, and dealing with modifying the resulting xml. I'm not aware of any sample code for this unfortunately.
High Level Steps
1. List out Profiles
You'll need to list out all the profiles that you want to update the field level security for
2. Construct your Project Manifest
Build a package.xml that includes all profiles from step 1, and any fields you want to set the security for. Profiles only include permissions related to the other components in the next step, so you must retrieve them in conjunction with any components you're update the security for.
3. Do a retrieve call and unzip the result
Use your project manifest to do a retrieve call and unzip the resulting zip file.
4. Update the permissions
Update the profile XML with the desired permissions
5. Deploy the changes
Zip everything back up and do a deploy call.
-
profiles require using retrieve and deploy calls - this is not true. Manifests, zipping and unzipping are not necessary. See other answer salesforce.stackexchange.com/a/58243/4126 Commented Feb 10, 2020 at 18:57
-
1yep, this answer is outdated and there are now better options available, updating the answer to reflect that Commented Feb 13, 2020 at 20:34
It does not have to be through the retrieve->deploy process. I got this to work using CRUD metadata api calls. This is the meat of the logic in C#
Logger.Info("SalesForceProxy.UpdateFieldVisibility invoked. (Profiles: {0}; Fields: {1})", String.Join(", ", profilefullNames), String.Join(", ", fieldfullNames));
if (String.IsNullOrWhiteSpace(_instanceUrl) || String.IsNullOrWhiteSpace(_accessToken))
{
Authenticate();
}
var permissionList = fieldfullNames.Select(field => new ProfileFieldLevelSecurity
{
field = field,
editable = true,
readable = true,
readableSpecified = true
}).ToArray();
Logger.Info("Updating Profile Metadata...");
var updateRequest = new updateMetadataRequest(
new SessionHeader() { sessionId = _accessToken },
new CallOptions(),
profilefullNames.Select(profileName => new Profile
{
fullName = profileName,
fieldPermissions = permissionList
}).Cast<Metadata.Metadata>().ToArray());
RequestObjectCache.Add(updateRequest);
var updateResponse = MetadataService.updateMetadata(updateRequest);
var updateSuccessful = true;
foreach (var result in updateResponse.result.Where(result => !result.success))
{
Logger.Error("Metadata Update Failed");
if (result.errors != null)
{
foreach (var errorMsg in result.errors)
{
Logger.Error("Error in Update Metadata (Code: {0} Message: {1})", errorMsg.statusCode,
errorMsg.message);
}
}
updateSuccessful = false;
}
Logger.Info("SalesForceProxy.UpdateFieldVisibility finished. (Success: {0})", updateSuccessful);
-
I would say this answer really answers this question best. Whilst the high level process outlined by @RalphCallaway will work, this process of using the metadata API directly is more in-line with how the salesforce APIs should be used. Commented Mar 21, 2016 at 11:17
-
-
Here's the reference information for ProfileFieldLevelSecurity developer.salesforce.com/docs/atlas.en-us.api_meta.meta/…– PHPDaveCommented Jun 24, 2018 at 20:10
-
You might also want to automate adding it to the page layouts developer.salesforce.com/docs/atlas.en-us.api_meta.meta/…– PHPDaveCommented Jun 24, 2018 at 20:15
To eleborate on the above answer, here is a demo code(tried & tested) to set FLS for field for all profiles.
Set Field Level security for profile using meta-data api
• Genarate Metadata and Partner WSDL Get MetaData and Partner WSDL links from your salesforce org to add as a service reference to your .Net Project. Your profile needs to have access to API integrations to generate the WSDL
Setup > Quick Find > API
This redirects to a XML page , save the link to add web reference.
• Add WSDL as web reference in your .NET project
In your .net project, right click on your solution and choose Add Service Reference
Click on Advanced to add WSDL as a Web reference
Click Add Web reference, , paste the URL you generated in the previous step to add the reference for both Partner and MetaData WSDL, with proper name , which will be used as reference in your project.
Demo Code:
using MetaDataAPIDemo.metaforce;
using MetaDataAPIDemo.sforce;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MetaDataAPIDemo
{
class Program
{
static async Task Main(string[] args)
{
//security Token is needed to be appendedShould be added if your IP is
not whitelisted
MetadataCreator mc = new MetadataCreator("username",
"Password"+"SecurityToken");
//Get All profile names to update FLS for all profiles
await mc.getProfileFullNames();
//Update FLS for field
mc.UpdateNewFieldPermissions();
}
}
class MetadataCreator
{
private MetadataService metadataService;
private SforceService sforceService;
private List<string> profileFullNames = new List<string>();
public MetadataCreator(String username, String password)
{
sforceService = new SforceService();
LoginResult lr = sforceService.login(username, password);
sforceService.Url = lr.serverUrl;
sforceService.SessionHeaderValue = new sforce.SessionHeader();
sforceService.SessionHeaderValue.sessionId = lr.sessionId;
metadataService = new MetadataService();
metadataService.Url = lr.metadataServerUrl;
metadataService.SessionHeaderValue = new metaforce.SessionHeader();
metadataService.SessionHeaderValue.sessionId = lr.sessionId;
}
public async Task getProfileFullNames()
{
ListMetadataQuery query = new ListMetadataQuery();
query.type = "Profile"; //Salesforce Type
double asOfVersion = 52.0; //Version of your SOAP API call
FileProperties[] profileDetails = metadataService.listMetadata(
new ListMetadataQuery[] { query }, asOfVersion);
profileFullNames = profileDetails.Select(x => x.fullName).ToList();
}
public void UpdateNewFieldPermissions()
{
List<Profile> updatedProfiles = new List<Profile>();
List<string> errorMessages = new List<string>();
foreach (var profileFullName in profileFullNames)
{
Profile admin = new Profile();
admin.fullName = profileFullName;
admin.custom = false;
ProfileFieldLevelSecurity fieldSec = new ProfileFieldLevelSecurity();
fieldSec.field = "FieldFullName"; //Ex: FullName: SalesforceObject.FieldName
fieldSec.editable = true;
fieldSec.readable = true;
fieldSec.readableSpecified = true;
admin.fieldPermissions = new ProfileFieldLevelSecurity[] { fieldSec };
updatedProfiles.Add(admin);
}
if (updatedProfiles.Count() > 0)
{
List<List<Profile>> profileBatchList = SplitList(updatedProfiles, 10);
foreach (List<Profile> batch in profileBatchList)
{
//Update data in batches of 10
metaforce.SaveResult[] results = metadataService.updateMetadata(batch.ToArray());
errorMessages = handleSaveResults(results);
if (errorMessages != null)
{
errorMessages.Concat(handleSaveResults(results));
}
}
}
}
public static List<string> handleSaveResults(metaforce.SaveResult[] saveResult)
{
if (saveResult == null || saveResult.Where(x => x.success).Any())
return null;
List<String> messages = new List<String>();
foreach (var result in saveResult)
{
messages.Add((result.errors.Length == 1 ? "Error " : "Errors ") + $"occured processing component {result.fullName}.");
}
return messages;
}
public static List<List<Profile>> SplitList(List<Profile> profiles, int nSize = 0)
{
var list = new List<List<Profile>>();
for (int i = 0; i < profiles.Count; i += nSize)
{
list.Add(profiles.GetRange(i, Math.Min(nSize, profiles.Count - i)));
}
return list;
}
}
}
Note: Found that metadataService.updateMetadata updates data only in batches on 10.
If anyone has any suggestions/tips on this, it would be appreciated.