Merge remote-tracking branch 'origin/master'

This commit is contained in:
Andreas N 2015-01-04 23:09:42 +01:00
commit a26b9e0a49
28 changed files with 274 additions and 91 deletions

View File

@ -20,6 +20,7 @@ gem 'bcrypt', '~> 3.1.7'
gem 'haml'
gem 'bootstrap-sass', '~> 3.2.0.1'
gem 'bootswatch-rails'
gem 'sweetalert-rails'
gem 'will_paginate'
gem 'will_paginate-bootstrap'
gem 'http_accept_language'

View File

@ -298,6 +298,8 @@ GEM
colorize (>= 0.7.0)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
sweetalert-rails (0.3.3)
railties (>= 3.1.0)
thin (1.6.3)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0)
@ -387,6 +389,7 @@ DEPENDENCIES
simplecov
sinatra
spring
sweetalert-rails
thin
turbolinks
twitter

View File

@ -1,8 +1,16 @@
$(document).on "click", "a[data-action=ab-comment-destroy]", (ev) ->
ev.preventDefault()
if confirm 'Are you sure?'
btn = $(this)
cid = btn[0].dataset.cId
btn = $(this)
cid = btn[0].dataset.cId
swal
title: "Really delete?"
text: "You will not be able to recover this comment."
type: "warning"
showCancelButton: true
confirmButtonColor: "#DD6B55"
confirmButtonText: "Delete"
closeOnConfirm: true
, ->
$.ajax
url: '/ajax/destroy_comment'
type: 'POST'

View File

@ -1,8 +1,16 @@
$(document).on "click", "a[data-action=ab-comment-report]", (ev) ->
ev.preventDefault()
if confirm 'Are you sure you want to report this comment?'
btn = $(this)
cid = btn[0].dataset.cId
btn = $(this)
cid = btn[0].dataset.cId
swal
title: "Really report?"
text: "A moderator will review this comment and decide what happens."
type: "warning"
showCancelButton: true
confirmButtonColor: "#DD6B55"
confirmButtonText: "Report"
closeOnConfirm: true
, ->
$.ajax
url: '/ajax/report'
type: 'POST'

View File

@ -1,8 +1,16 @@
$(document).on "click", "a[data-action=ab-destroy]", (ev) ->
ev.preventDefault()
if confirm 'Are you sure?'
btn = $(this)
aid = btn[0].dataset.aId
btn = $(this)
aid = btn[0].dataset.aId
swal
title: "Really delete?"
text: "The question will be moved back to your inbox."
type: "warning"
showCancelButton: true
confirmButtonColor: "#DD6B55"
confirmButtonText: "Delete"
closeOnConfirm: true
, ->
$.ajax
url: '/ajax/destroy_answer' # TODO: find a way to use rake routes instead of hardcoding them here
type: 'POST'

View File

@ -1,8 +1,16 @@
$(document).on "click", "a[data-action=ab-report]", (ev) ->
ev.preventDefault()
if confirm 'Are you sure you want to report this answer?'
btn = $(this)
aid = btn[0].dataset.aId
btn = $(this)
aid = btn[0].dataset.aId
swal
title: "Really report?"
text: "A moderator will review this answer and decide what happens."
type: "warning"
showCancelButton: true
confirmButtonColor: "#DD6B55"
confirmButtonText: "Report"
closeOnConfirm: true
, ->
$.ajax
url: '/ajax/report' # TODO: find a way to use rake routes instead of hardcoding them here
type: 'POST'

View File

@ -8,6 +8,7 @@
#= require growl
#= require cheet
#= require jquery.guillotine
#= require sweet-alert
#= require_tree .
NProgress.configure
@ -24,3 +25,9 @@ window.showNotification = (text, success=true) ->
$(document).on "click", "button#create-account", ->
Turbolinks.visit "/sign_up"
_ready = ->
sweetAlertInitialize()
$(document).ready _ready
$(document).on 'page:load', _ready

View File

