From 0cf68e271439025d51d1147145c1c0f14d214226 Mon Sep 17 00:00:00 2001 From: Dan Neumann Date: Fri, 8 Feb 2013 01:56:12 -0600 Subject: [PATCH 01/14] Extracted default value initializers. --- lib/discourse_plugin_registry.rb | 32 ++++++++++++------- .../discourse_plugin_registry_spec.rb | 21 ++++++++++++ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/lib/discourse_plugin_registry.rb b/lib/discourse_plugin_registry.rb index a56862a67e9..8f7abca4c8d 100644 --- a/lib/discourse_plugin_registry.rb +++ b/lib/discourse_plugin_registry.rb @@ -9,10 +9,21 @@ class DiscoursePluginRegistry attr_accessor :stylesheets end - def register_js(filename, options={}) - self.class.javascripts ||= Set.new - self.class.server_side_javascripts ||= Set.new + # Default accessor values + # + def self.stylesheets + @stylesheets ||= Set.new + end + + def self.javascripts + @javascripts ||= Set.new + end + + def self.server_side_javascripts + @server_side_javascripts ||= Set.new + end + def register_js(filename, options={}) # If we have a server side option, add that too. self.class.server_side_javascripts << options[:server_side] if options[:server_side].present? @@ -20,12 +31,11 @@ class DiscoursePluginRegistry end def register_css(filename) - self.class.stylesheets ||= Set.new self.class.stylesheets << filename end def stylesheets - self.class.stylesheets || Set.new + self.class.stylesheets end def register_archetype(name, options={}) @@ -33,17 +43,17 @@ class DiscoursePluginRegistry end def server_side_javascripts - self.class.javascripts || Set.new + self.class.javascripts end def javascripts - self.class.javascripts || Set.new + self.class.javascripts end def self.clear - self.stylesheets = Set.new - self.server_side_javascripts = Set.new - self.javascripts = Set.new + self.stylesheets = nil + self.server_side_javascripts = nil + self.javascripts = nil end def self.setup(plugin_class) @@ -52,6 +62,4 @@ class DiscoursePluginRegistry plugin.setup end - - end diff --git a/spec/components/discourse_plugin_registry_spec.rb b/spec/components/discourse_plugin_registry_spec.rb index fe064e6bced..ea2ad312ca5 100644 --- a/spec/components/discourse_plugin_registry_spec.rb +++ b/spec/components/discourse_plugin_registry_spec.rb @@ -4,6 +4,27 @@ require 'discourse_plugin_registry' describe DiscoursePluginRegistry do let(:registry) { DiscoursePluginRegistry.new } + + context '#stylesheets' do + it 'defaults to an empty Set' do + DiscoursePluginRegistry.stylesheets = nil + DiscoursePluginRegistry.stylesheets.should == Set.new + end + end + + context '#javascripts' do + it 'defaults to an empty Set' do + DiscoursePluginRegistry.javascripts = nil + DiscoursePluginRegistry.javascripts.should == Set.new + end + end + + context '#server_side_javascripts' do + it 'defaults to an empty Set' do + DiscoursePluginRegistry.server_side_javascripts = nil + DiscoursePluginRegistry.server_side_javascripts.should == Set.new + end + end context '.register_css' do before do From 37fb2ddb6b1806d2c8f4e44625670d1656600c62 Mon Sep 17 00:00:00 2001 From: Charles Roper Date: Sun, 10 Feb 2013 08:44:58 +0000 Subject: [PATCH 02/14] Update DEVELOPMENT.md Add missing `git clone` command. --- DEVELOPMENT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index e590127d13d..6b2d7e687d3 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -10,7 +10,7 @@ on Discourse with: 1. Install VirtualBox: https://www.virtualbox.org/wiki/Downloads 2. Install Vagrant: https://www.vagrantup.com/ 3. Open a terminal -4. Clone the project: `git@github.com:discourse/discourse.git` +4. Clone the project: `git clone git@github.com:discourse/discourse.git` 5. Enter the project directory: `cd discourse` ### Using Vagrant From b7a76cbd2484f1c40a071e7ad8237db7e6d9925e Mon Sep 17 00:00:00 2001 From: Edward Ocampo-Gooding Date: Mon, 11 Feb 2013 01:03:21 -0500 Subject: [PATCH 03/14] Consistency in SQL style --- lib/search.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/search.rb b/lib/search.rb index e91486da791..b6ebf70de52 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -100,7 +100,7 @@ module Search db_result = [] [user_query_sql, category_query_sql, topic_query_sql].each do |sql| - sql << " limit " << Search.per_facet.to_s + sql << " LIMIT " << Search.per_facet.to_s db_result += ActiveRecord::Base.exec_sql(sql , query: terms.join(" & ")).to_a end end @@ -109,12 +109,14 @@ module Search expected_topics = 0 expected_topics = Search.facets.size unless type_filter.present? - expected_topics = Search.per_facet * Search.facets.size if type_filter == 'topic' + expected_topics = Search.per_facet * Search.facets.size if type_filter == 'topic' + if expected_topics > 0 db_result.each do |row| expected_topics -= 1 if row['type'] == 'topic' end end + if expected_topics > 0 tmp = ActiveRecord::Base.exec_sql "#{post_query_sql} limit :per_facet", query: terms.join(" & "), per_facet: expected_topics * 3 @@ -134,11 +136,9 @@ module Search db_result += tmp[0..expected_topics-1] end - # Group the results by type grouped = {} db_result.each do |row| - type = row.delete('type') # Add the slug for topics From 240a290422ea7ddab84f8da40b411f5531d8be3a Mon Sep 17 00:00:00 2001 From: Chris Bell Date: Mon, 11 Feb 2013 12:08:50 +0000 Subject: [PATCH 04/14] Fix 1px button cut off on topic progress up / down buttons. --- app/assets/stylesheets/application/topic.css.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/application/topic.css.scss b/app/assets/stylesheets/application/topic.css.scss index a63f9235393..6b5a30472e8 100644 --- a/app/assets/stylesheets/application/topic.css.scss +++ b/app/assets/stylesheets/application/topic.css.scss @@ -387,7 +387,7 @@ kbd { z-index: 1; } button { - padding: 0; + padding: 0 1px; cursor: pointer; z-index: 1000; position: absolute; From ecbaa45736d929d2e52b9b5051d7785f1af31f57 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Mon, 11 Feb 2013 16:14:44 -0800 Subject: [PATCH 05/14] remove extraneous text on PM summary --- .../templates/topic_summary/private_message.js.handlebars | 1 - config/locales/en.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/app/assets/javascripts/discourse/templates/topic_summary/private_message.js.handlebars b/app/assets/javascripts/discourse/templates/topic_summary/private_message.js.handlebars index b61798b62ad..550f7118f91 100644 --- a/app/assets/javascripts/discourse/templates/topic_summary/private_message.js.handlebars +++ b/app/assets/javascripts/discourse/templates/topic_summary/private_message.js.handlebars @@ -1,5 +1,4 @@

{{i18n private_message_info.title}}

-

{{{i18n private_message_info.description}}}

{{#each content.allowed_users}}
diff --git a/config/locales/en.yml b/config/locales/en.yml index 114e3241cee..e6a0203b993 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -596,7 +596,6 @@ en: private_message_info: title: "Private Conversation" - description: "Participants in this private conversation" invite: "Invite Others..." email: 'Email' From 9daf53df730c93c1732ca70e41cbe0dbbf993738 Mon Sep 17 00:00:00 2001 From: Dan Neumann Date: Mon, 11 Feb 2013 20:34:38 -0600 Subject: [PATCH 06/14] lean on Inflector transliteration --- lib/slug.rb | 11 ++++------- spec/components/slug_spec.rb | 6 ++++++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/slug.rb b/lib/slug.rb index c4fe8fdfb0f..13dc53033eb 100644 --- a/lib/slug.rb +++ b/lib/slug.rb @@ -11,14 +11,11 @@ module Slug str.gsub!(/^\s+|\s+$/, '') str.downcase! - from = "àáäâèéëêìíïîòóöôùúüûñç·/_,:;." - to = "aaaaeeeeiiiioooouuuunc-------" + # The characters we want to replace with a hyphen + str.tr!("·/_,:;.", "\-") - idx = 0 - from.each_char do |c| - str.gsub!(c, to[idx]) - idx += 1 - end + # Convert to ASCII or remove if transliteration is unknown. + str = ActiveSupport::Inflector.transliterate(str, '') str.gsub!(/[^a-z0-9 -]/, '') str.gsub!(/\s+/, '-') diff --git a/spec/components/slug_spec.rb b/spec/components/slug_spec.rb index fde5ebd8e33..1390103cd3a 100644 --- a/spec/components/slug_spec.rb +++ b/spec/components/slug_spec.rb @@ -35,5 +35,11 @@ describe Slug do Slug.for("...hello").should == "hello" end + it 'handles our initial transliteration' do + from = "àáäâčďèéëěêìíïîľĺňòóöôŕřšťůùúüûýžñç" + to = "aaaacdeeeeeiiiillnoooorrstuuuuuyznc" + Slug.for(from).should == to + end + end From 50cf8cd4d56c1c7f42f6622975abbada4908db78 Mon Sep 17 00:00:00 2001 From: Dan Neumann Date: Mon, 11 Feb 2013 20:36:54 -0600 Subject: [PATCH 07/14] Set up slug.rb for obvious method extractions. --- lib/slug.rb | 16 ++++++++++------ spec/components/slug_spec.rb | 2 -- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/slug.rb b/lib/slug.rb index 13dc53033eb..86025079c5f 100644 --- a/lib/slug.rb +++ b/lib/slug.rb @@ -6,20 +6,24 @@ module Slug def self.for(string) - - str = string.dup - str.gsub!(/^\s+|\s+$/, '') - str.downcase! - + str = string.dup.strip.downcase + # The characters we want to replace with a hyphen str.tr!("·/_,:;.", "\-") # Convert to ASCII or remove if transliteration is unknown. str = ActiveSupport::Inflector.transliterate(str, '') - + + # Remove everything except alphanumberic, space, and hyphen characters. str.gsub!(/[^a-z0-9 -]/, '') + + # Replace multiple spaces with one hyphen. str.gsub!(/\s+/, '-') + + # Replace multiple hyphens with one hyphen. str.gsub!(/\-+/, '-') + + # Remove leading and trailing hyphens str.gsub!(/^-|-$/, '') str diff --git a/spec/components/slug_spec.rb b/spec/components/slug_spec.rb index 1390103cd3a..44bd1177e8c 100644 --- a/spec/components/slug_spec.rb +++ b/spec/components/slug_spec.rb @@ -1,12 +1,10 @@ # encoding: utf-8 require 'spec_helper' - require 'slug' describe Slug do - it 'replaces spaces with hyphens' do Slug.for("hello world").should == 'hello-world' end From 260935045799abd351ca6f904ddbe748ba269a39 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Tue, 12 Feb 2013 13:44:44 +1100 Subject: [PATCH 08/14] sample bluepill config --- config/discourse.pill.sample | 89 ++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 config/discourse.pill.sample diff --git a/config/discourse.pill.sample b/config/discourse.pill.sample new file mode 100644 index 00000000000..9b8165d73b4 --- /dev/null +++ b/config/discourse.pill.sample @@ -0,0 +1,89 @@ +rails_env = ENV['RAILS_ENV'] || "production" +rails_root = ENV['RAILS_ROOT'] || "/var/rails/my_discourse" + +user = ENV["DISCOURSE_USER"] || ENV['USER'] || 'user_running_app' +group = ENV["DISCOURSE_GROUP"] || ENV['GROUP'] || 'www-data' +num_webs = ENV["NUM_WEBS"].to_i > 0 ? ENV["NUM_WEBS"].to_i : 4 + +# to debug use +#Bluepill.application("your_app", :foreground => true) do |app| +Bluepill.application("your_app") do |app| + + app.gid = group + app.uid = user + + # getting this to work was a nightmare + # bundle exec spawns a process totally messing with the demonize option + # so we suck the environment out and set it up first + app.environment = `env -i BUNDLE_GEMFILE=#{rails_root}/Gemfile /usr/local/rvm/bin/bootup_bundle exec env`.lines.inject({}) do |env_hash,l| + kv = l.chomp.split('=',2) + env_hash[kv[0]] = kv[1] + env_hash + end if File.exist?("/usr/local/rvm/bin/rvm") + + app.environment ||= {} + app.environment['RAILS_ENV'] = rails_env + + app.gid = group + app.uid = user + + app.working_dir = rails_root + num_webs.times do |i| + app.process("thin-#{i}") do |process| + process.start_command = "bundle exec thin start -e production -t 0 -p #{9040 + i} -P #{rails_root}/tmp/pids/thin#{i}.pid -d" + process.pid_file = "#{rails_root}/tmp/pids/thin#{i}.pid" + process.start_grace_time = 30.seconds + process.stop_grace_time = 10.seconds + process.restart_grace_time = 10.seconds + process.group = "thins" + process.uid = user + process.gid = group + process.daemonize = false + process.stdout = process.stderr = "#{rails_root}/log/thin#{i}.log" + end + end + +#debug instance + app.process("thin-debug") do |process| + process.start_command = "bundle exec thin start -e development -t 0 -p 10040 -P #{rails_root}/tmp/pids/thin-debug.pid -d" + process.pid_file = "#{rails_root}/tmp/pids/thin-debug.pid" + process.start_grace_time = 30.seconds + process.stop_grace_time = 10.seconds + process.restart_grace_time = 10.seconds + process.group = "thins" + process.uid = user + process.gid = group + process.daemonize = false + process.stdout = process.stderr = "#{rails_root}/log/thin-debug.log" + end + + app.process("sidekiq-worker") do |process| + pidfile = "#{rails_root}/tmp/pids/sidekiq-worker.pid" + + process.start_command = "/usr/bin/env PIDFILE=#{pidfile} RAILS_ENV=#{rails_env} bundle exec sidekiq" + process.pid_file = pidfile + process.start_grace_time = 30.seconds + process.stop_grace_time = 10.seconds + process.restart_grace_time = 10.seconds + process.uid = user + process.gid = group + process.daemonize = true + end + + if `hostname`.strip == "host to run on" + app.process("clockwork") do |process| + pidfile = "#{rails_root}/tmp/pids/clockwork.pid" + + process.start_command = "/usr/bin/env RAILS_ENV=#{rails_env} bundle exec clockwork config/clock.rb" + process.pid_file = pidfile + process.start_grace_time = 30.seconds + process.stop_grace_time = 10.seconds + process.restart_grace_time = 10.seconds + process.uid = user + process.gid = group + process.daemonize = true + end + end + +end + From 2b276bc2c8e7a2264176426d9e3ac12d56b14020 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Tue, 12 Feb 2013 13:45:08 +1100 Subject: [PATCH 09/14] gist oneboxer issues --- lib/oneboxer/gist_onebox.rb | 8 +------- spec/components/oneboxer/gist_onebox_spec.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) create mode 100644 spec/components/oneboxer/gist_onebox_spec.rb diff --git a/lib/oneboxer/gist_onebox.rb b/lib/oneboxer/gist_onebox.rb index d64f05474ab..a3f63cb8638 100644 --- a/lib/oneboxer/gist_onebox.rb +++ b/lib/oneboxer/gist_onebox.rb @@ -7,22 +7,16 @@ module Oneboxer favicon 'github.png' def translate_url - m = @url.match(/gist\.github\.com\/(?[0-9a-f]+)/mi) + m = @url.match(/gist\.github\.com\/([^\/]+\/)?(?[0-9a-f]+)/mi) return "https://api.github.com/gists/#{m[:id]}" if m - @url end def parse(data) - parsed = JSON.parse(data) - result = {files: [], title: parsed['description']} - parsed['files'].each do |filename, attrs| result[:files] << {filename: filename}.merge!(attrs) end - - result end diff --git a/spec/components/oneboxer/gist_onebox_spec.rb b/spec/components/oneboxer/gist_onebox_spec.rb new file mode 100644 index 00000000000..9a8bf5fd4a3 --- /dev/null +++ b/spec/components/oneboxer/gist_onebox_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' +require 'oneboxer' +require 'oneboxer/gist_onebox' + +describe Oneboxer::GistOnebox do + it "does not trip on user names" do + o = Oneboxer::GistOnebox.new('https://gist.github.com/aaa/4599619') + o.translate_url.should == 'https://api.github.com/gists/4599619' + end + + it "works for old school urls too" do + o = Oneboxer::GistOnebox.new('https://gist.github.com/4599619') + o.translate_url.should == 'https://api.github.com/gists/4599619' + end +end + From 878fcd2c613fe5c8e095f86979f27cabfc0d830d Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Tue, 12 Feb 2013 15:06:34 +1100 Subject: [PATCH 10/14] sketchy logo, so our techincolor logo is not sprawled across the web leading to confusion --- app/assets/images/d-logo-sketch-small.png | Bin 0 -> 7008 bytes app/assets/images/d-logo-sketch.png | Bin 0 -> 16505 bytes app/models/site_setting.rb | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 app/assets/images/d-logo-sketch-small.png create mode 100755 app/assets/images/d-logo-sketch.png diff --git a/app/assets/images/d-logo-sketch-small.png b/app/assets/images/d-logo-sketch-small.png new file mode 100644 index 0000000000000000000000000000000000000000..3467f147f559bd9a656af20bee122c040462d073 GIT binary patch literal 7008 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 literal 0 HcmV?d00001 diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb index 37ec0810eab..708c15d0c98 100644 --- a/app/models/site_setting.rb +++ b/app/models/site_setting.rb @@ -10,8 +10,8 @@ class SiteSetting < ActiveRecord::Base # settings available in javascript under Discourse.SiteSettings client_setting(:title, "Discourse") - client_setting(:logo_url, '/assets/logo.png') - client_setting(:logo_small_url, '') + client_setting(:logo_url, '/assets/d-logo-sketch.png') + client_setting(:logo_small_url, '/assets/d-logo-sketch-small.png') client_setting(:traditional_markdown_linebreaks, false) client_setting(:popup_delay, 1500) client_setting(:top_menu, 'popular|new|unread|favorited|categories') From 818b84f02ce489f90b3119e9c3c062dde7a654d9 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Tue, 12 Feb 2013 15:17:33 +1100 Subject: [PATCH 11/14] we are using structure.sql having this around only causes confusion --- db/schema.rb | 514 --------------------------------------------------- 1 file changed, 514 deletions(-) delete mode 100644 db/schema.rb diff --git a/db/schema.rb b/db/schema.rb deleted file mode 100644 index 929afd1e0df..00000000000 --- a/db/schema.rb +++ /dev/null @@ -1,514 +0,0 @@ -# encoding: UTF-8 -# This file is auto-generated from the current state of the database. Instead -# of editing this file, please use the migrations feature of Active Record to -# incrementally modify your database, and then regenerate this schema definition. -# -# Note that this schema.rb definition is the authoritative source for your -# database schema. If you need to create the application database on another -# system, you should be using db:schema:load, not running all the migrations -# from scratch. The latter is a flawed and unsustainable approach (the more migrations -# you'll amass, the slower it'll run and the greater likelihood for issues). -# -# It's strongly recommended to check this file into your version control system. - -ActiveRecord::Schema.define(:version => 20130205021905) do - - create_table "categories", :force => true do |t| - t.string "name", :limit => 50, :null => false - t.string "color", :limit => 6, :default => "AB9364", :null => false - t.integer "topic_id" - t.integer "top1_topic_id" - t.integer "top2_topic_id" - t.integer "top1_user_id" - t.integer "top2_user_id" - t.integer "topic_count", :default => 0, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "user_id", :null => false - t.integer "topics_year" - t.integer "topics_month" - t.integer "topics_week" - t.string "slug", :null => false - end - - add_index "categories", ["name"], :name => "index_categories_on_name", :unique => true - add_index "categories", ["topic_count"], :name => "index_categories_on_forum_thread_count" - - create_table "categories_search", :id => false, :force => true do |t| - t.integer "id", :null => false - t.tsvector "search_data" - end - - add_index "categories_search", ["search_data"], :name => "idx_search_category" - - create_table "category_featured_topics", :id => false, :force => true do |t| - t.integer "category_id", :null => false - t.integer "topic_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "category_featured_topics", ["category_id", "topic_id"], :name => "cat_featured_threads", :unique => true - - create_table "category_featured_users", :force => true do |t| - t.integer "category_id" - t.integer "user_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "category_featured_users", ["category_id", "user_id"], :name => "index_category_featured_users_on_category_id_and_user_id", :unique => true - - create_table "draft_sequences", :force => true do |t| - t.integer "user_id", :null => false - t.string "draft_key", :null => false - t.integer "sequence", :null => false - end - - add_index "draft_sequences", ["user_id", "draft_key"], :name => "index_draft_sequences_on_user_id_and_draft_key", :unique => true - - create_table "drafts", :force => true do |t| - t.integer "user_id", :null => false - t.string "draft_key", :null => false - t.text "data", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "sequence", :default => 0, :null => false - end - - add_index "drafts", ["user_id", "draft_key"], :name => "index_drafts_on_user_id_and_draft_key" - - create_table "email_logs", :force => true do |t| - t.string "to_address", :null => false - t.string "email_type", :null => false - t.integer "user_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "email_logs", ["created_at"], :name => "index_email_logs_on_created_at", :order => {"created_at"=>:desc} - add_index "email_logs", ["user_id", "created_at"], :name => "index_email_logs_on_user_id_and_created_at", :order => {"created_at"=>:desc} - - create_table "email_tokens", :force => true do |t| - t.integer "user_id", :null => false - t.string "email", :null => false - t.string "token", :null => false - t.boolean "confirmed", :default => false, :null => false - t.boolean "expired", :default => false, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "email_tokens", ["token"], :name => "index_email_tokens_on_token", :unique => true - - create_table "facebook_user_infos", :force => true do |t| - t.integer "user_id", :null => false - t.integer "facebook_user_id", :limit => 8, :null => false - t.string "username", :null => false - t.string "first_name" - t.string "last_name" - t.string "email" - t.string "gender" - t.string "name" - t.string "link" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "facebook_user_infos", ["facebook_user_id"], :name => "index_facebook_user_infos_on_facebook_user_id", :unique => true - add_index "facebook_user_infos", ["user_id"], :name => "index_facebook_user_infos_on_user_id", :unique => true - - create_table "incoming_links", :force => true do |t| - t.string "url", :limit => 1000, :null => false - t.string "referer", :limit => 1000, :null => false - t.string "domain", :limit => 100, :null => false - t.integer "topic_id" - t.integer "post_number" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "incoming_links", ["topic_id", "post_number"], :name => "incoming_index" - - create_table "invites", :force => true do |t| - t.string "invite_key", :limit => 32, :null => false - t.string "email", :null => false - t.integer "invited_by_id", :null => false - t.integer "user_id" - t.datetime "redeemed_at" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.datetime "deleted_at" - end - - add_index "invites", ["email", "invited_by_id"], :name => "index_invites_on_email_and_invited_by_id", :unique => true - add_index "invites", ["invite_key"], :name => "index_invites_on_invite_key", :unique => true - - create_table "message_bus", :force => true do |t| - t.string "name" - t.string "context" - t.text "data" - t.datetime "created_at" - end - - add_index "message_bus", ["created_at"], :name => "index_message_bus_on_created_at" - - create_table "notifications", :force => true do |t| - t.integer "notification_type", :null => false - t.integer "user_id", :null => false - t.string "data", :null => false - t.boolean "read", :default => false, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "topic_id" - t.integer "post_number" - t.integer "post_action_id" - end - - add_index "notifications", ["post_action_id"], :name => "index_notifications_on_post_action_id" - add_index "notifications", ["user_id", "created_at"], :name => "index_notifications_on_user_id_and_created_at" - - create_table "onebox_renders", :force => true do |t| - t.string "url", :null => false - t.text "cooked", :null => false - t.datetime "expires_at", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.text "preview" - end - - add_index "onebox_renders", ["url"], :name => "index_onebox_renders_on_url", :unique => true - - create_table "post_action_types", :force => true do |t| - t.string "name_key", :limit => 50, :null => false - t.boolean "is_flag", :default => false, :null => false - t.string "icon", :limit => 20 - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "position", :default => 0, :null => false - end - - create_table "post_actions", :force => true do |t| - t.integer "post_id", :null => false - t.integer "user_id", :null => false - t.integer "post_action_type_id", :null => false - t.datetime "deleted_at" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "deleted_by" - t.text "message" - end - - add_index "post_actions", ["post_id"], :name => "index_post_actions_on_post_id" - add_index "post_actions", ["user_id", "post_action_type_id", "post_id", "deleted_at"], :name => "idx_unique_actions", :unique => true - - create_table "post_onebox_renders", :id => false, :force => true do |t| - t.integer "post_id", :null => false - t.integer "onebox_render_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "post_onebox_renders", ["post_id", "onebox_render_id"], :name => "index_post_onebox_renders_on_post_id_and_onebox_render_id", :unique => true - - create_table "post_replies", :id => false, :force => true do |t| - t.integer "post_id" - t.integer "reply_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "post_replies", ["post_id", "reply_id"], :name => "index_post_replies_on_post_id_and_reply_id", :unique => true - - create_table "post_timings", :id => false, :force => true do |t| - t.integer "topic_id", :null => false - t.integer "post_number", :null => false - t.integer "user_id", :null => false - t.integer "msecs", :null => false - end - - add_index "post_timings", ["topic_id", "post_number", "user_id"], :name => "post_timings_unique", :unique => true - add_index "post_timings", ["topic_id", "post_number"], :name => "post_timings_summary" - - create_table "posts", :force => true do |t| - t.integer "user_id", :null => false - t.integer "topic_id", :null => false - t.integer "post_number", :null => false - t.text "raw", :null => false - t.text "cooked", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "reply_to_post_number" - t.integer "cached_version", :default => 1, :null => false - t.integer "reply_count", :default => 0, :null => false - t.integer "quote_count", :default => 0, :null => false - t.integer "reply_below_post_number" - t.datetime "deleted_at" - t.integer "off_topic_count", :default => 0, :null => false - t.integer "like_count", :default => 0, :null => false - t.integer "incoming_link_count", :default => 0, :null => false - t.integer "bookmark_count", :default => 0, :null => false - t.integer "avg_time" - t.float "score" - t.integer "reads", :default => 0, :null => false - t.integer "post_type", :default => 1, :null => false - t.integer "vote_count", :default => 0, :null => false - t.integer "sort_order" - t.integer "last_editor_id" - t.boolean "hidden", :default => false, :null => false - t.integer "hidden_reason_id" - t.integer "custom_flag_count", :default => 0, :null => false - t.integer "spam_count", :default => 0, :null => false - t.integer "illegal_count", :default => 0, :null => false - t.integer "inappropriate_count", :default => 0, :null => false - t.datetime "last_version_at", :null => false - end - - add_index "posts", ["reply_to_post_number"], :name => "index_posts_on_reply_to_post_number" - add_index "posts", ["topic_id", "post_number"], :name => "index_posts_on_topic_id_and_post_number", :unique => true - - create_table "posts_search", :id => false, :force => true do |t| - t.integer "id", :null => false - t.tsvector "search_data" - end - - add_index "posts_search", ["search_data"], :name => "idx_search_post" - - create_table "site_customizations", :force => true do |t| - t.string "name", :null => false - t.text "stylesheet" - t.text "header" - t.integer "position", :null => false - t.integer "user_id", :null => false - t.boolean "enabled", :null => false - t.string "key", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.boolean "override_default_style", :default => false, :null => false - t.text "stylesheet_baked", :default => "", :null => false - end - - add_index "site_customizations", ["key"], :name => "index_site_customizations_on_key" - - create_table "site_settings", :force => true do |t| - t.string "name", :null => false - t.integer "data_type", :null => false - t.text "value" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - create_table "topic_allowed_users", :force => true do |t| - t.integer "user_id", :null => false - t.integer "topic_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "topic_allowed_users", ["topic_id", "user_id"], :name => "index_topic_allowed_users_on_topic_id_and_user_id", :unique => true - add_index "topic_allowed_users", ["user_id", "topic_id"], :name => "index_topic_allowed_users_on_user_id_and_topic_id", :unique => true - - create_table "topic_invites", :force => true do |t| - t.integer "topic_id", :null => false - t.integer "invite_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "topic_invites", ["invite_id"], :name => "index_topic_invites_on_invite_id" - add_index "topic_invites", ["topic_id", "invite_id"], :name => "index_topic_invites_on_topic_id_and_invite_id", :unique => true - - create_table "topic_link_clicks", :force => true do |t| - t.integer "topic_link_id", :null => false - t.integer "user_id" - t.integer "ip", :limit => 8, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "topic_link_clicks", ["topic_link_id"], :name => "index_forum_thread_link_clicks_on_forum_thread_link_id" - - create_table "topic_links", :force => true do |t| - t.integer "topic_id", :null => false - t.integer "post_id" - t.integer "user_id", :null => false - t.string "url", :limit => 500, :null => false - t.string "domain", :limit => 100, :null => false - t.boolean "internal", :default => false, :null => false - t.integer "link_topic_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.boolean "reflection", :default => false - t.integer "clicks", :default => 0, :null => false - t.integer "link_post_id" - end - - add_index "topic_links", ["topic_id", "post_id", "url"], :name => "index_forum_thread_links_on_forum_thread_id_and_post_id_and_url", :unique => true - add_index "topic_links", ["topic_id"], :name => "index_forum_thread_links_on_forum_thread_id" - - create_table "topic_users", :id => false, :force => true do |t| - t.integer "user_id", :null => false - t.integer "topic_id", :null => false - t.boolean "starred", :default => false, :null => false - t.boolean "posted", :default => false, :null => false - t.integer "last_read_post_number" - t.integer "seen_post_count" - t.datetime "starred_at" - t.datetime "last_visited_at" - t.datetime "first_visited_at" - t.integer "notification_level", :default => 1, :null => false - t.datetime "notifications_changed_at" - t.integer "notifications_reason_id" - t.integer "total_msecs_viewed", :default => 0, :null => false - end - - add_index "topic_users", ["topic_id", "user_id"], :name => "index_forum_thread_users_on_forum_thread_id_and_user_id", :unique => true - -# Could not dump table "topics" because of following StandardError -# Unknown type 'hstore' for column 'meta_data' - - create_table "twitter_user_infos", :force => true do |t| - t.integer "user_id", :null => false - t.string "screen_name", :null => false - t.integer "twitter_user_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "twitter_user_infos", ["twitter_user_id"], :name => "index_twitter_user_infos_on_twitter_user_id", :unique => true - add_index "twitter_user_infos", ["user_id"], :name => "index_twitter_user_infos_on_user_id", :unique => true - - create_table "uploads", :force => true do |t| - t.integer "user_id", :null => false - t.integer "topic_id", :null => false - t.string "original_filename", :null => false - t.integer "filesize", :null => false - t.integer "width" - t.integer "height" - t.string "url", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "uploads", ["topic_id"], :name => "index_uploads_on_forum_thread_id" - add_index "uploads", ["user_id"], :name => "index_uploads_on_user_id" - - create_table "user_actions", :force => true do |t| - t.integer "action_type", :null => false - t.integer "user_id", :null => false - t.integer "target_topic_id" - t.integer "target_post_id" - t.integer "target_user_id" - t.integer "acting_user_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "user_actions", ["acting_user_id"], :name => "index_actions_on_acting_user_id" - add_index "user_actions", ["action_type", "user_id", "target_topic_id", "target_post_id", "acting_user_id"], :name => "idx_unique_rows", :unique => true - add_index "user_actions", ["user_id", "action_type"], :name => "index_actions_on_user_id_and_action_type" - - create_table "user_open_ids", :force => true do |t| - t.integer "user_id", :null => false - t.string "email", :null => false - t.string "url", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.boolean "active", :null => false - end - - add_index "user_open_ids", ["url"], :name => "index_user_open_ids_on_url" - - create_table "user_visits", :force => true do |t| - t.integer "user_id", :null => false - t.date "visited_at", :null => false - end - - add_index "user_visits", ["user_id", "visited_at"], :name => "index_user_visits_on_user_id_and_visited_at", :unique => true - - create_table "users", :force => true do |t| - t.string "username", :limit => 20, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.string "name" - t.text "bio_raw" - t.integer "seen_notification_id", :default => 0, :null => false - t.datetime "last_posted_at" - t.string "email", :limit => 256, :null => false - t.string "password_hash", :limit => 64 - t.string "salt", :limit => 32 - t.boolean "active" - t.string "username_lower", :limit => 20, :null => false - t.string "auth_token", :limit => 32 - t.datetime "last_seen_at" - t.string "website" - t.boolean "admin", :default => false, :null => false - t.datetime "last_emailed_at" - t.boolean "email_digests", :default => true, :null => false - t.integer "trust_level", :null => false - t.text "bio_cooked" - t.boolean "email_private_messages", :default => true - t.boolean "email_direct", :default => true, :null => false - t.boolean "approved", :default => false, :null => false - t.integer "approved_by_id" - t.datetime "approved_at" - t.integer "topics_entered", :default => 0, :null => false - t.integer "posts_read_count", :default => 0, :null => false - t.integer "digest_after_days", :default => 7, :null => false - t.datetime "previous_visit_at" - t.datetime "banned_at" - t.datetime "banned_till" - t.date "date_of_birth" - t.integer "auto_track_topics_after_msecs" - t.integer "views", :default => 0, :null => false - t.integer "flag_level", :default => 0, :null => false - t.integer "time_read", :default => 0, :null => false - t.integer "days_visited", :default => 0, :null => false - t.string "ip_address", :limit => nil - end - - add_index "users", ["auth_token"], :name => "index_users_on_auth_token" - add_index "users", ["email"], :name => "index_users_on_email", :unique => true - add_index "users", ["last_posted_at"], :name => "index_users_on_last_posted_at" - add_index "users", ["username"], :name => "index_users_on_username", :unique => true - add_index "users", ["username_lower"], :name => "index_users_on_username_lower", :unique => true - - create_table "users_search", :id => false, :force => true do |t| - t.integer "id", :null => false - t.tsvector "search_data" - end - - add_index "users_search", ["search_data"], :name => "idx_search_user" - - create_table "versions", :force => true do |t| - t.integer "versioned_id" - t.string "versioned_type" - t.integer "user_id" - t.string "user_type" - t.string "user_name" - t.text "modifications" - t.integer "number" - t.integer "reverted_from" - t.string "tag" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "versions", ["created_at"], :name => "index_versions_on_created_at" - add_index "versions", ["number"], :name => "index_versions_on_number" - add_index "versions", ["tag"], :name => "index_versions_on_tag" - add_index "versions", ["user_id", "user_type"], :name => "index_versions_on_user_id_and_user_type" - add_index "versions", ["user_name"], :name => "index_versions_on_user_name" - add_index "versions", ["versioned_id", "versioned_type"], :name => "index_versions_on_versioned_id_and_versioned_type" - - create_table "views", :id => false, :force => true do |t| - t.integer "parent_id", :null => false - t.string "parent_type", :limit => 50, :null => false - t.integer "ip", :limit => 8, :null => false - t.date "viewed_at", :null => false - t.integer "user_id" - end - - add_index "views", ["parent_id", "parent_type"], :name => "index_views_on_parent_id_and_parent_type" - -end From bdba0a78c49295ed1a7ab7e2a585002034bf5fa9 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Tue, 12 Feb 2013 18:01:38 +1100 Subject: [PATCH 12/14] scaffolding for message bus diags --- vendor/gems/message_bus/lib/message_bus.rb | 18 +++++++--- .../lib/message_bus/rack/diagnostics.rb | 35 +++++++++++++++++++ .../lib/message_bus/rack/middleware.rb | 5 +++ .../message_bus/spec/lib/middleware_spec.rb | 15 ++++++-- 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 vendor/gems/message_bus/lib/message_bus/rack/diagnostics.rb diff --git a/vendor/gems/message_bus/lib/message_bus.rb b/vendor/gems/message_bus/lib/message_bus.rb index 7b3fefc09df..514e6f2001b 100644 --- a/vendor/gems/message_bus/lib/message_bus.rb +++ b/vendor/gems/message_bus/lib/message_bus.rb @@ -10,6 +10,7 @@ require "message_bus/client" require "message_bus/connection_manager" require "message_bus/message_handler" require "message_bus/rack/middleware" +require "message_bus/rack/diagnostics" # we still need to take care of the logger if defined?(::Rails) @@ -71,19 +72,28 @@ module MessageBus::Implementation end def site_id_lookup(&blk) - @site_id_lookup ||= blk + @site_id_lookup = blk if blk + @site_id_lookup end def user_id_lookup(&blk) - @user_id_lookup ||= blk + @user_id_lookup = blk if blk + @user_id_lookup + end + + def is_admin_lookup(&blk) + @is_admin_lookup = blk if blk + @is_admin_lookup end def on_connect(&blk) - @on_connect ||= blk + @on_connect = blk if blk + @on_connect end def on_disconnect(&blk) - @on_disconnect ||= blk + @on_disconnect = blk if blk + @on_disconnect end def allow_broadcast=(val) diff --git a/vendor/gems/message_bus/lib/message_bus/rack/diagnostics.rb b/vendor/gems/message_bus/lib/message_bus/rack/diagnostics.rb new file mode 100644 index 00000000000..09426227884 --- /dev/null +++ b/vendor/gems/message_bus/lib/message_bus/rack/diagnostics.rb @@ -0,0 +1,35 @@ +module MessageBus::Rack; end + +class MessageBus::Rack::Diagnostics + def initialize(app, config = {}) + @app = app + end + + def index + html = < + + + +

Message Bus Diags

+ + +HTML + return [200, {"content-type" => "text/html;"}, html] + end + + def call(env) + + return @app.call(env) unless env['PATH_INFO'].start_with? '/message-bus/_diagnostics' + + route = env['PATH_INFO'].split('/message_bus/_diagnostics')[1] + + if MessageBus.is_admin_lookup.nil? || !MessageBus.is_admin_lookup.call + return [403, {}, ["not allowed"]] + end + + return index unless route + + return [404, {}, ["not found"]] + end +end diff --git a/vendor/gems/message_bus/lib/message_bus/rack/middleware.rb b/vendor/gems/message_bus/lib/message_bus/rack/middleware.rb index 7f9e0ec402f..f240266a4f0 100644 --- a/vendor/gems/message_bus/lib/message_bus/rack/middleware.rb +++ b/vendor/gems/message_bus/lib/message_bus/rack/middleware.rb @@ -46,6 +46,11 @@ class MessageBus::Rack::Middleware return [200,{"Content-Type" => "text/html"},["sent"]] end + if env['PATH_INFO'].start_with? '/message-bus/_diagnostics' + diags = MessageBus::Rack::Diagnostics.new(@app) + return diags.call(env) + end + client_id = env['PATH_INFO'].split("/")[2] return [404, {}, ["not found"]] unless client_id diff --git a/vendor/gems/message_bus/spec/lib/middleware_spec.rb b/vendor/gems/message_bus/spec/lib/middleware_spec.rb index 1d7bd279797..65306cf5c65 100644 --- a/vendor/gems/message_bus/spec/lib/middleware_spec.rb +++ b/vendor/gems/message_bus/spec/lib/middleware_spec.rb @@ -107,11 +107,22 @@ describe MessageBus::Rack::Middleware do ensure MessageBus.long_polling_interval = 5000 end - - end end + describe "diagnostics" do + + it "should return a 403 if a user attempts to get at the _diagnostics path" do + get "/message-bus/_diagnostics" + last_response.status.should == 403 + end + + it "should get a 200 with html for an authorized user" do + MessageBus.stub(:is_admin_lookup).and_return(lambda{ true }) + get "/message-bus/_diagnostics" + last_response.status.should == 200 + end + end describe "polling" do before do From 99526c33da63ca90a8ad40064b166da9c9f5fbdf Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Tue, 12 Feb 2013 18:43:48 +1100 Subject: [PATCH 13/14] emoji should not be coupled into the core avatars were being counted and should not have been for basic users --- app/models/post.rb | 15 +++++++++++++-- spec/models/post_spec.rb | 11 ++++++++--- .../discourse_emoji/lib/discourse_emoji/engine.rb | 3 ++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index 496224570c3..b97aa40af49 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -115,10 +115,21 @@ class Post < ActiveRecord::Base self.cooked = nil end + def self.white_listed_image_classes + @white_listed_image_classes ||= ['avatar'] + end + def image_count return 0 unless self.raw.present? - cooked_document.search("img.emoji").remove - cooked_document.search("img").count + + cooked_document.search("img").reject{ |t| + dom_class = t["class"] + if dom_class + (Post.white_listed_image_classes & dom_class.split(" ")).count > 0 + else + false + end + }.count end def link_count diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index 88c943ec0ca..146a51599f8 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -86,7 +86,8 @@ describe Post do let(:post_no_images) { Fabricate.build(:post, post_args) } let(:post_one_image) { Fabricate.build(:post, post_args.merge(raw: "![sherlock](http://bbc.co.uk/sherlock.jpg)")) } let(:post_two_images) { Fabricate.build(:post, post_args.merge(raw: " ")) } - let(:post_with_emoticons) { Fabricate.build(:post, post_args.merge(raw: 'smiley wink')) } + let(:post_with_avatars) { Fabricate.build(:post, post_args.merge(raw: 'smiley wink')) } + let(:post_with_two_classy_images) { Fabricate.build(:post, post_args.merge(raw: " ")) } it "returns 0 images for an empty post" do Fabricate.build(:post).image_count.should == 0 @@ -100,10 +101,14 @@ describe Post do post_two_images.image_count.should == 2 end - it "doesn't count emoticons as images" do - post_with_emoticons.image_count.should == 0 + it "doesn't count avatars as images" do + post_with_avatars.image_count.should == 0 end + it "doesn't count whitelisted images" do + Post.stubs(:white_listed_image_classes).returns(["classy"]) + post_with_two_classy_images.image_count.should == 0 + end context "validation" do it "allows a new user to make a post with one image" do diff --git a/vendor/gems/discourse_emoji/lib/discourse_emoji/engine.rb b/vendor/gems/discourse_emoji/lib/discourse_emoji/engine.rb index 3944406a357..5caafd703d2 100644 --- a/vendor/gems/discourse_emoji/lib/discourse_emoji/engine.rb +++ b/vendor/gems/discourse_emoji/lib/discourse_emoji/engine.rb @@ -9,8 +9,9 @@ module DiscourseEmoji app.config.after_initialize do DiscoursePluginRegistry.setup(DiscourseEmoji::Plugin) + Post.white_listed_image_classes << "emoji" end end end -end \ No newline at end of file +end From 925925817fb67abe510a61a344ecc48d48fd40ac Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Tue, 12 Feb 2013 18:49:57 +1100 Subject: [PATCH 14/14] remove old buggy code see: http://meta.discourse.org/t/quoted-you-emails/2226/3 notify by display name is silly, display name is not unique in the system --- app/models/post_alert_observer.rb | 2 +- spec/models/post_alert_observer_spec.rb | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/app/models/post_alert_observer.rb b/app/models/post_alert_observer.rb index 2fb9164546e..08112cb58cf 100644 --- a/app/models/post_alert_observer.rb +++ b/app/models/post_alert_observer.rb @@ -101,7 +101,7 @@ class PostAlertObserver < ActiveRecord::Observer result = [] post.raw.scan(/\[quote=\"([^,]+),.+\"\]/).uniq.each do |m| username = m.first.strip.downcase - user = User.where("(LOWER(username_lower) = :username or LOWER(name) = :username) and id != :id", username: username, id: post.user_id).first + user = User.where("username_lower = :username and id != :id", username: username, id: post.user_id).first result << user if user.present? end result diff --git a/spec/models/post_alert_observer_spec.rb b/spec/models/post_alert_observer_spec.rb index 7b6ad2cf35c..0daed2202c3 100644 --- a/spec/models/post_alert_observer_spec.rb +++ b/spec/models/post_alert_observer_spec.rb @@ -37,11 +37,6 @@ describe PostAlertObserver do context 'quotes' do - it 'notifies a user by display username' do - lambda { - Fabricate(:post, raw: '[quote="Evil Trout, post:1"]whatup[/quote]') - }.should change(evil_trout.notifications, :count).by(1) - end it 'notifies a user by username' do lambda {