||
Skip to end of metadata
Go to start of metadata

The asset.js script is the core component of any asset extension. This script allows business logic of an asset type to be altered with the use of several callback methods. The following sections explain the asset.js script in detail:

Sample asset extension

The default asset extension for the Publisher is available in the <ES_HOME>/repository/deployment/server/jaggeryapps/publisher/extensions/assets/default/asset.js  file. While, the default asset extension for the Store is available in the <ES_HOME>/ repository/deployment/server/jaggeryapps/store/extensions/assets/default/asset.js file.

 Click here to see the sample asset.js
asset.manager = function(ctx) {
    var notifier = require('store').notificationManager;
    var storeConstants = require('store').storeConstants;
    var COMMENT = 'User comment';
    var carbon = require('carbon');
    var social = carbon.server.osgiService('org.wso2.carbon.social.core.service.SocialActivityService');
    var log = new Log('default-asset');
    return {
        create: function(options) {
            var ref = require('utils').time;
            //Check if the options object has a createdtime attribute and populate it
            if ((options.attributes) && ctx.rxtManager.getRxtField(ctx.assetType, 'overview_createdtime')) {
                options.attributes.overview_createdtime = ref.getCurrentTime();
            }
            this._super.create.call(this, options);
            var asset = this.get(options.id); //TODO avoid get: expensive operation
            var assetPath = asset.path;
            var user = ctx.username;
            var userRoles = ctx.userManager.getRoleListOfUser(user);
            try {
                social.warmUpRatingCache(ctx.assetType + ':' + options.id);
            } catch (e) {
                log.warn("Unable to publish the asset: " + ctx.assetType + ":" + options.id + " to social cache. This may affect on sort by popularity function.");
            }
            //Check whether the user has admin role
            var endpoint = storeConstants.PRIVATE_ROLE_ENDPOINT + user;
            for (var role in userRoles) {
                if (userRoles.hasOwnProperty(role) && userRoles[role] == storeConstants.ADMIN_ROLE) {
                    endpoint = storeConstants.ADMIN_ROLE_ENDPOINT;
                }
            }
            //Subscribe the asset author for LC update event and asset update event
            notifier.subscribeToEvent(options.attributes.overview_provider, assetPath, endpoint, storeConstants.LC_STATE_CHANGE);
            notifier.subscribeToEvent(options.attributes.overview_provider, assetPath, endpoint, storeConstants.asset_UPDATE);
        },
        update: function(options) {
            this._super.update.call(this, options);
            var asset = this.get(options.id); //TODO avoid get: expensive operation
            //trigger notification on asset update
            notifier.notifyEvent(storeConstants.asset_UPDATE_EVENT, asset.type, asset.name, null, asset.path, ctx.tenantId);
        },
        search: function(query, paging) {
            return this._super.search.call(this, query, paging);
        },
        list: function(paging) {
            return this._super.list.call(this, paging);
        },
        get: function(id) {
            return this._super.get.call(this, id);
        },
        invokeLcAction: function(asset, action, lcName) {
            var success;
            if (lcName) {
                success = this._super.invokeLcAction.call(this, asset, action, lcName);
            } else {
                success = this._super.invokeLcAction.call(this, asset, action);
            }
            //trigger notification on LC state change
            notifier.notifyEvent(storeConstants.LC_STATE_CHANGE_EVENT, asset.type, asset.name, COMMENT, asset.path, ctx.tenantId);
            return success;
        }
    };
};
asset.server = function(ctx) {
    var type = ctx.type;
    return {
        onUserLoggedIn: function() {},
        endpoints: {
            apis: [{
                url: 'assets',
                path: 'assets.jag'
            }, {
                url: 'asset',
                path: 'asset.jag'
            }, {
                url: 'statistics',
                path: 'statistics.jag'
            }],
            pages: [{
                title: 'asset: ' + type,
                url: 'asset',
                path: 'asset.jag'
            }, {
                title: 'assets ' + type,
                url: 'assets',
                path: 'assets.jag'
            }, {
                title: 'Create ' + type,
                url: 'create',
                path: 'create.jag',
                permission: 'asset_CREATE'
            }, {
                title: 'Update ' + type,
                url: 'update',
                path: 'update.jag',
                permission: 'asset_UPDATE'
            }, {
                title: 'Details ' + type,
                url: 'details',
                path: 'details.jag'
            }, {
                title: 'List ' + type,
                url: 'list',
                path: 'list.jag',
                permission: 'asset_LIST'
            }, {
                title: 'Lifecycle',
                url: 'lifecycle',
                path: 'lifecycle.jag',
                permission: 'asset_LIFECYCLE'
            }, {
                title: 'Old lifecycle ',
                url: 'old-lifecycle',
                path: 'old-lifecycle.jag'
            }, {
                title: 'Statistics',
                url: 'statistics',
                path: 'statistics.jag'
            }, {
                title: 'Copy ' + type,
                url: 'copy',
                path: 'copy.jag',
                permission: 'asset_CREATE'
            }]
        }
    };
};
asset.configure = function() {
    return {
        table: {
            overview: {
                fields: {
                    provider: {
                        readonly: true
                    },
                    name: {
                        name: {
                            name: 'name',
                            label: 'Name'
                        },
                        updatable: false,
                        validation: function() {}
                    },
                    version: {
                        name: {
                            label: 'Version'
                        }
                    },
                    createdtime: {
                        hidden: true
                    }
                }
            },
            images: {
                fields: {
                    thumbnail: {
                        type: 'file'
                    },
                    banner: {
                        type: 'file'
                    }
                }
            }
        },
        meta: {
            lifecycle: {
                name: 'SampleLifeCycle2',
                commentRequired: false,
                defaultLifecycleEnabled: true,
                defaultAction: 'Promote',
                deletableStates: [],
                publishedStates: ['Published'],
                lifecycleEnabled: true
            },
            ui: {
                icon: 'fw fw-resource'
            },
            categories: {
                categoryField: 'overview_category'
            },
            thumbnail: 'images_thumbnail',
            banner: 'images_banner',
            versionAttribute: 'overview_version',
            providerAttribute: 'overview_provider',
            timestamp: 'overview_createdtime',
            permissions: {
                configureRegistryPermissions: function(ctx) {
                    var type = ctx.type;
                    var tenantId = ctx.tenantId;
                    var rxtManager = ctx.rxtManager;
                    var staticPath = rxtManager.getStaticRxtStoragePath(type);
                    var Utils = ctx.utils;
                    staticPath = Utils.governanceRooted(staticPath);
                    log.debug('[configure-registry-permissions] assigning permissions to static path ' + staticPath);
                    Utils.authorizeActionsForEveryone(tenantId, staticPath);
                }
            }
        }
    };
};
asset.renderer = function(ctx) {
    var type = ctx.assetType;
    var permissionAPI = require('rxt').permissions;
    var isassetWithLifecycle = function(asset) {
        if ((asset.lifecycle) && (asset.lifecycleState)) {
            return true;
        }
        log.warn('asset: ' + asset.name + ' does not have a lifecycle or a state.The lifecycle view will not be rendered for this asset');
        return false;
    };
    var buildListLeftNav = function(page, util) {
        var navList = util.navList();
        if (permissionAPI.hasassetPermission(permissionAPI.asset_CREATE, ctx.assetType, ctx.session)) {
            navList.push('Add ' + type, 'btn-add-new', util.buildUrl('create'));
            navList.push('Statistics', 'btn-stats', '/assets/' + type + '/statistics');
        }
        //navList.push('Configuration', 'icon-dashboard', util.buildUrl('configuration'));
        return navList.list();
    };
    var buildDefaultLeftNav = function(page, util) {
        var id = page.assets.id;
        var navList = util.navList();
        var isLCViewEnabled = ctx.rxtManager.isLifecycleViewEnabled(ctx.assetType);
        if (permissionAPI.hasassetPermission(permissionAPI.asset_UPDATE, ctx.assetType, ctx.session)) {
            navList.push('Edit', 'btn-edit', util.buildUrl('update') + '/' + id);
        }
        navList.push('Overview', 'btn-overview', util.buildUrl('details') + '/' + id);
        //Only render the view if the asset has a 
        if ((isLCViewEnabled) && (isassetWithLifecycle(page.assets))) {
            if (permissionAPI.hasassetPermission(permissionAPI.asset_LIFECYCLE, ctx.assetType, ctx.session)) {
                navList.push('Life Cycle', 'btn-lifecycle', util.buildUrl('lifecycle') + '/' + id);
            }
        }
        if (permissionAPI.hasassetPermission(permissionAPI.asset_CREATE, ctx.assetType, ctx.session)) {
            navList.push('Copy', 'btn-copy', util.buildUrl('copy') + '/' + id);
        }
        return navList.list();
    };
    var buildAddLeftNav = function(page, util) {
        return [];
    };
    var isActivatedasset = function(assetType) {
        var app = require('rxt').app;
        var activatedassets = app.getActivatedassets(ctx.tenantId); //ctx.tenantConfigs.assets;
        //return true;
        if (!activatedassets) {
            throw 'Unable to load all activated assets for current tenant: ' + ctx.tenatId + '.Make sure that the assets property is present in the tenant config';
        }
        for (var index in activatedassets) {
            if (activatedassets[index] == assetType) {
                return true;
            }
        }
        return false;
    };
    return {
        list: function(page) {
            var assets = page.assets;
            for (var index in assets) {
                var asset = assets[index];
                var timestampAttribute = ctx.rxtManager.getTimeStampAttribute(ctx.assetType);
                if (asset.attributes.hasOwnProperty(timestampAttribute)) {
                    var value = asset.attributes[timestampAttribute];
                    var date = new Date();
                    date.setTime(value);
                    asset.attributes[timestampAttribute] = date.toUTCString();
                }
            }
            require('/modules/page-decorators.js').pageDecorators.assetCategoryDetails(ctx, page, this);
        },
        details: function(page) {
            var tables = page.assets.tables;
            //TODO:This cannot be hardcoded
            var timestampAttribute = 'createdtime'; //ctx.rxtManager.getTimeStampAttribute(this.assetType);
            for (var index in tables) {
                var table = tables[index];
                if ((table.name == 'overview') && (table.fields.hasOwnProperty(timestampAttribute))) {
                    var value = table.fields[timestampAttribute].value || '';
                    var date = new Date();
                    date.setTime(value);
                    table.fields[timestampAttribute].value = date.toUTCString();
                }
            }
        },
        create: function(page) {
            var tables = page.assets.tables;
            var providerAttribute = 'provider';
            for (var index in tables) {
                var table = tables[index];
                if ((table.name == 'overview') && (table.fields.hasOwnProperty(providerAttribute))) {
                    table.fields[providerAttribute].value = page.cuser.username;
                }
            }
        },
        update: function(page) {
            var tables = page.assets.tables;
            var timestampAttribute = 'createdtime';
            for (var index in tables) {
                var table = tables[index];
                if ((table.name == 'overview') && (table.fields.hasOwnProperty(timestampAttribute))) {
                    var value = table.fields[timestampAttribute].value;
                    var date = new Date();
                    date.setTime(value);
                    table.fields[timestampAttribute].value = date.toUTCString();
                }
            }
        },
        pageDecorators: {
            leftNav: function(page) {
                if (log.isDebugEnabled()) {
                    log.debug('Using default leftNav');
                }
                switch (page.meta.pageName) {
                    case 'list':
                        page.leftNav = buildListLeftNav(page, this);
                        break;
                    case 'create':
                        page.leftNav = buildAddLeftNav(page, this);
                        break;
                    case 'statistics':
                        page.leftNav = buildListLeftNav(page, this);
                        break;
                    default:
                        page.leftNav = buildDefaultLeftNav(page, this);
                        break;
                }
                if (page.leftNav) {
                    for (var navItem in page.leftNav) {
                        if (page.leftNav[navItem].name) {
                            page.leftNav[navItem].id = page.leftNav[navItem].name.replace(/\s/g, "");
                        }
                    }
                }
                return page;
            },
            ribbon: function(page) {
                var ribbon = page.ribbon = {};
                var DEFAULT_ICON = 'fw fw-circle';
                var assetTypes = [];
                var assetType;
                var assetList = ctx.rxtManager.listRxtTypeDetails();
                for (var index in assetList) {
                    assetType = assetList[index];
                    //Only populate the link if the asset type is activated and the logged in user has permission to that asset
                    if ((isActivatedasset(assetType.shortName)) && (permissionAPI.hasassetPermission(permissionAPI.asset_LIST, assetType.shortName, ctx.session))) {
                        assetTypes.push({
                            url: this.buildBaseUrl(assetType.shortName) + '/list',
                            assetIcon: assetType.ui.icon || DEFAULT_ICON,
                            assetTitle: assetType.singularLabel
                        });
                    }
                }
                ribbon.currentType = page.rxt.singularLabel;
                ribbon.currentTitle = page.rxt.singularLabel;
                ribbon.currentUrl = this.buildBaseUrl(type) + '/list'; //page.meta.currentPage;
                ribbon.shortName = page.rxt.singularLabel;
                ribbon.query = 'Query';
                ribbon.breadcrumb = assetTypes;
                return page;
            },
            populateAttachedLifecycles: function(page) {
                if (page.assets.id) {
                    require('/modules/page-decorators.js').pageDecorators.populateAttachedLifecycles(ctx, page, this);
                }
            },
            populateassetVersionDetails: function(page) {
                if (page.assets.id) {
                    require('/modules/page-decorators.js').pageDecorators.populateassetVersionDetails(ctx, page, this);
                }
            },
            populateTags: function(page){
                if(page.assets.id){
                    require('/modules/page-decorators.js').pageDecorators.populateTagDetails(ctx,page);
                }
            },
            sorting: function(page){
                require('/modules/page-decorators.js').pageDecorators.sorting(ctx,page);
            }
        }
    };
};
 Click here to see the sample asset.js