@ -22,7 +22,15 @@
($ document).on "click", "button#ib-delete-all", ->
btn = ($ this)
count = btn[0].dataset.ibCount
if confirm "Really delete #{count} questions?"
swal
title: "Really delete #{count} questions?"
text: "They will be gone forever."
type: "warning"
showCancelButton: true
confirmButtonColor: "#DD6B55"
confirmButtonText: "Delete"
closeOnConfirm: true
, ->
btn.button "loading"
succ = no
$.ajax
@ -85,8 +93,16 @@ $(document).on "click", "button[name=ib-answer]", ->
$(document).on "click", "button[name=ib-destroy]", ->
if confirm 'Are you sure?'
btn = $(this)
btn = $(this)
swal
title: "Really delete?"
text: "This question will be gone forever."
type: "warning"
showCancelButton: true
confirmButtonColor: "#DD6B55"
confirmButtonText: "Delete"
closeOnConfirm: true
, ->
btn.button "loading"
iid = btn[0].dataset.ibId
$("textarea[name=ib-answer][data-id=#{iid}]").attr "readonly", "readonly"

View File

@ -68,9 +68,17 @@ $(document).on "input", "input[name=mod-comment-new]", (evt) ->
# destroy
$(document).on "click", "a[data-action=mod-comment-destroy]", (ev) ->
ev.preventDefault()
if confirm 'Are you sure?'
btn = $(this)
cid = btn[0].dataset.id
btn = $(this)
cid = btn[0].dataset.id
swal
title: "Really delete?"
text: "You will not be able to recover this comment."
type: "warning"
showCancelButton: true
confirmButtonColor: "#DD6B55"
confirmButtonText: "Delete"
closeOnConfirm: true
, ->
$.ajax
url: '/ajax/mod/destroy_comment'
type: 'POST'

View File

@ -1,7 +1,15 @@
$(document).on "click", "button[name=mod-delete-report]", ->
if confirm 'Are you sure?'
btn = $(this)
id = btn[0].dataset.id
btn = $(this)
id = btn[0].dataset.id
swal
title: "Really delete?"
text: "You will not be able to recover this report."
type: "warning"
showCancelButton: true
confirmButtonColor: "#DD6B55"
confirmButtonText: "Delete"
closeOnConfirm: true
, ->
$.ajax
url: '/ajax/mod/destroy_report'
type: 'POST'

View File

@ -2,14 +2,14 @@ $(document).on "keydown", "textarea#q-answer", (evt) ->
qid = $(this)[0].dataset.id
if evt.keyCode == 13 and evt.ctrlKey
# trigger warning:
$("button#q-answer[data-q-id=#{qid}]").trigger 'click'
$("button#q-answer").trigger 'click'
$(document).on "click", "button#q-answer", ->
btn = $(this)
btn.button "loading"
qid = btn[0].dataset.qId
$("textarea#q-answer[data-q=#{qid}]").attr "readonly", "readonly"
$("textarea#q-answer").attr "readonly", "readonly"
shareTo = []
($ "input[type=checkbox][name=share][data-q-id=#{qid}]:checked").each (i, share) ->
@ -27,12 +27,11 @@ $(document).on "click", "button#q-answer", ->
success: (data, status, jqxhr) ->
if data.success
$("div#q-answer-box").slideUp()
# TODO:
# ($ "div#q-answer-box").prepend data.render
($ "div#answers").prepend data.render
showNotification data.message, data.success
error: (jqxhr, status, error) ->
console.log jqxhr, status, error
showNotification "An error occurred, a developer should check the console for details", false
complete: (jqxhr, status) ->
btn.button "reset"
$("textarea#q-answer[data-id=#{qid}]").removeAttr "readonly"
$("textarea#q-answer").removeAttr "readonly"

View File

@ -50,7 +50,16 @@ $(document).on "click", "a[data-action=report-user]", (ev) ->
ev.preventDefault()
btn = $(this)
target = btn[0].dataset.target
if confirm "Are you sure you want to report #{target}?"
swal
title: "Really report #{target}?"
text: "A moderator will review this user and decide what happens."
type: "warning"
showCancelButton: true
confirmButtonColor: "#DD6B55"
confirmButtonText: "Report"
closeOnConfirm: true
, ->
$.ajax
url: '/ajax/report'
type: 'POST'

