Blog Comments using Github's Issue Tracker. Part2

In the previous part of this tutorial we setup the layout for our comment section. In this part we will be adding the functionality to get and post comments.

At the bottom of the _layout/post.html file, I added some code that initializes the page when the document loads, we will be filling in those function in this tutorial.


$(document).ready(function(){
    // get comment data
    getPostComments("{{page.issue_number}}", function(data){
        generateCommentSection(data);
        setupAddComments();
        setupPostComment("{{page.issue_number}}");
    });
});

First things first though. Remember those two modals we setup in Part 1? We need to add the code to get those open!

// comments.js

function setupAddComments()
{
    $("#addCommentForm").submit(function(event){

        // disable the default action of the form so we can add our own functionality
        event.preventDefault();

        // get the text of the comment
        var commentText = $("#commentTextField").val();

        // if there is text
        if(commentText)
        {
            // open the credentials dialog
            $("#credDialog").modal();
        }
        else
        {
            // if not, open the warning
            $("#warningDialog").modal();
        }
    });
}

Getting and displaying comments from the Github issue tracker

Github has provided developer with an easy to use API for getting information from their site.

To get comments from a particular issue, we can do an HTTP GET request on the following URL.

https://api.github.com/repos/yourusername/yourblogrepo/issues/:issuenumber

After that its just a matter of extracting the information we need.

function getPostComments(issueNumber, callback)
{
    // get the issue, specified by number, for the site page
    $.get("https://api.github.com/repos/:user/:repo/issues/" + issueNumber, function(issueData){
        ...
    });
}

We start by doing GET request for the issue information.

Now we could be in the situation where there are no comments present in the tracker. We are going to check that this issue has comments first, then do another GET request to get the comments.

function getPostComments(issueNumber, callback)
{
    // get the issue, specified by number, for the site page
    $.get("https://api.github.com/repos/nnarain/nnarain.github.io/issues/" + issueNumber, function(issueData){

        // get the issue's comments url
        var commentsUrl = issueData.comments_url;

        // if the issuse has comments
        if(issueData.comments != 0)
        {
            // get the comments
            $.get(commentsUrl, function(commentsData){
                var ret = {"comments":[]};
                ...
                callback(ret);
            });
        }
        else
        {
            // return an empty array of comments
            callback({"comments":[]});
        }
    });
}

Now we can start filtering through the comment data and pick out what we want. This depends on what you want to display about the comment, for example the user, created date, edit date, etc. For more information refer to the official docs here.

function getPostComments(issueNumber, callback)
{
    // get the issue, specified by number, for the site page
    $.get("https://api.github.com/repos/nnarain/nnarain.github.io/issues/" + issueNumber, function(issueData){

        // get the issue's comments url
        var commentsUrl = issueData.comments_url;

        // if the issue has comments
        if(issueData.comments != 0)
        {
            // get the comments
            $.get(commentsUrl, function(commentsData){

                var ret = {"comments":[]};

                // for every comment object
                var len = commentsData.length;
                for(var i = 0; i < len; ++i)
                {
                    var data = commentsData["" + i];

                    var comment = {};
                    comment["body"] = toMarkdown(data.body);
                    comment["date"] = data.created_at;

                    comment["user"] = {
                        "name"       : data.user.login,
                        "avatar_url" : data.user.avatar_url,
                        "url"        : "https://github.com/" + data.user.login
                    };

                    // add a comment to return
                    ret.comments.push(comment);
                }

                callback(ret);
            });
        }
        else
        {
            callback({"comments":[]});
        }
    });
}

var converter = new showdown.Converter();
function toMarkdown(markdownText)
{
    var htmlText = "";

    if(markdownText)
    {    
        htmlText = converter.makeHtml(markdownText);
    }

    return htmlText;
}

Above I extract that comment body, data, user, user avatar and user profile url from the comment body.

Also I added a function to convert the comment body to HTML from its Markdown format. For this I use Showdown JS.

That is actually all is takes to pull comments down from the issue tracker!

Next we will need to write the code that will generate the comment list.

/**
    Generate the comment section for the comments recieved
*/
function generateCommentSection(data)
{
    var comments = data.comments;
    var len = comments.length;
    var output = '';

    for(var i = 0; i < len; ++i)
    {
        var comment = comments[i];
        output += generateCommentListItem(comment);
    }

    $("#commentList").html(output);
}

data is the return value of the previous function. Iterate over every comment recieved and generate a list item using the information provided.

function generateCommentListItem(comment)
{
    var output = '';

    output += '<li>';
    {
        output += '<div class="comment-avatar">';
        {
            output += '<a href="' + comment.user.url + '">';
            {
                output += '<img src="' + comment.user.avatar_url + '"/>';
            }
            output += '</a>';
        }
        output += '</div>';
        output += '<div class="comment-text">';
        {
            output += comment.body;   
            output += '<span class="date sub-text">' + comment.date.split('T')[0] + '</span>';
        }
        output += '</div>';
    }
    output += '</li>';

    return output;
}

This function generates the list item for a single comment using the custom CSS we made in Part 1.

Now that we can display comments, we can move on to posting comments!

Posting comments to the Github issue tracker

The last step! Post a comment from the blog page. The comment will be submitted through the user credential modal we made in Part 1.

...
function setupPostComment(issueNumber)
{
    // focus on the username input field when credential form is displayed
    $("#credDialog").on('shown.bs.modal', function(){
        $("#usernameField").focus();
    });

    // override the default form action
    $("#credForm").submit(function(event){
        event.preventDefault();

        var username = $("#usernameField").val();
        var password = $("#passwordField").val();

        var commentBody = $("#commentTextField").val();

        // check that the username, password and comment body are not null
        if(username && password && commentBody)
        {
            ...
        }
    });
}
...

To post a comment to the issue tracker we need to do a HTTP POST request to Github’s API. Two important things to note.

  1. Our POST request needs to be authorized.
  2. We need to set our content and data type to a json string, that’s what the Github API expects.

In order to authorize the request we need to send a Authorization header before the post. This will take the form

Authorization: Basic <hash>

The hash is generated using the user’s username and password. Of course we wouldn’t want to send user private information as plain text over the internet!

Simply function to generate the hash:

...

function makeBasicAuth(username, password)
{
    var token = username + ":" + password;
    var hash = btoa(token);

    return "Basic " + hash;
}

...

JQuery’s ajax function can set all the parameters we need to do the post correctly!

...

function setupPostComment(issueNumber)
{
    // focus on the username input field when credential form is displayed
    $("#credDialog").on('shown.bs.modal', function(){
        $("#usernameField").focus();
    });

    $("#credForm").submit(function(event){
        event.preventDefault();

        var username = $("#usernameField").val();
        var password = $("#passwordField").val();

        var commentBody = $("#commentTextField").val();

        if(username && password && commentBody)
        {
            $.ajax({
                type:"POST",
                url: "https://api.github.com/repos/yourusername/yourblogrepo/issues/" + issueNumber + "/comments",
                dataType: "json",
                contentType:"application/json",
                data:JSON.stringify({"body":commentBody}),
                beforeSend: function(xhr){
                    xhr.setRequestHeader("Authorization", makeBasicAuth(username, password));
                },
                success:function(data){
                    location.reload();
                },
                error: function(xhr, ajaxOptions, error){
                    console.log(xhr.responseText);
                }
            });
        }
    });
}

...

Notice the beforeSend function sends the Authorization header and a successful post will reload the page.

That’s it! You now have working comment system hosted in the Github issue tracker!