RestrictSources
What It Does
Controls which call sources (phone lines / Source__c records) the running user is allowed to see.
The source restriction is evaluated at the start of every timeline request and applied as a SOQL filter alongside the handler restriction. A call only appears if both the source restriction and the handler restriction are satisfied.
The default implementation allows all sources. Implement RestrictSources.IStrategy to restrict users to a subset of sources — for example, to the lines associated with their department or office.
Interface
global interface IStrategy {
void getAllowed(Context context);
}
Context
Input
The Context has no input fields. Use UserInfo.getUserId(), custom metadata, custom settings, or SOQL queries against your own org data to determine which sources the running user may access.
Write Methods
Call one of these before returning. If you call none, the default is allow-all (all sources visible).
| Method | Description |
|---|---|
allowSingle(Id id) |
Allow exactly one Source__c record ID. Throws if id is null. |
allowSet(Set<Id> ids) |
Allow a specific set of Source__c record IDs. Throws if ids is null. An empty set means no sources are allowed. |
excludeAll() |
Allow no sources — no calls will be visible to the user. |
Unlike RestrictCallHandlers, there is no explicit allowAll() method. Simply do not call any write method and the framework treats the result as allow-all.
The Id values must be Source__c record IDs.
Discriminator
This strategy has no SObject discriminator. There is one global implementation per org. Use default as the discriminator value.
Default Behaviour
Allow all sources (AnySource implementation — no filtering applied).
Example: Restrict Sources by Custom Metadata Mapping
Use custom metadata to map each Salesforce Profile to a set of allowed source routes.
public class RestrictSourcesByProfile
implements callcoreio.RestrictSources.IStrategy {
public void getAllowed(callcoreio.RestrictSources.Context context) {
Id profileId = UserInfo.getProfileId();
// SourceProfileAccess__mdt has fields: ProfileId__c, SourceRoute__c
List<SourceProfileAccess__mdt> rules = [
SELECT SourceRoute__c
FROM SourceProfileAccess__mdt
WHERE ProfileId__c = :profileId
];
if (rules.isEmpty()) {
// No rules configured for this profile — allow all
return;
}
Set<String> allowedRoutes = new Set<String>();
for (SourceProfileAccess__mdt r : rules) allowedRoutes.add(r.SourceRoute__c);
List<Source__c> sources = [
SELECT Id FROM callcoreio__Source__c
WHERE callcoreio__Route__c IN :allowedRoutes
];
Set<Id> allowedIds = new Set<Id>();
for (Source__c s : sources) allowedIds.add(s.Id);
if (allowedIds.isEmpty()) {
context.excludeAll();
} else {
context.allowSet(allowedIds);
}
}
}
Example: Restrict to a Single Named Source
Allow only calls that came through a specific phone line, identified by its Route__c external ID.
public class RestrictToSalesLine
implements callcoreio.RestrictSources.IStrategy {
private static final String SALES_ROUTE = 'sales.main';
public void getAllowed(callcoreio.RestrictSources.Context context) {
List<Source__c> sources = [
SELECT Id FROM callcoreio__Source__c
WHERE callcoreio__Route__c = :SALES_ROUTE
LIMIT 1
];
if (sources.isEmpty()) {
context.excludeAll();
} else {
context.allowSingle(sources[0].Id);
}
}
}
Notes
- Fail closed. If your implementation throws an unhandled exception, the framework calls
excludeAll()and the user sees no calls. Design your logic to be defensive. - Sources are identified by their
Source__crecord ID (not byRoute__cor any other field). You will typically need a SOQL query to translate route names or metadata values into record IDs. - In the subscriber org, the
Source__cobject API name iscallcoreio__Source__cand theRoute__cfield iscallcoreio__Route__c. Adjust your queries accordingly. - If both
RestrictSourcesandRestrictCallHandlersare configured, both must pass. A call on an allowed source handled by a restricted handler will not appear. - A warning is logged if your strategy results in an allow-none state. If the timeline is empty for all users and debug mode is off, check whether
RestrictSourcesorRestrictCallHandlersis returning an empty restriction.