node-echo v0.1.9

Display Filters

file activityObjects.js

//Load dependencies
if(typeof Class === 'undefined') Class = require('./Class.js').Class;
var utils = require("./utils.js");
var render = require("./render.js").Render;
var cons = require("./Const.js");

var ActivityObject = Class.extend({
    /**
     * Parent class to define all the Activity Objects Echo deals with, and their method for XML rendering according to their verb.
     * <a href="http://wiki.aboutecho.com/w/page/24780107/How%20To%20-%20Getting%20us%20your%20Firehose#Supportedactivityobjecttypes">See Echo documentation</a>
     * 
     * @class ActivityObject
     * @constructor
     * @param {object} properties Specify:
     * <ul>
     *     <li>properties.item.content : the item you want to create (depends on its kind, see subclasses documentation)</li>
     *     <li>properties.item.user : the user interacting with this item</li>
     *     <li>properties.item.feed : the feed this item is posted to.</li>
     *     <li>properties.item.verb : (optional) overwrite default verb (post) for this item</li>
     * </ul>
     * @private
     */

     init: function(){
        /**
         * Initialised the ActivityObject. Meta data Check.
         * Needs to be extended by Child classes (for content checking).
         * Is automatically called at object spawning.
         * @method init
         */
        if (!(this.item.user && this.item.user.id && this.item.user.avatarURL && this.item.user.name)){
            throw {name :"Invalid user exception", error : "Invalid user"}
        }
        if (!(this.item.feed)){
            throw {name : "Invalid options exception", error :"Invalid feed"};
        }
        // Set defaults.
        this.item.type = "abstract";
        if(!this.item.verb){
            this.verb = cons.VERB_POST;
        } else {this.verb = this.item.verb}
        if(!(this.item.target)){ this.item.target = {} }

     }
     ,renderPost: function(callback){
       /**
        * Forge a proper XML document ready for posting, using base template.
        * @method renderPost
        * @param {function} callback callback (should very likely be a call to a "submit" method)
        */
        var self = this;
        this.renderItem(function(err,renderedData){
           if(err){ callback(err,"") } else {
              render.renderTemplate(
                 __dirname + '/templates/base.xml'
                ,self.itemTemplate(renderedData)
                ,function(error,renderedMessage){ // Third arg of render.renderTemplate
                    if(error)callback(error,"");
                    else{
                       callback("",{ content: renderedMessage })
                    }
                 });
              }
           }
        )
     }
    ,itemTemplate: function(data){
        /**
         * Select and return the proper properties for an object.
         * @method itemTemplate
         * @private
         */
        var date = utils.ISODateString(new Date());
        return {
                activityObject: data
               ,feed: {
                  idUrl: this.item.feed,
                  updated: date
               }
               ,entry: {
                  id: this.item.content.permalink,
                  published: date
               }
               ,target: {
                   type: this.item.target.type
                  ,url: this.item.target.id
               }
               ,actor: {
                    url: this.item.user.id
                   ,name: this.item.user.name
                   ,avatar: this.item.user.avatarURL
               }
               ,verb:this.verb
            }
    }
    ,renderItem : function(callback){
        /**
         * Render the part of the Item that is <i>specific</i> to this item, using templates.
         * @method renderItem
         * @param {function} callback callback
         */
        callback("","")
    } // Different for all items, must be extended

    // Properties (common to all Items):
    ,item:{
        /**
         * Define the values for this item.
         * @property item
         */
        enumerable: true
    }
});

var Article = ActivityObject.extend({
    /**
     * Article.
     * @class Article
     * @extends ActivityObject
     * @private
     * @param {object} properties Specify:
     * <ul>
     *     <li>properties.item.content : the article. Need to specify:
     *     <ul>
     *         <li>properties.item.content.title : title of the article</li>
     *         <li>properties.item.content.content : the main content of the article,</li>
     *         <li>properties.item.content.permalink : a unique URL for this item.</li>
     *         <li>properties.item.content.summary : a short summary for that item</li>
     *     </ul></li>
     *     <li>properties.item.user : user posting that item.</li>
     *     <li>properties.item.target : (optional) a target for this item. Default: current item. Specify
     *     <ul>
     *         <li>properties.item.target.id : the permalink of the target</li>
     *         <li>properties.item.type : the type of the target</li>
     *     </ul></li>
     *     <li>properties.item.feed : the feed this item is posted to.</li>
     *     <li>properties.item.verb : (optional) overwrite default verb (post) for this item</li>
     * </ul>
     * @constructor
     *
     */
    init: function(){
        // Call parent
        this._super();

        // Set specific parameters
        this.item.type = cons.TYPE_ARTICLE;

        // Check content:        
        if (!(this.item.content && this.item.content.title && this.item.content.summary && this.item.content.content && this.item.content.permalink && this.item.feed)){
            throw {name : "Invalid Article exception", error:"Article needs a title, a summary, a content, a permalink and a feed ID"}
        } else {
            // Format content
            this.item.content.summary = utils.Encoder.htmlEncode(this.item.content.summary,true);
            this.item.content.content = utils.Encoder.htmlEncode(this.item.content.content,true);
            this.item.content.title = utils.Encoder.htmlEncode(this.item.content.title,true);
        }

        if(!(this.item.target && this.item.target.id && this.item.target.type)){
             this.item.target = {
                 id:this.item.content.permalink
                 , type : this.item.type
             }
        }
    },
    renderItem : function(callback){
        render.renderTemplate(__dirname + '/templates/article.xml', { article: this.item.content }, callback)
    }
});