View File

@ -2,6 +2,7 @@
*= require rails_bootstrap_forms
*= require growl
*= require jquery.guillotine
*= require sweet-alert
*= require_self
*/

View File

@ -69,4 +69,8 @@ body {
.j2-up {
text-transform: uppercase;
}
.sweet-overlay {
z-index: 1031;
}

View File

@ -18,6 +18,13 @@ class Ajax::AnswerController < ApplicationController
end
else
question = Question.find(params[:id])
unless question.user.privacy_allow_stranger_answers
@status = :privacy_stronk
@message = "This user does not want other users to answer their question."
@success = false
return
end
end
answer = nil
@ -38,10 +45,14 @@ class Ajax::AnswerController < ApplicationController
services = JSON.parse params[:share]
ShareWorker.perform_async(current_user.id, answer.id, services)
@status = :okay
@message = "Successfully answered question."
@success = true
@render = render_to_string(partial: 'shared/answerbox', locals: { a: answer, show_question: false }) unless inbox
unless inbox
@question = 1
@render = render_to_string(partial: 'shared/answerbox', locals: { a: answer, show_question: false })
end
end
def destroy

View File

@ -2,7 +2,7 @@ class PublicController < ApplicationController
before_filter :authenticate_user!
def index
@timeline = Answer.all.reverse_order.paginate(page: params[:page])
@timeline = Answer.joins(:user).where(users: { privacy_allow_public_timeline: true }).all.reverse_order.paginate(page: params[:page])
respond_to do |format|
format.html
format.js

View File

@ -1,6 +1,10 @@
class QuestionController < ApplicationController
def show
@question = Question.find(params[:id])
@answers = @question.answers.reverse_order
@answers = @question.answers.reverse_order.paginate(page: params[:page])
respond_to do |format|
format.html
format.js
end
end
end

View File

@ -1,5 +1,5 @@
class UserController < ApplicationController
before_filter :authenticate_user!, only: %w(edit update)
before_filter :authenticate_user!, only: %w(edit update edit_privacy update_privacy)
def show
@user = User.where('LOWER(screen_name) = ?', params[:username].downcase).first!
@ -10,6 +10,7 @@ class UserController < ApplicationController
end
end
# region Account settings
def edit
end
@ -25,6 +26,25 @@ class UserController < ApplicationController
end
redirect_to edit_user_profile_path
end
# endregion
# region Privacy settings
def edit_privacy
end
def update_privacy
user_attributes = params.require(:user).permit(:privacy_allow_anonymous_questions,
:privacy_allow_public_timeline,
:privacy_allow_stranger_answers,
:privacy_show_in_search)
if current_user.update_attributes(user_attributes)
flash[:success] = 'Your privacy settings have been updated!'
else
flash[:error] = 'An error occurred. ;_;'
end
redirect_to edit_user_privacy_path
end
# endregion
def followers
@title = 'Followers'

View File

@ -5,6 +5,8 @@ class Answer < ActiveRecord::Base
has_many :smiles, dependent: :destroy
after_create do
Inbox.where(user: self.user, question: self.question).destroy_all
Notification.notify self.question.user, self unless self.question.author_is_anonymous
self.user.increment! :answered_count
self.question.increment! :answer_count

View File

@ -2,6 +2,10 @@ class Inbox < ActiveRecord::Base
belongs_to :user
belongs_to :question
before_create do
raise "User does not want to receive anonymous questions" if self.question.author_is_anonymous and !self.user.privacy_allow_anonymous_questions?
end
def answer(answer_content, user)
answer = user.answer(self.question, answer_content)
self.destroy

View File

@ -14,7 +14,17 @@
ago
%p.answerbox--question-text= @question.content
- if user_signed_in? and !current_user.answered? @question
#answers
- @answers.each do |a|
= render 'shared/answerbox', a: a, show_question: false
#pagination= will_paginate @answers, renderer: BootstrapPagination::Rails, page_links: false
- if @answers.next_page
%button#load-more-btn.btn.btn-default{type: :button, data: { current_page: @answers.current_page }}
Load more
- if user_signed_in? and !current_user.answered? @question and current_user != @question.user and @question.user.privacy_allow_stranger_answers
.panel.panel-default#q-answer-box
.panel-heading
%h3.panel-title This question was not in your inbox? Answer it here!
@ -27,8 +37,4 @@
%label
%input{type: 'checkbox', name: 'share', checked: :checked, data: { q_id: @question.id, service: service.provider }}
Post to
= service.provider.capitalize
- @answers.each do |a|
= render 'shared/answerbox', a: a, show_question: false
= service.provider.capitalize

View File

@ -0,0 +1,8 @@
$('#answers').append('<% @answers.each do |answer|
%><%= j render 'shared/answerbox', a: answer, show_question: false
%><% end %>');
<% if @answers.next_page %>
$('#pagination').html('<%= j will_paginate @answers, renderer: BootstrapPagination::Rails, page_links: false %>');
<% else %>
$('#pagination, #load-more-btn').remove();
<% end %>

View File

@ -6,41 +6,47 @@
- else
= @user.motivation_header
.panel-body
#question-box
.row
.col-xs-12
%textarea.form-control{:name => "qb-question", :placeholder => "Type your question here…"}
.row{:style => "padding-top: 5px; padding-left: 5px; padding-right: 5px;"}
.col-xs-6
- if user_signed_in? # and @user.allow_anonymous
%input{:name => "qb-anonymous", :type => "checkbox"}/
Hide your name
%br/
.col-xs-6
%p.pull-right
%input{name: 'qb-to', type: 'hidden', :value => @user.id}/
%button.btn.btn-primary{name: 'qb-ask', :type => "button", data: {loading_text: 'Asking...', promote: user_signed_in? ? "false" : "true" }} Ask
- if user_signed_in? or @user.privacy_allow_anonymous_questions?
#question-box
.row
.col-xs-12
%textarea.form-control{:name => "qb-question", :placeholder => "Type your question here…"}
.row{:style => "padding-top: 5px; padding-left: 5px; padding-right: 5px;"}
.col-xs-6
- if user_signed_in?
- if @user.privacy_allow_anonymous_questions?
%input{:name => "qb-anonymous", :type => "checkbox"}/
Hide your name
%br/
- else
%input{:name => "qb-anonymous", :type => "hidden", :value => "false"}/
.col-xs-6
%p.pull-right
%input{name: 'qb-to', type: 'hidden', :value => @user.id}/
%button.btn.btn-primary{name: 'qb-ask', :type => "button", data: {loading_text: 'Asking...', promote: user_signed_in? ? "false" : "true" }} Ask
- unless user_signed_in?
#question-box-promote.row{:style => "display: none;"}
.row
.col-xs-12.text-center
%strong Your question has been sent.
.row
.col-sm-1
.col-sm-5
%button#create-account.btn.btn-block.btn-primary Create an account
.col-sm-5
%button#new-question.btn.btn-block.btn-default Ask another question
.col-sm-1
.row
.col-sm-1
.col-xs-12.col-sm-10
%small
Join
= APP_CONFIG['site_name']
today! You'll be able to follow and ask people you know and a lot more.
.col-sm-1
/ %p
/ This user does not want to get asked by strangers. Why don't you
/ = succeed "?" do
/ %a{:href => "{{ url_for('register') }}"} sign up
- if @user.privacy_allow_anonymous_questions?
#question-box-promote.row{:style => "display: none;"}
.row
.col-xs-12.text-center
%strong Your question has been sent.
.row
.col-sm-1
.col-sm-5
%button#create-account.btn.btn-block.btn-primary Create an account
.col-sm-5
%button#new-question.btn.btn-block.btn-default Ask another question
.col-sm-1
.row
.col-sm-1
.col-xs-12.col-sm-10
%small
Join
= APP_CONFIG['site_name']
today! You'll be able to follow and ask people you know and a lot more.
.col-sm-1
- else
%p
This user does not want to get asked by strangers. Why don't you
= succeed "?" do
%a{:href => "{{ url_for('register') }}"} sign up

View File

@ -4,6 +4,8 @@
%ul.nav.nav-pills.nav-stacked
= nav_entry "Account", edit_user_registration_path
= nav_entry "Profile", edit_user_profile_path
= nav_entry "Privacy", edit_user_privacy_path
= nav_entry "Sharing", services_path
.hidden-xs= render "shared/links"

View File

@ -0,0 +1,13 @@
.container.j2-page
= render 'settings_tabs'
.col-md-9.col-xs-12.col-sm-9
= render 'layouts/messages'
.panel.panel-default
.panel-body
= bootstrap_form_for(current_user, url: {action: "edit_privacy"}, method: "patch") do |f|
= f.check_box :privacy_allow_anonymous_questions, label: "Allow anonymous questions"
= f.check_box :privacy_allow_public_timeline, label: "Show your answers in the public timeline"
= f.check_box :privacy_allow_stranger_answers, label: "Allow other people to answer your questions"
= f.submit "Save settings", class: 'btn btn-primary'

View File

@ -57,6 +57,9 @@ Rails.application.routes.draw do
end
end
match '/settings/privacy', to: 'user#edit_privacy', via: :get, as: :edit_user_privacy
match '/settings/privacy', to: 'user#update_privacy', via: :patch, as: :update_user_privacy
namespace :ajax do
match '/ask', to: 'question#create', via: :post, as: :ask
match '/generate_question', to: 'inbox#create', via: :post, as: :generate_question

View File

@ -0,0 +1,12 @@
class AddPrivacyOptionsToUsers < ActiveRecord::Migration
def change
%i{
privacy_allow_anonymous_questions
privacy_allow_public_timeline
privacy_allow_stranger_answers
privacy_show_in_search
}.each do |sym|
add_column :users, sym, :boolean, default: true
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: 20150102231343) do
ActiveRecord::Schema.define(version: 20150103200732) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -133,12 +133,12 @@ ActiveRecord::Schema.define(version: 20150102231343) do
add_index "smiles", ["user_id"], name: "index_smiles_on_user_id", using: :btree
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
@ -146,19 +146,19 @@ ActiveRecord::Schema.define(version: 20150102231343) do
t.datetime "created_at"
t.datetime "updated_at"
t.string "screen_name"
t.integer "friend_count", default: 0, null: false
t.integer "follower_count", default: 0, null: false
t.integer "asked_count", default: 0, null: false
t.integer "answered_count", default: 0, null: false
t.integer "commented_count", default: 0, null: false
t.integer "friend_count", default: 0, null: false
t.integer "follower_count", default: 0, null: false
t.integer "asked_count", default: 0, null: false
t.integer "answered_count", default: 0, null: false
t.integer "commented_count", default: 0, null: false
t.string "display_name"
t.integer "smiled_count", default: 0, null: false
t.boolean "admin", default: false, null: false
t.string "motivation_header", default: "", null: false
t.string "website", default: "", null: false
t.string "location", default: "", null: false
t.text "bio", default: "", null: false
t.boolean "moderator", default: false, null: false
t.integer "smiled_count", default: 0, null: false
t.boolean "admin", default: false, null: false
t.string "motivation_header", default: "", null: false
t.string "website", default: "", null: false
t.string "location", default: "", null: false
t.text "bio", default: "", null: false
t.boolean "moderator", default: false, null: false
t.string "profile_picture_file_name"
t.string "profile_picture_content_type"
t.integer "profile_picture_file_size"
@ -168,7 +168,11 @@ ActiveRecord::Schema.define(version: 20150102231343) do
t.integer "crop_y"
t.integer "crop_w"
t.integer "crop_h"
t.boolean "supporter", default: false
t.boolean "supporter", default: false
t.boolean "privacy_allow_anonymous_questions", default: true
t.boolean "privacy_allow_public_timeline", default: true
t.boolean "privacy_allow_stranger_answers", default: true
t.boolean "privacy_show_in_search", default: true
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree