Skip to content

Instantly share code, notes, and snippets.

@jbandura
Last active June 1, 2022 13:07
Show Gist options
  • Save jbandura/78f79c72126b2d978bd100605bf7d2be to your computer and use it in GitHub Desktop.
Save jbandura/78f79c72126b2d978bd100605bf7d2be to your computer and use it in GitHub Desktop.
interface Capability {
isAllowed(args: Record<string, any>): boolean;
get disallowReason(): string;
get name(): string;
get accountId(): string;
}
class CapabilityService extends Service {
capabilities: Capability[];
constructor() {
super();
this._registerCapabilities();
}
// the main method for checking the capability
hasCapability(capabilityName: string, args?: Record<string, any>) {
const capability = this.capabilities.findBy('name', capabilityName);
if (!capability) return false;
return capability.isAllowed(args);
}
// in case user does not have a capability this method can be additonally used to display a message
getDisallowReason(capabilityName: string) {
return this.capabilities.findBy('name', capabilityName).disallowReason;
}
// main place to register capabilities that need to be calculated on the frontend
private _registerCapabilities() {
const capabilitiesToRegister = [
new CanStartTrialCapability(getOwner(this))
];
this.capabilities = [...this.capabilities, ...capabilitiesToRegister];
}
// main method for fetching capabilities by name, called in one of top-level routes
async fetchCapabilities(capabilityNames: string[]) {
// fetching from backend goes here
const capabilitiesFromBackend = [
{
name: 'can_start_trial',
// this is ED's model method that would just alias to 'allowed' attribute returned from backend
isAllowed() { return true; },
disallowReason: null
},
];
this.capabilities = [...this.capabilities, ...capabilitiesFromBackend];
}
// main method for fetching single capability, useful for computationally heavy logic
async fetchCapability(capabilityName: string) {
// fetching from backend goes here
const capability = { name: 'can_see_trial_ended_banner', isAllowed: () => true, disallowReason: null };
this.capabilities = [...this.capabilities, capability];
}
}
// example of capability logic implemented on the frontend
class CanStartTrialCapability implements Capability {
@service declare session: Service['session'];
get accountId() { return this.session.currentAccount.id }
name: 'can_start_trial';
constructor(owner: EmberOwner) {
setOwner(this, owner);
}
isAllowed(args: Record<string, any>) {
return this.session.currentAccount.isPremium;
}
get disallowReason(): string {
if(!this.isAllowed) return 'Not a premium account';
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment