diff --git a/Gemfile b/Gemfile index af1d4a74..dd1e8e80 100644 --- a/Gemfile +++ b/Gemfile @@ -40,11 +40,15 @@ gem 'sinatra', require: false gem 'questiongenerator', git: 'https://github.com/justask/questiongenerator.git' +gem 'sanitize' +gem 'redcarpet' + # OmniAuth and providers gem 'omniauth' gem 'omniauth-twitter' gem 'foreman' +gem 'redis' group :development do gem 'spring' diff --git a/Gemfile.lock b/Gemfile.lock index c19e111c..73345c77 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,8 +1,8 @@ GIT remote: https://github.com/justask/questiongenerator.git - revision: 95bfac7b8e9157702befb5a6f7ea8220037fd804 + revision: 64d82a2b9de9df699fe5cf53bdfc90cb2bc3e771 specs: - questiongenerator (0.0.1) + questiongenerator (0.0.2) GEM remote: https://rubygems.org/ @@ -77,6 +77,7 @@ GEM coffee-script-source (1.8.0) colorize (0.7.5) connection_pool (2.1.0) + crass (1.0.1) daemons (1.1.9) database_cleaner (1.3.0) devise (3.4.1) @@ -152,6 +153,8 @@ GEM net-ssh (2.9.1) nokogiri (1.6.5) mini_portile (~> 0.6.0) + nokogumbo (1.2.0) + nokogiri nprogress-rails (0.1.6.3) oauth (0.4.7) omniauth (1.2.2) @@ -214,6 +217,7 @@ GEM rake (10.4.2) rdoc (4.2.0) json (~> 1.4) + redcarpet (3.2.2) redis (3.2.0) redis-namespace (1.5.1) redis (~> 3.0, >= 3.0.4) @@ -238,6 +242,10 @@ GEM rspec-support (3.0.4) ruby-progressbar (1.7.0) safe_yaml (1.0.4) + sanitize (3.1.0) + crass (~> 1.0.1) + nokogiri (>= 1.4.4) + nokogumbo (= 1.2.0) sass (3.2.19) sass-rails (4.0.5) railties (>= 4.0.0, < 5.0) @@ -352,8 +360,11 @@ DEPENDENCIES rails (= 4.1.8) rails-assets-growl rails_admin + redcarpet + redis rspec-rails (~> 3.0.0) ruby-progressbar + sanitize sass-rails (~> 4.0.3) sdoc (~> 0.4.1) sidekiq diff --git a/Rakefile b/Rakefile index 9634c893..fbbe217b 100644 --- a/Rakefile +++ b/Rakefile @@ -117,4 +117,91 @@ namespace :justask do puts "Purged #{destroyed_count} dead notifications." end + + desc "Fixes everything else" + task fix_db: :environment do + format = '%t (%c/%C) [%b>%i] %e' + destroyed_count = { + inbox: 0, + question: 0, + answer: 0, + smile: 0, + comment: 0 + } + + total = Inbox.count + progress = ProgressBar.create title: 'Processing inboxes', format: format, starting_at: 0, total: total + Inbox.all.each do |n| + if n.question.nil? + n.destroy + destroyed_count[:inbox] += 1 + end + progress.increment + end + + total = Question.count + progress = ProgressBar.create title: 'Processing questions', format: format, starting_at: 0, total: total + Question.all.each do |q| + if q.user.nil? + q.user_id = nil + q.author_is_anonymous = true + destroyed_count[:question] += 1 + end + progress.increment + end + + total = Answer.count + progress = ProgressBar.create title: 'Processing answers', format: format, starting_at: 0, total: total + Answer.all.each do |a| + if a.user.nil? or a.question.nil? + a.destroy + destroyed_count[:answer] += 1 + end + progress.increment + end + + total = Comment.count + progress = ProgressBar.create title: 'Processing comments', format: format, starting_at: 0, total: total + Comment.all.each do |c| + if c.user.nil? or c.answer.nil? + c.destroy + destroyed_count[:comment] += 1 + end + progress.increment + end + + puts "Purged #{destroyed_count[:inbox]} dead inbox entries." + puts "Marked #{destroyed_count[:question]} questions as anonymous." + puts "Purged #{destroyed_count[:answer]} dead answers." + puts "Purged #{destroyed_count[:answer]} dead comments." + end + + desc "Prints lonely people." + task loners: :environment do + people = {} + Question.all.each do |q| + if q.author_is_anonymous and q.author_name != 'justask' + q.answers.each do |a| + if q.user == a.user + people[q.user.screen_name] ||= 0 + people[q.user.screen_name] += 1 + puts "#{q.user.screen_name} -- answer id #{a.id}" + end + end + end + end + + max = 0 + res = [] + people.each { |k, v| max = v if v > max } + people.each { |k, v| res << k if v == max } + if res.length == 0 + puts "No one? I hope you're just on the development session." + else + puts res.length == 1 ? "And the winner is..." : "And the winners are..." + print "\033[5;31m" + res.each { |name| puts " - #{name}" } + print "\033[0m" + end + end end diff --git a/app/assets/javascripts/inbox.coffee b/app/assets/javascripts/inbox.coffee index 32abdec6..384c337b 100644 --- a/app/assets/javascripts/inbox.coffee +++ b/app/assets/javascripts/inbox.coffee @@ -42,7 +42,7 @@ complete: (jqxhr, status) -> btn.button "reset" if succ - btn.attr "disabled", "disabled" # this doesn't really work like I wanted it to… + btn.prop "disabled", true # this doesn't really work like I wanted it to… btn[0].dataset.ibCount = 0 diff --git a/app/controllers/ajax/inbox_controller.rb b/app/controllers/ajax/inbox_controller.rb index 21ff83dc..52b4ca8a 100644 --- a/app/controllers/ajax/inbox_controller.rb +++ b/app/controllers/ajax/inbox_controller.rb @@ -46,14 +46,8 @@ class Ajax::InboxController < ApplicationController return end - # sharing - begin - share_to = JSON.parse params[:share] - current_user.services.each do |service| - service.post(answer) if share_to.include? service.provider - end - rescue - end + services = JSON.parse params[:share] + ShareWorker.perform_async(current_user.id, answer.id, services) @status = :okay @message = "Successfully answered question." diff --git a/app/helpers/markdown_helper.rb b/app/helpers/markdown_helper.rb new file mode 100644 index 00000000..169900e5 --- /dev/null +++ b/app/helpers/markdown_helper.rb @@ -0,0 +1,21 @@ +module MarkdownHelper + + def markdown(content) + md = Redcarpet::Markdown.new(FlavoredMarkdown, + filter_html: true, + escape_html: true, + no_images: true, + no_styles: true, + safe_links_only: true, + xhtml: false, + hard_wrap: true, + no_intra_emphasis: true, + tables: true, + fenced_code_blocks: true, + autolink: true, + disable_indented_code_blocks: true, + strikethrough: true, + superscript: true) + Sanitize.fragment(md.render(content), EVIL_TAGS).html_safe + end +end \ No newline at end of file diff --git a/app/models/question.rb b/app/models/question.rb index 740d59d6..aed4ec91 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -1,6 +1,7 @@ class Question < ActiveRecord::Base belongs_to :user has_many :answers + has_many :inboxes, dependent: :destroy validates :content, length: { maximum: 255 } diff --git a/app/models/services/twitter.rb b/app/models/services/twitter.rb index 04ea97ce..b8b33d47 100644 --- a/app/models/services/twitter.rb +++ b/app/models/services/twitter.rb @@ -22,7 +22,7 @@ class Services::Twitter < Service end def post_tweet(answer) - client.update prepare_tweet(answer) + client.update! prepare_tweet(answer) end def prepare_tweet(answer) @@ -35,7 +35,7 @@ class Services::Twitter < Service host: APP_CONFIG['hostname'], protocol: (APP_CONFIG['https'] ? :https : :http) ) - "#{question_content[0..55]}#{'…' if question_content.length > 56}" \ + "#{question_content[0..54]}#{'…' if question_content.length > 55}" \ " — #{answer_content[0..55]}#{'…' if answer_content.length > 56} #{answer_url}" end end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index dcb17ad9..50e21918 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -19,9 +19,9 @@ class User < ActiveRecord::Base dependent: :destroy has_many :friends, through: :active_relationships, source: :target has_many :followers, through: :passive_relationships, source: :source - has_many :smiles - has_many :services - has_many :notifications, foreign_key: :recipient_id + has_many :smiles, dependent: :destroy + has_many :services, dependent: :destroy + has_many :notifications, foreign_key: :recipient_id, dependent: :destroy has_many :reports, dependent: :destroy SCREEN_NAME_REGEX = /\A[a-zA-Z0-9_]{1,16}\z/ @@ -126,14 +126,4 @@ class User < ActiveRecord::Base increment! :commented_count answer.increment! :comment_count end - - # @return [Boolean] is the user a moderator? - def mod? - return true if self.moderator? or self.admin? - false - end - - def report(object) - Report.create(type: "Reports::#{object.class}", target_id: object.id, user_id: self.id) - end end diff --git a/app/services/flavored_markdown.rb b/app/services/flavored_markdown.rb new file mode 100644 index 00000000..e88f0453 --- /dev/null +++ b/app/services/flavored_markdown.rb @@ -0,0 +1,26 @@ +class FlavoredMarkdown < Redcarpet::Render::HTML + include Rails.application.routes.url_helpers + + def preprocess(text) + wrap_mentions(text) + end + + def wrap_mentions(text) + text.gsub! /(^|\s)(@\w+)/ do + "#{$1}[#{$2}](#{show_user_profile_path $2.tr('@', '')})" + end + text + end + + def header(text, _header_level) + paragraph text + end + + def paragraph(text) + "
#{text}
" + end + + def raw_html(raw_html) + Rack::Utils.escape_html raw_html + end +end \ No newline at end of file diff --git a/app/views/shared/_answerbox.html.haml b/app/views/shared/_answerbox.html.haml index 8a53cdaa..fc24adae 100644 --- a/app/views/shared/_answerbox.html.haml +++ b/app/views/shared/_answerbox.html.haml @@ -23,16 +23,15 @@ %p.answerbox--question-text = a.question.content .panel-body - %p - - if @display_all.nil? - = a.content[0..255] - - if a.content.length > 255 - [...] - %p - %a.btn.btn-primary{href: show_user_answer_path(a.user.screen_name, a.id)} - Read the entire answer - - else - = a.content + - if @display_all.nil? + = markdown a.content[0..255] + - if a.content.length > 255 + [...] + %p + %a.btn.btn-primary{href: show_user_answer_path(a.user.screen_name, a.id)} + Read the entire answer + - else + = markdown a.content - if @user.nil? .row .col-md-6.col-sm-4.col-xs-7.text-left.text-muted diff --git a/app/workers/share_worker.rb b/app/workers/share_worker.rb index 079baaee..e607919b 100644 --- a/app/workers/share_worker.rb +++ b/app/workers/share_worker.rb @@ -3,7 +3,16 @@ class ShareWorker sidekiq_options queue: :share - def perform(answer_id) - # fuck this… for now + # @param user_id [Integer] the user id + # @param answer_id [Integer] the user id + # @param services [Array] array containing strings + def perform(user_id, answer_id, services) + User.find(user_id).services.each do |service| + begin + service.post(Answer.find(answer_id)) if services.include? service.provider + rescue => e + Rails.logger.error "failed to post answer #{answer_id} to #{service.provider} for user #{user_id}: #{e.message}" + end + end end end \ No newline at end of file diff --git a/config/initializers/sanitize.rb b/config/initializers/sanitize.rb new file mode 100644 index 00000000..d6a4ffa9 --- /dev/null +++ b/config/initializers/sanitize.rb @@ -0,0 +1,9 @@ +EVIL_TAGS = { + elements: %w(blockquote a p i strong em del pre code table tr td th br ul ol li hr), + attributes: { + 'a' => %w(href) + }, + protocols: { + 'a' => { 'href' => ['http', 'https', :relative] } + } +} \ No newline at end of file