Merge branch 'omniauth'

This commit is contained in:
nilsding 2014-12-13 15:40:50 +01:00
commit 82277847b9
23 changed files with 271 additions and 9 deletions

View File

@ -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

View File

@ -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!

2
Procfile Normal file
View File

@ -0,0 +1,2 @@
unicorn: bundle exec unicorn -E production -l unix:./tmp/sockets/justask.sock
sidekiq: bundle exec sidekiq -C './config/sidekiq.yml'

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,2 @@
module ServicesHelper
end

View File

@ -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

40
app/models/service.rb Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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}"

View File

@ -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"

View File

@ -0,0 +1,9 @@
class ShareWorker
include Sidekiq::Worker
sidekiq_options queue: :share
def perform(answer_id)
# fuck this… for now
end
end

View File

@ -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

View File

@ -5,7 +5,7 @@ production:
adapter: postgresql
encoding: unicode
database: justask_production
pool: 10
pool: 25
# username: justask
# password:
# host: localhost

View File

@ -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

View File

@ -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"

View File

@ -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

9
config/sidekiq.yml Normal file
View File

@ -0,0 +1,9 @@
---
:concurrency: 5
:pidfile: ./tmp/pids/sidekiq.pid
staging:
:concurrency: 10
production:
:concurrency: 25
:queues:
- share

View File

@ -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

View File

@ -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"