Commit 62b7ab50 by Jim Abramson

Merge pull request #76 from edx/feature/jsa/i18n

set up i18n in comments service
parents 28f2a9eb 5c5a5a6c
......@@ -26,7 +26,6 @@ gem 'delayed_job_mongoid', :git => 'https://github.com/dementrock/delayed_job_mo
gem 'mongoid-tree', :git => 'https://github.com/dementrock/mongoid-tree.git'
gem 'voteable_mongo', :git => 'https://github.com/dementrock/voteable_mongo.git'
gem 'mongoid_taggable_with_context', :git => 'https://github.com/dementrock/mongoid_taggable_with_context.git'
gem 'mongoid_magic_counter_cache', :git => 'https://github.com/dementrock/mongoid-magic-counter-cache.git'
gem 'kaminari', :require => 'kaminari/sinatra', :git => 'https://github.com/dementrock/kaminari.git'
......@@ -55,3 +54,4 @@ gem 'newrelic_rpm'
gem 'newrelic_moped'
gem 'unicorn'
gem "rack-timeout", "0.1.0beta3"
gem "i18n"
......@@ -30,13 +30,6 @@ GIT
mongoid (>= 3.0, <= 4.0)
GIT
remote: https://github.com/dementrock/mongoid_taggable_with_context.git
revision: 7cf165bd828f969cdd386102eed04ac35431a920
specs:
mongoid_taggable_with_context (0.8.1.1)
mongoid (>= 3.0.1)
GIT
remote: https://github.com/dementrock/voteable_mongo.git
revision: 538e86856daa1c180ba80b7c6f2805e531ba420c
specs:
......@@ -178,12 +171,12 @@ DEPENDENCIES
faker
guard
guard-unicorn
i18n
kaminari!
mongo
mongoid (= 3.0.15)
mongoid-tree!
mongoid_magic_counter_cache!
mongoid_taggable_with_context!
moped (= 1.5.1)
newrelic_moped
newrelic_rpm
......
......@@ -25,10 +25,6 @@ end
put "#{APIPREFIX}/threads/:thread_id" do |thread_id|
thread.update_attributes(params.slice(*%w[title body closed commentable_id group_id]))
filter_blocked_content thread
if params["tags"]
thread.tags = params["tags"]
thread.save
end
if thread.errors.any?
error 400, thread.errors.full_messages.to_json
......
......@@ -18,7 +18,6 @@ post "#{APIPREFIX}/:commentable_id/threads" do |commentable_id|
thread = CommentThread.new(params.slice(*%w[title body course_id ]).merge(commentable_id: commentable_id))
thread.anonymous = bool_anonymous || false
thread.anonymous_to_peers = bool_anonymous_to_peers || false
thread.tags = params["tags"] || ""
if params["group_id"]
thread.group_id = params["group_id"]
......
......@@ -19,7 +19,7 @@ get "#{APIPREFIX}/search/threads" do
sort_keyword_valid = (!params["sort_key"] && !params["sort_order"] || sort_key && sort_order)
if (!params["text"] && !params["tags"] && !params["commentable_ids"]) || !sort_keyword_valid
if (!params["text"] && !params["commentable_ids"]) || !sort_keyword_valid
{}.to_json
else
page = (params["page"] || DEFAULT_PAGE).to_i
......@@ -95,15 +95,3 @@ get "#{APIPREFIX}/search/threads/recent_active" do
comment_threads.where(query_params.merge(:last_activity_at => {:$gte => from_time})).order_by(:last_activity_at.desc).limit(5).to_a.map(&:to_hash).to_json
end
get "#{APIPREFIX}/search/tags/trending" do
query_params = {}
query_params["course_id"] = params["course_id"] if params["course_id"]
query_params["commentable_id"] = params["commentable_id"] if params["commentable_id"]
CommentThread.where(query_params).only(:tags_array).to_a
.map(&:tags_array).flatten.group_by{|x| x}
.map{|k, v| [k, v.count]}
.sort_by {|x| - x.last}[0..4]
.to_json
end
get "#{APIPREFIX}/threads/tags" do
CommentThread.tags.to_json
end
get "#{APIPREFIX}/threads/tags/autocomplete" do
CommentThread.tags_autocomplete(:tags, params["value"].strip, max: 5, sort_by_count: true).map(&:first).to_json
end
......@@ -59,6 +59,17 @@ Mongoid.load!("config/mongoid.yml", environment)
Mongoid.logger.level = Logger::INFO
Moped.logger.level = ENV["ENABLE_MOPED_DEBUGGING"] ? Logger::DEBUG : Logger::INFO
# set up i18n
I18n.load_path += Dir[File.join(File.dirname(__FILE__), 'locale', '*.yml').to_s]
I18n.default_locale = CommentService.config[:default_locale]
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
helpers do
def t(*args)
I18n.t(*args)
end
end
Dir[File.dirname(__FILE__) + '/lib/**/*.rb'].each {|file| require file}
Dir[File.dirname(__FILE__) + '/models/*.rb'].each {|file| require file}
Dir[File.dirname(__FILE__) + '/presenters/*.rb'].each {|file| require file}
......@@ -106,7 +117,6 @@ use Rack::Mongoid::Middleware::IdentityMap
# these files must be required in order
require './api/search'
require './api/commentables'
require './api/tags'
require './api/comment_threads'
require './api/comments'
require './api/users'
......@@ -124,11 +134,11 @@ if RACK_ENV.to_s == "development"
end
error Moped::Errors::InvalidObjectId do
error 400, ["requested object not found"].to_json
error 400, [t(:requested_object_not_found)].to_json
end
error Mongoid::Errors::DocumentNotFound do
error 400, ["requested object not found"].to_json
error 400, [t(:requested_object_not_found)].to_json
end
error ArgumentError do
......
......@@ -2,3 +2,4 @@ level_limit: 3
api_key: <%= ENV['API_KEY'] || 'PUT_YOUR_API_KEY_HERE' %>
elasticsearch_server: <%= ENV['SEARCH_SERVER'] || 'http://localhost:9200' %>
max_deep_search_comment_count: 5000
default_locale: en-US
......@@ -7,7 +7,7 @@ helpers do
end
def user # TODO handle 404 if integrated user service
raise ArgumentError, "User id is required" unless @user || params[:user_id]
raise ArgumentError, t(:user_id_is_required) unless @user || params[:user_id]
@user ||= User.find_by(external_id: params[:user_id])
end
......@@ -28,27 +28,27 @@ helpers do
when "other"
Commentable.find(params["source_id"])
else
raise ArgumentError, "Source type must be 'user', 'thread' or 'other'"
raise ArgumentError, t(:source_type_must_be_user_thread_or_other)
end
end
def vote_for(obj)
raise ArgumentError, "User id is required" unless user
raise ArgumentError, "Value is required" unless params["value"]
raise ArgumentError, "Value is invalid" unless %w[up down].include? params["value"]
raise ArgumentError, t(:user_id_is_required) unless user
raise ArgumentError, t(:value_is_required) unless params["value"]
raise ArgumentError, t(:value_is_invalid) unless %w[up down].include? params["value"]
user.vote(obj, params["value"].to_sym)
obj.reload.to_hash.to_json
end
def flag_as_abuse(obj)
raise ArgumentError, "User id is required" unless user
raise ArgumentError, t(:user_id_is_required) unless user
obj.abuse_flaggers << user.id unless obj.abuse_flaggers.include? user.id
obj.save
obj.reload.to_hash.to_json
end
def un_flag_as_abuse(obj)
raise ArgumentError, "User id is required" unless user
raise ArgumentError, t(:user_id_is_required) unless user
if params["all"]
obj.historical_abuse_flaggers += obj.abuse_flaggers
obj.historical_abuse_flaggers = obj.historical_abuse_flaggers.uniq
......@@ -62,21 +62,21 @@ helpers do
end
def undo_vote_for(obj)
raise ArgumentError, "must provide user id" unless user
raise ArgumentError, t(:user_id_is_required) unless user
user.unvote(obj)
obj.reload.to_hash.to_json
end
def pin(obj)
raise ArgumentError, "User id is required" unless user
raise ArgumentError, t(:user_id_is_required) unless user
obj.pinned = true
obj.save
obj.reload.to_hash.to_json
end
def unpin(obj)
raise ArgumentError, "User id is required" unless user
raise ArgumentError, t(:user_id_is_required) unless user
obj.pinned = nil
obj.save
obj.reload.to_hash.to_json
......@@ -268,7 +268,7 @@ helpers do
end
content_obj = {}
content_obj["username"] = c.author_with_anonymity(:username, "(anonymous)")
content_obj["username"] = c.author_with_anonymity(:username, t(:anonymous))
content_obj["updated_at"] = c.updated_at
content_obj["body"] = c.body
t["content"] << content_obj
......@@ -289,8 +289,9 @@ helpers do
return
end
if CommentService.blocked_hashes.include? hash then
logger.warn "blocked content with body hash [#{hash}]"
error 503
msg = t(:blocked_content_with_body_hash, :hash => hash)
logger.warn msg
error 503, [msg].to_json
end
end
......
en-US:
requested_object_not_found: "requested object not found"
user_id_is_required: "User id is required"
source_type_must_be_user_thread_or_other: "Source type must be 'user', 'thread' or 'other'"
value_is_required: "Value is required"
value_is_invalid: "Value is invalid"
anonymous: "anonymous"
blocked_content_with_body_hash: blocked content with body hash %{hash}
......@@ -4,10 +4,6 @@ require_relative 'content'
class CommentThread < Content
include Mongoid::Timestamps
include Mongoid::TaggableWithContext
include Mongoid::TaggableWithContext::AggregationStrategy::RealTime
taggable separator: ',', default: []
voteable self, :up => +1, :down => -1
......@@ -32,8 +28,6 @@ class CommentThread < Content
mapping do
indexes :title, type: :string, analyzer: :snowball, boost: 5.0, stored: true, term_vector: :with_positions_offsets
indexes :body, type: :string, analyzer: :snowball, stored: true, term_vector: :with_positions_offsets
indexes :tags_in_text, type: :string, as: 'tags_array', index: :analyzed
indexes :tags_array, type: :string, as: 'tags_array', index: :not_analyzed, included_in_all: false
indexes :created_at, type: :date, included_in_all: false
indexes :updated_at, type: :date, included_in_all: false
indexes :last_activity_at, type: :date, included_in_all: false
......@@ -61,9 +55,6 @@ class CommentThread < Content
validates_presence_of :commentable_id
validates_presence_of :author, autosave: false
validate :tag_names_valid
validate :tag_names_unique
before_create :set_last_activity_at
before_update :set_last_activity_at, :unless => lambda { closed_changed? }
......@@ -78,7 +69,6 @@ class CommentThread < Content
c.commentable_id = options[:commentable_id] || "commentable_id"
c.course_id = options[:course_id] || "course_id"
c.author = options[:author] || User.first
c.tags = options[:tags] || "test-tag-1, test-tag-2"
c.save!
c
end
......@@ -110,7 +100,6 @@ class CommentThread < Content
search.query {|query| query.text :_all, params["text"]} if params["text"]
search.highlight({title: { number_of_fragments: 0 } } , {body: { number_of_fragments: 0 } }, options: { tag: "<highlight>" })
search.filter(:bool, :must => params["tags"].split(/,/).map{ |tag| { :term => { :tags_array => tag } } }) if params["tags"]
search.filter(:term, commentable_id: params["commentable_id"]) if params["commentable_id"]
search.filter(:terms, commentable_id: params["commentable_ids"]) if params["commentable_ids"]
search.filter(:term, course_id: params["course_id"]) if params["course_id"]
......@@ -248,7 +237,7 @@ class CommentThread < Content
# abuse_flaggers
# from original document
# tags
# from orig doc tags_array
# deprecated - empty array
# type
# hardcoded "thread"
# group_id
......@@ -263,7 +252,7 @@ class CommentThread < Content
"username" => author_username,
"votes" => votes.slice(*%w[count up_count down_count point]),
"abuse_flaggers" => abuse_flaggers,
"tags" => tags_array,
"tags" => [],
"type" => "thread",
"group_id" => group_id,
"pinned" => pinned?,
......@@ -271,10 +260,6 @@ class CommentThread < Content
end
def self.tag_name_valid?(tag)
!!(tag =~ RE_TAG)
end
def comment_thread_id
#so that we can use the comment thread id as a common attribute for flagging
self.id
......@@ -282,25 +267,6 @@ class CommentThread < Content
private
RE_HEADCHAR = /[a-z0-9]/
RE_ENDONLYCHAR = /\+/
RE_ENDCHAR = /[a-z0-9\#]/
RE_CHAR = /[a-z0-9\-\#\.]/
RE_WORD = /#{RE_HEADCHAR}(((#{RE_CHAR})*(#{RE_ENDCHAR})+)?(#{RE_ENDONLYCHAR})*)?/
RE_TAG = /^#{RE_WORD}( #{RE_WORD})*$/
def tag_names_valid
unless tags_array.all? {|tag| self.class.tag_name_valid? tag}
errors.add :tag, "can consist of words, numbers, dashes and spaces only and cannot start with dash"
end
end
def tag_names_unique
unless tags_array.uniq.size == tags_array.size
errors.add :tags, "must be unique"
end
end
def set_last_activity_at
self.last_activity_at = Time.now.utc unless last_activity_at_changed?
end
......
......@@ -52,10 +52,12 @@ describe "app" do
it "returns 400 when the comment does not exist" do
create_comment_flag("does_not_exist", User.first.id)
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 400 when user_id is not provided" do
create_comment_flag("#{Comment.first.id}", nil)
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:user_id_is_required)
end
#Would like to test the output of to_hash, but not sure how to deal with a Moped::BSON::Document object
#it "has a correct hash" do
......@@ -78,10 +80,12 @@ describe "app" do
it "returns 400 when the thread does not exist" do
create_thread_flag("does_not_exist", User.first.id)
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 400 when user_id is not provided" do
create_thread_flag("#{Comment.first.comment_thread.id}", nil)
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:user_id_is_required)
end
#Would like to test the output of to_hash, but not sure how to deal with a Moped::BSON::Document object
#it "has a correct hash" do
......@@ -106,13 +110,20 @@ describe "app" do
comment.abuse_flaggers.count.should == prev_abuse_flaggers_count - 1
comment.abuse_flaggers.to_a.should_not include User.first.id
end
it "returns 400 when the thread does not exist" do
it "returns 400 when the comment does not exist" do
remove_comment_flag("does_not_exist", User.first.id)
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 400 when the thread does not exist" do
remove_thread_flag("does_not_exist", User.first.id)
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 400 when user_id is not provided" do
remove_comment_flag("#{Comment.first.comment_thread.id}", nil)
remove_thread_flag("#{Comment.first.comment_thread.id}", nil)
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:user_id_is_required)
end
#Would like to test the output of to_hash, but not sure how to deal with a Moped::BSON::Document object
#it "has a correct hash" do
......@@ -140,10 +151,12 @@ describe "app" do
it "returns 400 when the thread does not exist" do
remove_thread_flag("does_not_exist", User.first.id)
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 400 when user_id is not provided" do
remove_thread_flag("#{Comment.first.comment_thread.id}", nil)
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:user_id_is_required)
end
#Would like to test the output of to_hash, but not sure how to deal with a Moped::BSON::Document object
#it "has a correct hash" do
......
......@@ -37,6 +37,7 @@ describe "app" do
it "returns 400 when the comment does not exist" do
get "/api/v1/comments/does_not_exist"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
end
describe "PUT /api/v1/comments/:comment_id" do
......@@ -51,11 +52,13 @@ describe "app" do
it "returns 400 when the comment does not exist" do
put "/api/v1/comments/does_not_exist", body: "new body", endorsed: true
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 503 when the post hash is blocked" do
comment = Comment.first
put "/api/v1/comments/#{comment.id}", body: "BLOCKED POST", endorsed: true
last_response.status.should == 503
parse(last_response.body).first.should == I18n.t(:blocked_content_with_body_hash, :hash => Digest::MD5.hexdigest("blocked post"))
end
end
describe "POST /api/v1/comments/:comment_id" do
......@@ -73,12 +76,14 @@ describe "app" do
it "returns 400 when the comment does not exist" do
post "/api/v1/comments/does_not_exist", body: "new comment", course_id: "1", user_id: User.first.id
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 503 when the post hash is blocked" do
comment = Comment.first.to_hash(recursive: true)
user = User.first
post "/api/v1/comments/#{comment["id"]}", body: "BLOCKED POST", course_id: "1", user_id: User.first.id
last_response.status.should == 503
parse(last_response.body).first.should == I18n.t(:blocked_content_with_body_hash, :hash => Digest::MD5.hexdigest("blocked post"))
end
end
describe "DELETE /api/v1/comments/:comment_id" do
......@@ -93,6 +98,7 @@ describe "app" do
it "returns 400 when the comment does not exist" do
delete "/api/v1/comments/does_not_exist"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
end
end
......
......@@ -366,28 +366,12 @@ describe "app" do
it "returns 400 when the thread does not exist" do
get "/api/v1/threads/does_not_exist"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
get "/api/v1/threads/5016a3caec5eb9a12300000b1"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "get information of a single comment thread with its tags" do
thread = CommentThread.new
thread.title = "new thread"
thread.body = "hahaah"
thread.course_id = "1"
thread.commentable_id = "1"
thread.author = User.first
thread.tags = "taga, tagb, tagc"
thread.save!
get "/api/v1/threads/#{thread.id}"
last_response.should be_ok
response_thread = parse last_response.body
check_thread_result(nil, thread, response_thread)
response_thread["tags"].length.should == 3
response_thread["tags"].should include "taga"
response_thread["tags"].should include "tagb"
response_thread["tags"].should include "tagc"
end
end
describe "PUT /api/v1/threads/:thread_id" do
......@@ -406,6 +390,7 @@ describe "app" do
it "returns 400 when the thread does not exist" do
put "/api/v1/threads/does_not_exist", body: "new body", title: "new title"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 503 if the post body has been blocked" do
thread = CommentThread.first
......@@ -414,22 +399,6 @@ describe "app" do
put "/api/v1/threads/#{thread.id}", body: "blocked, post...", title: "new title", commentable_id: "new_commentable_id"
last_response.status.should == 503
end
it "updates tag of comment thread" do
thread = CommentThread.first
put "/api/v1/threads/#{thread.id}", tags: "haha, hoho, huhu"
last_response.should be_ok
thread.reload
thread.tags_array.length.should == 3
thread.tags_array.should include "haha"
thread.tags_array.should include "hoho"
thread.tags_array.should include "huhu"
put "/api/v1/threads/#{thread.id}", tags: "aha, oho"
last_response.should be_ok
thread.reload
thread.tags_array.length.should == 2
thread.tags_array.should include "aha"
thread.tags_array.should include "oho"
end
end
describe "POST /api/v1/threads/:thread_id/comments" do
......@@ -465,6 +434,7 @@ describe "app" do
it "returns 400 when the thread does not exist" do
post "/api/v1/threads/does_not_exist/comments", default_params
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns error when body or course_id does not exist, or when body is blank" do
post "/api/v1/threads/#{CommentThread.first.id}/comments", default_params.merge(body: nil)
......@@ -489,49 +459,7 @@ describe "app" do
it "returns 400 when the thread does not exist" do
delete "/api/v1/threads/does_not_exist"
last_response.status.should == 400
end
end
end
describe "GET /api/v1/threads/tags" do
it "get all tags used in threads" do
CommentThread.recalculate_all_context_tag_weights!
thread1 = CommentThread.all.to_a.first
thread2 = CommentThread.all.to_a.last
thread1.tags = "a, b, c"
thread1.save
thread2.tags = "d, e, f"
thread2.save
get "/api/v1/threads/tags"
last_response.should be_ok
tags = parse last_response.body
tags.length.should == 6
end
end
describe "GET /api/v1/threads/tags/autocomplete" do
def create_comment_thread(tags)
c = CommentThread.new(title: "Interesting question", body: "cool")
c.course_id = "1"
c.author = User.first
c.tags = tags
c.commentable_id = "1"
c.save!
c
end
it "returns autocomplete results" do
CommentThread.delete_all
CommentThread.recalculate_all_context_tag_weights!
create_comment_thread "c++, clojure, common-lisp, c#, c, coffeescript"
create_comment_thread "c++, clojure, common-lisp, c#, c"
create_comment_thread "c++, clojure, common-lisp, c#"
create_comment_thread "c++, clojure, common-lisp"
create_comment_thread "c++, clojure"
create_comment_thread "c++"
get "/api/v1/threads/tags/autocomplete", value: "c"
last_response.should be_ok
results = parse last_response.body
results.length.should == 5
%w[c++ clojure common-lisp c# c].each_with_index do |tag, index|
results[index].should == tag
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
end
end
......
......@@ -99,36 +99,7 @@ describe "app" do
it "returns 503 when the post content is blocked" do
post '/api/v1/question_1/threads', default_params.merge(body: "BLOCKED POST")
last_response.status.should == 503
end
it "create a new comment thread with tag" do
old_count = CommentThread.count
post '/api/v1/question_1/threads', default_params.merge(tags: "a, b, c")
last_response.should be_ok
CommentThread.count.should == old_count + 1
thread = CommentThread.where(title: "Interesting question").first
thread.tags_array.length.should == 3
thread.tags_array.should include "a"
thread.tags_array.should include "b"
thread.tags_array.should include "c"
end
it "strip spaces in tags" do
old_count = CommentThread.count
post '/api/v1/question_1/threads', default_params.merge(tags: " a, b ,c ")
last_response.should be_ok
CommentThread.count.should == old_count + 1
thread = CommentThread.where(title: "Interesting question").first
thread.tags_array.length.should == 3
thread.tags_array.should include "a"
thread.tags_array.should include "b"
thread.tags_array.should include "c"
end
it "accepts [a-z 0-9 + # - .]words, numbers, dashes, spaces but no underscores in tags" do
old_count = CommentThread.count
post '/api/v1/question_1/threads', default_params.merge(tags: "artificial-intelligence, machine-learning, 7-is-a-lucky-number, interesting problem, interesting problems in c++")
last_response.should be_ok
CommentThread.count.should == old_count + 1
thread = CommentThread.where(title: "Interesting question").first
thread.tags_array.length.should == 5
parse(last_response.body).first.should == I18n.t(:blocked_content_with_body_hash, :hash => Digest::MD5.hexdigest("blocked post"))
end
end
end
......
require 'spec_helper'
describe "app" do
describe "search" do
before(:each) { init_without_subscriptions }
describe "GET /api/v1/search/threads" do
it "returns all threads tagged with all tags" do
thread1 = CommentThread.all.to_a.first
thread2 = CommentThread.all.to_a.last
ai = "artificial intelligence"
ml = "marchine learning"
random1 = "random1"
random2 = "random2"
random3 = "random3"
thread1.tags = [ai, ml, random1].join ","
thread1.save
thread2.tags = [ai, ml, random2].join ","
thread2.save
sleep 1
get "/api/v1/search/threads", tags: [ai, ml].join(",")
last_response.should be_ok
threads = parse(last_response.body)['collection']
threads.length.should == 2
check_thread_result(nil, thread1, threads.select{|t| t["id"] == thread1.id.to_s}.first, false, true)
check_thread_result(nil, thread2, threads.select{|t| t["id"] == thread2.id.to_s}.first, false, true)
get "/api/v1/search/threads", tags: [ai].join(",")
last_response.should be_ok
threads = parse(last_response.body)['collection']
threads.length.should == 2
check_thread_result(nil, thread1, threads.select{|t| t["id"] == thread1.id.to_s}.first, false, true)
check_thread_result(nil, thread2, threads.select{|t| t["id"] == thread2.id.to_s}.first, false, true)
get "/api/v1/search/threads", tags: [ai, random1].join(",")
last_response.should be_ok
threads = parse(last_response.body)['collection']
threads.length.should == 1
check_thread_result(nil, thread1, threads.select{|t| t["id"] == thread1.id.to_s}.first, false, true)
get "/api/v1/search/threads", tags: [random1].join(",")
last_response.should be_ok
threads = parse(last_response.body)['collection']
threads.length.should == 1
check_thread_result(nil, thread1, threads.select{|t| t["id"] == thread1.id.to_s}.first, false, true)
get "/api/v1/search/threads", tags: [random1, random2].join(",")
last_response.should be_ok
threads = parse(last_response.body)['collection']
threads.length.should == 0
end
end
end
end
......@@ -17,16 +17,20 @@ describe "app" do
it "returns 400 when the comment does not exist" do
put "/api/v1/comments/does_not_exist/votes", user_id: User.first.id, value: "down"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 400 when user_id is not provided" do
put "/api/v1/comments/#{Comment.first.id}/votes", value: "down"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:user_id_is_required)
end
it "returns 400 when value is not provided or invalid" do
put "/api/v1/comments/#{Comment.first.id}/votes", user_id: User.first.id
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:value_is_required)
put "/api/v1/comments/#{Comment.first.id}/votes", user_id: User.first.id, value: "superdown"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:value_is_invalid)
end
end
describe "DELETE /api/v1/comments/:comment_id/votes" do
......@@ -43,10 +47,12 @@ describe "app" do
it "returns 400 when the comment does not exist" do
delete "/api/v1/comments/does_not_exist/votes", user_id: User.first.id
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 400 when user_id is not provided" do
delete "/api/v1/comments/#{Comment.first.id}/votes"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:user_id_is_required)
end
end
describe "PUT /api/v1/threads/:thread_id/votes" do
......@@ -63,16 +69,20 @@ describe "app" do
it "returns 400 when the thread does not exist" do
put "/api/v1/threads/does_not_exist/votes", user_id: User.first.id, value: "down"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 400 when user_id is not provided" do
put "/api/v1/threads/#{CommentThread.first.id}/votes", value: "down"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:user_id_is_required)
end
it "returns 400 when value is not provided or invalid" do
put "/api/v1/threads/#{CommentThread.first.id}/votes", user_id: User.first.id
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:value_is_required)
put "/api/v1/threads/#{CommentThread.first.id}/votes", user_id: User.first.id, value: "superdown"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:value_is_invalid)
end
end
describe "DELETE /api/v1/threads/:thread_id/votes" do
......@@ -89,10 +99,12 @@ describe "app" do
it "returns 400 when the comment does not exist" do
delete "/api/v1/threads/does_not_exist/votes", user_id: User.first.id
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:requested_object_not_found)
end
it "returns 400 when user_id is not provided" do
delete "/api/v1/threads/#{CommentThread.first.id}/votes"
last_response.status.should == 400
parse(last_response.body).first.should == I18n.t(:user_id_is_required)
end
end
end
......
require 'spec_helper'
describe CommentThread do
it "validates tag name" do
CommentThread.tag_name_valid?("a++").should be_true
CommentThread.tag_name_valid?("a++ b++ c++").should be_true
CommentThread.tag_name_valid?("a#b+").should be_true
CommentThread.tag_name_valid?("a##").should be_true
CommentThread.tag_name_valid?("a#-b#").should be_true
CommentThread.tag_name_valid?("000a123").should be_true
CommentThread.tag_name_valid?("artificial-intelligence").should be_true
CommentThread.tag_name_valid?("artificial intelligence").should be_true
CommentThread.tag_name_valid?("well-known formulas").should be_true
CommentThread.tag_name_valid?("a#+b#").should be_false
CommentThread.tag_name_valid?("a# +b#").should be_false
CommentThread.tag_name_valid?("--a").should be_false
CommentThread.tag_name_valid?("artificial_intelligence").should be_false
CommentThread.tag_name_valid?("#this-is-a-tag").should be_false
CommentThread.tag_name_valid?("_this-is-a-tag").should be_false
CommentThread.tag_name_valid?("this-is+a-tag").should be_false
end
context "endorsed?" do
......
......@@ -200,7 +200,7 @@ def check_thread_result(user, thread, json_response, check_comments=false, is_se
json_response["votes"]["up_count"].should == thread.votes["up_count"]
json_response["votes"]["down_count"].should == thread.votes["down_count"]
json_response["abuse_flaggers"].should == thread.abuse_flaggers
json_response["tags"].should == thread.tags_array
json_response["tags"].should == []
json_response["type"].should == "thread"
json_response["group_id"].should == thread.group_id
json_response["pinned"].should == thread.pinned?
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment