Creating an Erlang comments section for this site.

λ July 10, 2020
Tags: erlang, postgres

I need a simple as can be comments addition to the bottom of my blog posts; I have decided to write one using Erlang. It’s been a while since I used Erlang but the love of it has never gone away. It will be an “mvp” solution but will incorporate a recaptcha / spam block because.

Yesterday I started a small side-project but one that has been long overdue for this site…the ability to add a comments section to the post pages. I used to use Disqus but they started wanting money. I looked at some open-source self hosted solutions first but didn’t have much success and I felt that it was time to roll my own.

Overall workflow

I envisage the process going something like this: user reads a page, is blown away and wants to leave a comment. Scrolls to “Leave a comment box” and makes a witty and insightful entry, completes the captcha and sends it.

The information goes to the server, the server checks if the email address is on the verified list or not. The comment is added to the table. A JSON response to the AJAX request is sent back along with the comment meta-data.

If the email address is unverified, a message is shown to the user indicating that they have 24 hours to verify their email address as a link has been sent to them. This leaves me open to spam no longer than that. On receiving an API call from the link, we can then mark that email as verified and ensure the comment is not auto-deleted.

Spam deletion / comment deletion

Auto-deletion is performed by another (internal) API call triggered by a cron job on the hosting server.

Erlang!

I first used Erlang about eight years ago now, I designed and implemented an SMS processing engine, with RabbitMQ and the SMPP library. Amazingly it is still alive here if you wanted it: https://sourceforge.net/projects/oserl/ and the full specification and documentation is on the official Open SMPP web-site

Postgres

I tend to use PostgreSQL for everything and this will be no different. Towards the end I may well add support for MySQL as well if I think it will help other people adopt the code. It will eventually end up on my GitHub pages too.

Creating the database schema

This is how I created the initial user and database to receive the comment data from the API calls:

    $ sudo -u postgres createuser scofuser
    $ sudo -u postgres createdb scofblog
    $ sudo -u postgres psql
    alter user scofuser with encrypted password 'sc0fus3r';
    grant all privileges on database scofblog to scofuser;
    \c scofblog
    create extension pgcrypto;

No, that won’t be the password on the final live deployment Mr. Clifford

The pgcrypto extension is necessary to enable the trigger (further down) to create an instance of the SHA256 hash based on the blog post “slug” portion of the URL.

Tables

In the spirit of keeping it simple I have opted for just three tables (so far) to manage the feedback, these are:

topic    Models a single bog post entry for child comments.
comment  Models a single submission from a reader.
author   Saves author email addresses and verified status.

The topic table has a unique constraint on the title column to ensure that the page hash is also unique. There is a trigger on the topic table that automatically generates a unique SHA256 hash on insert. This is great as I also have a bunch of existing pages that will have to be imported; the trigger makes it easier for the import code.

create table topic (
    id           serial primary key,
    title        varchar(100) not null unique,
    hash         bytea,
    created_ts   timestamp not null default now()
);

create function topic_hash_update_tg() returns trigger as $$
begin
    if tg_op = 'INSERT' then
        NEW.hash = digest(NEW.title, 'sha256');
        return NEW;
    end if;
end;
$$ language plpgsql;

create trigger topic_table_topic_hash_update
before insert or update on topic
    for each row execute procedure topic_hash_update_tg();

The remaining tables are much simpler but the operation of the author table is my next thing to ponder.

Spam – a fact of life :|

If you put up an unprotected web form, well, more fool you. I have used both reCaptcha and Akismet in the past so I will probably incorporate them in the mix at some point.

Initially though, I am going to implement a system such that the comment author has to provide a valid email address. On receipt of a comment from an unverified address I send out a confirmation email and then the link in the email will activate the comment and the email becomes verified at the same time. That will be an interesting bit to work on.

This means the first comment you make will need a secondary action by the author to keep the comment alive…I have decided that I will accept comments from unverified emails but they will remain on the page for a day at most unless the link is activated. That way the author gets the instant gratification of seeing their post get added to the page immediately but also gets told that if they don’t verify then their comment will vanish…

JavaScript

The JavaScript code will take care of most of the user input stuff and the displaying of the comments. Each page has an SHA256 hash buried in it and once the page has finished loading, an AJAX request will ask the API for the comments by hash. It should work well as most posts are longer than a page or two so by the time the user gets to the bottom of the page it will already contain the fully rendered comment section if any.

Open Sourced on GitHub

Once done and working to my satisfaction I will publish it to GitHub but for now it’s firmly in Bit-Bucket hiding from the light!

Happy hacking!

Comments