mirror of
https://github.com/Fishwaldo/huginn.git
synced 2025-03-15 19:31:26 +00:00
Merge pull request #558 from knu/refactor-omniauth
Refactor OmniAuth integration.
This commit is contained in:
commit
7fc9fbb2d6
14 changed files with 200 additions and 73 deletions
|
@ -5,9 +5,9 @@ module TwitterConcern
|
|||
include Oauthable
|
||||
|
||||
validate :validate_twitter_options
|
||||
valid_oauth_providers 'twitter'
|
||||
valid_oauth_providers :twitter
|
||||
|
||||
gem_dependency_check { defined?(Twitter) && has_oauth_configuration_for?('twitter') }
|
||||
gem_dependency_check { defined?(Twitter) && Devise.omniauth_providers.include?(:twitter) }
|
||||
end
|
||||
|
||||
def validate_twitter_options
|
||||
|
@ -20,11 +20,11 @@ module TwitterConcern
|
|||
end
|
||||
|
||||
def twitter_consumer_key
|
||||
ENV['TWITTER_OAUTH_KEY']
|
||||
(config = Devise.omniauth_configs[:twitter]) && config.strategy.consumer_key
|
||||
end
|
||||
|
||||
def twitter_consumer_secret
|
||||
ENV['TWITTER_OAUTH_SECRET']
|
||||
(config = Devise.omniauth_configs[:twitter]) && config.strategy.consumer_secret
|
||||
end
|
||||
|
||||
def twitter_oauth_token
|
||||
|
|
|
@ -27,7 +27,7 @@ class ApplicationController < ActionController::Base
|
|||
private
|
||||
|
||||
def twitter_oauth_check
|
||||
if ENV['TWITTER_OAUTH_KEY'].blank? || ENV['TWITTER_OAUTH_SECRET'].blank?
|
||||
unless Devise.omniauth_providers.include?(:twitter)
|
||||
if @twitter_agent = current_user.agents.where("type like 'Agents::Twitter%'").first
|
||||
@twitter_oauth_key = @twitter_agent.options['consumer_key'].presence || @twitter_agent.credential('twitter_consumer_key')
|
||||
@twitter_oauth_secret = @twitter_agent.options['consumer_secret'].presence || @twitter_agent.credential('twitter_consumer_secret')
|
||||
|
@ -36,7 +36,7 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def basecamp_auth_check
|
||||
if ENV['THIRTY_SEVEN_SIGNALS_OAUTH_KEY'].blank? || ENV['THIRTY_SEVEN_SIGNALS_OAUTH_SECRET'].blank?
|
||||
unless Devise.omniauth_providers.include?(:'37signals')
|
||||
@basecamp_agent = current_user.agents.where(type: 'Agents::BasecampAgent').first
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,4 +40,13 @@ module ApplicationHelper
|
|||
link_to 'No', agent_path(agent, tab: (agent.recent_error_logs? ? 'logs' : 'details')), class: 'label label-danger'
|
||||
end
|
||||
end
|
||||
|
||||
def icon_for_service(service)
|
||||
case service.to_sym
|
||||
when :twitter, :github
|
||||
"<i class='fa fa-#{service}'></i>".html_safe
|
||||
else
|
||||
"<i class='fa fa-lock'></i>".html_safe
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@ module Agents
|
|||
cannot_receive_events!
|
||||
|
||||
include Oauthable
|
||||
valid_oauth_providers '37signals'
|
||||
valid_oauth_providers :'37signals'
|
||||
|
||||
description <<-MD
|
||||
The BasecampAgent checks a Basecamp project for new Events
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
class Service < ActiveRecord::Base
|
||||
PROVIDER_TO_ENV_MAP = {'37signals' => 'THIRTY_SEVEN_SIGNALS'}
|
||||
|
||||
attr_accessible :provider, :name, :token, :secret, :refresh_token, :expires_at, :global, :options, :uid
|
||||
|
||||
serialize :options, Hash
|
||||
|
@ -51,23 +49,19 @@ class Service < ActiveRecord::Base
|
|||
URI.join(client_options['site'], client_options['token_url'])
|
||||
end
|
||||
|
||||
def provider_to_env
|
||||
PROVIDER_TO_ENV_MAP[provider].presence || provider.upcase
|
||||
end
|
||||
|
||||
def oauth_key
|
||||
ENV["#{provider_to_env}_OAUTH_KEY"]
|
||||
(config = Devise.omniauth_configs[provider.to_sym]) && config.args[0]
|
||||
end
|
||||
|
||||
def oauth_secret
|
||||
ENV["#{provider_to_env}_OAUTH_SECRET"]
|
||||
(config = Devise.omniauth_configs[provider.to_sym]) && config.args[1]
|
||||
end
|
||||
|
||||
def self.provider_specific_options(omniauth)
|
||||
case omniauth['provider']
|
||||
when 'twitter', 'github'
|
||||
case omniauth['provider'].to_sym
|
||||
when :twitter, :github
|
||||
{ name: omniauth['info']['nickname'] }
|
||||
when '37signals'
|
||||
when :'37signals'
|
||||
{ user_id: omniauth['extra']['accounts'][0]['id'], name: omniauth['info']['name'] }
|
||||
else
|
||||
{ name: omniauth['info']['nickname'] }
|
||||
|
@ -86,4 +80,4 @@ class Service < ActiveRecord::Base
|
|||
options: options
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
# Huginn is designed to be a multi-User system. Users have many Agents (and Events created by those Agents).
|
||||
class User < ActiveRecord::Base
|
||||
# Include default devise modules. Others available are:
|
||||
# :token_authenticatable, :confirmable,
|
||||
# :lockable, :timeoutable and :omniauthable
|
||||
devise :database_authenticatable, :registerable,
|
||||
:recoverable, :rememberable, :trackable, :validatable, :lockable
|
||||
:recoverable, :rememberable, :trackable, :validatable, :lockable,
|
||||
:omniauthable
|
||||
|
||||
INVITATION_CODES = [ENV['INVITATION_CODE'] || 'try-huginn']
|
||||
|
||||
|
|
|
@ -11,15 +11,9 @@
|
|||
<%= link_to 'wiki', 'https://github.com/cantino/huginn/wiki/Configuring-OAuth-applications', target: :_blank %>
|
||||
for guidance.
|
||||
</p>
|
||||
<% if has_oauth_configuration_for?('twitter') %>
|
||||
<p><%= link_to "/auth/twitter", class: 'btn btn-default btn-auth btn-auth-twitter' do %><i class='fa fa-twitter'></i><span>Authenticate with Twitter</span><% end %></p>
|
||||
<% end %>
|
||||
<% if has_oauth_configuration_for?('37signals') %>
|
||||
<p><%= link_to "/auth/37signals", class: 'btn btn-default btn-auth btn-auth-37signals' do %><i class='fa fa-lock'></i><span>Authenticate with 37Signals (Basecamp)</span><% end %></p>
|
||||
<% end -%>
|
||||
<% if has_oauth_configuration_for?('github') %>
|
||||
<p><%= link_to "/auth/github", class: 'btn btn-default btn-auth btn-auth-github' do %><i class='fa fa-github'></i><span>Authenticate with Github</span><% end %></p>
|
||||
<% end -%>
|
||||
<%- Devise.omniauth_providers.each { |provider| -%>
|
||||
<p><%= link_to user_omniauth_authorize_path(provider), class: "btn btn-default btn-auth btn-auth-#{provider}" do %><%= icon_for_service(provider) %><span>Authenticate with <%= t("devise.omniauth_providers.#{provider}") %></span><% end %></p>
|
||||
<%- } -%>
|
||||
<hr>
|
||||
|
||||
<div class='table-responsive'>
|
||||
|
|
|
@ -4,6 +4,8 @@ require 'rails/all'
|
|||
|
||||
Bundler.require(:default, Rails.env)
|
||||
|
||||
Dotenv.overload File.expand_path('../../spec/env.test', __FILE__) if Rails.env.test?
|
||||
|
||||
module Huginn
|
||||
class Application < Rails::Application
|
||||
# Settings in config/environments/* take precedence over those specified here.
|
||||
|
|
|
@ -213,6 +213,23 @@ Devise.setup do |config|
|
|||
# Add a new OmniAuth provider. Check the wiki for more information on setting
|
||||
# up on your models and hooks.
|
||||
# config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo'
|
||||
if defined?(OmniAuth::Strategies::Twitter) &&
|
||||
(key = ENV["TWITTER_OAUTH_KEY"]).present? &&
|
||||
(secret = ENV["TWITTER_OAUTH_SECRET"]).present?
|
||||
config.omniauth :twitter, key, secret, authorize_params: {force_login: 'true', use_authorize: 'true'}
|
||||
end
|
||||
|
||||
if defined?(OmniAuth::Strategies::ThirtySevenSignals) &&
|
||||
(key = ENV["THIRTY_SEVEN_SIGNALS_OAUTH_KEY"]).present? &&
|
||||
(secret = ENV["THIRTY_SEVEN_SIGNALS_OAUTH_SECRET"]).present?
|
||||
config.omniauth :'37signals', key, secret
|
||||
end
|
||||
|
||||
if defined?(OmniAuth::Strategies::GitHub) &&
|
||||
(key = ENV["GITHUB_OAUTH_KEY"]).present? &&
|
||||
(secret = ENV["GITHUB_OAUTH_SECRET"]).present?
|
||||
config.omniauth :github, key, secret
|
||||
end
|
||||
|
||||
# ==> Warden configuration
|
||||
# If you want to use other strategies, that are not supported by Devise, or
|
||||
|
@ -236,4 +253,5 @@ Devise.setup do |config|
|
|||
# When using omniauth, Devise cannot automatically set Omniauth path,
|
||||
# so you need to do it manually. For the users scope, it would be:
|
||||
# config.omniauth_path_prefix = "/my_engine/users/auth"
|
||||
end
|
||||
config.omniauth_path_prefix = "/auth"
|
||||
end
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
OMNIAUTH_PROVIDERS = {}.tap { |providers|
|
||||
if defined?(OmniAuth::Strategies::Twitter) &&
|
||||
(key = ENV["TWITTER_OAUTH_KEY"]).present? &&
|
||||
(secret = ENV["TWITTER_OAUTH_SECRET"]).present?
|
||||
providers['twitter'] = {
|
||||
omniauth_params: [key, secret, authorize_params: {force_login: 'true', use_authorize: 'true'}]
|
||||
}
|
||||
end
|
||||
|
||||
if defined?(OmniAuth::Strategies::ThirtySevenSignals) &&
|
||||
(key = ENV["THIRTY_SEVEN_SIGNALS_OAUTH_KEY"]).present? &&
|
||||
(secret = ENV["THIRTY_SEVEN_SIGNALS_OAUTH_SECRET"]).present?
|
||||
providers['37signals'] = {
|
||||
omniauth_params: [key, secret]
|
||||
}
|
||||
end
|
||||
|
||||
if defined?(OmniAuth::Strategies::GitHub) &&
|
||||
(key = ENV["GITHUB_OAUTH_KEY"]).present? &&
|
||||
(secret = ENV["GITHUB_OAUTH_SECRET"]).present?
|
||||
providers['github'] = {
|
||||
omniauth_params: [key, secret]
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
def has_oauth_configuration_for?(provider)
|
||||
OMNIAUTH_PROVIDERS.key?(provider.to_s)
|
||||
end
|
||||
|
||||
Rails.application.config.middleware.use OmniAuth::Builder do
|
||||
OMNIAUTH_PROVIDERS.each { |name, config|
|
||||
provider name, *config[:omniauth_params]
|
||||
}
|
||||
end
|
|
@ -49,6 +49,10 @@ en:
|
|||
omniauth_callbacks:
|
||||
success: 'Successfully authenticated from %{kind} account.'
|
||||
failure: 'Could not authenticate you from %{kind} because "%{reason}".'
|
||||
omniauth_providers:
|
||||
twitter: 'Twitter'
|
||||
github: 'GitHub'
|
||||
37signals: '37Signals (Basecamp)'
|
||||
mailer:
|
||||
confirmation_instructions:
|
||||
subject: 'Confirmation instructions'
|
||||
|
|
|
@ -66,8 +66,9 @@ Huginn::Application.routes.draw do
|
|||
post "/users/:user_id/webhooks/:agent_id/:secret" => "web_requests#handle_request" # legacy
|
||||
post "/users/:user_id/update_location/:secret" => "web_requests#update_location" # legacy
|
||||
|
||||
match '/auth/:provider/callback', to: 'services#callback',
|
||||
via: [:get, :post] #, constraints: { provider: Regexp.union(Devise.omniauth_providers.map(&:to_s)) }
|
||||
devise_for :users, :sign_out_via => [ :post, :delete ]
|
||||
get '/auth/:provider/callback', to: 'services#callback'
|
||||
|
||||
get "/about" => "home#about"
|
||||
root :to => "home#index"
|
||||
|
|
146
spec/helpers/application_helper_spec.rb
Normal file
146
spec/helpers/application_helper_spec.rb
Normal file
|
@ -0,0 +1,146 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ApplicationHelper do
|
||||
describe '#nav_link' do
|
||||
it 'returns a nav link' do
|
||||
stub(self).current_page?('/things') { false }
|
||||
nav = nav_link('Things', '/things')
|
||||
a = Nokogiri(nav).at('li:not(.active) > a[href="/things"]')
|
||||
expect(a.text.strip).to eq('Things')
|
||||
end
|
||||
|
||||
it 'returns a nav link with a glyphicon' do
|
||||
stub(self).current_page?('/things') { false }
|
||||
nav = nav_link('Things', '/things', glyphicon: 'help')
|
||||
expect(nav).to be_html_safe
|
||||
a = Nokogiri(nav).at('li:not(.active) > a[href="/things"]')
|
||||
expect(a.at('span.glyphicon.glyphicon-help')).to be_a Nokogiri::XML::Element
|
||||
expect(a.text.strip).to eq('Things')
|
||||
end
|
||||
|
||||
it 'returns an active nav link' do
|
||||
stub(self).current_page?('/things') { true }
|
||||
nav = nav_link('Things', '/things')
|
||||
expect(nav).to be_html_safe
|
||||
a = Nokogiri(nav).at('li.active > a[href="/things"]')
|
||||
expect(a).to be_a Nokogiri::XML::Element
|
||||
expect(a.text.strip).to eq('Things')
|
||||
end
|
||||
|
||||
describe 'with block' do
|
||||
it 'returns a nav link with menu' do
|
||||
stub(self).current_page?('/things') { false }
|
||||
stub(self).current_page?('/things/stuff') { false }
|
||||
nav = nav_link('Things', '/things') { nav_link('Stuff', '/things/stuff') }
|
||||
expect(nav).to be_html_safe
|
||||
a0 = Nokogiri(nav).at('li.dropdown.dropdown-hover:not(.active) > a[href="/things"]')
|
||||
expect(a0).to be_a Nokogiri::XML::Element
|
||||
expect(a0.text.strip).to eq('Things')
|
||||
a1 = Nokogiri(nav).at('li.dropdown.dropdown-hover:not(.active) > li:not(.active) > a[href="/things/stuff"]')
|
||||
expect(a1).to be_a Nokogiri::XML::Element
|
||||
expect(a1.text.strip).to eq('Stuff')
|
||||
end
|
||||
|
||||
it 'returns an active nav link with menu' do
|
||||
stub(self).current_page?('/things') { true }
|
||||
stub(self).current_page?('/things/stuff') { false }
|
||||
nav = nav_link('Things', '/things') { nav_link('Stuff', '/things/stuff') }
|
||||
expect(nav).to be_html_safe
|
||||
a0 = Nokogiri(nav).at('li.dropdown.dropdown-hover.active > a[href="/things"]')
|
||||
expect(a0).to be_a Nokogiri::XML::Element
|
||||
expect(a0.text.strip).to eq('Things')
|
||||
a1 = Nokogiri(nav).at('li.dropdown.dropdown-hover.active > li:not(.active) > a[href="/things/stuff"]')
|
||||
expect(a1).to be_a Nokogiri::XML::Element
|
||||
expect(a1.text.strip).to eq('Stuff')
|
||||
end
|
||||
|
||||
it 'returns an active nav link with menu when on a child page' do
|
||||
stub(self).current_page?('/things') { false }
|
||||
stub(self).current_page?('/things/stuff') { true }
|
||||
nav = nav_link('Things', '/things') { nav_link('Stuff', '/things/stuff') }
|
||||
expect(nav).to be_html_safe
|
||||
a0 = Nokogiri(nav).at('li.dropdown.dropdown-hover.active > a[href="/things"]')
|
||||
expect(a0).to be_a Nokogiri::XML::Element
|
||||
expect(a0.text.strip).to eq('Things')
|
||||
a1 = Nokogiri(nav).at('li.dropdown.dropdown-hover.active > li:not(.active) > a[href="/things/stuff"]')
|
||||
expect(a1).to be_a Nokogiri::XML::Element
|
||||
expect(a1.text.strip).to eq('Stuff')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#yes_no' do
|
||||
it 'returns a label "Yes" if any truthy value is given' do
|
||||
[true, Object.new].each { |value|
|
||||
label = yes_no(value)
|
||||
expect(label).to be_html_safe
|
||||
expect(Nokogiri(label).text).to eq 'Yes'
|
||||
}
|
||||
end
|
||||
|
||||
it 'returns a label "No" if any falsy value is given' do
|
||||
[false, nil].each { |value|
|
||||
label = yes_no(value)
|
||||
expect(label).to be_html_safe
|
||||
expect(Nokogiri(label).text).to eq 'No'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe '#working' do
|
||||
before do
|
||||
@agent = agents(:jane_website_agent)
|
||||
end
|
||||
|
||||
it 'returns a label "Disabled" if a given agent is disabled' do
|
||||
stub(@agent).disabled? { true }
|
||||
label = working(@agent)
|
||||
expect(label).to be_html_safe
|
||||
expect(Nokogiri(label).text).to eq 'Disabled'
|
||||
end
|
||||
|
||||
it 'returns a label "Missing Gems" if a given agent has dependencies missing' do
|
||||
stub(@agent).dependencies_missing? { true }
|
||||
label = working(@agent)
|
||||
expect(label).to be_html_safe
|
||||
expect(Nokogiri(label).text).to eq 'Missing Gems'
|
||||
end
|
||||
|
||||
it 'returns a label "Yes" if a given agent is working' do
|
||||
stub(@agent).working? { true }
|
||||
label = working(@agent)
|
||||
expect(label).to be_html_safe
|
||||
expect(Nokogiri(label).text).to eq 'Yes'
|
||||
end
|
||||
|
||||
it 'returns a label "No" if a given agent is not working' do
|
||||
stub(@agent).working? { false }
|
||||
label = working(@agent)
|
||||
expect(label).to be_html_safe
|
||||
expect(Nokogiri(label).text).to eq 'No'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#icon_for_service' do
|
||||
it 'returns a correct icon tag for Twitter' do
|
||||
icon = icon_for_service(:twitter)
|
||||
expect(icon).to be_html_safe
|
||||
elem = Nokogiri(icon).at('i.fa.fa-twitter')
|
||||
expect(elem).to be_a Nokogiri::XML::Element
|
||||
end
|
||||
|
||||
it 'returns a correct icon tag for GitHub' do
|
||||
icon = icon_for_service(:github)
|
||||
expect(icon).to be_html_safe
|
||||
elem = Nokogiri(icon).at('i.fa.fa-github')
|
||||
expect(elem).to be_a Nokogiri::XML::Element
|
||||
end
|
||||
|
||||
it 'returns a correct icon tag for other services' do
|
||||
icon = icon_for_service(:'37signals')
|
||||
expect(icon).to be_html_safe
|
||||
elem = Nokogiri(icon).at('i.fa.fa-lock')
|
||||
expect(elem).to be_a Nokogiri::XML::Element
|
||||
end
|
||||
end
|
||||
end
|
|
@ -8,10 +8,6 @@ else
|
|||
Coveralls.wear!('rails')
|
||||
end
|
||||
|
||||
# Required ENV variables that are normally set in .env are setup here for the test environment.
|
||||
require 'dotenv'
|
||||
Dotenv.overload File.join(File.dirname(__FILE__), "env.test")
|
||||
|
||||
require File.expand_path("../../config/environment", __FILE__)
|
||||
require 'rspec/rails'
|
||||
require 'rspec/autorun'
|
||||
|
|
Loading…
Add table
Reference in a new issue