asset.manager = function(ctx) {
    /**
     * The function augments the provided query to include published state information
     * @param  {[type]} query [description]
     * @return {[type]}       The provided query object 
     */
    var buildPublishedQuery = function(query) {
        query = query || {};
        var isLCEnabled = ctx.rxtManager.isLifecycleEnabled(ctx.assetType);
        //If lifecycles are not enabled then do nothing
        if(!isLCEnabled){
            log.warn('lifecycles disabled,not adding published states to search query');
            return query;
        }
        //Get all of the published assets
        var publishedStates = ctx.rxtManager.getPublishedStates(ctx.assetType) || [];
        //Determine if there are any published states
        if (publishedStates.length == 0) {
            return query;
        }
        //TODO: Even though an array is sent in only the first search value is accepted
        query.lcState=[publishedStates[0]];
        return query;
    };
    return {
        search: function(query, paging) {
            query=buildPublishedQuery(query);
            var assets = this._super.search.call(this, query, paging);
            return assets;
        },
        list: function(paging) {
            var assets = this._super.list.call(this, paging);
            return assets;
        },
        get: function(id) {
            var asset = this._super.get.call(this, id);
            return asset;
        }
    };
};
asset.server = function(ctx) {
    var type = ctx.assetType;
    var typeDetails = ctx.rxtManager.listRxtTypeDetails(type);
    var typeSingularLabel = type; //Assume the type details are not returned
    if (typeDetails) {
        typeSingularLabel = typeDetails.singularLabel;
    }
    return {
        onUserLoggedIn: function() {},
        endpoints: {
            apis: [{
                url: 'assets',
                path: 'assets.jag'
            }, {
                url: 'subscriptions',
                path: 'subscriptions.jag'
            }, {
                url: 'rate',
                path: 'rate.jag'
            }],
            pages: [{
                title: 'Store |  ' + typeSingularLabel,
                url: 'details',
                path: 'details.jag',
                permission:'asset_DETAILS'
            }, {
                title: 'Store | ' + typeSingularLabel,
                url: 'list',
                path: 'list.jag',
                permission:'asset_LIST'
            }, {
                title: 'Store | ' + typeSingularLabel,
                url: 'subscriptions',
                path: 'subscriptions.jag'
            }]
        }
    };
};
asset.configure = function() {
    return {
        table: {
            overview: {
                fields: {
                    provider: {
                        readonly: true
                    }
                }
            },
            images: {
                fields: {
                    thumbnail: {
                        type: 'file'
                    },
                    banner: {
                        type: 'file'
                    }
                }
            }
        },
        meta: {
            lifecycle: {
                name: 'SampleLifeCycle2',
                commentRequired: false,
                defaultAction: 'Promote',
                deletableStates: [],
                publishedStates: ['Published'],
                lifecycleEnabled:true
            },
            ui: {
                icon: 'fw fw-resource'
            },
            categories: {
                categoryField: 'overview_category'
            },
            search: {
                searchableFields: ['all'],
            },
            paging: {
                size: 10
            },
            thumbnail: 'images_thumbnail',
            banner: 'images_banner',
            versionAttribute:'overview_version',
            providerAttribute:'overview_provider',
            timestamp:'overview_createdtime',
        }
    };
};
asset.renderer = function(ctx) {
    var decoratorApi = require('/modules/page-decorators.js').pageDecorators;
    return {
        pageDecorators: {
            navigationBar: function(page) {
                return decoratorApi.navigationBar(ctx, page, this);
            },
            searchBar: function(page) {
                return decoratorApi.searchBar(ctx, page, this);
            },
            categoryBox: function(page) {
                return decoratorApi.categoryBox(ctx, page, this);
            },
            authenticationDetails: function(page) {
                return decoratorApi.authenticationDetails(ctx, page, this);
            },
            recentassets: function(page) {
                return decoratorApi.recentassets(ctx, page);
            },
            tags: function(page) {
                return decoratorApi.tags(ctx, page);
            },
            myassets: function(page) {
                return decoratorApi.myassets(ctx, page);
            },
            socialFeature: function(page) {
                return decoratorApi.socialFeature(ctx, page);
            },
            socialSites: function(page, meta) {
                return decoratorApi.socialSites(ctx,page, meta, this);
            },
            embedLinks: function(page, meta) {
                return decoratorApi.embedLinks(ctx,page, meta);
            },
            populateassetVersionDetails:function(page,meta){
                return decoratorApi.populateassetVersionDetails(ctx,page,this);
            },
            sorting: function(page,meta){
                return decoratorApi.sorting(ctx,page,this);
            },
            populateActionBar: function(page,meta){
                page.actionBar = {};
                page.actionBar.actions = [];
                //Format
                //var action = {};
                //action.url = '/list';
                //action.iconClass ='ast-create';
                //action.name ='Create';
                //page.actionBar.actions.push(action);
            }
        }
    };
};

