GithubHelp home page GithubHelp logo

skx / e-comments Goto Github PK

View Code? Open in Web Editor NEW
101.0 9.0 7.0 98 KB

External comments for static HTML pages, a lightweight self-hosted disqus alternative.

License: MIT License

Ruby 36.22% CSS 1.33% JavaScript 55.66% Perl 3.58% Makefile 1.01% HTML 2.21%
external-comments self-hosted ruby sqlite redis disqus

e-comments's Introduction

External Comments

This is an open source commenting system, allowing you to include comments on your static website(s) without the privacy concerns of using an external system such as disqus.

Embedding comments is as simple as including a couple of small javascript files, along with a CSS file for styling.

Features:

  • Multiple backends for storage:
    • Redis
    • SQlite
    • Adding new backends is simple.
  • Markdown formatting of comments.
  • Support for threaded discussion.
    • You can limit the depth of discussions, to a given depth.
    • Or leave the defaults in-place to allow arbitrarily nested replies.
  • Anti-spam plugins:
    • Three simple plugins included as a demonstration.
    • The sample plugins block hyperlinks in comment-author names, bodies which reference viagra, and any remote IPs which have been locally blacklisted.
  • Simplicity
    • The code is small enough to easily understand and extend for your custom needs, but functional as-is.
  • Degrades gracefully when Javascript is disabled
    • No white boxes, empty spaces, or error-messages.

Anti-features:

  • There is no administrative panel to edit/delete comments.
    • This requires manual intervention in the back-end.
  • Commenters do not get their details remembered.
    • Nor can they receive emails on replies to their comments.

Run-time (client-side) dependencies:

  • jQuery
  • mustache.js
    • Included in this repository.

This server was originally written for a server optimization guide but since it seemed like a generally-useful piece of code it was moved into its own repository.

Contents

The Comment Server

The comment server exports a public API allowing the javascript on your (static) pages to add comments, and retrieve those comments which already exist. It is written in Ruby using the sinatra, framework.

There are two choices for storing the actual comment data:

Adding new backends should be straight-forward, and pull-requests are welcome for MySQL, CouchDB, etc.

Comment Server API

The server implements the following two API methods:

  • GET /comments/ID
    • This retrieves the comments associated with the given ID.
    • The return value is an array of hashes.
    • The hashes have keys such as author, body & ip.
  • POST /comments/ID
    • Adds a new comment to the collection for the given ID.
    • The submission should have the fields author and body.
    • Optionally the submission might contain the field email.
      • If an email is stored a Gravitar field will be present in the retrieval, but the actual email address will not be sent back to avoid a privacy leak.
    • Optionally the submission might contain a parent field.
      • This is used to support nested comments.
      • There are no limits on the number of nested comments.

Comment Server Dependencies

These dependencies were tested on a Debian GNU/Linux stable machine, but are a good starting point for other distributions:

apt-get install ruby ruby-json ruby-sinatra ruby-redcarpet ruby-uuidtools ruby-rack-test

For storage you get to choose between one of these two alternatives:

apt-get install libsqlite3-ruby

Or

apt-get install ruby-redis

Comment Server Deployment

Deploying the server involves two steps:

  • Actually launching the server, via systemd, runit, or similar.
  • Configuring your webserver to proxy to it.

To launch the comment server you'll run one of these two commands, depending on which storage back-end you prefer to use:

 $ ./server/comments.rb --storage=redis  --storage-args=127.0.0.1
 $ ./server/comments.rb --storage=sqlite --storage-args=/tmp/foo.db

The server will bind to 127.0.0.1:9393 by default, so you'll need to setup a virtual host in nginx/apache which will forward connections to that instance.

For nginx this would look something like this:

server {
  listen          80;
  server_name     comments.example.com;
  location / {
    proxy_pass        http://127.0.0.1:9393;
    proxy_redirect    off;
    proxy_set_header  X-Forwarded-For $remote_addr;
  }
}

Client-Side Setup

To allow comments upon your static site you must update your page(s) to include the appropriate javascript libraries, and the CSS.

For basic usage you'll be adding this to the <head> of your HTML:

<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="/js/mustache.js" type="text/javascript"></script>
<script src="/js/e-comments.js" type="text/javascript"></script>

<script type="text/javascript">
  $( document ).ready(function() {
    discussion( "http://server.name/comments/COMMENT_ID" );
});
</script>

At the place you wish your comments to be displayed you'll add:

<div id="comments"></div>

Advanced Usage

The example above configured the display of comments with the defaults, but the discussion() method actually accepts two arguments:

  • The URL of the comment-server you've got running, including a discussion ID.
  • An optional hash of parameters, to customize behaviour.

The discussion will require a unique key, which will be specified as an URL. For example your home-page might include this:

    discussion( "http://comments.example.com/comments/home" );

Your about page this:

    discussion( "http://comments.example.com/comments/about" );

This will ensure that each page will have a distinct discussion-thread upon it.

The second parameter, which is optional, allows things to be customized. Valid options for this hash include:

  • comments
    • The ID of the <div> in which comments will be inserted.
    • The default will be comments, as documented above.
  • max_depth
    • This should be an integer holding the maximum thread-depth permitted.
    • The default value is 0, which allows an unlimited thread-depth.
  • threading
    • A boolean to control whether threading is enabled/disabled.
    • The default value is true.
  • comment_template
    • The ID of a script-div which contains a template for comment-formatting.
  • reply_template
    • The ID of a script-div which contains a template for the "add comment" form.

