Permalink
Browse files

Merge branch 'master' into erb-emails

Conflicts:
	app/views/inviter/request_answer.text.erb
	config/locales/notifier/en.yml
  • Loading branch information...
2 parents 0dd3264 + 2568e78 commit 3eb535b8aab07f34f8f2c5359ef904029541267d @mpereira mpereira committed Oct 31, 2011
Showing with 440 additions and 178 deletions.
  1. +2 −0 Gemfile
  2. +10 −0 Gemfile.lock
  3. +32 −0 app/controllers/application_controller.rb
  4. +5 −2 app/controllers/questions_controller.rb
  5. +2 −1 app/controllers/search_results_controller.rb
  6. +13 −0 app/controllers/users_controller.rb
  7. +15 −0 app/controllers/vanity_controller.rb
  8. +7 −6 app/controllers/welcome_controller.rb
  9. +31 −4 app/helpers/application_helper.rb
  10. +1 −0 app/mailers/notifier.rb
  11. +2 −1 app/models/search_result.rb
  12. +10 −0 app/models/sent_survey_mail.rb
  13. +18 −12 app/models/suggestion_list.rb
  14. +6 −0 app/models/user.rb
  15. +17 −18 app/stylesheets/landing.sass
  16. +45 −1 app/stylesheets/themes/plain/_questions.sass
  17. +1 −2 app/views/inviter/request_answer.html.haml
  18. +1 −1 app/views/inviter/request_answer.text.erb
  19. +18 −34 app/views/layouts/_footer.html.haml
  20. +0 −20 app/views/layouts/_footer_landing.html.haml
  21. +1 −1 app/views/layouts/welcome.html.haml
  22. +38 −0 app/views/questions/_answer_with_form.html.haml
  23. +7 −0 app/views/questions/_bing_result.html.haml
  24. +19 −0 app/views/questions/_bing_results.html.haml
  25. +12 −0 app/views/questions/_question_responding_helper.html.haml
  26. +0 −24 app/views/questions/show.atom.builder
  27. +15 −38 app/views/questions/show.html.haml
  28. +4 −1 app/views/search_results/_search_result.html.haml
  29. +36 −0 app/views/users/_signup.html.haml
  30. +6 −3 app/views/welcome/landing.html.haml
  31. +1 −0 config/environments/development.rb
  32. +4 −0 config/initializers/rbing.rb
  33. +2 −0 config/locales/devise/devise.en.yml
  34. +1 −1 config/locales/layouts/en.yml
  35. +3 −3 config/locales/notifier/en.yml
  36. +5 −0 config/locales/questions/en.yml
  37. +5 −0 config/locales/questions/pt-BR.yml
  38. +3 −1 config/locales/users/en.yml
  39. +2 −0 config/routes.rb
  40. +4 −0 experiments/answer_with_form_position.rb
  41. +3 −0 experiments/metrics/new_search_result.rb
  42. +3 −0 experiments/metrics/question_posted.rb
  43. +3 −0 experiments/metrics/signup_method.rb
  44. +4 −0 experiments/question_responding_helpers.rb
  45. +4 −0 experiments/signup_method_helpers.rb
  46. +12 −0 lib/support/bing.rb
  47. +5 −3 lib/tasks/cron.rake
  48. +1 −0 lib/tasks/deploy.rake
  49. BIN public/images/favicons/bing.ico
  50. BIN public/images/favicons/google.png
  51. +1 −1 public/javascripts/modules/new_question.js
View
@@ -45,6 +45,7 @@ gem 'postmark', '~>0.9.0'
gem 'postmark-rails', '~>0.4.0'
gem 'rails', :git => 'git://github.com/umamao/rails.git', :branch => '3-0-7'
gem 'rake', '0.8.7'
+gem 'rbing', '1.1.0'
gem 'rdiscount', '~>1.6.3.1'
gem 'remotipart'
gem 'responders'
@@ -57,6 +58,7 @@ gem 'twitter', '~> 1.1.0'
gem 'twitter-text', '~>1.1.1'
gem 'twitter_oauth', '~>0.3.6'
gem 'uuidtools', '~>2.1.1'
+gem 'vanity', '1.6.1' # Version 1.7.1 is screwed up.
gem 'warden', '~>0.10.7'
gem 'whatlanguage', '~>1.0.0'
View
@@ -304,7 +304,12 @@ GEM
rack-test (0.5.7)
rack (>= 1.0)
rake (0.8.7)
+ rbing (1.1.0)
+ httparty (>= 0.4.0)
rdiscount (1.6.3.2)
+ redis (2.2.2)
+ redis-namespace (1.0.3)
+ redis (< 3.0.0)
remotipart (0.3.4)
responders (0.6.2)
rest-client (1.6.1)
@@ -366,6 +371,9 @@ GEM
oauth (>= 0.3.6)
tzinfo (0.3.27)
uuidtools (2.1.2)
+ vanity (1.6.1)
+ redis (~> 2.0)
+ redis-namespace (~> 1.0.0)
warden (0.10.7)
rack (>= 1.0.0)
whatlanguage (1.0.0)
@@ -424,6 +432,7 @@ DEPENDENCIES
postmark-rails (~> 0.4.0)
rails!
rake (= 0.8.7)
+ rbing (= 1.1.0)
rdiscount (~> 1.6.3.1)
remotipart
responders
@@ -440,6 +449,7 @@ DEPENDENCIES
twitter-text (~> 1.1.1)
twitter_oauth (~> 0.3.6)
uuidtools (~> 2.1.1)
+ vanity (= 1.6.1)
warden (~> 0.10.7)
whatlanguage (~> 1.0.0)
yaml_waml (= 0.3.0)
@@ -1,6 +1,7 @@
# -*- coding: undecided -*-
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
+require 'singleton'
class ApplicationController < ActionController::Base
include AuthenticatedSystem
@@ -18,6 +19,27 @@ class ApplicationController < ActionController::Base
before_filter :track_user
layout :set_layout
+ # Vanity expects an object that responds to #id.
+ class UntrackedUser
+ include Singleton
+
+ def id
+ '03571a60f217cf68f795875d108a73fa21e0c2bcce7f'
+ end
+ end
+
+ # This is a turnaround for the shortcomings of the vanity gem. This code will
+ # create at most one participant and one conversion in a random group for all
+ # our untracked users. This is necessary because `use_vanity` is a class-level
+ # macro, and can't be conditionally evaluated per-request.
+ use_vanity :_vanity_identity
+
+ def _vanity_identity
+ if current_user
+ current_user.tracked? ? current_user : UntrackedUser.instance
+ end
+ end
+
DEVELOPMENT_DOMAIN = 'localhost.lan'
TEST_DOMAIN = '127.0.0.1'
@@ -78,6 +100,16 @@ def track_event(event, properties = {})
end
end
+ def track_bingo(event)
+ with_trackable_users { track!(event) }
+ end
+
+ def with_trackable_users
+ unless current_user && !current_user.tracked?
+ yield
+ end
+ end
+
def after_sign_in_path_for(resource)
track_event(:sign_in)
if resource.is_a?(User) && !resource.has_been_through_wizard?
@@ -167,18 +167,20 @@ def show
end
set_page_title(@question.title)
- add_feeds_url(url_for(:format => "atom"), t("feeds.question"))
@follow_up_question = {
:parent_question_id => @question.id,
:body => render_to_string(:file => 'questions/_new_follow_up_question.text.erb')
}
@follow_up_questions = Question.children_of(@question)
+ if ab_test(:question_responding_helpers) == :bing_results
+ @bing_response = Support::Bing.search(@question.title)
+ end
+
respond_to do |format|
format.html
format.json { render :json => @question.to_json(:except => %w[_keywords slug watchers]) }
- format.atom
end
end
@@ -229,6 +231,7 @@ def create
track_event(:asked_question, :body_present => @question.body.present?,
:topics_count => @question.topics.size)
+ track_bingo(:question_posted)
format.html do
flash[:notice] = t(:flash_notice, :scope => "questions.create")
@@ -23,8 +23,9 @@ def create
track_event(:commented, :commentable => @search_result.class.name)
end
end
- track_event(:added_link,
+ track_event(:added_link,
:latency => (@search_result.created_at - @question.created_at).to_i / 60)
+ track_bingo(:new_search_result)
notice_message = t(:flash_notice, :scope => "search_results.create")
format.html do
flash[:notice] = notice_message
@@ -58,8 +58,20 @@ def new
if params[:ref]
unless @url_invitation = UrlInvitation.find_by_ref(params[:ref])
+ flash[:notice] = t(:not_found, :scope => [:url_invitations, :show])
redirect_to(root_path(:focus => 'signup')) and return
end
+
+ # A/B test for ref link invitation
+ if ab_test(:signup_method_helpers) == :users_new
+ @user = User.new
+ @user.timezone = AppConfig.default_timezone
+ render 'new', :layout => 'welcome'
+ else
+ redirect_to(root_path(:url_invitation => @url_invitation.ref))
+ end
+ return
+
end
@user = User.new
@@ -155,6 +167,7 @@ def create
if @url_invitation = UrlInvitation.find_by_ref(params[:ref])
tracking_properties[:invited_by] = @url_invitation.inviter.id
@url_invitation.add_invitee(@user)
+ track_bingo(:signup_method)
end
if invitation && invitation.topics
@@ -0,0 +1,15 @@
+class VanityController < ApplicationController
+ include Vanity::Rails::Dashboard
+
+ before_filter :login_required
+ before_filter :only_allow_admins
+
+private
+
+ def only_allow_admins
+ unless current_user.admin?
+ flash[:error] = t('global.permission_denied')
+ redirect_to root_url
+ end
+ end
+end
@@ -20,12 +20,13 @@ def landing
@affiliation = Affiliation.new
- @signin_index, @signup_index =
- if params[:focus] == "signup"
- [3, 1]
- else
- [1, 5]
- end
+ if @ref = params[:url_invitation]
+ @user = User.new
+ @user.timezone = AppConfig.default_timezone
+ @signin_index, @signup_index = [6, 1]
+ else
+ @signin_index, @signup_index = [1, 5]
+ end
render 'landing', :layout => 'welcome'
end
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Methods added to this helper will be available to all templates in the application.
+require 'cgi'
require 'uri'
module ApplicationHelper
@@ -317,20 +318,25 @@ def waiting_tag
:class => "waiting")
end
- def shorten_url(url)
+ def shorten_url(url, options = {})
+ # the default length is 63 so both head and tail will have 30
+ # characters, plus the 3-character '...' divider
+ options = {:length => 63}.merge(options)
+ half_length = (options[:length] - 3) / 2
uri = URI.parse(url)
port = lambda { |uri| [80, 443].include?(uri.port) ? '' : ":#{uri.port}" }
relevant_path = lambda do |uri|
request_uri =
uri.to_s[((uri.scheme.to_s + uri.host.to_s).to_s.length + 3)..-1].to_s
- head = truncate(request_uri[0..(request_uri.length / 2.0).ceil - 1], :length => 30)
+ head = truncate(request_uri[0..(request_uri.length / 2.0).ceil - 1],
+ :length => half_length)
tail = truncate(request_uri.reverse[0..(request_uri.length / 2) - 1],
- :length => 30).reverse
+ :length => half_length).reverse
(head + tail).sub('......', '...').squeeze('/')
end
"#{uri.scheme}://#{uri.host}#{port.call(uri)}#{relevant_path.call(uri)}"
rescue URI::InvalidURIError
- truncate(url, :length => 100)
+ truncate(url, :length => options[:length])
end
def markdown2txt(string)
@@ -352,5 +358,26 @@ def find_link_to_method(object_class)
find_link_to_method(object_super)
end
end
+
+ def link_to_search(engine, query_string, options = {})
+ url = case engine
+ when :google then 'http://www.google.com/search?q='
+ when :bing then 'http://bing.com/search?q='
+ end << CGI.escape(query_string)
+ default_options = { :target => :_blank }
+ link_to(options.delete(:content) || query_string,
+ url,
+ default_options.merge(options))
+ end
+
+ def link_to_google_search(query_string, options = {})
+ default_options = { :id => :google_search_link }
+ link_to_search(:google, query_string, default_options.merge(options))
+ end
+
+ def link_to_bing_search(query_string, options = {})
+ default_options = { :id => :bing_search_link }
+ link_to_search(:bing, query_string, default_options.merge(options))
+ end
end
View
@@ -166,6 +166,7 @@ def wait(waiting_user)
def survey(user)
@user = user
+ SentSurveyMail.create(:user_id => user.id)
mail(:to => user.email,
:subject => t(:subject, :scope => [:notifier, :survey]))
end
@@ -126,7 +126,8 @@ def response_body_present?
end
def response_body_text?
- @response.content_type.split('/').first == 'text'
+ @response.content_type.respond_to?(:split) &&
+ @response.content_type.split('/').first == 'text'
end
def response_body
@@ -0,0 +1,10 @@
+class SentSurveyMail
+ include MongoMapper::Document
+
+ key :user_id, String
+ belongs_to :user
+
+ timestamps!
+
+ validates_presence_of :user
+end
@@ -158,9 +158,9 @@ def suggest_from_group_invitation
# Suggest topics listed in shapado.yml
def suggest_first_topics
- return if AppConfig.topic_suggestion.blank?
- AppConfig.topic_suggestion.each do |id_or_slug|
- t = Topic.find_by_slug_or_id(id_or_slug)
+ topics = configured_suggestions
+ return if topics.blank?
+ topics.each do |t|
self.suggest(t, "popular") if t.present?
end
end
@@ -196,15 +196,12 @@ def refresh_topic_suggestions
end
count = Hash.new(0) # Scores for suggestions
- UserTopicInfo.find_each(:user_id => user.id,
- :followed_at.ne => nil) do |user_topic|
- topic = user_topic.topic
- topic.related_topics.each do |related_topic|
- next if self.user.following?(related_topic) ||
- self.uninteresting_topic_ids.include?(related_topic.id) ||
- kept_suggestions.any?{|suggestion| suggestion.entry == related_topic}
- count[related_topic.id] += 1
- end
+ topics = configured_suggestions
+ topics.each do |topic|
+ next if self.user.following?(topic) ||
+ self.uninteresting_topic_ids.include?(topic.id) ||
+ kept_suggestions.any?{|suggestion| suggestion.entry == topic}
+ count[topic.id] += 1
end
self.topic_suggestions = kept_suggestions
@@ -217,4 +214,13 @@ def refresh_topic_suggestions
end
end
+protected
+ def configured_suggestions
+ ids = AppConfig.topic_suggestion
+ if ids.blank?
+ []
+ else
+ ids.map{ |id| Topic.find_by_slug_or_id(id) }.select{ |t| t.present?}
+ end
+ end
end
View
@@ -1012,6 +1012,12 @@ def associate_with_waiting_users
end
end
+ def tracked?
+ untracked_emails = AppConfig.untrackable_user_emails
+ untracked_emails.respond_to?(:include?) ? !untracked_emails.include?(email) :
+ true
+ end
+
protected
def password_required?
(encrypted_password.blank? || !password.blank?)
Oops, something went wrong.

0 comments on commit 3eb535b

Please sign in to comment.