Merge pull request #549 from deanputney/master

TumblrPublishAgent
This commit is contained in:
Andrew Cantino 2014-10-01 13:40:05 -07:00
commit 8d6090faf9
11 changed files with 289 additions and 28 deletions

View file

@ -89,6 +89,9 @@ THIRTY_SEVEN_SIGNALS_OAUTH_SECRET=
GITHUB_OAUTH_KEY=
GITHUB_OAUTH_SECRET=
TUMBLR_OAUTH_KEY=
TUMBLR_OAUTH_SECRET=
#############################
# AWS and Mechanical Turk #
#############################

View file

@ -20,6 +20,10 @@ gem 'twitter', '~> 5.8.0' # Must to be loaded before cantino-twitter-stream.
gem 'cantino-twitter-stream', github: 'cantino/twitter-stream', branch: 'master'
gem 'omniauth-twitter'
# Tumblr Agents
gem 'tumblr_client'
gem 'omniauth-tumblr'
# Optional Services.
gem 'omniauth-37signals' # BasecampAgent
# gem 'omniauth-github'

View file

@ -214,6 +214,8 @@ GEM
multi_json (~> 1.3)
oauth2 (~> 0.9.3)
omniauth (~> 1.2)
omniauth-tumblr (1.1)
omniauth-oauth (~> 1.0)
omniauth-twitter (1.0.1)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
@ -340,6 +342,13 @@ GEM
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
tumblr_client (0.8.4)
faraday (~> 0.9.0)
faraday_middleware (~> 0.9.0)
json
mime-types
oauth
simple_oauth
twilio-ruby (3.11.6)
builder (>= 2.1.2)
jwt (>= 0.1.2)
@ -431,6 +440,7 @@ DEPENDENCIES
nokogiri (~> 1.6.1)
omniauth
omniauth-37signals
omniauth-tumblr
omniauth-twitter
pg
protected_attributes (~> 1.0.8)
@ -454,6 +464,7 @@ DEPENDENCIES
spring
spring-commands-rspec
therubyracer (~> 0.12.1)
tumblr_client
twilio-ruby (~> 3.11.5)
twitter (~> 5.8.0)
typhoeus (~> 0.6.3)

View file

@ -0,0 +1,36 @@
module TumblrConcern
extend ActiveSupport::Concern
included do
include Oauthable
valid_oauth_providers :tumblr
end
def tumblr_consumer_key
ENV['TUMBLR_OAUTH_KEY']
end
def tumblr_consumer_secret
ENV['TUMBLR_OAUTH_SECRET']
end
def tumblr_oauth_token
service.token
end
def tumblr_oauth_token_secret
service.secret
end
def tumblr
Tumblr.configure do |config|
config.consumer_key = tumblr_consumer_key
config.consumer_secret = tumblr_consumer_secret
config.oauth_token = tumblr_oauth_token
config.oauth_token_secret = tumblr_oauth_token_secret
end
Tumblr::Client.new
end
end

View file

@ -43,7 +43,7 @@ module ApplicationHelper
def icon_for_service(service)
case service.to_sym
when :twitter, :github
when :twitter, :tumblr, :github
"<i class='fa fa-#{service}'></i>".html_safe
else
"<i class='fa fa-lock'></i>".html_safe

View file

@ -0,0 +1,163 @@
require "tumblr_client"
module Agents
class TumblrPublishAgent < Agent
include TumblrConcern
cannot_be_scheduled!
description <<-MD
#{'## Include `tumblr_client` and `omniauth-tumblr` in your Gemfile to use this Agent!' if dependencies_missing?}
The TumblrPublishAgent publishes Tumblr posts from the events it receives.
To be able to use this Agent you need to authenticate with Tumblr in the [Services](/services) section first.
**Required fields:**
`blog_name` Your Tumblr URL (e.g. "mustardhamsters.tumblr.com")
`post_type` One of [text, photo, quote, link, chat, audio, video]
-------------
You may leave any of the following optional fields blank. Including a field not allowed for the specified `post_type` will cause a failure.
**Any post type**
* `state` published, draft, queue, private
* `tags` Comma-separated tags for this post
* `tweet` off, text for tweet
* `date` GMT date and time of the post as a string
* `format` html, markdown
* `slug` short text summary at end of the post URL
**Text** `title` `body`
**Photo** `caption` `link` `source`
**Quote** `quote` `source`
**Link** `title` `url` `description`
**Chat** `title` `conversation`
**Audio** `caption` `external_url`
**Video** `caption` `embed`
-------------
[Full information on field options](https://www.tumblr.com/docs/en/api/v2#posting)
Set `expected_update_period_in_days` to the maximum amount of time that you'd expect to pass between Events being created by this Agent.
MD
gem_dependency_check { defined?(Tumblr) }
def validate_options
errors.add(:base, "expected_update_period_in_days is required") unless options['expected_update_period_in_days'].present?
end
def working?
event_created_within?(interpolated['expected_update_period_in_days']) && most_recent_event && most_recent_event.payload['success'] == true && !recent_error_logs?
end
def default_options
{
'expected_update_period_in_days' => "10",
'blog_name' => "{{blog_name}}",
'post_type' => "{{post_type}}",
'options' => {
'state' => "{{state}}",
'tags' => "{{tags}}",
'tweet' => "{{tweet}}",
'date' => "{{date}}",
'format' => "{{format}}",
'slug' => "{{slug}}",
'title' => "{{title}}",
'body' => "{{body}}",
'caption' => "{{caption}}",
'link' => "{{link}}",
'source' => "{{source}}",
'quote' => "{{quote}}",
'url' => "{{url}}",
'description' => "{{description}}",
'conversation' => "{{conversation}}",
'external_url' => "{{external_url}}",
'embed' => "{{embed}}",
},
}
end
def receive(incoming_events)
# if there are too many, dump a bunch to avoid getting rate limited
if incoming_events.count > 20
incoming_events = incoming_events.first(20)
end
incoming_events.each do |event|
blog_name = interpolated(event)['blog_name']
post_type = interpolated(event)['post_type']
options = interpolated(event)['options']
begin
post = publish_post(blog_name, post_type, options)
create_event :payload => {
'success' => true,
'published_post' => "["+blog_name+"] "+post_type,
'post_id' => post["id"],
'agent_id' => event.agent_id,
'event_id' => event.id
}
end
end
end
def publish_post(blog_name, post_type, options)
options_obj = {
:state => options['state'],
:tags => options['tags'],
:tweet => options['tweet'],
:date => options['date'],
:format => options['format'],
:slug => options['slug'],
}
case post_type
when "text"
options_obj[:title] = options['title']
options_obj[:body] = options['body']
tumblr.text(blog_name, options_obj)
when "photo"
options_obj[:caption] = options['caption']
options_obj[:link] = options['link']
options_obj[:source] = options['source']
tumblr.photo(blog_name, options_obj)
when "quote"
options_obj[:quote] = options['quote']
options_obj[:source] = options['source']
tumblr.quote(blog_name, options_obj)
when "link"
options_obj[:title] = options['title']
options_obj[:url] = options['url']
options_obj[:description] = options['description']
tumblr.link(blog_name, options_obj)
when "chat"
options_obj[:title] = options['title']
options_obj[:conversation] = options['conversation']
tumblr.chat(blog_name, options_obj)
when "audio"
options_obj[:caption] = options['caption']
options_obj[:external_url] = options['external_url']
tumblr.audio(blog_name, options_obj)
when "video"
options_obj[:caption] = options['caption']
options_obj[:embed] = options['embed']
tumblr.video(blog_name, options_obj)
end
end
end
end

View file

@ -219,6 +219,12 @@ Devise.setup do |config|
config.omniauth :twitter, key, secret, authorize_params: {force_login: 'true', use_authorize: 'true'}
end
if defined?(OmniAuth::Strategies::Tumblr) &&
(key = ENV["TUMBLR_OAUTH_KEY"]).present? &&
(secret = ENV["TUMBLR_OAUTH_SECRET"]).present?
config.omniauth :'tumblr', key, secret
end
if defined?(OmniAuth::Strategies::ThirtySevenSignals) &&
(key = ENV["THIRTY_SEVEN_SIGNALS_OAUTH_KEY"]).present? &&
(secret = ENV["THIRTY_SEVEN_SIGNALS_OAUTH_SECRET"]).present?

View file

@ -51,6 +51,7 @@ en:
failure: 'Could not authenticate you from %{kind} because "%{reason}".'
omniauth_providers:
twitter: 'Twitter'
tumblr: 'Tumblr'
github: 'GitHub'
37signals: '37Signals (Basecamp)'
mailer:

View file

@ -11,14 +11,11 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20140901143732) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
ActiveRecord::Schema.define(version: 20140906030139) do
create_table "agent_logs", force: true do |t|
t.integer "agent_id", null: false
t.text "message", limit: 16777215, null: false, charset: "utf8mb4", collation: "utf8mb4_bin"
t.text "message", null: false, charset: "utf8mb4", collation: "utf8mb4_bin"
t.integer "level", default: 3, null: false
t.integer "inbound_event_id"
t.integer "outbound_event_id"
@ -28,7 +25,7 @@ ActiveRecord::Schema.define(version: 20140901143732) do
create_table "agents", force: true do |t|
t.integer "user_id"
t.text "options", limit: 16777215, charset: "utf8mb4", collation: "utf8mb4_bin"
t.text "options", charset: "utf8mb4", collation: "utf8mb4_bin"
t.string "type", collation: "utf8_bin"
t.string "name", charset: "utf8mb4", collation: "utf8mb4_bin"
t.string "schedule", collation: "utf8_bin"
@ -36,17 +33,17 @@ ActiveRecord::Schema.define(version: 20140901143732) do
t.datetime "last_check_at"
t.datetime "last_receive_at"
t.integer "last_checked_event_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.text "memory", limit: 2147483647, charset: "utf8mb4", collation: "utf8mb4_bin"
t.datetime "last_web_request_at"
t.integer "keep_events_for", default: 0, null: false
t.datetime "last_event_at"
t.datetime "last_error_log_at"
t.boolean "propagate_immediately", default: false, null: false
t.boolean "disabled", default: false, null: false
t.string "guid", null: false, charset: "ascii", collation: "ascii_bin"
t.boolean "propagate_immediately", default: false, null: false
t.boolean "disabled", default: false, null: false
t.integer "service_id"
t.string "guid", null: false
end
add_index "agents", ["guid"], name: "index_agents_on_guid", using: :btree
@ -67,8 +64,8 @@ ActiveRecord::Schema.define(version: 20140901143732) do
create_table "delayed_jobs", force: true do |t|
t.integer "priority", default: 0
t.integer "attempts", default: 0
t.text "handler", limit: 16777215, charset: "utf8mb4", collation: "utf8mb4_bin"
t.text "last_error", limit: 16777215, charset: "utf8mb4", collation: "utf8mb4_bin"
t.text "handler", limit: 16777215, charset: "utf8mb4", collation: "utf8mb4_bin"
t.text "last_error", charset: "utf8mb4", collation: "utf8mb4_bin"
t.datetime "run_at"
t.datetime "locked_at"
t.datetime "failed_at"
@ -83,11 +80,11 @@ ActiveRecord::Schema.define(version: 20140901143732) do
create_table "events", force: true do |t|
t.integer "user_id"
t.integer "agent_id"
t.decimal "lat", precision: 15, scale: 10
t.decimal "lng", precision: 15, scale: 10
t.text "payload", limit: 2147483647, charset: "utf8mb4", collation: "utf8mb4_bin"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.decimal "lat", precision: 15, scale: 10
t.decimal "lng", precision: 15, scale: 10
t.text "payload", limit: 16777215, charset: "utf8mb4", collation: "utf8mb4_bin"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "expires_at"
end
@ -117,13 +114,13 @@ ActiveRecord::Schema.define(version: 20140901143732) do
add_index "scenario_memberships", ["scenario_id"], name: "index_scenario_memberships_on_scenario_id", using: :btree
create_table "scenarios", force: true do |t|
t.string "name", null: false, charset: "utf8mb4", collation: "utf8mb4_bin"
t.integer "user_id", null: false
t.string "name", null: false, charset: "utf8mb4", collation: "utf8mb4_bin"
t.integer "user_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.text "description", charset: "utf8mb4", collation: "utf8mb4_bin"
t.boolean "public", default: false, null: false
t.string "guid", null: false, charset: "ascii", collation: "ascii_bin"
t.text "description", charset: "utf8mb4", collation: "utf8mb4_bin"
t.boolean "public", default: false, null: false
t.string "guid", null: false, charset: "ascii", collation: "ascii_bin"
t.string "source_url"
t.string "tag_bg_color"
t.string "tag_fg_color"
@ -154,8 +151,8 @@ ActiveRecord::Schema.define(version: 20140901143732) do
t.integer "user_id", null: false
t.string "credential_name", null: false
t.text "credential_value", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.string "mode", default: "text", null: false, collation: "utf8_bin"
end
@ -172,8 +169,8 @@ ActiveRecord::Schema.define(version: 20140901143732) do
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "admin", default: false, null: false
t.integer "failed_attempts", default: 0
t.string "unlock_token"

View file

@ -1,6 +1,8 @@
APP_SECRET_TOKEN=notarealappsecrettoken
TWITTER_OAUTH_KEY=twitteroauthkey
TWITTER_OAUTH_SECRET=twitteroauthsecret
TUMBLR_OAUTH_KEY=tumblroauthsecret
TUMBLR_OAUTH_SECRET=tumblroauthsecret
THIRTY_SEVEN_SIGNALS_OAUTH_KEY=TESTKEY
THIRTY_SEVEN_SIGNALS_OAUTH_SECRET=TESTSECRET
FAILED_JOBS_TO_KEEP=2

View file

@ -0,0 +1,38 @@
require 'spec_helper'
describe Agents::TumblrPublishAgent do
before do
@opts = {
:blog_name => "huginnbot.tumblr.com",
:post_type => "text",
:expected_update_period_in_days => "2",
:options => {
:title => "{{title}}",
:body => "{{body}}",
},
}
@checker = Agents::TumblrPublishAgent.new(:name => "HuginnBot", :options => @opts)
@checker.service = services(:generic)
@checker.user = users(:bob)
@checker.save!
@event = Event.new
@event.agent = agents(:bob_weather_agent)
@event.payload = { :title => "Gonna rain...", :body => 'San Francisco is gonna get wet' }
@event.save!
stub.any_instance_of(Agents::TumblrPublishAgent).tumblr {
stub!.text(anything, anything) { { "id" => "5" } }
}
end
describe '#receive' do
it 'should publish any payload it receives' do
Agents::TumblrPublishAgent.async_receive(@checker.id, [@event.id])
@checker.events.count.should eq(1)
@checker.events.first.payload['post_id'].should eq('5')
@checker.events.first.payload['published_post'].should eq('[huginnbot.tumblr.com] text')
end
end
end