mirror of
https://github.com/discourse/discourse.git
synced 2025-03-20 02:56:41 +08:00
Merge branch 'master' of github.com:discourse/discourse
This commit is contained in:
commit
37fa61ab51
@ -129,7 +129,6 @@ window.Discourse.ComposerController = Ember.Controller.extend Discourse.Presence
|
||||
click: ->
|
||||
if @get('content.composeState') == Discourse.Composer.DRAFT
|
||||
@set('content.composeState', Discourse.Composer.OPEN)
|
||||
false
|
||||
|
||||
shrink: ->
|
||||
if @get('content.reply') == @get('content.originalText') then @close() else @collapse()
|
||||
|
@ -60,12 +60,13 @@ Handlebars.registerHelper 'avatar', (user, options) ->
|
||||
user = Ember.Handlebars.get(this, user, options) if typeof user is 'string'
|
||||
username = Em.get(user, 'username')
|
||||
username ||= Em.get(user, options.hash.usernamePath)
|
||||
title = Em.get(user, 'title') || Em.get(user, 'description') unless options.hash.ignoreTitle
|
||||
|
||||
new Handlebars.SafeString Discourse.Utilities.avatarImg(
|
||||
size: options.hash.imageSize
|
||||
extraClasses: Em.get(user, 'extras') || options.hash.extraClasses
|
||||
username: username
|
||||
title: Em.get(user, 'title') || Em.get(user, 'description') || username
|
||||
title: title || username
|
||||
avatarTemplate: Ember.get(user, 'avatar_template') || options.hash.avatarTemplate
|
||||
)
|
||||
|
||||
@ -125,4 +126,9 @@ Handlebars.registerHelper 'date', (property, options) ->
|
||||
|
||||
new Handlebars.SafeString("<span class='date' title='#{fullReadable}'>#{displayDate}</span>")
|
||||
|
||||
|
||||
Handlebars.registerHelper 'personalizedName', (property, options) ->
|
||||
name = Ember.Handlebars.get(this, property, options);
|
||||
username = Ember.Handlebars.get(this, options.hash.usernamePath, options) if options.hash.usernamePath
|
||||
|
||||
return name unless username == Discourse.get('currentUser.username')
|
||||
return Em.String.i18n('you')
|
||||
|
@ -2,11 +2,12 @@
|
||||
{{#collection contentBinding="stream" itemClass="item"}}
|
||||
{{#with view.content}}
|
||||
<div class='clearfix info'>
|
||||
<a href="/users/{{unbound username}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar this imageSize="large" extraClasses="actor" avatarTemplatePath="avatar_template"}}</div></a>
|
||||
<a href="/users/{{unbound username}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar this imageSize="large" extraClasses="actor" avatarTemplatePath="avatar_template" ignoreTitle="true"}}</div></a>
|
||||
<span class='time'>{{date path="created_at" leaveAgo="true"}}</span>
|
||||
<a class='name' href="{{unbound postUrl}}">{{unbound name}}</a><br>
|
||||
<a class="title" href="{{unbound postUrl}}">{{unbound title}}</a><br>
|
||||
<a class='name' href="/users/{{unbound username}}">{{personalizedName name usernamePath="username"}}</a>
|
||||
<span class='type'>{{unbound description}}</span>
|
||||
<span class='title'><span class="post-number">#{{unbound post_number}}</span> <a href="{{unbound postUrl}}">{{unbound title}}</a></span>
|
||||
<a class="post-number" href="{{unbound postUrl}}">#{{unbound post_number}}</a>
|
||||
</div>
|
||||
<p class='excerpt'>
|
||||
{{{unbound excerpt}}}
|
||||
|
@ -129,7 +129,7 @@ window.Discourse.ComposerView = window.Discourse.View.extend
|
||||
Discourse.UserSearch.search
|
||||
term: term,
|
||||
callback: callback,
|
||||
exclude: selected
|
||||
exclude: selected.concat [Discourse.get('currentUser.username')]
|
||||
onChangeItems: (items) =>
|
||||
items = $.map items, (i) -> if i.username then i.username else i
|
||||
@set('content.targetUsernames', items.join(","))
|
||||
|
@ -347,7 +347,7 @@
|
||||
}
|
||||
}
|
||||
.reply-to-tab {
|
||||
z-index: 999;
|
||||
z-index: 980;
|
||||
font-size: 12px;
|
||||
color: $darkish_gray;
|
||||
display: block;
|
||||
|
@ -241,10 +241,6 @@
|
||||
color: lighten($black, 30%);
|
||||
}
|
||||
.item {
|
||||
.post-number {
|
||||
color: lighten($black, 40%);
|
||||
margin-right: 4px;
|
||||
}
|
||||
padding: 10px 8px;
|
||||
background-color: white;
|
||||
border: 1px solid #b9b9b9;
|
||||
@ -266,7 +262,7 @@
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.name {
|
||||
.title {
|
||||
display: inline-block;
|
||||
margin-bottom: 4px;
|
||||
font-size: 14px;
|
||||
|
@ -1419,7 +1419,7 @@ body {
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
:-moz-placeholder {
|
||||
color: #999999;
|
||||
color: #999999 !important;
|
||||
}
|
||||
::-webkit-input-placeholder {
|
||||
color: #999999;
|
||||
|
@ -3,7 +3,7 @@ class Admin::UsersController < Admin::AdminController
|
||||
def index
|
||||
# Sort order
|
||||
if params[:query] == "active"
|
||||
@users = User.order("COALESCE(last_seen_at, '01-01-1970') DESC, username")
|
||||
@users = User.order("COALESCE(last_seen_at, to_date('1970-01-01', 'YYYY-MM-DD')) DESC, username")
|
||||
else
|
||||
@users = User.order("created_at DESC, username")
|
||||
end
|
||||
|
@ -76,7 +76,10 @@ class ApplicationController < ActionController::Base
|
||||
|
||||
def store_preloaded(key, json)
|
||||
@preloaded ||= {}
|
||||
@preloaded[key] = json
|
||||
# I dislike that there is a gsub as opposed to a gsub!
|
||||
# but we can not be mucking with user input, I wonder if there is a way
|
||||
# to inject this safty deeper in the library or even in AM serializer
|
||||
@preloaded[key] = json.gsub("</", "<\\/")
|
||||
end
|
||||
|
||||
# If we are rendering HTML, preload the session data
|
||||
|
15
app/controllers/robots_txt_controller.rb
Normal file
15
app/controllers/robots_txt_controller.rb
Normal file
@ -0,0 +1,15 @@
|
||||
class RobotsTxtController < ApplicationController
|
||||
layout false
|
||||
skip_before_filter :check_xhr
|
||||
skip_before_filter :check_restricted_access
|
||||
|
||||
def index
|
||||
path = if SiteSetting.allow_index_in_robots_txt && !SiteSetting.restrict_access
|
||||
:index
|
||||
else
|
||||
:no_index
|
||||
end
|
||||
|
||||
render path, content_type: 'text/plain'
|
||||
end
|
||||
end
|
@ -106,6 +106,7 @@ footer:after{ content: '#{error}' }"
|
||||
|
||||
@lock.synchronize do
|
||||
style = self.where(key: key).first
|
||||
style.ensure_stylesheet_on_disk!
|
||||
@cache[key] = style
|
||||
end
|
||||
end
|
||||
@ -140,9 +141,13 @@ footer:after{ content: '#{error}' }"
|
||||
Digest::MD5.hexdigest(self.stylesheet)
|
||||
end
|
||||
|
||||
def cache_fullpath
|
||||
"#{Rails.root}/public/#{CACHE_PATH}"
|
||||
end
|
||||
|
||||
def ensure_stylesheet_on_disk!
|
||||
path = stylesheet_fullpath
|
||||
dir = "#{Rails.root}/public/#{CACHE_PATH}"
|
||||
dir = cache_fullpath
|
||||
FileUtils.mkdir_p(dir)
|
||||
unless File.exists?(path)
|
||||
File.open(path, "w") do |f|
|
||||
@ -152,23 +157,18 @@ footer:after{ content: '#{error}' }"
|
||||
end
|
||||
|
||||
def stylesheet_filename
|
||||
file = ""
|
||||
dir = "#{Rails.root}/public/#{CACHE_PATH}"
|
||||
path = dir + file
|
||||
|
||||
"/#{CACHE_PATH}/#{self.key}.css"
|
||||
"/#{self.key}.css"
|
||||
end
|
||||
|
||||
def stylesheet_fullpath
|
||||
"#{Rails.root}/public#{self.stylesheet_filename}"
|
||||
"#{self.cache_fullpath}#{self.stylesheet_filename}"
|
||||
end
|
||||
|
||||
def stylesheet_link_tag
|
||||
return "" unless self.stylesheet.present?
|
||||
return @stylesheet_link_tag if @stylesheet_link_tag
|
||||
ensure_stylesheet_on_disk!
|
||||
@stylesheet_link_tag = "<link class=\"custom-css\" rel=\"stylesheet\" href=\"#{self.stylesheet_filename}?#{self.stylesheet_hash}\" type=\"text/css\" media=\"screen\">"
|
||||
@stylesheet_link_tag = "<link class=\"custom-css\" rel=\"stylesheet\" href=\"/#{CACHE_PATH}#{self.stylesheet_filename}?#{self.stylesheet_hash}\" type=\"text/css\" media=\"screen\">"
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
@ -30,8 +30,6 @@ class SiteSetting < ActiveRecord::Base
|
||||
client_setting(:max_topic_title_length, 255)
|
||||
client_setting(:flush_timings_secs, 5)
|
||||
|
||||
|
||||
|
||||
# settings only available server side
|
||||
setting(:auto_track_topics_after, 60000)
|
||||
setting(:long_polling_interval, 15000)
|
||||
@ -91,6 +89,8 @@ class SiteSetting < ActiveRecord::Base
|
||||
|
||||
setting(:allow_duplicate_topic_titles, false)
|
||||
|
||||
setting(:add_rel_nofollow_to_user_content, true)
|
||||
setting(:exclude_rel_nofollow_domains, '')
|
||||
setting(:post_excerpt_maxlength, 300)
|
||||
setting(:post_onebox_maxlength, 500)
|
||||
setting(:best_of_score_threshold, 15)
|
||||
@ -102,6 +102,8 @@ class SiteSetting < ActiveRecord::Base
|
||||
# we need to think of a way to force users to enter certain settings, this is a minimal config thing
|
||||
setting(:notification_email, 'info@discourse.org')
|
||||
|
||||
setting(:allow_index_in_robots_txt, true)
|
||||
|
||||
setting(:send_welcome_message, true)
|
||||
|
||||
setting(:twitter_consumer_key, '')
|
||||
|
@ -1,20 +1,19 @@
|
||||
class UserSearch
|
||||
|
||||
def self.search term, topic_id = nil
|
||||
User.find_by_sql sql(term, topic_id)
|
||||
end
|
||||
sql = User.sql_builder(
|
||||
"select id, username, name, email from users u
|
||||
/*left_join*/
|
||||
/*where*/
|
||||
/*order_by*/")
|
||||
|
||||
private
|
||||
|
||||
def self.sql term, topic_id
|
||||
sql = "select id, username, name, email from users u "
|
||||
|
||||
if topic_id
|
||||
sql << "left join (select distinct p.user_id from posts p where topic_id = :topic_id) s on
|
||||
s.user_id = u.id "
|
||||
sql.left_join "(select distinct p.user_id from posts p where topic_id = :topic_id) s on s.user_id = u.id", topic_id: topic_id
|
||||
end
|
||||
|
||||
if term.present?
|
||||
sql << "where username ilike :term_like or
|
||||
|
||||
if term.present?
|
||||
sql.where("username_lower like :term_like or
|
||||
to_tsvector('simple', name) @@
|
||||
to_tsquery('simple',
|
||||
regexp_replace(
|
||||
@ -22,22 +21,18 @@ class UserSearch
|
||||
cast(plainto_tsquery(:term) as text)
|
||||
,'\''(?: |$)', ':*''', 'g'),
|
||||
'''', '', 'g')
|
||||
) "
|
||||
)", term: term, term_like: "#{term.downcase}%")
|
||||
|
||||
sql.order_by "case when username_lower = :term then 0 else 1 end asc"
|
||||
end
|
||||
|
||||
sql << "order by case when username_lower = :term then 0 else 1 end asc, "
|
||||
|
||||
if topic_id
|
||||
sql << " case when s.user_id is null then 0 else 1 end desc, "
|
||||
sql.order_by "case when s.user_id is null then 0 else 1 end desc"
|
||||
end
|
||||
|
||||
sql << " case when last_seen_at is null then 0 else 1 end desc, last_seen_at desc, username asc limit(20)"
|
||||
sql.order_by "case when last_seen_at is null then 0 else 1 end desc, last_seen_at desc, username asc limit(20)"
|
||||
|
||||
sanitize_sql_array(sql, topic_id: topic_id, term_like: "#{term}%", term: term)
|
||||
sql.exec
|
||||
end
|
||||
|
||||
def self.sanitize_sql_array *args
|
||||
ActiveRecord::Base.send(:sanitize_sql_array, args)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,2 @@
|
||||
# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
|
||||
#
|
||||
# To ban all spiders from the entire site uncomment the next two lines:
|
||||
# User-Agent: *
|
||||
# Disallow: /
|
6
app/views/robots_txt/no_index.erb
Normal file
6
app/views/robots_txt/no_index.erb
Normal file
@ -0,0 +1,6 @@
|
||||
# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
|
||||
#
|
||||
User-Agent: *
|
||||
Disallow: /
|
||||
|
||||
|
@ -20,8 +20,6 @@ module Discourse
|
||||
# -- all .rb files in that directory are automatically loaded.
|
||||
|
||||
require 'discourse'
|
||||
# initializes message bus too early, not picking on redis settings, needs to be fixed
|
||||
# require 'message_bus_diags'
|
||||
|
||||
# Custom directories with classes and modules you want to be autoloadable.
|
||||
config.autoload_paths += %W(#{config.root}/app/serializers)
|
||||
|
1
config/initializers/sql_builder.rb
Normal file
1
config/initializers/sql_builder.rb
Normal file
@ -0,0 +1 @@
|
||||
require 'sql_builder'
|
@ -219,6 +219,8 @@ en:
|
||||
max_image_width: "maximum width for an image in a post"
|
||||
category_featured_topics: "number of topics displayed in the category list"
|
||||
popup_delay: "Length of time in ms before popups appear on the screen"
|
||||
add_rel_nofollow_to_user_content: "Add rel nofollow to all submitted user content, except for internal links (including parent domains) changing this requires you update all your baked markdown"
|
||||
exclude_rel_nofollow_domains: "A comma delimited list of domains where nofollow is not added (tld.com will automatically allow sub.tld.com as well)"
|
||||
post_excerpt_maxlength: "Maximum length in chars of a post's excerpt."
|
||||
post_onebox_maxlength: "Maximum length of a oneboxed discourse post."
|
||||
category_post_template: "The post template that appears once you create a category"
|
||||
@ -257,6 +259,9 @@ en:
|
||||
posts_per_page: "How many posts are returned on a topic page"
|
||||
system_username: "Username that sends system messages"
|
||||
send_welcome_message: "Do new users get a welcome private message?"
|
||||
|
||||
allow_index_in_robots_txt: "Site should be indexed by search engines (update robots.txt)"
|
||||
|
||||
port: "If you'd like to specify a port in the URL. Useful in development mode. Leave blank for none."
|
||||
force_hostname: "If you'd like to specify a hostname in the URL. Useful in development mode. Leave blank for none."
|
||||
|
||||
@ -435,6 +440,7 @@ en:
|
||||
show_more: "show more"
|
||||
links: Links
|
||||
faq: "FAQ"
|
||||
you: "You"
|
||||
|
||||
suggested_topics:
|
||||
title: "Suggested Topics"
|
||||
|
@ -207,6 +207,9 @@ Discourse::Application.routes.draw do
|
||||
post 'draft' => 'draft#update'
|
||||
delete 'draft' => 'draft#destroy'
|
||||
|
||||
|
||||
get 'robots.txt' => 'robots_txt#index'
|
||||
|
||||
# You can have the root of your site routed with "root"
|
||||
# just remember to delete public/index.html.
|
||||
root :to => 'list#index'
|
||||
|
Binary file not shown.
Binary file not shown.
@ -172,7 +172,42 @@ module PrettyText
|
||||
cloned = opts.dup
|
||||
# we have a minor inconsistency
|
||||
cloned[:topicId] = opts[:topic_id]
|
||||
Sanitize.clean(markdown(text.dup, cloned), PrettyText.whitelist)
|
||||
sanitized = Sanitize.clean(markdown(text.dup, cloned), PrettyText.whitelist)
|
||||
if SiteSetting.add_rel_nofollow_to_user_content
|
||||
sanitized = add_rel_nofollow_to_user_content(sanitized)
|
||||
end
|
||||
sanitized
|
||||
end
|
||||
|
||||
def self.add_rel_nofollow_to_user_content(html)
|
||||
whitelist = []
|
||||
|
||||
l = SiteSetting.exclude_rel_nofollow_domains
|
||||
if l.present?
|
||||
whitelist = l.split(",")
|
||||
end
|
||||
|
||||
site_uri = nil
|
||||
doc = Nokogiri::HTML.fragment(html)
|
||||
doc.css("a").each do |l|
|
||||
href = l["href"].to_s
|
||||
begin
|
||||
uri = URI(href)
|
||||
site_uri ||= URI(Discourse.base_url)
|
||||
|
||||
if !uri.host.present? ||
|
||||
uri.host.ends_with?(site_uri.host) ||
|
||||
whitelist.any?{|u| uri.host.ends_with?(u)}
|
||||
# we are good no need for nofollow
|
||||
else
|
||||
l["rel"] = "nofollow"
|
||||
end
|
||||
rescue URI::InvalidURIError
|
||||
# add a nofollow anyway
|
||||
l["rel"] = "nofollow"
|
||||
end
|
||||
end
|
||||
doc.to_html
|
||||
end
|
||||
|
||||
def self.extract_links(html)
|
||||
|
@ -21,7 +21,7 @@ module Search
|
||||
NULL AS color
|
||||
FROM users AS u
|
||||
JOIN users_search s on s.id = u.id
|
||||
WHERE s.search_data @@ TO_TSQUERY(:query)
|
||||
WHERE s.search_data @@ TO_TSQUERY('english', :query)
|
||||
ORDER BY last_posted_at desc
|
||||
"
|
||||
end
|
||||
@ -36,13 +36,13 @@ module Search
|
||||
FROM topics AS ft
|
||||
JOIN posts AS p ON p.topic_id = ft.id AND p.post_number = 1
|
||||
JOIN posts_search s on s.id = p.id
|
||||
WHERE s.search_data @@ TO_TSQUERY(:query)
|
||||
WHERE s.search_data @@ TO_TSQUERY('english', :query)
|
||||
AND ft.deleted_at IS NULL
|
||||
AND ft.visible
|
||||
AND ft.archetype <> '#{Archetype.private_message}'
|
||||
ORDER BY
|
||||
TS_RANK_CD(TO_TSVECTOR('english', ft.title), TO_TSQUERY(:query)) desc,
|
||||
TS_RANK_CD(search_data, TO_TSQUERY(:query)) desc,
|
||||
TS_RANK_CD(TO_TSVECTOR('english', ft.title), TO_TSQUERY('english', :query)) desc,
|
||||
TS_RANK_CD(search_data, TO_TSQUERY('english', :query)) desc,
|
||||
bumped_at desc"
|
||||
end
|
||||
|
||||
@ -57,13 +57,13 @@ module Search
|
||||
FROM topics AS ft
|
||||
JOIN posts AS p ON p.topic_id = ft.id AND p.post_number <> 1
|
||||
JOIN posts_search s on s.id = p.id
|
||||
WHERE s.search_data @@ TO_TSQUERY(:query)
|
||||
WHERE s.search_data @@ TO_TSQUERY('english', :query)
|
||||
AND ft.deleted_at IS NULL and p.deleted_at IS NULL
|
||||
AND ft.visible
|
||||
AND ft.archetype <> '#{Archetype.private_message}'
|
||||
ORDER BY
|
||||
TS_RANK_CD(TO_TSVECTOR('english', ft.title), TO_TSQUERY(:query)) desc,
|
||||
TS_RANK_CD(search_data, TO_TSQUERY(:query)) desc,
|
||||
TS_RANK_CD(TO_TSVECTOR('english', ft.title), TO_TSQUERY('english', :query)) desc,
|
||||
TS_RANK_CD(search_data, TO_TSQUERY('english', :query)) desc,
|
||||
bumped_at desc"
|
||||
end
|
||||
|
||||
@ -76,7 +76,7 @@ module Search
|
||||
c.color
|
||||
FROM categories AS c
|
||||
JOIN categories_search s on s.id = c.id
|
||||
WHERE s.search_data @@ TO_TSQUERY(:query)
|
||||
WHERE s.search_data @@ TO_TSQUERY('english', :query)
|
||||
ORDER BY topics_month desc
|
||||
"
|
||||
end
|
||||
|
@ -1,9 +1,10 @@
|
||||
class SqlBuilder
|
||||
|
||||
def initialize(template)
|
||||
def initialize(template,klass=nil)
|
||||
@args = {}
|
||||
@sql = template
|
||||
@sections = {}
|
||||
@klass = klass
|
||||
end
|
||||
|
||||
[:set, :where2,:where,:order_by,:limit,:left_join,:join,:offset].each do |k|
|
||||
@ -40,9 +41,17 @@ class SqlBuilder
|
||||
|
||||
sql.sub!("/*#{k}*/", joined)
|
||||
end
|
||||
|
||||
ActiveRecord::Base.exec_sql(sql,@args)
|
||||
|
||||
if @klass
|
||||
@klass.find_by_sql(ActiveRecord::Base.send(:sanitize_sql_array, [sql, @args]))
|
||||
else
|
||||
ActiveRecord::Base.exec_sql(sql,@args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ActiveRecord::Base
|
||||
def self.sql_builder(template)
|
||||
SqlBuilder.new(template, self)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
@ -75,6 +75,33 @@ test
|
||||
.should == "<pre><code>```\nhello\n```\n</code></pre>"
|
||||
end
|
||||
end
|
||||
|
||||
describe "rel nofollow" do
|
||||
before do
|
||||
SiteSetting.stubs(:add_rel_nofollow_to_user_content).returns(true)
|
||||
SiteSetting.stubs(:exclude_rel_nofollow_domains).returns("foo.com,bar.com")
|
||||
end
|
||||
|
||||
it "should inject nofollow in all user provided links" do
|
||||
PrettyText.cook('<a href="http://cnn.com">cnn</a>').should =~ /nofollow/
|
||||
end
|
||||
|
||||
it "should not inject nofollow in all local links" do
|
||||
(PrettyText.cook("<a href='#{Discourse.base_url}/test.html'>cnn</a>") !~ /nofollow/).should be_true
|
||||
end
|
||||
|
||||
it "should not inject nofollow in all subdomain links" do
|
||||
(PrettyText.cook("<a href='#{Discourse.base_url.sub('http://', 'http://bla.')}/test.html'>cnn</a>") !~ /nofollow/).should be_true
|
||||
end
|
||||
|
||||
it "should not inject nofollow for foo.com" do
|
||||
(PrettyText.cook("<a href='http://foo.com/test.html'>cnn</a>") !~ /nofollow/).should be_true
|
||||
end
|
||||
|
||||
it "should not inject nofollow for bar.foo.com" do
|
||||
(PrettyText.cook("<a href='http://bar.foo.com/test.html'>cnn</a>") !~ /nofollow/).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "Excerpt" do
|
||||
it "should preserve links" do
|
||||
@ -130,6 +157,7 @@ test
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "apply cdn" do
|
||||
it "should detect bare links to images and apply a CDN" do
|
||||
PrettyText.apply_cdn("<a href='/hello.png'>hello</a><img src='/a.jpeg'>","http://a.com").should ==
|
||||
|
@ -4,32 +4,48 @@ require_dependency 'sql_builder'
|
||||
|
||||
describe SqlBuilder do
|
||||
|
||||
before do
|
||||
@builder = SqlBuilder.new("select * from (select :a A union all select :b) as X /*where*/ /*order_by*/ /*limit*/ /*offset*/")
|
||||
describe "attached" do
|
||||
before do
|
||||
@builder = Post.sql_builder("select * from posts /*where*/ /*limit*/")
|
||||
end
|
||||
|
||||
it "should find a post by id" do
|
||||
p = Fabricate(:post)
|
||||
@builder.where('id = :id and topic_id = :topic_id', id: p.id, topic_id: p.topic_id)
|
||||
p2 = @builder.exec.first
|
||||
p2.id.should == p.id
|
||||
p2.should == p
|
||||
end
|
||||
end
|
||||
|
||||
it "should allow for 1 param exec" do
|
||||
@builder.exec(a: 1, b: 2).values[0][0].should == '1'
|
||||
end
|
||||
describe "detached" do
|
||||
before do
|
||||
@builder = SqlBuilder.new("select * from (select :a A union all select :b) as X /*where*/ /*order_by*/ /*limit*/ /*offset*/")
|
||||
end
|
||||
|
||||
it "should allow for a single where" do
|
||||
@builder.where(":a = 1")
|
||||
@builder.exec(a: 1, b: 2).values[0][0].should == '1'
|
||||
end
|
||||
it "should allow for 1 param exec" do
|
||||
@builder.exec(a: 1, b: 2).values[0][0].should == '1'
|
||||
end
|
||||
|
||||
it "should allow where chaining" do
|
||||
@builder.where(":a = 1")
|
||||
@builder.where("2 = 1")
|
||||
@builder.exec(a: 1, b: 2).to_a.length.should == 0
|
||||
end
|
||||
it "should allow for a single where" do
|
||||
@builder.where(":a = 1")
|
||||
@builder.exec(a: 1, b: 2).values[0][0].should == '1'
|
||||
end
|
||||
|
||||
it "should allow order by" do
|
||||
@builder.order_by("A desc").limit(1)
|
||||
.exec(a:1, b:2).values[0][0].should == "2"
|
||||
end
|
||||
it "should allow offset" do
|
||||
@builder.order_by("A desc").offset(1)
|
||||
.exec(a:1, b:2).values[0][0].should == "1"
|
||||
it "should allow where chaining" do
|
||||
@builder.where(":a = 1")
|
||||
@builder.where("2 = 1")
|
||||
@builder.exec(a: 1, b: 2).to_a.length.should == 0
|
||||
end
|
||||
|
||||
it "should allow order by" do
|
||||
@builder.order_by("A desc").limit(1)
|
||||
.exec(a:1, b:2).values[0][0].should == "2"
|
||||
end
|
||||
it "should allow offset" do
|
||||
@builder.order_by("A desc").offset(1)
|
||||
.exec(a:1, b:2).values[0][0].should == "1"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
26
spec/controllers/robots_txt_controller_spec.rb
Normal file
26
spec/controllers/robots_txt_controller_spec.rb
Normal file
@ -0,0 +1,26 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe RobotsTxtController do
|
||||
|
||||
context '.index' do
|
||||
it "returns noindex when indexing is disallowed" do
|
||||
SiteSetting.stubs(:allow_index_in_robots_txt).returns(true)
|
||||
get :index
|
||||
response.should render_template :index
|
||||
end
|
||||
|
||||
it "returns index when indexing is allowed" do
|
||||
SiteSetting.stubs(:allow_index_in_robots_txt).returns(false)
|
||||
get :index
|
||||
response.should render_template :no_index
|
||||
end
|
||||
|
||||
it "serves it regardless if a site is in private mode" do
|
||||
SiteSetting.stubs(:allow_index_in_robots_txt).returns(true)
|
||||
SiteSetting.stubs(:restrict_access).returns(true)
|
||||
get :index
|
||||
response.should render_template :no_index
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -26,6 +26,7 @@ describe SiteCustomization do
|
||||
SiteCustomization.enabled_style_key.should be_nil
|
||||
end
|
||||
|
||||
|
||||
it 'finds the enabled style' do
|
||||
@customization.enabled = true
|
||||
@customization.save
|
||||
@ -45,6 +46,16 @@ describe SiteCustomization do
|
||||
end
|
||||
end
|
||||
|
||||
it 'ensure stylesheet is on disk on first fetch' do
|
||||
c = customization
|
||||
c.remove_from_cache!
|
||||
File.delete(c.stylesheet_fullpath)
|
||||
|
||||
SiteCustomization.custom_stylesheet(c.key)
|
||||
File.exists?(c.stylesheet_fullpath).should == true
|
||||
|
||||
end
|
||||
|
||||
it 'should allow me to lookup a filename containing my preview stylesheet' do
|
||||
SiteCustomization.custom_stylesheet(customization.key).should ==
|
||||
"<link class=\"custom-css\" rel=\"stylesheet\" href=\"/stylesheet-cache/#{customization.key}.css?#{customization.stylesheet_hash}\" type=\"text/css\" media=\"screen\">"
|
||||
|
Loading…
x
Reference in New Issue
Block a user