If you wished to disable threading, allowing only a flat discussion hierarchy, you'd use this:

 discussion( "http://comments.example.com/comments/about",
             { threading: false });

If you wished to allow comments, but stop arbitrary nesting:

 discussion( "http://comments.example.com/comments/about",
             { threading: true, max_depth: 2 });

Theming

You could customize the formatting of comments, and the comment-submission form via CSS, however you might prefer to replace the presentation with something entirely different.

To allow this we use mustache.js templates for:

  • The display of the individual comments.
  • The display of the reply-form.

You can hide templates for both of these things inside your static HTML-files and cause them to be used by specifing their IDs like so:

    discussion( "http://localhost:9393/comments/id",
                { comment_template: '#comment_template',
                  reply_template: '#reply_form'} );

This would require your HTML-page to contain something like this:

<script id="comment_template" type="x-tmpl-mustache">
 <div class="comment">
 <div class="link"><a href="#comment_{{ id }}">#{{ id }}</a></div>
 ..
</script>

NOTE: You can find the default templates which are used inside the e-comments.js file.

Replacing the template entirely allows you to display different data, for example you might wish to show the thread-level of each comment. This could be achived by adding the following to the comment-template:

 Depth:{{#depth}}{{ uuid }}{{/depth}}

I'm open to pull-requests adding more formatting options, if you have something you think would be useful. (Similarly any improvements to the presentation of comments by default would be appreciated.)

Alternative Systems

Running Locally

Providing you have the dependencies installed you can run the same demo locally:

  • Launch the comment-server in one terminal.
    • ./server/comments.rb --storage=sqlite --storage-args=/tmp/foo.db
    • The file /tmp/foo.db will be created, and used to store your comments.
  • Start a local HTTP server in clients in another:
    • cd client ; python -m SimpleHTTPServer
  • Open your browser:

This local demo works because the demo.html file is configured to access comments at http://localhost:9393/. In a real deployment you'd hide the comment-server behind a reverse proxy and access it via a public name such as comments.example.com.

Steve

e-comments's People

Contributors

skx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

e-comments's Issues

Handle cross-origin requests properly.

The jQuery request should add (automatically)

Access-Control-Request-Headers: x-requested-with

The server should set:

Access-Control-Allow-Headers: x-requested-with 

Allow restricting discussion ids.

Currently you can start a discussion thread with any ID, by including the appropriate javascript and adding:

  • http://localhost:9393/comments/$anything

This means that it is possible somebody other than you might include discussion, storing it on your server. We should allow that to be locked-down.

This is a paranoid thing.

Default to SQLite

Since I've started phasing out Redis, and only using it for session-storage, and other transient data.

Storing the reply-form inline is a mistake.

Although it eases deployment it makes things harder for the user.

Instead we should allow the user to code their own reply form, we will just insist the client-page has:

 <div id="comments"></div>
 <div id="comments-reply" style="display:none;"></div>

If we find that DIV we'll show it, and if not default to our own (nasty) table.

Help wanted: Submitting spam silently fails.

Overview

We use jquery to post our anonymous form, and if we added an error handler this constantly receives a HTTP-status code of zero.

How to reproduce:

Open two terminals.

In the first start the server:

   ./server/comments.rb

In the second start a simple HTTP server:

   cd client/
   python -m SimpleHTTPServer 9090

Now open http://localhost:9090/demo.html

You can submit comments as expected, because the demo-form links to the comment-server running on localhost:9393.

If you submit a comment-body which contains the word "viagra" it will be rejected, but this isn't obvious, it just looks like a failed request.

Failed Attempts to Solve

The obvious approach is to change the error handler in the code:

    //
    // Send the POST
    //
    $.ajax({
        type: "POST",
        url: url,
        data: $("#myform").serialize(),
        error: function(r, e) {
            loadComments(url);
        },

No matter what I tried though I always received a status code of "0" which meant that I couldn't differentiate between a valid submission (status code 204) from an invalid one (status code 500).

Code a blogspam.net plugin.

This will just need an email field in the submission form.

See #2 for updates to the server - the server will clearly serialize all the submitted fields, providing that both author and body are present.

Handle nested comments.

We don't need a full tree, but at least:

  • comment 1
  • comment 2
    • comment 6
    • comment 7
  • comment 3
    • comment 4
  • comment 5

Change the storage-back-end

To allow for future updates to (optionally) allow submission of email addresses we should store JSON hashes in the backing store.

This will be a compatibility-breaking change.

Error handling is horrid.

At the moment an alert box pops up with HTML in it.

To reproduce attempt to submit a comment:

  • Name: "Steve"
  • Email: [empty]
  • Body: "viagra"

Should be possible to disable (deep) nesting.

Right now you can have threaded comments, or flat-comments.

It should be possible to limit the depth of threads, which is not currently possible.

For example this might be OK:

 original
  \--- first-reply
          \----- second-reply

But this not:

 original
  \---- first-reply
        \----- second-reply
                \---- third-reply
                         \---- fourth-reply
                                 \---- fifth-reply
                                         \---- sixth-reply

Right now we don't even count thread-depth, but it should be easy to keep track of state as we process each comment.

Our README.md could be improved.

It needs more love, specifically on the template-customization, and on the parameters which are supported.

The intro, with features and anti-features, is nice though :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.