1. Introduction
GR8 CRM is a set of Grails Web Application Framework plugins that makes it easy to develop web applications with CRM functionality.
You can find more information about GR8 CRM on the main documentation site http://gr8crm.github.io.
1.1. Customer relationship management
Customer relationship management (CRM) is a system for managing a company’s interactions with current and future customers. It involves using technology to organize, automate and synchronize sales, marketing, customer service, and technical support. Wikipedia
The GR8 CRM "Ecosystem" currently contains over 40 Grails plugins. For a complete list of plugins see http://gr8crm.github.io.
Each GR8 CRM plugin defines a Bounded Context that focus on one specific domain, for example contact, project or document.
2. CRM Feature Plugin
The crm-feature
plugin manages installed features in a GR8 CRM application. A feature is a unit of functionality that can be
enabled or disabled per user role. Application code can check if a feature is enabled before doing some work.
Typically one GR8 CRM plugin provides one feature but there is no limit to the number of features a plugin can provide.
3. Adding features to an application
Features can be added to an application in two ways.
-
Add a features property to the plugin descriptor
-
Adding features using CrmFeatureService
3.1. Add a feature property to the plugin descriptor
If a plugin provides a feature, the easiest way to add it to the application is by adding
a property called features
to the plugin descriptor. The features property must return a Map or a Closure.
class CrmContactGrailsPlugin {
...
def features = [name: "crmContact", description: "Contact Management",
enabled: true, main: [controller: 'crmContact']]
}
If you prefer the Closure variant it follows the same structure.
class CrmAgreementGrailsPlugin {
....
def features = {
crmAgreement {
description "Agreement Management"
main controller: "crmAgreement", action: "index"
enabled false // this is default
}
}
}
3.1.1. Feature DSL
The feature plugin scans all installed plugins and look for a features
property in the plugin descriptor.
If the plugin has a features
property it is parsed by the Feature DSL parser. The following example is from the
crm-tags
plugin. It provides tagging support in a GR8 CRM application. A feature with name crmTag will be
installed in the application. The feature DSL also specifies standard permissions for common user roles.
def features = {
crmTag {
description "Tag domain instances with user-defined labels"
permissions {
guest "crmTag:list"
partner "crmTag:list"
user "crmTag:*"
admin "crmTag,crmTagAdmin:*"
}
theme "premium" // Feature is only available to tenants with the premium theme.
required true
hidden true
}
}
3.1.2. Feature Permissions
In the above example the crmTag feature DSL specifies a set of standard permissions that will be declared in th application. Users with the role guest will only get permission to call the list action on the crmTag controller. Users with role user call all actions on the crmTag controller. And the role admin can also call admin actions.
A developer can programatically add more roles and permissions if needed, but the feature DSL is an easy way to add necessary permissions during application startup.
3.1.3. Required/Default Features
The required true
statement specifies that this feature is required, it will be enabled for all users and roles automatically.
3.1.4. Hidden Features
The hidden true
statement specifies that this feature should not be displayed in any feature settings pages.
It’s a default/required feature so there is no reason to let the application administrator enable or disable it.
3.1.5. Theme Features
The theme
statement specifies that the feature is only available to tenants that uses a specific CRM theme.
3.2. Adding features using CrmFeatureService
You can also add features to the application by calling crmFeatureService.addApplicationFeature(Map metadata)
.
def metadata = [name:"awesome", description: "This feature is awesome", controller: "awesome", action: "index"]
crmFeatureService.addApplicationFeature(metadata)
3.3. Enabling/disabling features programatically
Although many features can be available in an application, features are normally not enabled by default. Application code can enable features for specific user roles and/or tenants.
Long tenant = grails.crm.core.TenantUtils.tenant
String role = "VIP_ROLE"
crmFeatureService.enableFeature("awesome", role, tenant)
You can also make it possible for system administrators to enable features on-demand, this is however application specific and can be implemented with code like above.
3.4. Check if feature is enabled
Long tenant = grails.crm.core.TenantUtils.tenant
if(crmFeatureService.hasFeature("awesome", null, tenant)) {
// The "awesome" feature is installed and enabled for all roles, great!
}
3.5. Get metadata for a feature
Each feature provide a set of [metadata|guide:feature-metadata] properties.
Map metadata = crmFeatureService.getFeature("awesome");
assert metadata.description == "This feature is awesome"
// null is returned if the feature is not installed
assert crmFeatureService.getFeature("not installed") == null
You can read metadata for a feature even though the feature is not enabled. |
4. Services
The crm-feature plugin provide a service called CrmFeatureService
.
This service contains methods for enabling/disabling features for users and roles.
4.1. CrmFeatureService
List<Feature> getApplicationFeatures()
Returns all the features that are available in the application, even disabled features are included.
Feature getApplicationFeature(final String name)
Returns metadata for a specific application feature. A metadata instance has the following properties:
Attribute |
Description |
name |
The unique name of the feature |
description |
Short text that describes the feature |
enabled |
If true the feature will be enabled by default, otherwise features are disabled by default. |
role |
If |
tenant |
If |
info |
(recommended) Map with parameters to createLink() to access this feature’s information page |
admin |
(optional) Map with parameters to createLink() to access this feature’s administration page |
main |
(optional) Map with parameters to createLink() to access this feature’s start page |
The properties info
, help
, admin
and main
contains a Map with the following properties:
Property |
Description |
controller |
controller attribute for createLink() |
action |
(optional) action attribute for createLink() |
mapping |
(optional) named URL mapping to use to rewrite the link |
params |
(optional) params attribute for createLink() |
removeApplicationFeature(String name)
To remove a feature you normally disable it instead of removing it. If an unwanted feature is the only feature provided by a plugin, it’s probably better to uninstall the plugin completely. But there may be occasions where you want one feature from a plugin that provides several features. In that case you can remove unwanted features at application startup. For example in BootStrap.groovy.
crmFeatureService.removeApplicationFeature("facebook")
void enableFeature(def features, Long tenant = null, String role = null, Date expires = null)
Enable a feature for a specific user role or for all roles in a tenant.
The features
parameter can be a feature name or a collection of feature names.
If no tenant
is specified then the current executing tenant will be used.
If no role
is specified then the feature will be enabled for all roles in the tenant.
An expiration date can be specified. When the date has passed the feature will be disabled.
This can be used to provide a trial period where a feature will be enabled for a limited period.
void disableFeature(def features, Long tenant = null, String role = null)
Disable a feature for a specific user role or for all roles in a tenant.
The features
parameter can be a feature name or a collection of feature names.
If no tenant
is specified then the current executing tenant will be used.
If no role
is specified then the feature will be disabled for all roles in the tenant.
boolean hasFeature(final String feature, Long tenant = null, String role = null)
Check if a feature is enabled.
If no tenant
is specified then the current executing tenant will be used.
If no role
is specified then it will check if the feature is enabled for all users in the tenant.
List<Feature> getFeatures(Long tenant = null, String role = null)
List all enabled features.
If no tenant
is specified then features enabled in the current executing tenant will be returned.
If no role
is specified then all features enabled in the tenant will be returned.
5. Tag Libraries
The crm-feature
plugin provides a few GSP tags under the crm
namespace.
5.1. featureLink
This tag renders a hyperlink to the main controller of a feature, if the feature is enabled for the current user.
Attribute |
Description |
feature |
Name of feature |
tenant |
Render link only if the feature is enabled in the specified tenant (default = current tenant) |
role |
Render link only if the feature is enabled for the specified user role |
enabled |
if true bypass checks and render the link even if the feature is not enabled |
nolink |
If true and the feature has no main controller, render tag body (but no hyperlink) |
5.2. hasFeature
Check if a feature is enabled and render the tag body if it is.
Attribute |
Description |
feature |
Name of feature |
tenant |
Render tag body only if the feature is enabled in the specified tenant (default = current tenant) |
role |
Render tag body only if the feature is enabled for the specified user role |
5.3. eachFeature
Iterate over all enabled features and render tag body for each iteration.
Attribute |
Description |
tenant |
Render tag body only if the feature is enabled in the specified tenant (default = current tenant) |
role |
Render tag body only if the feature is enabled for the specified user role |
var |
Name of iteration variable (default = "it") |
status |
Name of iteration count variable |
An important design philosophy with GR8 CRM is to avoid tight coupling between plugins. This means that if you develop a GR8 CRM plugin you should try to avoid checking if features from other plugins are installed or not. The application is the container that knows about all installed plugins and you are free to check for feature availability in application code, but you should avoid checking for features in plugin code. Use events instead. |
6. Changes
- 2.4.3
-
The enableFeature event is only sent when the feature was not previously enabled
- 2.4.2
-
The method
hasFeature(String name, Long tenant, String role)
now uses the current tenant if no tenant is specified - 2.4.1
-
A feature can now be tied to a theme. Only tenants with that theme will have access to the feature
- 2.4.0
-
First version compatible with Grails 2.4.4.
- 2.0.1
-
A feature can now be tied to a theme. Only tenants with that theme will have access to the feature
- 2.0.0
-
First public release
7. License
This plugin is licensed with Apache License version 2.0
8. Source Code
The source code for this plugin is available at https://github.com/goeh/grails-crm-core
9. Contributing
Please report issues or suggestions.
Want to improve the plugin: Fork the repository and send a pull request.