Building Open News Wire


What am I building?

Forum software.

People make message posts with a title, url, image, and/or text. Each messagae post will be in a Channel. Topic channels allow multiple people to post to a channel. User channels allow the user to post to a channel that is inherently their own. Each person can subscribe to Topics and Users and have a cronological feed of new posts.

Topic and User channels can be subscribed to over RSS for server-to-server exchange. An authentication header can be passed to login to an account to gain user-specific permissions. Simple federation. Given alice@foo.com and bob@bar.com, if foo.com and bar.com are configured, each user could be able to write to Topic Channels on the other server, and have user-specific permissions to read from Topic and User channels.

How am I going to build it?

I'm going to fork HouseNewsWire and then add one feature at a time until I have OpenNewsWire.

I'm going first to want to change the name of all of the DB and Web libraries. So the first thing I should do then is to make a script to change everything from HouseNewsWire to whatever random name one wants. I should also commit this back to HouseNewsWire.

While I am doing that I should let me mind wander to Topic Channels.

Task - Make Forking HouseNewsWire Easier

I've created a script and added it to the HouseNewsWire repo. Now it's much easier to rename, and this is complete.

Task - Make mockups of Website

I have thought now, and drawn out the pages I would like to make. These are the drawings.

OpenNewsWire Drawings

Task - Make an outline

Now that I have these designs I should look at them and discover what I must build.

  • Database
  • Messages - Recursive on parent_id, have all the stuff for a message — use this for everything.
  • Topic - A topic channel
  • TopicMessage - Table to link messages to a given topic channel
  • UserMessage - Table to link messages to a given user channel
  • PrivateMessage - Table to link messages to a given private message conversation
  • Votes - A Table to hold votes for messages, should make vote_up, vote_down, vote_score vote_count on each Message by default
  • URLS
  • /create/message - Make a message
  • /create/topic - Make a topic channel
  • /t/TopicName/
  • /t/TopicName/popular (Default for /t/TopicName)
  • /t/TopicName/new/
  • /t/TopicName/$message-id/
  • /u/UserName
  • /u/UserName/posts (Default for /u/UserName)
  • /u/UserName/submissions
  • /u/UserName/comments
  • /vote - Handle Voting
  • Controllers
  • Create - /create/
  • TopicChannel - /t/
  • UserChannel - /u/
  • Vote - /vote
  • Tasks
  • Update schema.sql with new models and regenerate DB
  • Update the HTML layout to get a sidebar on the right hand side
  • Add the Create controller to make topics POST/GET and add HTML pages.
  • Add the POST/GET to the Create controller for messages and add HTML pages.
  • Add the TopicChannel controller and make a GET for /t/topicname with a template.
  • Update the Create controller to redirect newly created topics to the TopicChannel controller for the new Topic
  • Update the /t/topicname template until it roughly matches what is on the page — update this list with what must be done later because it can’t link now.
  • Create /t/topicname/$message-id/ GET handler and template. Update template until it roughly matches what’s on the page
  • Add the Vote controller and handle building votes
  • Add voting to the template and ensure it works for the TopicChannels
  • Add the UserChannel controller and make templates. Should be like TopicChannels without voting.
  • Add JSON handlers
  • Add RSS handlers
  • What is missing?
  • User settings
  • Topic channel settings
  • Server Settings
  • Federation
  • Now I have a vague notion of what I am building and tasks to start with, it's time to begin building.

    Let's Build

    Now I have made a new repository and added the initial fork made by rename.sh. I should address the database schema first.

    I'll want to do is extend the schema to support topic channels. Now that I have done that, I'll need to regenerate the classes from the schema. Finally, I'd like to add a bit so I can have ->setting('name', 'value') for channels and people, so I'll add that too.

    Next I want to add a sidebar.

    I have the first two tasks done. Next I'm going to want to dive into the create controller so that I can make a topic channel and messages. Then I'll get into the fun of the topic channel UI for displaying a list of messages, and for showing the message thread itself.

    Next I create topic channels and now I have the ability to create a topic channel, post a message to a topic channel, and support comments. My UI is looking pretty close to what I expect, except I have no voting and no expanding of images/text for the post.

    Next I could work on voting, or I could work on the User Channel stuff.

    I've choosen to work on the User Channel stuff. Now I can make a message to u/MyUserName and the message shows up under u/MyUserName. That page also shows what is in the user setting named 'bio', and displays submissions and comments. I dislike how I have done comments, since you cannot see what a user has responded to. I ought to think a bit more about this model, I might want to know what the root message is and if it is a UserChannel or TopicChannel type. In the interim, I have done it like this.

    After I completed that, I did a few more tweaks.

    Let's Deploy

    Now I have the bones of Open News Wire written. I would like to deploy it on a server, so I'll take a copy of MeshMage's ansible role and copy it down to OpenNewsWire.

    While building up the new ansible playbook, I added Database deployment with DBIx::Class::DeploymentHandler.

    I've updated the NS records at the registrar to point to Linode, and added the zone to Linode. I want to use their DNS because I'll be able to use DNS verification with certbot. It's not super important now if I use an HTTP or DNS challenge, with just one server. However it's designed to scale to multiple http servers, so getting my SSL certs through DNS challenge keeps the solution simple if I move to multiple servers and doesn't cost anything extra now.

    I add an A record to opennewswire.com pointing to my new VM, and CNAME www to opennewswire.com.

    Now I have commited the ansible code and I am ready to install.

    
    symkat@devel:~/Code/HouseNewsWire/.ansible$ ansible-playbook -i '45.79.9.171,' setup.yml
    
    

    This runs for a while, once it is complete I have the website running.

    I would like to consider SSL, and I haven't done that in the ansible playbook. So I quickly make a /root/.linode file with my credentials:

    
    dns_linode_key = 827398a89ad9ad89ad8988779a....
    
    

    With that file in place I can generate SSL keys:

    
    root@localhost:~# certbot certonly -n --dns-linode --dns-linode-credentials /root/.linode -d www.opennewswire.com -d opennewswire.com --agree-tos -m symkat@symkat.com
    
    

    Now I'll update my /etc/nginx/sites-enabled/opennewswire.com file:

    
    server {
        listen 443 ssl;
        server_name opennewswire.com;
    
        ssl_certificate     /etc/letsencrypt/live/www.opennewswire.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.opennewswire.com/privkey.pem;
    
        location / {
            proxy_pass       http://localhost:8080;
            proxy_set_header Host             $host;
            proxy_set_header X-Real-IP        $remote_addr;
            proxy_set_header X-Forwarded-For  $remote_addr;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Port 443;
        }
    }
    
    server {
        listen 443 ssl;
        server_name www.opennewswire.com;
    
        ssl_certificate     /etc/letsencrypt/live/www.opennewswire.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.opennewswire.com/privkey.pem;
    
        return 301 https://opennewswire.com$request_uri;
    }
    
    server {
        listen 80;
        server_name opennewswire.com www.opennewswire.com;
        return 301 https://opennewswire.com$request_uri;
    }
    
    

    With a couple of restarts, OpenNewsWire is now working!

    OpenNewsWire Topics

    OpenNewsWire User Profile

    Next I will have to explore the cycle for pushing updates and deploying OpenNewsWire. For now, I'm thrilled it's running and working.


    Contact Me