First run with node.js and Express

07 October, 2014

I began a project using node.js just to get a feel of it. I am writing this post so that it serves as a development log and reference for myself. It could also help you if you work with Quickbooks and node.js.

The objective is to create an interface for viewing reports from Quickbooks.

The code lives here: Finance App
The premise is simple enough for me to start using a framework and there is already an API wrapper for me to experiment with.1 Based on the requirements of the project, I broke down it's implementation into the following parts:

Part I
1. Connect to the API
2. Retrieve the report data
3. Display it

Part II
1. Add custom fields to the report
2. Save the customized report to a local database
3. Sync the custom report data with the online report

Part III
1. Add the ability to add/remove date ranges for forecast reports
2. Add custom filters to get specific views of the reports
3. Writing the report data back to Quickbooks

I am currently focussing on Part I, as it is sufficiently involved. I started off with all the code in one file, following this guide2 step-by-step. This guide helped me organize my project files better. The project is still nowhere near organized as it should be, but it gave me a place to start.

I am using Jade as my template engine and Express framework for Node.js

Getting connected to the API was easy. You need a developer account with Intuit Partner Platform3. Then you are asked to create an app and enter the URLs for the landing page, callback and authentication. Quickbooks Online uses OAuth for authentication. Upon providing a consumerKey and a consumerSecret, the API will give you an accessToken and accessTokenSecret that you will have to store locally so it is available to the app session-wide.

Once connection is established, I instantiate a QuickBooks object like so:

1
2
3
4
5
6
qbo = new QuickBooks(creds.consumerKey,
                         creds.consumerSecret,
                         accessToken.oauth_token,
                         accessToken.oauth_token_secret,
                         postBody.oauth.realmId,
                         true); 

Now, I have access to the various API endpoints to send/receive data.
I make calls to the API by writing routes that correspond to specific reports that I want the data for.

Here's an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.get('/vendorbalancedetail', express.bodyParser(), function(req, res){
    qbo.reportVendorBalanceDetail({date_macro:'This Month-to-date', appaid: 'Unpaid'},function(_,report){

      //console.log(report)
    res.render('vendorbalancedetail.jade', {title: "Report Detail",
                              reportname: report["Header"]['ReportName'],
                              daterange: "From:"+report["Header"]["StartPeriod"]+" to: "+report["Header"]["EndPeriod"],
                              alldata: report,
                              columns: report["Columns"],
                              rowsperclient: report["Rows"]
                            });
      })

    })

Let's break it down.