var Comment = ActivityObject.extend({
    /**
     * Comment.
     * @extends ActivityObject
     * @class Comment
     * @private
     * @param {object} properties Specify:
     * <ul>
     *     <li>properties.item.content : the comment. Need to specify:
     *     <ul>
     *         <li>properties.item.content.subject : subject of the comment (can be blank, can't be undefined</li>
     *         <li>properties.item.content.content : the main content of the comment,</li>
     *         <li>properties.item.content.permalink : a unique URL for this item.</li>
     *     </ul></li>
     *     <li>properties.item.user : user posting that comment.</li>
     *     <li>properties.item.target : (optional) a target for this item. Default: Current item. Specify
     *     <ul>
     *         <li>properties.item.target.id : the permalink of the target</li>
     *         <li>properties.item.type : the type of the target</li>
     *     </ul></li>
     *     <li>properties.item.feed : the feed this item is posted to.</li>
     *     <li>properties.item.verb : (optional) overwrite default verb (post) for this item</li>
     * </ul>
     * @constructor
     */
    init: function(){
        // Call parent init
        this._super();
        // Set specifics
        this.item.type = cons.TYPE_COMMENT;
        //Data check and formatting
        if (!(this.item.content && this.item.content.content && this.item.content.subject && this.item.content.permalink)){
            throw {name : "Invalid Comment exception", error:"Comment needs a subject, a content and a permalink"}
        } else {
            this.item.content.content = utils.Encoder.htmlEncode(this.item.content.content,true);
            this.item.content.subject = utils.Encoder.htmlEncode(this.item.content.subject,true);
        }
        if(!(this.item.target && this.item.target.id && this.item.target.type)){
             this.item.target = {
                 id:this.item.content.permalink
                 , type : this.item.type
             }
        }
    },
    renderItem : function(callback){
        render.renderTemplate(__dirname + '/templates/comment.xml', { comment: this.item.content }, callback)
    }
});

var Note = ActivityObject.extend({
    /**
     * Note.
     * @private
     * @extends ActivityObject
     * @param {object} properties Specify:
     * <ul>
     *     <li>properties.item.content : the note. Need to specify:
     *     <ul>
     *         <li>properties.item.content.content : the main content of the Note.</li>
     *         <li>properties.item.content.permalink : a unique URL for this item.</li>
     *     </ul></li>
     *     <li>properties.item.user : user posting that item.</li>
     *     <li>properties.item.target : (optional) a target for this item. Default: Current item. Specify
     *     <ul>
     *         <li>properties.item.target.id : the permalink of the target</li>
     *         <li>properties.item.type : the type of the target</li>
     *     </ul></li>
     *     <li>properties.item.feed : the feed this item is posted to.</li>
     *     <li>properties.item.verb : (optional) overwrite default verb (post) for this item</li>
     * </ul>
     * @class Note
     * @constructor
     */
    init: function(){
        // Call parent init
        this._super();
        // Set specifics
        this.item.type = cons.TYPE_NOTE;
        //Data check and formatting
        if (!(this.item.content && this.item.content.content && this.item.content.permalink)){
            throw {name : "Invalid Note exception", error:"Note needs a content and a permalink"}
        } else {
            this.item.content.content = utils.Encoder.htmlEncode(this.item.content.content,true);
        }
        if(!(this.item.target && this.item.target.id && this.item.target.type)){
             this.item.target = {
                 id:this.item.content.permalink
                 , type : this.item.type
             }
        }
    },
    renderItem : function(callback){
        render.renderTemplate(__dirname + '/templates/note.xml', { note: this.item.content }, callback)
    }
});

// Interestingly, a "Status" is strictly equivalent to a "Note". But it's worth separating both objects.
var Status = ActivityObject.extend({
    /**
     * Status.
     * @class Status
     * @private
     * @extends ActivityObject
     * @param {object} properties Specify:
     * <ul>
     *     <li>properties.item.content : the status. Need to specify:
     *     <ul>
     *         <li>properties.item.content.content : the main content of the status.</li>
     *         <li>properties.item.content.permalink : a unique URL for this item.</li>
     *     </ul></li>
     *     <li>properties.item.user : user posting that item.</li>
     *     <li>properties.item.target : (optional) a target for this item. Default: Current item. Specify
     *     <ul>
     *         <li>properties.item.target.id : the permalink of the target</li>
     *         <li>properties.item.type : the type of the target</li>
     *     </ul></li>
     *     <li>properties.item.feed : the feed this item is posted to.</li>
     *     <li>properties.item.verb : (optional) overwrite default verb (post) for this item</li>
     * </ul>
     * @constructor
     */
    init: function(){
        // Call parent init
        this._super();
        // Set specifics
        this.item.type = cons.TYPE_STATUS;
        //Data check and formatting
        if (!(this.item.content && this.item.content.content && this.item.content.permalink)){
            throw {name : "Invalid Status exception", error:"Status needs a content and a permalink"}
        } else {
            this.item.content.content = utils.Encoder.htmlEncode(this.item.content.content,true);
        }
        if(!(this.item.target && this.item.target.id && this.item.target.type)){
             this.item.target = {
                 id:this.item.content.permalink
                 , type : this.item.type
             }
        }
    },
    renderItem : function(callback){
        render.renderTemplate(__dirname + '/templates/status.xml', { status: this.item.content }, callback)
    }
});

