Last active
August 29, 2015 13:56
-
-
Save elizabrock/9212713 to your computer and use it in GitHub Desktop.
elizabrocksoftware.com's Freckle Integration. This drives: http://elizabrocksoftware.com/what_are_they_doing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# encoding: UTF-8 | |
# This file is auto-generated from the current state of the database. Instead | |
# of editing this file, please use the migrations feature of Active Record to | |
# incrementally modify your database, and then regenerate this schema definition. | |
# | |
# Note that this schema.rb definition is the authoritative source for your | |
# database schema. If you need to create the application database on another | |
# system, you should be using db:schema:load, not running all the migrations | |
# from scratch. The latter is a flawed and unsustainable approach (the more migrations | |
# you'll amass, the slower it'll run and the greater likelihood for issues). | |
# | |
# It's strongly recommended that you check this file into your version control system. | |
ActiveRecord::Schema.define(version: 20131113162700) do | |
# These are extensions that must be enabled in order to support this database | |
enable_extension "plpgsql" | |
create_table "active_admin_comments", force: true do |t| | |
t.string "namespace" | |
t.text "body" | |
t.string "resource_id", null: false | |
t.string "resource_type", null: false | |
t.integer "author_id" | |
t.string "author_type" | |
t.datetime "created_at" | |
t.datetime "updated_at" | |
end | |
add_index "active_admin_comments", ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id", using: :btree | |
add_index "active_admin_comments", ["namespace"], name: "index_active_admin_comments_on_namespace", using: :btree | |
add_index "active_admin_comments", ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id", using: :btree | |
create_table "admin_users", force: true do |t| | |
t.string "email", default: "", null: false | |
t.string "encrypted_password", default: "", null: false | |
t.string "reset_password_token" | |
t.datetime "reset_password_sent_at" | |
t.datetime "remember_created_at" | |
t.integer "sign_in_count", default: 0 | |
t.datetime "current_sign_in_at" | |
t.datetime "last_sign_in_at" | |
t.string "current_sign_in_ip" | |
t.string "last_sign_in_ip" | |
t.datetime "created_at" | |
t.datetime "updated_at" | |
end | |
add_index "admin_users", ["email"], name: "index_admin_users_on_email", unique: true, using: :btree | |
add_index "admin_users", ["reset_password_token"], name: "index_admin_users_on_reset_password_token", unique: true, using: :btree | |
create_table "messages", force: true do |t| | |
t.string "from" | |
t.string "name" | |
t.text "message" | |
t.datetime "created_at" | |
t.datetime "updated_at" | |
end | |
create_table "project_screenshots", force: true do |t| | |
t.integer "project_id" | |
t.string "image" | |
t.datetime "created_at" | |
t.datetime "updated_at" | |
end | |
create_table "project_services", force: true do |t| | |
t.integer "project_id" | |
t.integer "service_id" | |
t.datetime "created_at" | |
t.datetime "updated_at" | |
end | |
create_table "projects", force: true do |t| | |
t.string "color" | |
t.integer "freckle_id" | |
t.string "logo" | |
t.string "freckle_name" | |
t.string "time_entry_name" | |
t.string "public_project_name" | |
t.text "client_description" | |
t.text "project_goal" | |
t.text "results" | |
t.datetime "created_at" | |
t.datetime "updated_at" | |
t.boolean "published" | |
t.boolean "testimonial_requested" | |
end | |
create_table "proposals", force: true do |t| | |
t.text "client_company_overview" | |
t.text "client_needs_overview" | |
t.text "executive_summary" | |
t.text "project_summary" | |
t.text "proposed_schedule" | |
t.datetime "created_at" | |
t.datetime "updated_at" | |
end | |
create_table "service_categories", force: true do |t| | |
t.text "description" | |
t.string "name" | |
t.integer "position" | |
t.datetime "created_at" | |
t.datetime "updated_at" | |
end | |
create_table "services", force: true do |t| | |
t.text "service_description" | |
t.integer "position" | |
t.text "process_description" | |
t.integer "service_category_id" | |
t.string "slug" | |
t.string "name" | |
t.datetime "created_at" | |
t.datetime "updated_at" | |
t.string "summary" | |
end | |
create_table "testimonials", force: true do |t| | |
t.integer "project_id" | |
t.text "testimonial" | |
t.string "client_name" | |
t.string "client_company" | |
t.string "client_link" | |
t.datetime "created_at" | |
t.datetime "updated_at" | |
end | |
create_table "time_entries", force: true do |t| | |
t.text "description_text" | |
t.date "entry_date" | |
t.integer "freckle_id" | |
t.integer "freckle_project_id" | |
t.integer "minutes" | |
t.text "tags" | |
t.text "url" | |
t.datetime "created_at" | |
t.datetime "updated_at" | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'freckle' | |
class Cron | |
def self.run! | |
Freckle.import_projects! | |
(0..7).each do |i| | |
Freckle.import_time_entries!(Time.zone.today - i) | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'httparty' | |
class Freckle | |
include HTTParty | |
base_uri 'https://elizabrock.letsfreckle.com/' | |
FRECKLE_PROJECT_MAPPINGS = { | |
:id => :freckle_id, | |
:color_hex => :color, | |
:name => :freckle_name | |
} | |
FRECKLE_TIME_ENTRY_MAPPINGS = { | |
:id => :freckle_id, | |
:project_id => :freckle_project_id, | |
:minutes => :minutes, | |
:description_text => :description_text, | |
:url => :url, | |
:date => :entry_date | |
} | |
def self.import_projects! | |
Freckle.new().import_projects | |
end | |
def self.import_time_entries! date = nil | |
date = Time.zone.today unless date | |
raise "Date cannot be in the future" if date.future? | |
Freckle.new().import_time_entries(date) | |
end | |
def import_time_entries date | |
options = default_options.merge( 'search[from]' => date.to_s(:freckle), 'search[to]' => date.to_s(:freckle) ) | |
time_entries = self.class.get('/api/entries.json', :query => options) | |
time_entries.collect { |te| import_time_entry(te['entry']) } | |
end | |
def import_projects | |
options = default_options | |
projects = self.class.get('/api/projects.json', :query => options) | |
projects.collect { |project| import_project(project['project']) } | |
end | |
private | |
def import_time_entry te | |
time_entry = TimeEntry.find_or_create_by(freckle_id: te["id"]) | |
updates = FRECKLE_TIME_ENTRY_MAPPINGS.each_pair do |freckle_attr, time_entry_attr| | |
time_entry.send("#{time_entry_attr}=", te[freckle_attr.to_s] || "") | |
end | |
time_entry.tags = te["tags"].map{|t| t["name"]}.join(", ") | |
time_entry.save | |
time_entry | |
end | |
def import_project p | |
project = Project.find_or_create_by(freckle_id: p["id"]) | |
updates = FRECKLE_PROJECT_MAPPINGS.each_pair do |freckle_attr, project_attr| | |
project.send("#{project_attr}=", p[freckle_attr.to_s] || "") | |
end | |
project.save | |
project | |
end | |
def default_options | |
{:token => "[my_freckle_api_token]" } | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'cron' | |
desc "Run cron job" | |
task :cron => :environment do | |
Cron.run! | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'freckle' | |
require 'spec_helper' | |
describe Freckle do | |
describe ".import_time_entries!", :vcr do | |
context "no arguments" do | |
it "calls itself with today's date" do | |
Freckle.any_instance.should_receive(:import_time_entries).with(Date.today) | |
Freckle.stub(:get).and_return([]) | |
Freckle.import_time_entries! | |
end | |
end | |
context "with a date argument in the future" do | |
it "returns raises an error" do | |
expect{ Freckle.import_time_entries!(Date.today + 3) }.to raise_error | |
end | |
it "does not hit freckle" do | |
Freckle.should_not_receive(:import_time_entries) | |
expect{ Freckle.import_time_entries!(Date.today + 3) }.to raise_error | |
end | |
end | |
context "with a date argument in the present/past" do | |
let(:date){ Date.parse("2011-07-04") } | |
let(:existing_project){ Fabricate(:project, freckle_id: 59449) } | |
let(:existing_time_entry){ Fabricate(:time_entry, freckle_id: 1103491, freckle_project_id: 59449, minutes: 20, description_text: "Add cucumber compass and rspec.", url: "https://github.com/elizabrock/watchelizago/commit/c426c7872766a68fcbc51809b2f27c89f2eca618", tags: "development", entry_date: Date.parse("2011-07-04")) } | |
let(:changed_time_entry){ Fabricate(:time_entry, freckle_id: 1103788, minutes: 345) } #actual time: 10 | |
before do | |
existing_project | |
existing_time_entry | |
changed_time_entry | |
end | |
def do_action | |
Freckle.import_time_entries!(date) | |
end | |
it "does not create time entries from other days" do | |
do_action.keep_if{|te| te.entry_date != date}.should be_empty | |
end | |
it "doesn't duplicate existing time entries" do | |
do_action | |
TimeEntry.where(:freckle_id => existing_time_entry.freckle_id).count.should == 1 | |
end | |
it "returns the new time entries" do | |
do_action.map(&:freckle_id).sort.should == [1103459, 1103491, 1103762, 1103779, 1103788, 1103801] | |
end | |
it "persists all of the time entries" do | |
a = do_action | |
b = TimeEntry.all | |
difference = ( (a || b) - ( a & b) ) #anything that isn't in both sets | |
difference.should be_empty | |
end | |
it "creates time entries that don't exist" do | |
TimeEntry.where(freckle_id: 1103762).to_a.should be_empty | |
do_action | |
TimeEntry.where(freckle_id: 1103762).to_a.should_not be_empty | |
end | |
it "updates time entries that have changed" do | |
expected_attributes = { freckle_id: 1103788, freckle_project_id: 59459, minutes: 10, description_text: "sending anne an email about the upcoming work", url: "", tags: "planning", entry_date: Date.parse("2011-07-04") } | |
do_action | |
changed_time_entry.reload | |
expected_attributes.each_pair do |attr, expected_value| | |
changed_time_entry[attr].should == expected_value | |
end | |
end | |
it "doesn't change time entries that haven't changed" do | |
expected = existing_time_entry.attributes | |
do_action | |
actual = TimeEntry.find(existing_time_entry.id) | |
actual.attributes.should == expected | |
end | |
it "creates any projects that don't exist" do | |
Project.where(freckle_id: 52665).to_a.should be_empty | |
do_action | |
Project.where(freckle_id: 52665).to_a.should_not be_empty | |
end | |
it "doesn't change projects that already exist" do | |
expect{ do_action }.to_not change{ existing_project.reload } | |
end | |
it "doesn't duplicate projects that already exist" do | |
do_action | |
Project.where(:freckle_id => existing_project.freckle_id).count.should == 1 | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I use the heroku schedule to run
rake cron
every hour.