Merge branch 'omniauth'
This commit is contained in:
commit
82277847b9
6
Gemfile
6
Gemfile
|
@ -40,6 +40,12 @@ gem 'sinatra', require: false
|
|||
|
||||
gem 'questiongenerator', git: 'https://github.com/justask/questiongenerator.git'
|
||||
|
||||
# OmniAuth and providers
|
||||
gem 'omniauth'
|
||||
gem 'omniauth-twitter'
|
||||
|
||||
gem 'foreman'
|
||||
|
||||
group :development do
|
||||
gem 'spring'
|
||||
end
|
||||
|
|
18
Gemfile.lock
18
Gemfile.lock
|
@ -72,6 +72,7 @@ GEM
|
|||
warden (~> 1.2.3)
|
||||
diff-lcs (1.2.5)
|
||||
docile (1.1.5)
|
||||
dotenv (1.0.2)
|
||||
equalizer (0.0.9)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.3)
|
||||
|
@ -89,8 +90,12 @@ GEM
|
|||
railties (>= 3.2, < 5.0)
|
||||
font-kit-rails (1.1.0)
|
||||
rails
|
||||
foreman (0.76.0)
|
||||
dotenv (~> 1.0.2)
|
||||
thor (~> 0.19.1)
|
||||
haml (4.0.6)
|
||||
tilt
|
||||
hashie (3.3.2)
|
||||
hike (1.2.3)
|
||||
hitimes (1.2.2)
|
||||
http (0.6.3)
|
||||
|
@ -129,6 +134,16 @@ GEM
|
|||
nokogiri (1.6.5)
|
||||
mini_portile (~> 0.6.0)
|
||||
nprogress-rails (0.1.6.3)
|
||||
oauth (0.4.7)
|
||||
omniauth (1.2.2)
|
||||
hashie (>= 1.2, < 4)
|
||||
rack (~> 1.0)
|
||||
omniauth-oauth (1.0.1)
|
||||
oauth
|
||||
omniauth (~> 1.0)
|
||||
omniauth-twitter (1.1.0)
|
||||
multi_json (~> 1.3)
|
||||
omniauth-oauth (~> 1.0)
|
||||
orm_adapter (0.5.0)
|
||||
pg (0.17.1)
|
||||
poltergeist (1.5.1)
|
||||
|
@ -295,6 +310,7 @@ DEPENDENCIES
|
|||
faker
|
||||
font-awesome-rails (~> 4.2.0.0)
|
||||
font-kit-rails
|
||||
foreman
|
||||
haml
|
||||
http_accept_language
|
||||
jbuilder (~> 2.2.4)
|
||||
|
@ -302,6 +318,8 @@ DEPENDENCIES
|
|||
jquery-turbolinks
|
||||
mysql2
|
||||
nprogress-rails
|
||||
omniauth
|
||||
omniauth-twitter
|
||||
pg
|
||||
poltergeist
|
||||
questiongenerator!
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
unicorn: bundle exec unicorn -E production -l unix:./tmp/sockets/justask.sock
|
||||
sidekiq: bundle exec sidekiq -C './config/sidekiq.yml'
|
|
@ -25,12 +25,18 @@ $(document).on "click", "button[name=ib-answer]", ->
|
|||
btn.button "loading"
|
||||
iid = btn[0].dataset.ibId
|
||||
$("textarea[name=ib-answer][data-id=#{iid}]").attr "readonly", "readonly"
|
||||
|
||||
shareTo = []
|
||||
($ "input[type=checkbox][name=ib-share][data-ib-id=#{iid}]:checked").each (i, share) ->
|
||||
shareTo.push share.dataset.service
|
||||
|
||||
$.ajax
|
||||
url: '/ajax/answer' # TODO: find a way to use rake routes instead of hardcoding them here
|
||||
url: '/ajax/answer'
|
||||
type: 'POST'
|
||||
data:
|
||||
id: iid
|
||||
answer: $("textarea[name=ib-answer][data-id=#{iid}]").val()
|
||||
share: JSON.stringify shareTo
|
||||
success: (data, status, jqxhr) ->
|
||||
if data.success
|
||||
$("div.inbox-box[data-id=#{iid}]").slideUp()
|
||||
|
|
|
@ -24,6 +24,7 @@ class Ajax::InboxController < ApplicationController
|
|||
def destroy
|
||||
params.require :id
|
||||
params.require :answer
|
||||
params.require :share
|
||||
|
||||
inbox = Inbox.find(params[:id])
|
||||
|
||||
|
@ -34,8 +35,10 @@ class Ajax::InboxController < ApplicationController
|
|||
return
|
||||
end
|
||||
|
||||
answer = nil
|
||||
|
||||
begin
|
||||
inbox.answer params[:answer], current_user
|
||||
answer = inbox.answer params[:answer], current_user
|
||||
rescue
|
||||
@status = :err
|
||||
@message = "An error occurred"
|
||||
|
@ -43,6 +46,14 @@ class Ajax::InboxController < ApplicationController
|
|||
return
|
||||
end
|
||||
|
||||
# sharing
|
||||
Thread.new do
|
||||
share_to = JSON.parse params[:share]
|
||||
current_user.services.each do |service|
|
||||
service.post(answer) if share_to.include? service.provider
|
||||
end
|
||||
end
|
||||
|
||||
@status = :okay
|
||||
@message = "Successfully answered question."
|
||||
@success = true
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
class ServicesController < ApplicationController
|
||||
|
||||
skip_before_action :verify_authenticity_token, :only => :create
|
||||
before_action :authenticate_user!
|
||||
|
||||
def index
|
||||
@services = current_user.services
|
||||
end
|
||||
|
||||
def create
|
||||
service = Service.initialize_from_omniauth( omniauth_hash )
|
||||
|
||||
if current_user.services << service
|
||||
flash[:success] = 'Successfully added service'
|
||||
else
|
||||
flash[:error] = 'Could not add service :('
|
||||
end
|
||||
|
||||
if origin
|
||||
redirect_to origin
|
||||
else
|
||||
redirect_to services_path
|
||||
end
|
||||
end
|
||||
|
||||
def failure
|
||||
Rails.logger.info "oauth error: #{params.inspect}"
|
||||
flash[:error] = 'An error occurred'
|
||||
redirect_to services_path
|
||||
end
|
||||
|
||||
def destroy
|
||||
@service = current_user.services.find(params[:id])
|
||||
@service.destroy
|
||||
flash[:success] = 'Successfully removed service'
|
||||
redirect_to services_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def origin
|
||||
request.env['omniauth.origin']
|
||||
end
|
||||
|
||||
def omniauth_hash
|
||||
request.env['omniauth.auth']
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module ServicesHelper
|
||||
end
|
|
@ -3,12 +3,13 @@ class Inbox < ActiveRecord::Base
|
|||
belongs_to :question
|
||||
|
||||
def answer(answer, user)
|
||||
Answer.create!(content: answer,
|
||||
user: user,
|
||||
question: self.question)
|
||||
answer = Answer.create!(content: answer,
|
||||
user: user,
|
||||
question: self.question)
|
||||
user.increment! :answered_count
|
||||
self.question.increment! :answer_count
|
||||
self.destroy
|
||||
answer
|
||||
end
|
||||
|
||||
def remove
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
class Service < ActiveRecord::Base
|
||||
attr_accessor :provider, :info
|
||||
|
||||
belongs_to :user
|
||||
validates_uniqueness_of :uid, scope: :type
|
||||
|
||||
class << self
|
||||
|
||||
def first_from_omniauth(auth_hash)
|
||||
@@auth = auth_hash
|
||||
where(type: service_type, uid: options[:uid]).first
|
||||
end
|
||||
|
||||
def initialize_from_omniauth(auth_hash)
|
||||
@@auth = auth_hash
|
||||
service_type.constantize.new(options)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def auth
|
||||
@@auth
|
||||
end
|
||||
|
||||
def service_type
|
||||
"Services::#{options[:provider].camelize}"
|
||||
end
|
||||
|
||||
def options
|
||||
{
|
||||
nickname: auth['info']['nickname'],
|
||||
access_token: auth['credentials']['token'],
|
||||
access_secret: auth['credentials']['secret'],
|
||||
uid: auth['uid'],
|
||||
provider: auth['provider'],
|
||||
info: auth['info']
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
class Services::Twitter < Service
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
def provider
|
||||
"twitter"
|
||||
end
|
||||
|
||||
def post(answer)
|
||||
Rails.logger.debug "posting to Twitter {'answer' => #{answer.id}, 'user' => #{self.user_id}}"
|
||||
post_tweet answer
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def client
|
||||
@client ||= Twitter::REST::Client.new(
|
||||
consumer_key: APP_CONFIG['sharing']['twitter']['consumer_key'],
|
||||
consumer_secret: APP_CONFIG['sharing']['twitter']['consumer_secret'],
|
||||
access_token: self.access_token,
|
||||
access_token_secret: self.access_secret
|
||||
)
|
||||
end
|
||||
|
||||
def post_tweet(answer)
|
||||
client.update prepare_tweet(answer)
|
||||
end
|
||||
|
||||
def prepare_tweet(answer)
|
||||
# TODO: improve this.
|
||||
question_content = answer.question.content
|
||||
answer_content = answer.content
|
||||
answer_url = show_user_answer_url(
|
||||
id: answer.id,
|
||||
username: answer.user.screen_name,
|
||||
host: APP_CONFIG['hostname'],
|
||||
protocol: (APP_CONFIG['https'] ? :https : :http)
|
||||
)
|
||||
"#{question_content[0..55]}#{'…' if question_content.length > 56}" \
|
||||
" — #{answer_content[0..55]}#{'…' if answer_content.length > 56} #{answer_url}"
|
||||
end
|
||||
end
|
|
@ -20,6 +20,7 @@ class User < ActiveRecord::Base
|
|||
has_many :friends, through: :active_relationships, source: :target
|
||||
has_many :followers, through: :passive_relationships, source: :source
|
||||
has_many :smiles
|
||||
has_many :services
|
||||
|
||||
SCREEN_NAME_REGEX = /\A[a-zA-Z0-9_]{1,16}\z/
|
||||
WEBSITE_REGEX = /https?:\/\/([A-Za-z.\-]+)\/?(?:.*)/i
|
||||
|
|
|
@ -22,4 +22,9 @@
|
|||
%button.btn.btn-success{name: 'ib-answer', data: { ib_id: i.id }}
|
||||
Answer
|
||||
%button.btn.btn-danger{name: 'ib-destroy', data: { ib_id: i.id }}
|
||||
Delete
|
||||
Delete
|
||||
- current_user.services.each do |service|
|
||||
%label
|
||||
%input{type: 'checkbox', name: 'ib-share', data: { ib_id: i.id, service: service.provider }}
|
||||
Post to
|
||||
= service.provider.capitalize
|
|
@ -0,0 +1,19 @@
|
|||
.container.j2-page
|
||||
= render 'user/settings_tabs'
|
||||
.col-md-9.col-xs-12.col-sm-9
|
||||
.panel.panel-default
|
||||
.panel-body
|
||||
- if @services.count > 0
|
||||
Sharing is enabled for the following services:
|
||||
%ul
|
||||
- @services.each do |service|
|
||||
%li
|
||||
%strong= service.provider.capitalize
|
||||
(#{service.nickname})
|
||||
= link_to 'Disconnect', service_path(service), data: { confirm: "Really disconnect service #{service.provider.capitalize}?" }, method: :delete
|
||||
- else
|
||||
You have not connected any services yet.
|
||||
|
||||
- APP_CONFIG['sharing'].each do |service, service_options|
|
||||
- if service_options['enabled'] and !@services.any? { |x| x.provider == service.to_s }
|
||||
%p=link_to "Connect to #{service.capitalize}", "/auth/#{service}"
|
|
@ -4,5 +4,6 @@
|
|||
%ul.nav.nav-pills.nav-stacked
|
||||
= nav_entry "Account", edit_user_registration_path
|
||||
= nav_entry "Profile", edit_user_profile_path
|
||||
= nav_entry "Sharing", services_path
|
||||
|
||||
.hidden-xs= render "shared/links"
|
|
@ -0,0 +1,9 @@
|
|||
class ShareWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: :share
|
||||
|
||||
def perform(answer_id)
|
||||
# fuck this… for now
|
||||
end
|
||||
end
|
|
@ -7,7 +7,7 @@ production:
|
|||
collation: utf8_general_ci
|
||||
reconnect: false
|
||||
database: justask_production
|
||||
pool: 10
|
||||
pool: 25
|
||||
username: justask
|
||||
password: "hack me"
|
||||
# host: localhost
|
||||
|
|
|
@ -5,7 +5,7 @@ production:
|
|||
adapter: postgresql
|
||||
encoding: unicode
|
||||
database: justask_production
|
||||
pool: 10
|
||||
pool: 25
|
||||
# username: justask
|
||||
# password:
|
||||
# host: localhost
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
Rails.application.config.middleware.use OmniAuth::Builder do
|
||||
if APP_CONFIG['sharing']['twitter']['enabled']
|
||||
provider :twitter, APP_CONFIG['sharing']['twitter']['consumer_key'], APP_CONFIG['sharing']['twitter']['consumer_secret']
|
||||
end
|
||||
end
|
|
@ -1,6 +1,9 @@
|
|||
# The site name, shown everywhere.
|
||||
site_name: "justask"
|
||||
|
||||
hostname: "justask.rrerr.net"
|
||||
https: true
|
||||
|
||||
# Name of the "Anonymous" user. (e.g. "Anonymous Coward", "Arno Nym", "Mr. X", ...)
|
||||
anonymous_name: "Anonymous"
|
||||
|
||||
|
|
|
@ -33,6 +33,16 @@ Rails.application.routes.draw do
|
|||
match '/settings/profile', to: 'user#edit', via: 'get', as: :edit_user_profile
|
||||
match '/settings/profile', to: 'user#update', via: 'patch', as: :update_user_profile
|
||||
|
||||
# resources :services, only: [:index, :destroy]
|
||||
match '/settings/services', to: 'services#index', via: 'get', as: :services
|
||||
match '/settings/services/:id', to: 'services#destroy', via: 'delete', as: :service
|
||||
controller :services do
|
||||
scope "/auth", as: "auth" do
|
||||
get ':provider/callback' => :create
|
||||
get :failure
|
||||
end
|
||||
end
|
||||
|
||||
namespace :ajax do
|
||||
match '/ask', to: 'question#create', via: :post, as: :ask
|
||||
match '/answer', to: 'inbox#destroy', via: :post, as: :answer
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
:concurrency: 5
|
||||
:pidfile: ./tmp/pids/sidekiq.pid
|
||||
staging:
|
||||
:concurrency: 10
|
||||
production:
|
||||
:concurrency: 25
|
||||
:queues:
|
||||
- share
|
|
@ -0,0 +1,14 @@
|
|||
class CreateServices < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :services do |t|
|
||||
t.string :type, null: false
|
||||
t.integer :user_id, null: false
|
||||
t.string :uid
|
||||
t.string :access_token
|
||||
t.string :access_secret
|
||||
t.string :nickname
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
13
db/schema.rb
13
db/schema.rb
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20141208111714) do
|
||||
ActiveRecord::Schema.define(version: 20141212193625) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -70,6 +70,17 @@ ActiveRecord::Schema.define(version: 20141208111714) do
|
|||
add_index "relationships", ["source_id"], name: "index_relationships_on_source_id", using: :btree
|
||||
add_index "relationships", ["target_id"], name: "index_relationships_on_target_id", using: :btree
|
||||
|
||||
create_table "services", force: true do |t|
|
||||
t.string "type", null: false
|
||||
t.integer "user_id", null: false
|
||||
t.string "uid"
|
||||
t.string "access_token"
|
||||
t.string "access_secret"
|
||||
t.string "nickname"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "smiles", force: true do |t|
|
||||
t.integer "user_id"
|
||||
t.integer "answer_id"
|
||||
|
|
Loading…
Reference in New Issue