Asset extension implementation

The asset.js file of each asset extension is always processed in context of the default extension. The following diagram explains how this implementation works, where gadget is the example asset type.

 

The asset.js script that corresponds to an asset extension (e.g., gadget asset extension) inherits callback methods from the default asset extension. In ES, you can use the asset.manager callback method, which corresponds to the asset extension, to customize assets as ES treats this method as a special case. ES uses the generic asset manager implementation, which is in the RXT module, as the parent implementation. Therefore, as the callback methods are inherited from the default asset extension, a developer can choose to implement only some of the callback methods, or even choose not to define any of the callback methods in the asset extension. Thereby, if a developer does not define any callback methods, the callback methods in the default asset extension are invoked. 

The asset extension behavior is implemented by first creating an instance of the generic asset manager, and then sequentially assigning the methods defined at the default and asset (e.g., gadget) levels as shown in the figure above. The default asset extension methods that are overridden by the asset extension (e.g., gadget asset extension) are placed in a special property referenced by _super. For more information on how to call the parent implementation see, Example 2 - Calling the parent implementation when overriding a method.

Asset extension callback methods

The asset.js script is the core of any asset extension. This script allows business logic of an asset type to be altered with the use of several callback methods, which are listed below:

Callback MethodDescription
asset.manager You can use this callback method to override the existing methods to handle the CRUD (create, read, update and delete) business logic of an asset type.
For more information, see asset.manager Method Definitions.
asset.server

You can use this callback method to create or override APIs and pages. Thereby, you can use this method to specify as to what URL structure the app should use. For more information, see asset.server Property Definitions.

asset.configure

You can use this callback method to alter RXT properties and define meta properties (i.e., thumbnail , banner and category ). Thereby, you can use this method to define how the asset needs to behave and also how it is rendered. For more information, see asset.configure Property Definitions.

asset.renderer You can use this callback method to intercept calls to render operations such as, control page decorators (e.g., tag cloud, social meta information, rating). For more information, see asset.render Property Definitions.
  • No labels