var Tag = ActivityObject.extend({
    /**
     * Tag/Untag.
     * @extends ActivityObject
     * @private
     * @class Tag
     * @param {object} properties Specify:
     * <ul>
     *     <li>properties.item.content : the tag. Need to specify:
     *     <ul>
     *         <li>properties.item.content.id : id of the tag.</li>
     *         <li>properties.item.content.title : the tag itself.</li>
     *     </ul></li>
     *     <li>properties.item.user : user posting that item.</li>
     *     <li>properties.item.target : a mandatory target for this tag. Specify
     *     <ul>
     *         <li>properties.item.target.id : the permalink of the target</li>
     *         <li>properties.item.type : the type of the target</li>
     *     </ul></li>
     *     <li>properties.item.feed : the feed this item is posted to.</li>
     *     <li>properties.item.verb : (optional) overwrite default verb for this item (post) -- set it to properly to tag or untag</li>
     * </ul>
     * @constructor
     */
    init:function(){
        this._super();
        if(!(this.item.target.id && this.item.target.type)){
            throw {name : "Invalid Tag exception", error:"Tag needs a valid target"}
        }
        if(!(this.item.content && this.item.content.id && this.item.content.title)){
            throw {name : "Invalid Tag exception", error:"Tag needs a title and an id"}
        }
        this.item.type = cons.TYPE_TAG;
    }
    ,renderItem : function(callback){
        render.renderTemplate(__dirname + '/templates/tag.xml', { tag: this.item.content }, callback)
    }
});

var Like = ActivityObject.extend({
    /**
     * Like/Unlike.
     * @extends ActivityObject
     * @class Like
     * @private
     * @param {object} properties Specify:
     * <ul>
     *     <li>properties.item.content : the like. Need to specify:
     *     <ul>
     *         <li>properties.item.content.id : id of the like.</li>
     *     </ul></li>
     *     <li>properties.item.user : user posting that item.</li>
     *     <li>properties.item.target : a mandatory target for the like. Specify
     *     <ul>
     *         <li>properties.item.target.id : the permalink of the target</li>
     *         <li>properties.item.type : the type of the target</li>
     *     </ul></li>
     *     <li>properties.item.feed : the feed this item is posted to.</li>
     *     <li>properties.item.verb : (optional) overwrite default verb for this item (post) -- set it to properly to like or unlike</li>
     * </ul>
     * @constructor
     */
    init:function(){
        this._super();
        if(!(this.item.target.id && this.item.target.type)){
            throw {name : "Invalid Like exception", error:"Like needs a valid target"}
        }
        if(!(this.item.content && this.item.content.id)){
            throw {name : "Invalid Like Exception", error:"Like needs an id"}
        }
        this.item.type = cons.TYPE_LIKE;
    }
    ,renderItem : function(callback){
        render.renderTemplate(__dirname + '/templates/like.xml', { like: this.item.content }, callback)
    }
});

var Flag = ActivityObject.extend({
    /**
     * Flag/Unflag.
     * @class Flag
     * @private
     * @extends ActivityObject
     * @param {object} properties Specify:
     * <ul>
     *     <li>properties.item.content : the flag. Need to specify:
     *     <ul>
     *         <li>properties.item.content.id : id of the flag.</li>
     *     </ul></li>
     *     <li>properties.item.user : user posting that item.</li>
     *     <li>properties.item.target : a mandatory target for the flag. Specify
     *     <ul>
     *         <li>properties.item.target.id : the permalink of the target</li>
     *         <li>properties.item.type : the type of the target</li>
     *     </ul></li>
     *     <li>properties.item.feed : the feed this item is posted to.</li>
     *     <li>properties.item.verb : (optional) overwrite default verb for this item (post) -- set it to properly to flag or unflag</li>
     * </ul>
     * @constructor
     */
    init:function(){
        this._super();
        if(!(this.item.target.id && this.item.target.type)){
            throw {name : "Invalid Flag exception", error:"Flag needs a valid target"}
        }
        this.item.type = cons.TYPE_FLAG;
    }
    ,renderItem : function(callback){
        render.renderTemplate(__dirname + '/templates/flag.xml', { flag: this.item.content }, callback)
    }
});


// Expose everything
exports.Article = Article;
exports.Comment = Comment;
exports.Note = Note;
exports.Status = Status;

exports.Tag = Tag;
exports.Flag = Flag;
exports.Like = Like;

// For test only, end-user shouldn't need that
exports.ActivityObject = ActivityObject;