Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'dev' into fixes-for-search-as-new-question

Conflicts:
	app/controllers/searches_controller.rb
	app/stylesheets/themes/plain/_base.sass
  • Loading branch information...
commit 51b8ec57d29788b6c7f0193f76d30f29f469a12e 2 parents e3f8c75 + e1a5292
Murilo Pereira mpereira authored
Showing with 945 additions and 308 deletions.
  1. +2 −1  Gemfile
  2. +11 −4 Gemfile.lock
  3. +4 −0 app/controllers/answers_controller.rb
  4. +8 −2 app/controllers/application_controller.rb
  5. +107 −0 app/controllers/auth_callback_controller.rb
  6. +17 −1 app/controllers/comments_controller.rb
  7. +8 −6 app/controllers/questions_controller.rb
  8. +1 −4 app/controllers/search_results_controller.rb
  9. +8 −1 app/controllers/searches_controller.rb
  10. +0 −40 app/controllers/settings/external_accounts_controller.rb
  11. +1 −0  app/controllers/signup_wizard_controller.rb
  12. +13 −2 app/controllers/topics_controller.rb
  13. +1 −0  app/controllers/url_invitations_controller.rb
  14. +2 −1  app/controllers/users_controller.rb
  15. +2 −0  app/controllers/votes_controller.rb
  16. +30 −16 app/models/answer.rb
  17. +0 −2  app/models/comment.rb
  18. +1 −3 app/models/news_item.rb
  19. +0 −1  app/models/question.rb
  20. +5 −9 app/models/search_result.rb
  21. +21 −1 app/models/user.rb
  22. +2 −5 app/stylesheets/_base.sass
  23. +8 −5 app/stylesheets/application.sass
  24. +1 −1  app/stylesheets/inline_edition.sass
  25. +25 −4 app/stylesheets/landing.sass
  26. +33 −0 app/stylesheets/partials/_facebook.scss
  27. +6 −0 app/stylesheets/themes/plain/_base.sass
  28. +26 −0 app/stylesheets/themes/plain/_questions.sass
  29. +2 −1  app/stylesheets/themes/plain/_sidebar.sass
  30. +3 −0  app/stylesheets/themes/plain/_users.sass
  31. +4 −0 app/views/answers/show.html.haml
  32. +15 −0 app/views/auth_callback/signup_with_provider.html.haml
  33. +0 −14 app/views/comments/_comment.html.haml
  34. +11 −2 app/views/comments/_count.html.haml
  35. +8 −5 app/views/comments/_form.html.haml
  36. +21 −0 app/views/comments/_inline_form.html.haml
  37. +1 −0  app/views/layouts/application.html.haml
  38. +1 −0  app/views/layouts/welcome.html.haml
  39. +1 −1  app/views/questions/_answer.html.haml
  40. +43 −27 app/views/questions/_answer_with_form.html.haml
  41. +5 −0 app/views/questions/_form.html.haml
  42. +1 −5 app/views/questions/_new_follow_up_question.text.erb
  43. +1 −1  app/views/questions/edit.html.haml
  44. +12 −14 app/views/questions/show.html.haml
  45. +22 −6 app/views/search_results/_form.html.haml
  46. +7 −5 app/views/search_results/_search_result.html.haml
  47. +5 −4 app/views/searches/search_as_new_question.html.haml
  48. +4 −12 app/views/shared/_analytics.haml
  49. +23 −2 app/views/shared/_comments.html.haml
  50. +3 −6 app/views/shared/_other_actions.html.haml
  51. +4 −0 app/views/signup_wizard/wizard.html.haml
  52. +2 −6 app/views/topics/_common.html.haml
  53. +4 −0 app/views/topics/show.html.haml
  54. +3 −0  app/views/users/_form_signup.html.haml
  55. +1 −1  app/views/users/_news_update.html.haml
  56. +2 −1  app/views/users/_profile_common.html.haml
  57. +6 −3 app/views/users/_signup.html.haml
  58. +4 −4 app/views/users/_user_bar.html.haml
  59. +2 −2 app/views/welcome/_news_item.html.haml
  60. +9 −0 app/views/welcome/landing.html.haml
  61. +4 −0 config/initializers/04_airbrake.rb
  62. +0 −4 config/initializers/04_hoptoad.rb
  63. +2 −2 config/initializers/delayed_job_config.rb
  64. +2 −1  config/locales/answers/en.yml
  65. +2 −1  config/locales/answers/pt-BR.yml
  66. +4 −0 config/locales/auth_callback/en.yml
  67. +4 −0 config/locales/auth_callback/pt-BR.yml
  68. +5 −1 config/locales/comments/en.yml
  69. +4 −0 config/locales/comments/pt-BR.yml
  70. +2 −2 config/locales/devise/devise.en.yml
  71. +1 −1  config/locales/global/en.yml
  72. +4 −4 config/locales/layouts/en.yml
  73. +1 −1  config/locales/questions/en.yml
  74. +2 −0  config/locales/search_results/en.yml
  75. +2 −0  config/locales/search_results/pt-BR.yml
  76. +6 −6 config/locales/sessions/en.yml
  77. +1 −1  config/locales/shared/en.yml
  78. +1 −1  config/locales/url_invitations/en.yml
  79. +1 −1  config/locales/url_invitations/pt-BR.yml
  80. +1 −0  config/locales/users/en.yml
  81. +3 −0  config/locales/users/pt-BR.yml
  82. +1 −0  config/locales/welcome/en.yml
  83. +1 −0  config/locales/welcome/pt-BR.yml
  84. +5 −3 config/routes.rb
  85. +0 −5 experiments/answer_with_form_position.rb
  86. +4 −0 experiments/inline_comment_helpers.rb
  87. +5 −0 experiments/link_only_answer_form.rb
  88. +3 −0  experiments/metrics/clicked_search_result.rb
  89. +3 −0  experiments/metrics/commented.rb
  90. +0 −3  experiments/metrics/search_results_news_items.rb
  91. +3 −0  experiments/metrics/signed_up_action.rb
  92. +0 −3  experiments/metrics/signup_method.rb
  93. +3 −0  experiments/metrics/used_today.rb
  94. +3 −0  experiments/metrics/voted.rb
  95. +1 −1  experiments/new_question_as_search.rb
  96. +1 −1  experiments/news_items_search_results_helpers.rb
  97. +1 −0  experiments/question_responding_helpers.rb
  98. +6 −0 experiments/sign_in_with_facebook.rb
  99. +0 −5 experiments/signup_method_helpers.rb
  100. +27 −0 lib/support/embedly.rb
  101. +6 −4 lib/support/response_fetcher.rb
  102. +1 −17 lib/tasks/data_migrations.rake
  103. +12 −1 lib/tasks/deploy.rake
  104. +20 −0 lib/tasks/news_items.rake
  105. +42 −0 lib/tasks/search_results.rake
  106. +109 −0 lib/tasks/topics.rake
  107. +3 −1 lib/umamao.rb
  108. +5 −2 public/javascripts/i18n/en.js
  109. +4 −1 public/javascripts/i18n/pt-BR.js
  110. +3 −3 public/javascripts/modules/inline_edition.js
  111. +48 −1 public/javascripts/modules/show_question.js
3  Gemfile
View
@@ -14,6 +14,7 @@ group :development do
gem 'yaml_waml', '0.3.0'
end
+gem 'airbrake', '3.0.5'
gem 'bitly'
gem 'bson_ext', :require => 'bson'
gem 'carrierwave' # file upload manager
@@ -30,11 +31,11 @@ gem 'faker'
gem 'fog' # connect to storage services such as cloudfiles
gem 'goalie'
gem 'haml', '~> 3.1.1'
-gem 'hoptoad_notifier'
gem 'jammit', '~>0.6.0'
gem 'jnunemaker-validatable', :require => 'validatable', :git => "git://github.com/umamao/validatable.git"
gem 'jquery-rails'
gem 'koala', '~> 0.10.0'
+gem 'language_detector', '0.1.2', :git => 'https://github.com/feedbackmine/language_detector.git'
gem 'mechanize', :require => false
gem 'mongo'
gem 'mongo_mapper', :git => 'git://github.com/umamao/mongomapper.git'
15 Gemfile.lock
View
@@ -97,6 +97,12 @@ GIT
jnunemaker-validatable (1.8.4)
activesupport (>= 2.3.4)
+GIT
+ remote: https://github.com/feedbackmine/language_detector.git
+ revision: 89102790194150b3a8110ce691f9989b8ce70f8d
+ specs:
+ language_detector (0.1.2)
+
GEM
remote: http://gemcutter.org/
specs:
@@ -108,6 +114,9 @@ GEM
ZenTest (4.5.0)
abstract (1.0.0)
addressable (2.2.4)
+ airbrake (3.0.5)
+ activesupport
+ builder
arel (2.0.9)
autotest-rails (4.1.0)
ZenTest
@@ -209,9 +218,6 @@ GEM
mime-types (~> 1.15)
haml (3.1.1)
hashie (1.0.0)
- hoptoad_notifier (2.4.9)
- activesupport
- builder
httparty (0.7.4)
crack (= 0.1.8)
i18n (0.5.0)
@@ -388,6 +394,7 @@ PLATFORMS
DEPENDENCIES
RedCloth (~> 4.1.1)
+ airbrake (= 3.0.5)
autotest-rails
bitly
bson_ext
@@ -416,11 +423,11 @@ DEPENDENCIES
goalie
grit
haml (~> 3.1.1)
- hoptoad_notifier
jammit (~> 0.6.0)
jnunemaker-validatable!
jquery-rails
koala (~> 0.10.0)
+ language_detector (= 0.1.2)!
launchy
mechanize
mongo
4 app/controllers/answers_controller.rb
View
@@ -143,6 +143,10 @@ def create
def edit
@question = @answer.question
+ unless current_user.can_modify?(@answer)
+ redirect_to [@question, @answer]
+ return
+ end
end
def update
10 app/controllers/application_controller.rb
View
@@ -40,9 +40,14 @@ def _vanity_identity
# This identifier recognizes untracked users' identities via cookies even if
# they're not logged in. It's used in our vanity experiment files.
- def identify_vanity
- if identity = _vanity_identity
+ #
+ # Options:
+ # exclude_guests: don't track non-logged visitors _at all_.
+ def identify_vanity(options = {})
+ if (identity = _vanity_identity) && !options[:preserve_identity]
identity.id
+ elsif options[:exclude_guests]
+ Umamao::UntrackedUser.instance.id
else
set_vanity_cookie(SecureRandom.hex(16)) unless cookies[:vanity_id]
cookies[:vanity_id]
@@ -189,6 +194,7 @@ def track_user
handle_event_tracking = lambda do |event|
Rails.cache.write(key, Date.today.to_s)
track_event(:used_today)
+ track_bingo(:used_today)
end
if last_day_used_at = Rails.cache.read(key)
if last_day_used_at != Date.today.to_s
107 app/controllers/auth_callback_controller.rb
View
@@ -0,0 +1,107 @@
+class AuthCallbackController < ApplicationController
+ respond_to :html
+ before_filter :login_required, :only => :create_external_account
+
+ def callback
+ auth_hash = request.env['omniauth.auth']
+ if not user_signed_in? && auth_hash['provider'] == 'facebook'
+ signup_with_provider
+ else
+ create_external_account
+ end
+ end
+
+ def failure
+ respond_to do |format|
+ format.html { redirect_to session["omniauth_return_url"] }
+ end
+ end
+
+ def create_external_account
+ auth_hash = request.env['omniauth.auth']
+
+ if session["umamao.topic_id"].present? &&
+ auth_hash.present? && auth_hash["provider"] == "twitter"
+ # Associate this Twitter account with a Topic.
+ topic = Topic.find_by_slug_or_id(session.delete("umamao.topic_id"))
+ raise Goalie::NotFound if topic.blank?
+ TopicExternalAccount.create(auth_hash.merge(:topic => topic))
+ redirect_to topic_path(topic)
+ return
+ end
+
+ if request.env['omniauth.error.type'].present?
+ respond_to do |format|
+ flash[:error] = I18n.t("external_accounts.connection_error")
+ format.html { redirect_to session["omniauth_return_url"] }
+ end
+ return
+ end
+
+ unless @external_account = UserExternalAccount.find_from_hash(auth_hash)
+ @external_account =
+ UserExternalAccount.create(auth_hash.merge(:user => current_user))
+ end
+
+ if @external_account && @external_account.user.id == current_user.id
+ respond_with(@external_account, :status => :created) do |format|
+ track_event("connected_#{@external_account.provider}".to_sym)
+ flash[:connected_to] = @external_account.provider
+ format.html { redirect_to session["omniauth_return_url"] }
+ end
+ else
+ flash[:error] = I18n.t("external_accounts.connection_error")
+ redirect_to session["omniauth_return_url"]
+ end
+ end
+
+ def signup_with_provider
+ auth_hash = request.env['omniauth.auth']
+
+ user_info = auth_hash["user_info"]
+ email = user_info["email"]
+ user = User.find_by_email(email)
+
+ if user
+ if user.external_accounts.first(:provider => auth_hash['provider'])
+ sign_in user
+ redirect_to root_path
+ else
+ session["omniauth-hash"] = auth_hash
+ @email = auth_hash["user_info"]["email"]
+ @user = User.new
+ render :signup_with_provider
+ end
+ else
+ if session['sign_up_allowed']
+ if user = User.create_with_provider(auth_hash)
+ track_bingo(:signed_up_action)
+
+ sign_in user
+ redirect_to wizard_path("follow")
+ else
+ head(:unprocessable_entity)
+ end
+ else
+ flash[:error] = I18n.t("welcome.landing.invitation_only")
+ redirect_to root_path
+ end
+ end
+ end
+
+ def sign_in_and_associate_provider
+ auth_hash = session['omniauth-hash']
+ user = User.find_by_email(auth_hash["user_info"]["email"])
+ if user.valid_password?(params[:user][:password])
+ session.delete('omniauth-hash')
+ sign_in user
+ UserExternalAccount.create(auth_hash.merge(:user => user))
+ redirect_to root_url
+ else
+ flash[:error] = I18n.t('auth_callback.invalid_password')
+ @email = auth_hash["user_info"]["email"]
+ @user = User.new
+ render :signup_with_provider
+ end
+ end
+end
18 app/controllers/comments_controller.rb
View
@@ -4,6 +4,8 @@ class CommentsController < ApplicationController
before_filter :check_permissions, :except => [:create]
def create
+ track_bingo(:commented)
+
@comment = Comment.new
@comment.body = params[:body]
@comment.commentable = scope
@@ -42,7 +44,9 @@ def create
}),
:count => render_to_string(:partial => "comments/count",
:locals => {
- :commentable => @comment.commentable
+ :commentable => @comment.commentable,
+ :inline => @comment.commentable.is_a?(SearchResult) &&
+ ab_test(:inline_comment_helpers) == :inline
})
}.to_json)
end
@@ -64,6 +68,18 @@ def create
def edit
@comment = current_scope.find(params[:id])
+ unless current_user.can_modify?(@comment)
+ format.html do
+ redirect_to [@comment.commentable, @comment]
+ end
+ format.js do
+ render :json => {:status => :error,
+ :message => t("global.permission_denied")
+ }
+ end
+ return
+ end
+
raise Goalie::NotFound unless @comment
respond_to do |format|
14 app/controllers/questions_controller.rb
View
@@ -149,10 +149,6 @@ def show
return
end
- if params[:r].present?
- track_bingo(:search_results_news_items)
- end
-
if params[:group_invitation]
session[:group_invitation] = params[:group_invitation]
end
@@ -190,8 +186,9 @@ def show
# GET /questions/new.xml
def new
if ab_test(:new_question_as_search) == :new_search_scheme
- if params[:question] && params[:question][:title].present?
- redirect_to search_path(:q => params[:question][:title])
+ if params[:question].present?
+ redirect_to search_path(:q => params[:question].delete(:title),
+ :question => params[:question])
else
redirect_to root_path
end
@@ -210,6 +207,11 @@ def new
# GET /questions/1/edit
def edit
+ @question = Question.find_by_slug_or_id(params[:id])
+ unless current_user.can_modify?(@question)
+ redirect_to @question
+ return
+ end
end
# POST /questions
5 app/controllers/search_results_controller.rb
View
@@ -2,14 +2,11 @@ class SearchResultsController < ApplicationController
before_filter :login_required, :only => [:create, :destroy, :flag]
def show
- if params[:r].present?
- track_bingo(:search_results_news_items)
- end
-
@search_result = SearchResult.find_by_id(params[:search_result_id])
track_event(:clicked_search_result,
:search_result_id => @search_result.id,
:url => @search_result.url)
+ track_bingo(:clicked_search_result)
redirect_to(@search_result.url)
end
9 app/controllers/searches_controller.rb
View
@@ -1,7 +1,7 @@
class SearchesController < ApplicationController
def index
- if params[:q].blank?
+ if params[:q].blank? && params[:question].blank?
redirect_to root_path
return
end
@@ -10,6 +10,13 @@ def index
if ab_test(:new_question_as_search) == :new_search_scheme
@question = Question.new(params[:q] ? { :title => params[:q] } : {})
+ # FIXME: rearrange logic.
+ if params[:question].present?
+ @question.safe_update(%w[body parent_question_id], params[:question])
+ end
+ if @question.parent_question_id
+ @question.topics = Question.find_by_id(@question.parent_question_id).topics
+ end
@bing_results = Support::Bing.search(@question.title, :max_results => 10)
end
40 app/controllers/settings/external_accounts_controller.rb
View
@@ -7,45 +7,6 @@ class Settings::ExternalAccountsController < ApplicationController
def index
end
- def create
- auth_hash = request.env['omniauth.auth']
-
- if session["umamao.topic_id"].present? &&
- auth_hash.present? && auth_hash["provider"] == "twitter"
- # Associate this Twitter account with a Topic.
- topic = Topic.find_by_slug_or_id(session.delete("umamao.topic_id"))
- raise Goalie::NotFound if topic.blank?
- TopicExternalAccount.create(auth_hash.merge(:topic => topic))
- redirect_to topic_path(topic)
- return
- end
-
- if request.env['omniauth.error.type'].present?
- respond_to do |format|
- flash[:error] = I18n.t("external_accounts.connection_error")
- format.html { redirect_to session["omniauth_return_url"] }
- end
- return
- end
-
- unless @external_account = UserExternalAccount.find_from_hash(auth_hash)
- @external_account =
- UserExternalAccount.create(auth_hash.merge(:user => current_user))
- end
-
- respond_with(@external_account, :status => :created) do |format|
- track_event("connected_#{@external_account.provider}".to_sym)
- flash[:connected_to] = @external_account.provider
- format.html { redirect_to session["omniauth_return_url"] }
- end
- end
-
- def failure
- respond_to do |format|
- format.html { redirect_to session["omniauth_return_url"] }
- end
- end
-
def destroy
@external_account = ExternalAccount.find(params[:id])
@external_account.destroy
@@ -53,5 +14,4 @@ def destroy
format.html { redirect_to session["omniauth_return_url"] }
end
end
-
end
1  app/controllers/signup_wizard_controller.rb
View
@@ -8,6 +8,7 @@ def wizard
current_user.save!
redirect_to root_path
else
+ @current_step = params[:current_step]
render :layout => "welcome"
end
end
15 app/controllers/topics_controller.rb
View
@@ -54,13 +54,20 @@ def show
@topic.indirect_question_lists.paginate(:per_page => 6,
:order => :created_at.desc)
- @news_items = NewsItem.paginate(
+ ni_sr = ab_test(:news_items_search_results_helpers)
+ if ni_sr == :answer
+ options = {:news_update_entry_type => {:$ne => "SearchResult"}}
+ else
+ options = {:news_update_entry_type => {:$ne => "Answer"}}
+ end
+
+ @news_items = NewsItem.paginate({
:recipient_id => @topic.id,
:recipient_type => "Topic",
:per_page => 30,
:page => params[:page] || 1,
:order => :created_at.desc,
- :visible => true)
+ :visible => true}.merge(options))
@questions = Question.paginate(
:topic_ids => @topic.id, :banned => false,
@@ -72,6 +79,10 @@ def show
def edit
@topic = Topic.find_by_slug_or_id(params[:id])
+ unless current_user.admin?
+ redirect_to @topic
+ return
+ end
raise Goalie::NotFound unless @topic
1  app/controllers/url_invitations_controller.rb
View
@@ -12,6 +12,7 @@ def show
@user = User.new
@user.timezone = AppConfig.default_timezone
@signin_index, @signup_index = [6, 1]
+ session['sign_up_allowed'] = true
render 'welcome/landing', :layout => 'welcome'
else
flash[:notice] =
3  app/controllers/users_controller.rb
View
@@ -78,6 +78,7 @@ def new
if @invitation || @group_invitation
@user.timezone = AppConfig.default_timezone
@signin_index, @signup_index = [6, 1]
+ session['sign_up_allowed'] = true
render 'welcome/landing', :layout => 'welcome'
else
return redirect_to(root_path(:focus => "signup"))
@@ -121,7 +122,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)
+ track_bingo(:signed_up_action)
end
if invitation && invitation.topics
2  app/controllers/votes_controller.rb
View
@@ -8,6 +8,8 @@ def index
# TODO: refactor
def create
+ track_bingo(:voted)
+
vote = Vote.new(:voteable_type => params[:voteable_type],
:voteable_id => params[:voteable_id],
:user => current_user)
46 app/models/answer.rb
View
@@ -42,10 +42,9 @@ class Answer < Comment
versionable_keys :body
filterable_keys :body
- validate :disallow_spam
-
after_create :create_news_update, :new_answer_notification,
:increment_user_topic_answers_count
+ after_update :update_search_result
before_destroy :unhide_news_update, :decrement_user_topic_answers_count
ensure_index([[:user_id, 1], [:question_id, 1]])
@@ -177,14 +176,9 @@ def create_news_update
NewsUpdate.create(:author => self.user, :entry => self,
:created_at => self.created_at, :action => 'created')
- hide_news_update
end
handle_asynchronously :create_news_update
- def hide_news_update
- self.question.news_update.hide!
- end
-
def unhide_news_update
if self.question.news_update && self.question.answers_count == 1
# if this is the last question, reshow question's news_update
@@ -243,6 +237,30 @@ def decrement_user_topic_answers_count
end
def save_with_search_result
+ search_result = new_search_result
+ if save && search_result.save
+ true
+ else
+ search_result.errors.full_messages.each do |error|
+ errors.add_to_base(error)
+ end
+ search_result.destroy
+ false
+ end
+ end
+
+ def update_search_result
+ if !self.search_result
+ create_search_result
+ return
+ end
+
+ self.search_result.set({:title => title(:truncated => true),
+ :summary => summary})
+ end
+
+protected
+ def new_search_result
search_result =
SearchResult.new(:title => title(:truncated => true),
:summary => summary,
@@ -255,14 +273,10 @@ def save_with_search_result
url_helpers.
question_answer_url(question, id))
self.search_result_id = search_result.id
- if save && search_result.save
- true
- else
- search_result.errors.full_messages.each do |error|
- errors.add_to_base(error)
- end
- search_result.destroy
- false
- end
+ search_result
+ end
+
+ def create_search_result
+ new_search_result.save
end
end
2  app/models/comment.rb
View
@@ -25,8 +25,6 @@ class Comment
validates_presence_of :user
- validate :disallow_spam
-
before_save :adjust_newlines
after_create :new_comment_notification,
:unless => :created_together_with_search_result
4 app/models/news_item.rb
View
@@ -116,8 +116,6 @@ def show!
# it's not a question that should be hidden
def should_be_hidden?(ignored_topic_ids = [])
entry = self.news_update.entry
-
- !! (entry.is_a?(Question) and entry.answers_count > 0) or
- ( (entry.topic_ids & ignored_topic_ids).any? )
+ (entry.topic_ids & ignored_topic_ids).any?
end
end
1  app/models/question.rb
View
@@ -136,7 +136,6 @@ class Question
validates_inclusion_of :language, :within => AVAILABLE_LANGUAGES
validates_true_for :language, :logic => lambda { |q| q.group.language == q.language },
:if => lambda { |q| !q.group.language.nil? }
- validate :disallow_spam
validate :check_useful
timestamps!
14 app/models/search_result.rb
View
@@ -110,16 +110,9 @@ def create_news_update
:created_at => self.created_at,
:action => 'created')
- hide_news_update
end
handle_asynchronously :create_news_update
- def hide_news_update
- if self.question.news_update
- self.question.news_update.hide!
- end
- end
-
def unhide_news_update
# if this is the last question, reshow question's news_update
self.question.news_update.show! if self.question.answers_count == 1
@@ -175,8 +168,7 @@ def fetch_response_body
end
def fill_title
- title = truncate(Nokogiri::HTML(response_body, nil, 'utf-8').
- xpath('//title').text,
+ title = truncate(Support::Embedly.new(url).title,
:length => TITLE_SIZE,
:omission => '',
:separator => ' ')
@@ -235,4 +227,8 @@ def flagged!
{ :$inc => { :flags_count => 1 } },
:upsert => true)
end
+
+ def topic_ids
+ self.question.topic_ids
+ end
end
22 app/models/user.rb
View
@@ -382,7 +382,8 @@ def age
def can_modify?(model)
return false unless model.respond_to?(:user)
- self.admin? || self == model.user
+ self.admin? ||
+ (self == model.user && !(model.is_a?(Topic)))
end
def groups(options = {})
@@ -1018,6 +1019,25 @@ def tracked?
true
end
+ def self.create_with_provider(auth_hash)
+ user_info = auth_hash["user_info"]
+ email = user_info["email"]
+ password = ActiveSupport::SecureRandom.base64(20)
+
+ user = User.create(:email => email,
+ :agrees_with_terms_of_service => true,
+ :name => user_info["name"],
+ :password => password,
+ :password_confirmation => password)
+
+ if user
+ UserExternalAccount.create(auth_hash.merge(:user => user))
+ user.confirm!
+ end
+
+ user
+ end
+
protected
def password_required?
(encrypted_password.blank? || !password.blank?)
7 app/stylesheets/_base.sass
View
@@ -232,12 +232,9 @@ input.checkbox
.right
float: right
textarea.comment_text_area
- font-size: 13px
- line-height: 26px
margin: -2px 0 -1px 0
- height: auto
- width: 560px
- padding: 0
+ width: 99%
+ padding: 3px 4px 3px 4px
label.label, input.text_field, textarea.text_area
font-size: 1.2em
padding: 1px 0
13 app/stylesheets/application.sass
View
@@ -41,13 +41,16 @@ textarea.text_area
height: 120px
textarea.comment_text_area
- height: 60px
- border-bottom: 1px solid #dddddd
- border-left: 2px solid #cccccc
- border-right: 1px solid #dddddd
- border-top: 2px solid #cccccc
+ border-bottom: 1px solid #ddd
+ border-left: 1px solid #ccc
+ border-right: 1px solid #ddd
+ border-top: 1px solid #ccc
+ border-radius: 2px
width: 99%
+textarea.comment_text_area.focussed
+ height: 2.5em
+
#main-doc
background-color: white
text-align: center
2  app/stylesheets/inline_edition.sass
View
@@ -22,7 +22,7 @@
a.active_inline_link
display: inline
- position: absolute
+ margin-left: 7px
z-index: 1
margin-top: 1px
29 app/stylesheets/landing.sass
View
@@ -13,6 +13,7 @@
@import footer
@import compass/typography/lists/inline-block-list
@import tooltip
+@import "partials/facebook"
body.bp
a, a:visited, a:hover
@@ -37,9 +38,10 @@ body.bp
.label
line-height: 1
#email_label
- +column(4)
+ +column(2)
+ +append(2)
#password_label
- +append(4)
+ +append(2)
+column(2, true)
#email_field
+column(4)
@@ -51,9 +53,17 @@ body.bp
+column(4)
line-height: 2
#recover_password
- +append(2)
- +column(4, true)
+ +append(4)
+ +column(2, true)
+ line-height: 2
+ #horizontal_bar
+ padding-top: 15px
+ +column(10)
+ line-height: 2
+ #facebook_sign_in
+ text-align: center
line-height: 2
+ +column(10, true)
input[type=submit]
width: 70px
margin-top: 6px
@@ -297,3 +307,14 @@ ul#team
list-style: none
li + li
margin-top: 10px
+
+#signup .facebook-signup
+ padding-top: 78px
+ padding-bottom: 78px
+ text-align: center
+ .fb_button
+ margin-top: 15px
+ margin-bottom: 15px
+ .agree
+ text-align: center
+
33 app/stylesheets/partials/_facebook.scss
View
@@ -0,0 +1,33 @@
+.fb_button_simple,.fb_button_simple_rtl{background-image:url(http://static.ak.fbcdn.net/rsrc.php/v1/yH/r/eIpbnVKI9lR.png);background-repeat:no-repeat;cursor:pointer;outline:none;text-decoration:none}
+.fb_button_simple_rtl{background-position:right 0}
+.fb_button_simple .fb_button_text{margin:0 0 0 20px;padding-bottom:1px}
+.fb_button_simple_rtl .fb_button_text{margin:0 10px 0 0}
+a.fb_button_simple:hover .fb_button_text,a.fb_button_simple_rtl:hover .fb_button_text,.fb_button_simple:hover .fb_button_text,.fb_button_simple_rtl:hover .fb_button_text{text-decoration:underline}
+.fb_button,.fb_button_rtl{background:#29447e url(http://static.ak.fbcdn.net/rsrc.php/v1/yL/r/FGFbc80dUKj.png);background-repeat:no-repeat;cursor:pointer;display:inline-block;padding:0 0 0 1px;text-decoration:none;outline:none}
+.fb_button .fb_button_text,.fb_button_rtl .fb_button_text{background:#5f78ab url(http://static.ak.fbcdn.net/rsrc.php/v1/yL/r/FGFbc80dUKj.png);border-top:solid 1px #879ac0;border-bottom:solid 1px #1a356e;color:#fff;display:block;font-family:"lucida grande",tahoma,verdana,arial,sans-serif;font-weight:bold;padding:2px 6px 3px 6px;margin:1px 1px 0 21px;text-shadow:none}
+a.fb_button,a.fb_button_rtl,.fb_button,.fb_button_rtl{text-decoration:none}
+a.fb_button:active .fb_button_text,a.fb_button_rtl:active .fb_button_text,.fb_button:active .fb_button_text,.fb_button_rtl:active .fb_button_text{border-bottom:solid 1px #29447e;border-top:solid 1px #45619d;background:#4f6aa3;text-shadow:none}
+.fb_button_xlarge,.fb_button_xlarge_rtl{background-position:left -60px;font-size: 24px;line-height:30px}
+.fb_button_xlarge .fb_button_text{padding:3px 8px 3px 12px;margin-left:38px}
+a.fb_button_xlarge:active{background-position:left -99px}
+.fb_button_xlarge_rtl{background-position:right -268px}
+.fb_button_xlarge_rtl .fb_button_text{padding:3px 8px 3px 12px;margin-right:39px}
+a.fb_button_xlarge_rtl:active{background-position:right -307px}
+.fb_button_large,.fb_button_large_rtl{background-position:left -138px;font-size: 13px;line-height:16px}
+.fb_button_large .fb_button_text{margin-left:24px;padding:2px 6px 4px 6px}
+a.fb_button_large:active{background-position:left -163px}
+.fb_button_large_rtl{background-position:right -346px}
+.fb_button_large_rtl .fb_button_text{margin-right:25px}
+a.fb_button_large_rtl:active{background-position:right -371px}
+.fb_button_medium,.fb_button_medium_rtl{background-position:left -188px;font-size: 11px;line-height:14px}
+a.fb_button_medium:active{background-position:left -210px}
+.fb_button_medium_rtl{background-position:right -396px}
+.fb_button_text_rtl,.fb_button_medium_rtl .fb_button_text{padding:2px 6px 3px 6px;margin-right:22px}
+a.fb_button_medium_rtl:active{background-position:right -418px}
+.fb_button_small,.fb_button_small_rtl{background-position:left -232px;font-size: 10px;line-height:10px}
+.fb_button_small .fb_button_text{padding:2px 6px 3px;margin-left:17px}
+a.fb_button_small:active,.fb_button_small:active{background-position:left -250px}
+.fb_button_small_rtl{background-position:right -440px}
+.fb_button_small_rtl .fb_button_text{padding:2px 6px;margin-right:18px}
+a.fb_button_small_rtl:active{background-position:right -458px}
+.fb_connect_bar .fb_buttons{float:right;margin-top:7px}
6 app/stylesheets/themes/plain/_base.sass
View
@@ -250,6 +250,12 @@ table
#post_as_new_question
float: right
+.search_result
+ .splitter
+ margin-bottom: 7px
+ .navform.hidden
+ display: none
+
.invitation_form
.tip
color: #666666
26 app/stylesheets/themes/plain/_questions.sass
View
@@ -167,6 +167,8 @@
margin-left: 3px
.search_result
+ float: left
+ width: 100%
.vote-col
float: left
margin-left: -30px
@@ -331,3 +333,27 @@ form
margin-top: -0.5em
font-family: Verdana, Tahoma, sans-serif
color: #444
+
+form#new_search_result
+ #search_result_area
+ background-color: #EEE
+ width: 552px
+ text-align: center
+ padding: 10px
+ label
+ padding-top: 1em
+ .submit_button
+ float: none
+ text-align: left
+ width: 100%
+ input#search_result_url.link_only_answer_form
+ float: none
+ font-size: 12px
+ height: 30px
+ border: 1px solid #BBB
+ margin: 0
+ padding: 0px 4px
+ clear: both
+ width: 542px
+ .hidden_until_url_is_clicked
+ display: none
3  app/stylesheets/themes/plain/_sidebar.sass
View
@@ -37,7 +37,8 @@
margin-bottom: 0.5em
.url_field
- font-size: 1.1em
+ color: black
+ width: 95%
padding: 2px
background-color: white
3  app/stylesheets/themes/plain/_users.sass
View
@@ -47,3 +47,6 @@ a.unfollow_link
margin: 3px
span
padding: 1px 2px
+
+.upvotes_count
+ padding-top: 1em
4 app/views/answers/show.html.haml
View
@@ -6,6 +6,10 @@
- content_for :sidebar do
= render :partial => 'shared/share_body', :locals => { :opts => { :content => @answer.id, :class_name => Answer.to_s.underscore } }
+- if current_user.blank?
+ - content_for :hellobar do
+ ~ AppConfig.hellobar_code_snippet
+
#question
%h1.navtitle.title.entry-title
&= link_to @answer.title, @question
15 app/views/auth_callback/signup_with_provider.html.haml
View
@@ -0,0 +1,15 @@
+.secondary-navigation
+ .navtitle= t('layouts.application.signup')
+ %p= t('auth_callback.password_required')
+ = form_for @user, :url => auth_sign_in_and_associate_provider_path, :html => {:class => "form"} do |f|
+ .group
+ =f.label :email, t(:email, :scope => "users.form"), :class => "label"
+ .info
+ .input #{ @email }
+
+ .group
+ = f.label :password, t(:password, :scope => "users.form"), :class => "label"
+ = f.password_field :password, :tabindex => 0, :class => "password text_field"
+
+ .group.navform
+ = f.submit t('users.signup.submit'), :tabindex => 1
14 app/views/comments/_comment.html.haml
View
@@ -25,20 +25,6 @@
= link_to comment.user.name, user_path(comment.user)
== #{t("comments.shared.said")}:
- .comment-votes
-
- - if logged_in? && current_user.can_vote_up_on?(current_group) && current_user != comment.user
- - form_tag votes_path(:format => :js),
- :class => "vote-up-comment-form",
- :remote => true, "data-type" => "json" do
- .fields
- = hidden_field_tag "voteable_type", comment.class.name, :id => "voteable_type_#{comment.id}"
- = hidden_field_tag "voteable_id", comment.id, :id => "voteable_id_#{comment.id}"
- = hidden_field_tag "source", request.path, :id => "source_#{comment.id}"
- - if vote = current_user.vote_on(comment)
- = image_submit_tag("dialog-ok-apply.png", :name=>"vote_up", :value=>"1", :title => t("votes.control.to_vote_up"), :class => "comment-voteup-button")
- - else
- = image_submit_tag("dialog-ok.png", :name=>"vote_up", :value=>"1", :title => t("votes.control.to_vote_up"), :class => "comment-voteup-button")
.comment-content.markdown
= shapado_auto_link(markdown(comment.body))
13 app/views/comments/_count.html.haml
View
@@ -1,3 +1,12 @@
+- message = local_assigns[:message]
+- hide = local_assigns[:hide]
+- if message.blank?
+ - inline = local_assigns[:inline]
+ - count = inline ? commentable.comments.count - 1 : commentable.comments.count
+ - if inline
+ - message = t("comments.count_inline", :count => count)
+ - else
+ - message = t("comments.count", :count => count)
.ccontrol
- %a{:href => "", :class => "ccontrol-link"}
- = t("comments.count", :count => commentable.comments.count)
+ %a{:href => "", :class => "ccontrol-link", :style => "display: #{hide ? 'none' : ''}"}
+ = message
13 app/views/comments/_form.html.haml
View
@@ -1,6 +1,9 @@
-.group
- = hidden_field_tag "source", source, :id => "source_#{commentable.id}"
+- if local_assigns[:inline]
+ = render :partial => "comments/inline_form", :locals => local_assigns
+- else
+ .group
+ = hidden_field_tag "source", source, :id => "source_#{commentable.id}"
- = text_area_tag "body", @comment.body, :class => "comment_text_area markdown_editor", :id => "comment_#{commentable.id}", :rows => 'auto', :cols => 'auto', "data-autocomplete-url" => autocomplete_url
- %ul.autocomplete-list{:id => "comment_#{commentable.id}_list"}
- %br.clear
+ = text_area_tag "body", @comment.body, :class => "comment_text_area markdown_editor", :id => "comment_#{commentable.id}", :rows => 'auto', :cols => 'auto', "data-autocomplete-url" => autocomplete_url
+ %ul.autocomplete-list{:id => "comment_#{commentable.id}_list"}
+ %br.clear
21 app/views/comments/_inline_form.html.haml
View
@@ -0,0 +1,21 @@
+
+.inline_comment
+ - # TODO maybe add a title
+ - @comment = Comment.new
+ = form_tag(url_for(local_assigns[:path_scope] + [@comment]) + ".js",
+ :class => "form inlineCommentForm",
+ :remote => true, "data-type" => "json") do
+ .group
+ = hidden_field_tag "source", source, :id => "source_#{commentable.id}"
+
+ = text_area_tag("body", @comment.body,
+ :class => "comment_text_area markdown_editor placeholder",
+ :id => "comment_#{commentable.id}",
+ :rows => 1, :cols => 'auto',
+ :placeholder => t(:leave_comment, :scope => [:helpers, :placeholder]),
+ "data-autocomplete-url" => autocomplete_url)
+ %ul.autocomplete-list{:id => "comment_#{commentable.id}_list"}
+ %br.clear
+
+ .navform.hidden
+ = submit_tag t("comments.shared.comment_submit"), :class => "button"
1  app/views/layouts/application.html.haml
View
@@ -11,6 +11,7 @@
<!--[if lt IE 8]><link type="text/css" rel="stylesheet" media="screen" href="/stylesheets/ie7.css"><![endif]-->
= include_javascripts :base
= javascript_include_tag AppConfig.mathjax_location
+ = yield :hellobar
= yield :js
%link{"rel" => "search", "type" => "application/opensearchdescription+xml", "href" => "/content-search.xml", "title" => "Content Search"}
1  app/views/layouts/welcome.html.haml
View
@@ -1,6 +1,7 @@
!!! Strict
%html{ "xml:lang" => I18n.locale, :lang => I18n.locale, :xmlns => "http://www.w3.org/1999/xhtml" }
%head
+ = yield :optimizely
%title
&= page_title
= include_stylesheets :landing, :media => 'all'
2  app/views/questions/_answer.html.haml
View
@@ -46,7 +46,7 @@
- if answer.versions.count > 0
= link_to t("wiki.history.link", :default => "history"), history_question_answer_path(question, answer)
- - if logged_in?
+ - if logged_in? && current_user.can_modify?(answer)
= link_to t('scaffold.edit'), edit_question_answer_path(question, answer)
.updated{:title => answer.updated_at}
.time_ago
70 app/views/questions/_answer_with_form.html.haml
View
@@ -2,37 +2,53 @@
.loader{:style => 'display: none;'}
= waiting_tag
- if logged_in? && !@question.closed
- .secondary-navigation
- %h2{:id => :title}= t(:title, :scope => [:questions, :show])
- - tabs_tag :namespace => :welcome_home, :open_tabs => { :class => :tabs } do |tab|
- = tab.link 'Link', '#', :id => 'link', :class => 'current'
- = tab.answer 'New Post', '#', :id => 'answer'
- #link
+ - if ab_test(:link_only_answer_form) == :link_only_answer_form
= form_for(@search_result,
- :url => question_search_results_path(@question.id, :format => :js),
- :html => { :class => 'form bp',
- :remote => true,
- :novalidate => true,
- :'data-type' => 'json' }) do |f|
+ :url => question_search_results_path(@question.id, :format => :js),
+ :html => { :class => 'form bp',
+ :remote => true,
+ :novalidate => true,
+ :'data-type' => 'json' }) do |f|
= render :partial => "search_results/form", :locals => { :f => f,
:question_id => @question.id,
:user_id => current_user.id,
:group_id => current_group.id }
- .group.navform
- = submit_tag 'Adicionar Link', :class => "button"
- #answer{:class => 'editor_hack'}
- = form_for(@answer,
- :url => question_answers_path(@question.id, :format => :js),
- :html => { :class => "form mainAnswerForm bp editor",
- :remote => true,
- :'data-type' => 'json' }) do |f|
- = render :partial => "answers/form", :locals => { :f => f, :markdown => true }
- .group.navform
- = submit_tag t("answers.form.submit"), :class => "button"
- -# Image upload prompt; hidden by default
- = render :partial => "shared/image_prompt", :locals => { :entry_type => "answer" }
+ - else
+ .secondary-navigation
+ %h2{:id => :title}= t(:title, :scope => [:questions, :show])
+ - tabs_tag :namespace => :welcome_home, :open_tabs => { :class => :tabs } do |tab|
+ = tab.link 'Link', '#', :id => 'link', :class => 'current'
+ = tab.answer 'New Post', '#', :id => 'answer'
+ #link
+ = form_for(@search_result,
+ :url => question_search_results_path(@question.id, :format => :js),
+ :html => { :class => 'form bp',
+ :remote => true,
+ :novalidate => true,
+ :'data-type' => 'json' }) do |f|
+ = render :partial => "search_results/form", :locals => { :f => f,
+ :question_id => @question.id,
+ :user_id => current_user.id,
+ :group_id => current_group.id }
+ #answer{:class => 'editor_hack'}
+ = form_for(@answer,
+ :url => question_answers_path(@question.id, :format => :js),
+ :html => { :class => "form mainAnswerForm bp editor",
+ :remote => true,
+ :'data-type' => 'json' }) do |f|
+ = render :partial => "answers/form", :locals => { :f => f, :markdown => true }
+ .group.navform
+ = submit_tag t("answers.form.submit"), :class => "button"
+ -# Image upload prompt; hidden by default
+ = render :partial => "shared/image_prompt", :locals => { :entry_type => "answer" }
- else
- - if not logged_in?
- %p= t("answers.form.not_logged", :link => new_user_session_path)
+ - if logged_in?
+ = render :partial => "questions/already_answered",
+ :locals => { :answer => Answer.first(:question_id => @question.id,
+ :user_id => current_user.id) }
- else
- = render :partial => "questions/already_answered", :locals => { :answer => Answer.first(:question_id => @question.id, :user_id => current_user.id) }
+ %p= t(:not_logged,
+ :scope => [:answers, :form],
+ :link => link_to(t(:sign_in, :scope => [:answers, :form]),
+ root_path(:return_to => request.path,
+ :group_invitation => session[:group_invitation])))
5 app/views/questions/_form.html.haml
View
@@ -29,6 +29,11 @@
%hr
.group
= render :partial => "shared/classify", :locals => {:classifiable => @question, :ajax_add => false}
+- else
+ - @question.topics.each do |topic|
+ = hidden_field_tag "question[topics][]", topic.title
+ = f.hidden_field :body
+
- if current_group.language.nil? && AppConfig.enable_i18n
.group
6 app/views/questions/_new_follow_up_question.text.erb
View
@@ -1,5 +1 @@
-
-
-
-
-This is a follow-up to "[<%= @question.title %>](<%= question_url(@question) %>)"<%= @question.title.strip[-1..-1] == '?' ? '' : '.' %>
+This is a follow-up to "[<%= @question.title %>](<%= question_url(@question) %>)"<%= @question.title.strip[-1..-1] == '?' ? '' : '.' %>
2  app/views/questions/edit.html.haml
View
@@ -12,7 +12,7 @@
- form_for(@question, :url => question_path(@question),
:html => {:class => "form editor"}) do |f|
- = render :partial => "form", :locals => {:f => f, :topics => false}
+ = render :partial => "form", :locals => {:f => f, :topics => false, :details => true}
.group.navform
= f.submit t("scaffold.update")
= t("global.or")
26 app/views/questions/show.html.haml
View
@@ -21,6 +21,10 @@
%meta{:name => "description", :content => question_body.gsub(/<\/?[^>]*>/, "")[0, 255] }
%link{:rel => "canonical", :href => question_url(@question) }
+- if current_user.blank?
+ - content_for :hellobar do
+ ~ AppConfig.hellobar_code_snippet
+
= error_messages_for 'answer'
#question.commentable
@@ -61,34 +65,28 @@
= link_to t("wiki.history.link", :default => "history"), history_question_path(@question)
- if logged_in?
- - if (@question.wiki && current_user.can_edit_wiki_post_on?(@question.group)) || current_user.can_edit_others_posts_on?(@question.group) || current_user.can_modify?(@question)
+ - if current_user.can_modify?(@question)
= link_to t('scaffold.edit'), edit_question_path(@question), :class => "button"
-
- = link_to t('.add_follow_up_question'), new_question_path(:question => @follow_up_question), :target => '_blank', :class => 'featured'
+ - if ab_test(:new_question_as_search) == :old_search_scheme
+ = link_to t('.add_follow_up_question'), new_question_path(:question => @follow_up_question), :target => '_blank', :class => 'featured'
#question_flag_div
= render :partial => "shared/comments", :locals => {:commentable => @question, :source => source, :path_scope => [@question]}
-- if ab_test(:answer_with_form_position) == :above
- = render(:partial => 'answer_with_form',
- :locals => { :question => @question,
- :search_result => @search_result,
- :answer => @answer })
+= render(:partial => 'answer_with_form',
+ :locals => { :question => @question,
+ :search_result => @search_result,
+ :answer => @answer })
#search_results
+ .new
- @search_results.each do |search_result|
= render(:partial => 'search_results/search_result',
:locals => { :question => @question,
:hide_controls => false,
:search_result => search_result })
-- if ab_test(:answer_with_form_position) == :below
- = render(:partial => 'answer_with_form',
- :locals => { :question => @question,
- :search_result => @search_result,
- :answer => @answer })
-
= render(:partial => 'bing_results',
:object => @bing_response[:results],
:locals => { :question => @question,
28 app/views/search_results/_form.html.haml
View
@@ -1,9 +1,25 @@
-= f.label(:url)
-= f.text_field(:url, :type => :url)
= f.hidden_field(:question_id, :value => question_id)
= f.hidden_field(:group_id, :value => group_id)
= f.hidden_field(:user_id, :value => user_id)
-= f.label(:comment)
-= f.text_area(:comment,
- :class => 'placeholder',
- :placeholder => t(:comment, :scope => [:helpers, :placeholder]))
+
+- if ab_test(:link_only_answer_form) == :link_only_answer_form
+ #search_result_area
+ = f.text_field(:url, :type => :url, :class => "link_only_answer_form",
+ :placeholder => t("search_results.add_link"))
+ .hidden_until_url_is_clicked
+ = f.label(:comment)
+ = f.text_area(:comment,
+ :class => 'placeholder',
+ :placeholder => t(:comment, :scope => [:helpers, :placeholder]))
+ .submit_button
+ = submit_tag t("search_results.add_link"), :class => "button"
+- else
+ = f.label(:url)
+ = f.text_field(:url, :type => :url)
+
+ = f.label(:comment)
+ = f.text_area(:comment,
+ :class => 'placeholder',
+ :placeholder => t(:comment, :scope => [:helpers, :placeholder]))
+ .group.navform
+ = submit_tag t("search_results.add_link"), :class => "button"
12 app/views/search_results/_search_result.html.haml
View
@@ -7,7 +7,7 @@
- title = search_result.title
- if title.blank? || title == search_result.url
- title = shorten_url(search_result.url, :length => 45)
- = link_to(title, trackable_search_result_url(search_result))
+ = link_to(title, trackable_search_result_url(search_result, Umamao::PAGE_MAPPING['questions#show']))
.url
%p
= shorten_url(search_result.url)
@@ -28,8 +28,10 @@
:method => :delete,
:class =>"cancel"
#search_result_flag_div
- = render :partial => 'shared/comments',
- :locals => { :commentable => search_result,
- :source => question_path(question),
- :path_scope => [question, search_result] }
+ .splitter
+ = render :partial => 'shared/comments',
+ :locals => { :commentable => search_result,
+ :source => question_path(question),
+ :path_scope => [question, search_result],
+ :inline => ab_test(:inline_comment_helpers) == :inline}
9 app/views/searches/search_as_new_question.html.haml
View
@@ -37,7 +37,8 @@
= render :partial => "shared/image_prompt",
:locals => { :entry_type => "question" }
-= render(:partial => 'questions/bing_results',
- :object => @bing_results[:results],
- :locals => { :question => @question,
- :bing_results_count => @bing_results[:total_results_count] })
+- if @bing_results[:results].present?
+ = render(:partial => 'questions/bing_results',
+ :object => @bing_results[:results],
+ :locals => { :question => @question,
+ :bing_results_count => @bing_results[:total_results_count] })
16 app/views/shared/_analytics.haml
View
@@ -1,13 +1,5 @@
-- if Rails.env.production? && !AppConfig.analytics_id.blank? && (!current_group.has_custom_analytics || current_group.analytics_id.blank?)
- = googlean_script(AppConfig.analytics_id, AppConfig.googlean_domain)
+- if Rails.env.production? && (!current_user || current_user && current_user.tracked?)
+ - if AppConfig.analytics_id && AppConfig.googlean_domain
+ = googlean_script(AppConfig.analytics_id, AppConfig.googlean_domain)
-- elsif Rails.env.production? && current_group.has_custom_analytics && current_group.analytics_vendor == 'googlean' && request.domain == AppConfig.domain
-
- = googlean_script(AppConfig.analytics_id, AppConfig.googlean_domain)
- = googlean_script(current_group.analytics_id, current_group.domain)
-
-- elsif Rails.env.production? && current_group.has_custom_analytics && current_group.analytics_vendor == 'googlean' && request.domain != AppConfig.domain
-
- = googlean_script(current_group.analytics_id, current_group.domain)
-
-~ AppConfig.analytics_javascripts if Rails.env.production?
+ ~ AppConfig.analytics_javascripts
25 app/views/shared/_comments.html.haml
View
@@ -1,12 +1,33 @@
- source = local_assigns[:source]
- commentable = local_assigns[:commentable]
- path_scope = local_assigns[:path_scope]
+- comments = commentable.comments
+- inline = local_assigns[:inline]
-= render :partial => 'comments/count', :locals => {:commentable => commentable}
+- hide_message = false
+- message = nil
+
+- if inline
+ - if comments.blank?
+ - hide_message = true
+ - if logged_in?
+ = render :partial => "comments/form",
+ :locals => {:source => source,
+ :commentable => commentable,
+ :path_scope => path_scope, :inline => true}
+ - else
+ %p= t("comments.shared.not_logged", :link => new_user_session_path)
+ - else
+ = render :partial => "comments/comment", :object => comments[0], :locals => {:source => source, :mini => true}
+ - comments = comments[1 .. comments.count]
+ - if comments.blank?
+ - message = t("comments.shared.add_comment")
+
+= render :partial => 'comments/count', :locals => {:commentable => commentable, :inline => inline, :message => message, :hide => hide_message}
.comments_wrapper
.comments
- - commentable.comments.each do |comment|
+ - comments.each do |comment|
= render :partial => "comments/comment", :object => comment, :locals => {:source => source, :mini => true}
- if logged_in?
.forms
9 app/views/shared/_other_actions.html.haml
View
@@ -14,9 +14,6 @@
= link_to t("layouts.application.logout"), destroy_user_session_path
- else
.log-in
- - if session[:group_invitation]
- = link_to t("layouts.application.log_in"),
- new_user_path(:group_invitation => session[:group_invitation])
- - else
- = link_to t("layouts.application.log_in"),
- root_path(:focus => "signup", :return_to => request.url)
+ = link_to(t(:log_in, :scope => [:layouts, :application]),
+ root_path(:return_to => request.path,
+ :group_invitation => session[:group_invitation]))
4 app/views/signup_wizard/wizard.html.haml
View
@@ -3,3 +3,7 @@
= include_javascripts :suggestions, :signup_follow
= render_cell "signup_wizard", :wizard
+
+- if @current_step == "follow"
+ - content_for :optimizely do
+ ~ AppConfig.optimizely_code_snippet
8 app/views/topics/_common.html.haml
View
@@ -9,12 +9,8 @@
.controls
.actions
- = link_to t('scaffold.edit'), edit_topic_path(@topic)
- - if @topic.allow_question_lists
- .featured
- = link_to t('.new_question_list'), new_question_list_path(:main_topic => @topic.slug, :class => "featured")
- .new_feature
- = t('new_feature')
+ - if logged_in? && current_user.admin?
+ = link_to t('scaffold.edit'), edit_topic_path(@topic)
.secondary-navigation
- tabs_tag :namespace => :topic_show, :open_tabs => {:class => :tabs} do |tab|
4 app/views/topics/show.html.haml
View
@@ -1,3 +1,7 @@
+- if current_user.blank?
+ - content_for :hellobar do
+ ~ AppConfig.hellobar_code_snippet
+
#topic
= render :partial => "common", :locals => {:topic => @topic, :students => @students_course}
3  app/views/users/_form_signup.html.haml
View
@@ -0,0 +1,3 @@
+#title
+ %h3 #{ t('layouts.application.signup') }
+= render :partial => 'users/signup_form'
2  app/views/users/_news_update.html.haml
View
@@ -4,7 +4,7 @@
- entry_type = news_update.entry_type.downcase
- question = (entry_type == 'question') ? entry : entry.question
- title = h(question.title)
-- question_link = question_path(question, :ab_test => true)
+- question_link = question_path(question)
- unless question.banned || entry.banned
%li.entry.item
3  app/views/users/_profile_common.html.haml
View
@@ -38,4 +38,5 @@
= markdown(@user.description)
-else
= markdown(@user.description)
- %div= t('users.show.upvotes_count', :upvotes_count => @user.upvotes_count)
+ .upvotes_count
+ = t('users.show.upvotes_count', :upvotes_count => @user.upvotes_count)
9 app/views/users/_signup.html.haml
View
@@ -1,3 +1,6 @@
-#title
- %h3 #{ t('layouts.application.signup') }
-= render :partial => 'users/signup_form'
+.facebook-signup
+ %a.fb_button.fb_button_large{:href => "/auth/facebook"}
+ %span.fb_button_text= t('.sign_up_with_facebook')
+
+ .field.agree
+ = t(:agree, :scope => 'users.new', :privacy => privacy_path, :tos => tos_path)
8 app/views/users/_user_bar.html.haml
View
@@ -1,16 +1,16 @@
- if logged_in?
#user-bar-greeting
- Logged in as
+ Signed in as
= link_to_current_user :content_method => :name
#user-bar-action
(
- = link_to "Log out", destroy_user_session_path, { :title => "Log out" }
+ = link_to "Sign out", destroy_user_session_path, { :title => "Sign out" }
)
- else
#user-bar-greeting
- = link_to_login_with_IP 'Not logged in', :style => 'border: none;'
+ = link_to_login_with_IP 'Not signed in', :style => 'border: none;'
#user-bar-action
- = link_to "Log in", new_user_session_path, { :title => "Log in" }
+ = link_to "Sign in", new_user_session_path, { :title => "Sign in" }
\/
= link_to "Sign up", signup_path, { :title => "Create an account" }
4 app/views/welcome/_news_item.html.haml
View
@@ -5,9 +5,9 @@
- entry = news_item.news_update.entry
- entry_type = news_item.news_update.entry_type.downcase
- question = entry_type == 'question' ? entry : entry.question
-- question_link = question_path(question, :r => 1)
+- question_link = question_path(question)
- if entry_type == "searchresult"
- - link = trackable_search_result_url(entry, 1)
+ - link = trackable_search_result_url(entry)
- else
- link = question_link
9 app/views/welcome/landing.html.haml
View
@@ -19,6 +19,13 @@
#recover_password
= link_to t("devise.passwords.link"), new_password_path("user")
+ #horizontal_bar
+ %hr
+
+ #facebook_sign_in
+ %a.fb_button.fb_button_medium{:href => "/auth/facebook"}
+ %span.fb_button_text= t('.sign_in_with_facebook')
+
- content_for :js do
= include_javascripts :landing
@@ -36,4 +43,6 @@
%p#invitation_only=t("welcome.landing.invitation_only")
= image_tag("mamaopq.png", :id => "mamao_signup")
- else
+ - content_for :optimizely do
+ ~ AppConfig.optimizely_code_snippet
= render :partial => 'users/signup'
4 config/initializers/04_airbrake.rb
View
@@ -0,0 +1,4 @@
+Airbrake.configure do |config|
+ config.api_key = AppConfig.airbrake['api_key']
+ config.ignore << 'Goalie::NotFound'
+end
4 config/initializers/04_hoptoad.rb
View
@@ -1,4 +0,0 @@
-HoptoadNotifier.configure do |config|
- config.api_key = AppConfig.hoptoad['api_key']
- config.ignore << 'Goalie::NotFound'
-end
4 config/initializers/delayed_job_config.rb
View
@@ -10,10 +10,10 @@
# so that we can receive e-mails when some task raises an error or fail
module MongoMapper::Document
def error(job, exception)
- notify_hoptoad(exception)
+ Airbrake.notify(exception)
end
def failure
- HoptoadNotifier.notify(:error_class => "Delayed::Job failed")
+ Airbrake.notify(:error_class => 'Delayed::Job failed')
end
end
3  config/locales/answers/en.yml
View
@@ -28,7 +28,8 @@ en:
answer_label: Answer the question
comment_label: Comment on this answer
comment_submit: Comment
- not_logged: Please <a href="%{link}">login</a> to answer question.
+ not_logged: Please %{link} to answer question.
+ sign_in: sign in
submit: Answer
revert:
title: Revert answer
3  config/locales/answers/pt-BR.yml
View
@@ -23,7 +23,8 @@ pt-BR:
answer_label: "Responder à pergunta"
comment_label: Comentar nesta resposta
comment_submit: Comentar
- not_logged: "É necessário <a href=\"%{link}\">se identificar</a> para responder à pergunta."
+ not_logged: "É necessário %{link} para responder à pergunta."
+ sign_in: se identificar
submit: Responder
revert:
title: Reverter resposta
4 config/locales/auth_callback/en.yml
View
@@ -0,0 +1,4 @@
+en:
+ auth_callback:
+ invalid_password: "Invalid password."
+ password_required: "Type your Umamao password to associate your Facebook account with your Umamao account."
4 config/locales/auth_callback/pt-BR.yml
View
@@ -0,0 +1,4 @@
+"pt-BR":
+ auth_callback:
+ invalid_password: "Senha inválida."
+ password_required: "Digite a sua senha do Umamão para associar sua conta do Facebook com a sua conta no Umamão."
6 config/locales/comments/en.yml
View
@@ -6,6 +6,9 @@ en:
none: Add coment
one: 1 comment
other: "%{count} comments"
+ count_inline:
+ one: 1 other comment
+ other: "%{count} other comments"
create:
flash_notice: Thanks for your comment
destroy:
@@ -13,8 +16,9 @@ en:
edit:
title: Edit comment
shared:
- add_comment: Add comment...
+ add_comment: Add comment
comment_submit: Comment
+ not_logged: <a href="%{link}">Sign in</a> to leave a comment.
reply: Reply
said: said
update:
4 config/locales/comments/pt-BR.yml
View
@@ -6,6 +6,9 @@ pt-BR:
none: "Adicionar comentário"
one: "1 comentário"
other: "%{count} comentários"
+ count_inline:
+ one: "mais 1 comentário"
+ other: "mais %{count} comentários"
create:
flash_notice: "Comentário enviado."
destroy:
@@ -15,6 +18,7 @@ pt-BR:
shared:
add_comment: "Adicionar comentário"
comment_submit: Comentar
+ not_logged: "<a href=\"%{link}\">Identifique-se</a> para deixar um comentário."
reply: Responder
said: disse
update:
4 config/locales/devise/devise.en.yml
View
@@ -17,7 +17,7 @@ en:
sessions:
signed_in: 'Signed in successfully.'
signed_out: 'Signed out successfully.'
- link: Log in
+ link: Sign in
new:
remember_me: Remember me
submit: Sign me in
@@ -28,7 +28,7 @@ en:
forgot_your_password: Want to reset your password?
edit:
submit: Submit
- link: "Forgot your password?"
+ link: "Can't sign in?"
send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
updated: 'Your password was changed successfully. You are now signed in.'
confirmations:
2  config/locales/global/en.yml
View
@@ -30,7 +30,7 @@ en:
group_not_found: The page %{url} doesn't exist
or: or
permission_denied: Permission denied
- please_login: Please log in
+ please_login: Please sign in
preview: Preview
previous: Previous
share: share
8 config/locales/layouts/en.yml
View
@@ -5,14 +5,14 @@ en:
forgot: Forgot?
home: Home
languages: Languages
- log_in: Login
- logged: Logged in as %{login}
- logout: Log out
+ log_in: Sign in
+ logged: Signed in as %{login}
+ logout: Sign out
manage_ads: Manage ads
moderate: Moderate
now: now!
openid:
- explaination: "If you would like to register or just log in, please select your OpenID provider:"
+ explaination: "If you would like to register or just sign in, please select your OpenID provider:"
pages: Pages
profile: Profile
questions: Questions
2  config/locales/questions/en.yml
View
@@ -28,7 +28,7 @@ en:
questions: Questions
questions:
answer:
- add_comment: Add comment...
+ add_comment: Add comment
flag: Flag
pick_answer: Pick as solution
share_new_answer: Share your answer with others!
2  config/locales/search_results/en.yml
View
@@ -30,6 +30,7 @@ en:
url: URL
placeholder:
comment: Why is this relevant?
+ leave_comment: Leave a comment
search_results:
attributes:
search_result:
@@ -42,3 +43,4 @@ en:
flag: Flag
show:
flagged_as: Flagged as
+ add_link: Add Link
2  config/locales/search_results/pt-BR.yml
View
@@ -30,6 +30,7 @@ pt-BR:
url: URL
placeholder:
comment: "Por que isso é relevante?"
+ leave_comment: "Deixe um comentário"
search_results:
attributes:
search_result:
@@ -42,3 +43,4 @@ pt-BR:
flag: Reportar
show:
flagged_as: Reportado como
+ add_link: Adicionar Link
12 config/locales/sessions/en.yml
View
@@ -1,18 +1,18 @@
en:
sessions:
create:
- flash_error: Could not log you in as '%{login}'
- flash_notice: Logged in successfully
+ flash_error: Could not sign you in as '%{login}'
+ flash_notice: Signed in successfully
destroy:
- flash_notice: You have been logged out.
+ flash_notice: You have been signed out.
new:
- log_in: Login
+ log_in: Sign in
not_registered: Not registered yet?
registered: Already registered?
remember_me: Remember me
sign_in: Sign in
signup: Sign up
- with_authentication: Log in with our authentication system
+ with_authentication: Sign in with our authentication system
with_facebook: Sign in with Facebook
- with_openid: Log in with OpenID
+ with_openid: Sign in with OpenID
with_twitter: Sign in with Twitter
2  config/locales/shared/en.yml
View
@@ -4,6 +4,6 @@ en:
title: Selected tags
topbar:
admin: Admin
- logged_as: Logged in as %{login}
+ logged_as: Signed in as %{login}
user_page: My page
wait_to_print: Preparing print version, please wait...
2  config/locales/url_invitations/en.yml
View
@@ -9,4 +9,4 @@ en:
clicks: clicks
left: left
sign_ups: sign ups
- title: Invite other people
+ title: Share this link to invite people
2  config/locales/url_invitations/pt-BR.yml
View
@@ -9,4 +9,4 @@ pt-BR:
clicks: cliques
left: sobrando
sign_ups: registros
- title: Convide outras pessoas
+ title: Compartilhe esse link para convidar pessoas
1  config/locales/users/en.yml
View
@@ -138,6 +138,7 @@ en:
upvotes_count: "Total upvotes received: %{upvotes_count}"
views: views
signup:
+ sign_up_with_facebook: Sign up with Facebook
submit: Sign up
validation:
errors:
3  config/locales/users/pt-BR.yml
View
@@ -136,6 +136,9 @@ pt-BR:
title: "%{user}"
upvotes_count: "Total de votos positivo recebidos: %{upvotes_count}"
views: visitas
+ signup:
+ sign_up_with_facebook: Cadastrar-se com o Facebook
+ submit: Cadastrar-se
validation:
errors:
did_not_agree: "Você deve concordar com os termos de uso e a política de privacidade\n"
1  config/locales/welcome/en.yml
View
@@ -22,6 +22,7 @@ en:
headline: Finally, an information desk for the Internet.
invitation_only: For the moment, you need an invitation to be able to sign up.
pitch: <p>When you go to a library, unless you know <em>exactly</em> what you're looking for, <strong>you just can't get around without asking for help</strong>, be it from the information desk or from a friend who you know has spent a lot of time around that technology, history or business section you're interested in.</p><p>Wouldn't it be great if you could do the same to <strong>find your way around the Internet</strong>? Now you can.</p>
+ sign_in_with_facebook: Sign in with Facebook
news_item:
answer:
topic:
1  config/locales/welcome/pt-BR.yml
View
@@ -26,6 +26,7 @@ pt-BR:
headline: "Finalmente, um balcão de informações para a Internet."
invitation_only: "Por enquanto, você precisa de um convite para conseguir se cadastrar."
pitch: "<p>Quando você vai à biblioteca, a não ser que você saiba <em>exatamente</em> o que está procurando, <strong>é impossível se encontrar sem pedir ajuda</strong>, seja no balcão de informações ou de um amigo que você sabe que conhece bem as prateleiras certas para o que você está procurando.</p><p><strong>Não ia ser ótimo se você pudesse fazer o mesmo na Internet?</strong> Agora você pode.</p>"
+ sign_in_with_facebook: Entrar com o Facebook
news_item:
answer:
topic:
8 config/routes.rb
View
@@ -96,9 +96,11 @@
post '/agreement' => 'agreement#update'
get '/agreement/refuse' => 'agreement#refuse', :as => :refuse_agreement
- match '/auth/:provider/callback' => 'settings/external_accounts#create'
+ match '/auth/:provider/callback' => 'auth_callback#callback'
match '/auth/dac' => 'affiliations#add_dac_student', :via => :post
- match '/auth/failure' => 'settings/external_accounts#failure'
+ match '/auth/failure' => 'auth_callback#failure'
+ match '/auth/signup_with_provider' => 'auth_callback#signup_with_provider'
+ match '/auth/sign_in_and_associate_provider' => 'auth_callback#sign_in_and_associate_provider', :via => :post
namespace :settings do
match 'profile' => 'profile#edit', :via => :get
@@ -116,7 +118,7 @@
match 'account' => 'account#update', :via => :put
match 'follow_topics' => 'follow_topics#edit', :via => :get
match 'ignore_topics' => 'ignore_topics#edit', :via => :get
- resources :external_accounts, :only => [:index, :destroy]
+ resources :external_accounts, :only => [:index, :destroy, :create]
end
resources :users, :except => [:edit, :update] do
5 experiments/answer_with_form_position.rb
View
@@ -1,5 +0,0 @@
-ab_test 'Answer with form position' do
- alternatives :below, :above
- metrics :new_search_result
- identify { |c| c.identify_vanity }
-end
4 experiments/inline_comment_helpers.rb
View
@@ -0,0 +1,4 @@
+ab_test 'Inline comment helpers' do
+ alternatives :none, :inline
+ metrics :clicked_search_result, :voted, :commented
+end
5 experiments/link_only_answer_form.rb
View
@@ -0,0 +1,5 @@
+ab_test 'Link only answer form' do
+ alternatives :full_answer_form, :link_only_answer_form
+ metrics :new_search_result
+ identify { |c| c.identify_vanity(:exclude_guests => true) }
+end
3  experiments/metrics/clicked_search_result.rb
View
@@ -0,0 +1,3 @@
+metric 'Clicked search result' do
+ description 'Tracks the influence of expriments on search result click'
+end
3  experiments/metrics/commented.rb
View
@@ -0,0 +1,3 @@
+metric 'Commented' do
+ description 'Tracks the influence of experiments in comments'
+end
3  experiments/metrics/search_results_news_items.rb
View
@@ -1,3 +0,0 @@
-metric 'News items search result' do
- description "Tracks the influence of showing answers' or search result s' news items"
-end
3  experiments/metrics/signed_up_action.rb
View
@@ -0,0 +1,3 @@
+metric 'Signed up action' do
+ description 'Tracks the influence of Facebook sign in'
+end
3  experiments/metrics/signup_method.rb