1
2
app.get('/vendorbalancedetail', express.bodyParser(), function(req, res){
    qbo.reportVendorBalanceDetail({date_macro:'This Month-to-date', appaid: 'Unpaid'},function(_,report)

I initiate a GET request invoked as a method on the app variable which is a reference to an instance of the express server. I want this request to be made if the user navigates to the /vendorbalancedetail location of the app.

1
qbo.reportVendorBalanceDetail({date_macro:'This Month-to-date', appaid: 'Unpaid'}, function(_, report)

This is an API call that requests the VendorBalanceDetail report for this month to date. It also returns only those transactions that have been marked as 'unpaid.' The call also makes the report object available so I can pass JSON to the view.

That is done like so:

1
2
3
4
5
6
7
res.render('vendorbalancedetail.jade', {title: "Report Detail",
                              reportname: report["Header"]['ReportName'],
                              daterange: "From:"+report["Header"]["StartPeriod"]+" to:     "+report["Header"]["EndPeriod"],
                              alldata: report,
                              columns: report["Columns"],
                              rowsperclient: report["Rows"]
                            });

This is self-explanatory. I render the response from the API call to a view called vendorbalancedetail.jade and make all the variables available inside it.

The tricky part is working with the JSON returned by the API and displaying it in a row/column format. I have used tables for my approach. If you think of a better solution, do let me know. The code for the view would be too much for this post. You can check it out on the Github page.

More to come.

Fruitr is on Rails 4

22 September, 2014

I have a side project that I am very passionate about.
It lives at fruitr.rishighan.com

It was originally developed on an older version of Rails. Since I revamped this site on Rails 4, I felt I should do the same for the project that deserves to be shown to the world.

It was relatively easy to upgrade it to Rails 4. Aside from the usual broken gem dependencies, there was nothing strange or extraordinary stopping the upgrade. I did have the Echonest API impose a rate limit on me; and the none of my API requests returned any response. This baffled me for a whole 15 minutes till I figured out that there is an option for developers to 'upgrade' their account. It is free, provided you tell them what your app does and they will remove that ridiculous rate limit.

As soon as I told Echonest that my app is not doing anything to threaten their existence, they upgraded my rate-limit and the app started working. I thought of writing a quick how-to on deploying the rails app using Capistrano.

I use the excellent hosting service provided by Linode. It runs an instance of Ubuntu 14.04. Now, on to the good stuff. Bear in mind, this assumes that you have already set up your server environment with rvm, passenger and the appropriate directives in nginx.conf

1
2
3
4
gem 'capistrano'
gem 'capistrano-recipes'
gem 'capistrano-rvm'
gem 'capistrano-bundler' 

Then install your capistrano files.

1
cap install

This generates the following:

1
2
3
4
5
6
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
Capified

Past this, ssh into the server and create the app directory. In this case, mkdir fruitr and set the appropriate ownership and permissions chown -R rishi:rishi fruitr and chmod -R 755 fruitr

Once this is done, modify your Capfile, production.rb and deploy.rb
In your Capfile, set the required gems. I needed

1
2
3
require 'capistrano/rvm'
require 'capistrano/deploy'
require 'capistrano/bundler'

My production.rb defines the hostname and the roles.

1
2
3
4
5
set :stage, :production
server 'rishighan.com', user: 'rishi', roles: %w{web app}

#RVM stuff
set :rvm_type, :user

Finally, my deploy.rb looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# config valid only for Capistrano 3.1
lock '3.2.1'

set :application, 'fruitr'
set :repo_url, 'git@github.com:rishighan/fruitr.git'

# Default branch is :master
# ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call

# Default deploy_to directory is /var/www/my_app
set :deploy_to, '/home/rishi/fruitr'

# Default value for :scm is :git
set :scm, :git

This configuration is specific for my project. However, you can use this if you have Linode as your host and are using git as your SCM.

Homelab

14 September, 2014

I am an avid lover of computers. If there is a need in my life that warrants fulfillment, like a moth is drawn to a flame, it is this: building computers. I need to build computers - it calms me down; I build machines that deliver content, back my data up and help me be productive.

I built and rebuilt a lot of computers that I owned over the course of six years.
Two years ago, I wanted a 24/7 machine that could act as a media server. I settled upon a 1U HP DL360 G5, which I mounted on the underside of a IKEA Lack side table. I set this up with Ubuntu Raring Ringtail running 24/7 as a torrenting/Usenet server. After a while, I was running FreePBX on it and experimenting with a SIP telephone I acquired from office.


IKEA LACK side table with DL360 G5 secured with lashing straps

I was happy, but I wanted to have a proper homelab, rack and all. Feeling confident, I decided to decouple functionality and purchased a 1U Dell Poweredge 1950 and set it up with FreeBSD. I set up Gitlab on it and used it as a secondary CVS for almost a year. I kept on adding to this setup and finally settled on a beefy setup that blew my power bill through the roof.


My homelab, at its peak

I started realizing that I wasn't really using these powerful devices to their fullest potential. Rather, I had consolidated my needs to a few; I needed a high-capacity NAS and a firewall.
So I pared down the setup to where it stands now.

Current Homelab setup
4U NAS Freenas, torrenting, Usenet, Plex
D-link 24-port Gigabit switch Switch
1U Motorola Symbol Appliance pfSense, firewall, gateway, DHCP server, Squid proxy
Airport Extreme WiFi router

Using scopes in Rails 4

09 August, 2014

I was introduced to scopes in Rails through my need to chain queries to get the result I needed. This site's hero navigation filters post titles from different categories. I need to display projects on the right and all other categories on the left.

The only category common to both is hero
Scopes in Rails are basically a way to define methods on a model, in such a way that you can retrieve data and information on a subset of a database.

Example:
This snippet defines two scopes on the Post model: hero and projects
Note that the scope uses associations I have set up between Post and Category

1
2
3
#scope that isolates "heroes" and "projects"
scope :hero, -> {Post.includes(:categories).where('categories.title = (?)', "Hero")}
scope :projects, -> {Post.includes(:categories).where('categories.title = (?)', "Projects")}

This will help me do the following:

1
2
Post.hero #basically returns all posts filed under "Hero" catgegory
Post.projects #Returns all posts under "Projects"

This also helps me do some advanced stuff such as chaining queries. I have a method that helps me filter drafts. Then, I merge the two queries to get only non-draft posts that fall under Projects and Hero

1
2
3
4
5
6
7
8
#checks for the is_draft flag
def self.is_draft(what)
   post = Post.where('is_draft = (?)', what )
end

#controller
#this is how you merge the two scopes and then get the desired result
@projects = Post.is_draft("no").projects & Post.hero

Scopes are a great way of working with subsets of your database that you work with frequently. To put it in context, I am often going to need to work with Project posts and I want the convenience of calling a method on the model, which feels natural.

The redemption of a certain Misal Pav

07 August, 2014

There are things that matter and there are things that can afford to slide.

Misal Pav is the former.

It is something that infuses life into the most derelict of tendencies. It is the fire that breathes life into fires. It is the product of a culture that was built on foundations of tumeric and red chili powder, with liberal amounts of salt to taste. Don't allow yourself to be fooled by the economy of ingredients. It is effective because of this economy, not in spite of it.

Misal Pav has transcended the boundaries of generations, lending itself to whoever creates it and puts their own mark on it, causing its name to prosper and flourish despite the apparent bastardization. There is only one true Misal Pav; that comes from wherever its creator says it came from.

This is the poor cousin of the poorest cousins of whatever snack/breakfast/lunch counterpart you can name from your country of origin. It's beauty lies in the simplicity of the ingredients that go into its making as well as the aftermath of its consumption. Fire all the way, they say.

Fire. All the way.