Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
cs_comments_service
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
cs_comments_service
Commits
66482b54
Commit
66482b54
authored
Aug 04, 2014
by
Jim Abramson
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #112 from edx/jsa/thread-filters
Add/update thread filters (flagged, unread, unanswered).
parents
3021d716
3f21215e
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
407 additions
and
218 deletions
+407
-218
api/comment_threads.rb
+20
-4
api/commentables.rb
+16
-4
api/notifications_and_subscriptions.rb
+12
-1
api/search.rb
+20
-39
config/application.yml
+1
-0
lib/helpers.rb
+73
-44
models/user.rb
+1
-1
spec/api/comment_thread_spec.rb
+101
-12
spec/api/notifications_and_subscriptions_spec.rb
+116
-0
spec/api/search_spec.rb
+47
-0
spec/api/subscription_and_notification_spec.rb
+0
-113
No files found.
api/comment_threads.rb
View file @
66482b54
get
"
#{
APIPREFIX
}
/threads"
do
# retrieve threads by course
threads
=
Content
.
where
({
"_type"
=>
"CommentThread"
,
"course_id"
=>
params
[
"course_id"
]})
if
params
[
:commentable_ids
]
threads
=
threads
.
in
({
"commentable_id"
=>
params
[
:commentable_ids
].
split
(
","
)})
end
#if a group id is sent, then process the set of threads with that group id or with no group id
threads
=
Content
.
where
(
_type
:"CommentThread"
,
course_id:
params
[
"course_id"
])
if
params
[
"group_id"
]
threads
=
threads
.
any_of
(
{
:group_id
=>
params
[
:group_id
].
to_i
},
{
:group_id
.
exists
=>
false
},
{
"group_id"
=>
params
[
:group_id
].
to_i
},
{
"group_id"
=>
{
"$exists"
=>
false
}
},
)
end
handle_threads_query
(
threads
)
handle_threads_query
(
threads
,
params
[
"user_id"
],
params
[
"course_id"
],
value_to_boolean
(
params
[
"flagged"
]),
value_to_boolean
(
params
[
"unread"
]),
value_to_boolean
(
params
[
"unanswered"
]),
params
[
"sort_key"
],
params
[
"sort_order"
],
params
[
"page"
],
params
[
"per_page"
]
).
to_json
end
get
"
#{
APIPREFIX
}
/threads/:thread_id"
do
|
thread_id
|
...
...
api/commentables.rb
View file @
66482b54
...
...
@@ -4,14 +4,26 @@ delete "#{APIPREFIX}/:commentable_id/threads" do |commentable_id|
end
get
"
#{
APIPREFIX
}
/:commentable_id/threads"
do
|
commentable_id
|
threads
=
Content
.
where
(
_type
:"CommentThread"
,
commentable_id:
commentable_id
)
threads
=
Content
.
where
(
{
"_type"
=>
"CommentThread"
,
"commentable_id"
=>
commentable_id
}
)
if
params
[
"group_id"
]
threads
=
threads
.
any_of
(
{
:group_id
=>
params
[
:group_id
].
to_i
},
{
:group_id
.
exists
=>
false
},
{
"group_id"
=>
params
[
:group_id
].
to_i
},
{
"group_id"
=>
{
"$exists"
=>
false
}},
)
end
handle_threads_query
(
threads
)
handle_threads_query
(
threads
,
params
[
"user_id"
],
params
[
"course_id"
],
value_to_boolean
(
params
[
"flagged"
]),
value_to_boolean
(
params
[
"unread"
]),
value_to_boolean
(
params
[
"unanswered"
]),
params
[
"sort_key"
],
params
[
"sort_order"
],
params
[
"page"
],
params
[
"per_page"
]
).
to_json
end
post
"
#{
APIPREFIX
}
/:commentable_id/threads"
do
|
commentable_id
|
...
...
api/notifications_and_subscriptions.rb
View file @
66482b54
...
...
@@ -3,7 +3,18 @@ get "#{APIPREFIX}/users/:user_id/notifications" do |user_id|
end
get
"
#{
APIPREFIX
}
/users/:user_id/subscribed_threads"
do
|
user_id
|
handle_threads_query
(
user
.
subscribed_threads
)
handle_threads_query
(
user
.
subscribed_threads
.
where
({
"course_id"
=>
params
[
:course_id
]}),
params
[
"user_id"
],
params
[
"course_id"
],
value_to_boolean
(
params
[
"flagged"
]),
value_to_boolean
(
params
[
"unread"
]),
value_to_boolean
(
params
[
"unanswered"
]),
params
[
"sort_key"
],
params
[
"sort_order"
],
params
[
"page"
],
params
[
"per_page"
]
).
to_json
end
post
"
#{
APIPREFIX
}
/users/:user_id/subscriptions"
do
|
user_id
|
...
...
api/search.rb
View file @
66482b54
...
...
@@ -2,15 +2,10 @@ require 'new_relic/agent/method_tracer'
get
"
#{
APIPREFIX
}
/search/threads"
do
local_params
=
params
# Necessary for params to be available inside blocks
sort_criteria
=
get_sort_criteria
(
local_params
)
search_text
=
local_params
[
"text"
]
if
!
search_text
||
!
sort_criteria
if
!
search_text
{}.
to_json
else
page
=
(
local_params
[
"page"
]
||
DEFAULT_PAGE
).
to_i
per_page
=
(
local_params
[
"per_page"
]
||
DEFAULT_PER_PAGE
).
to_i
# Because threads and comments are currently separate unrelated documents in
# Elasticsearch, we must first query for all matching documents, then
# extract the set of thread ids, and then sort the threads by the specified
...
...
@@ -72,40 +67,26 @@ get "#{APIPREFIX}/search/threads" do
corrected_text
=
nil
if
thread_ids
.
empty?
end
results
=
nil
self
.
class
.
trace_execution_scoped
([
"Custom/get_search_threads/mongo_sort_page"
])
do
results
=
CommentThread
.
where
(
:id
.
in
=>
thread_ids
.
to_a
).
order_by
(
sort_criteria
).
page
(
page
).
per
(
per_page
).
to_a
end
total_results
=
thread_ids
.
size
num_pages
=
(
total_results
+
per_page
-
1
)
/
per_page
if
results
.
length
==
0
collection
=
[]
else
pres_threads
=
ThreadListPresenter
.
new
(
results
,
local_params
[
:user_id
]
?
user
:
nil
,
local_params
[
:course_id
]
||
results
.
first
.
course_id
)
collection
=
pres_threads
.
to_hash
end
json_output
=
nil
self
.
class
.
trace_execution_scoped
([
'Custom/get_search_threads/json_serialize'
])
do
json_output
=
{
collection:
collection
,
corrected_text:
corrected_text
,
total_results:
total_results
,
num_pages:
num_pages
,
page:
page
,
}.
to_json
result_obj
=
handle_threads_query
(
CommentThread
.
in
({
"_id"
=>
thread_ids
.
to_a
}),
local_params
[
"user_id"
],
local_params
[
"course_id"
],
value_to_boolean
(
local_params
[
"flagged"
]),
value_to_boolean
(
local_params
[
"unread"
]),
value_to_boolean
(
local_params
[
"unanswered"
]),
local_params
[
"sort_key"
],
local_params
[
"sort_order"
],
local_params
[
"page"
],
local_params
[
"per_page"
]
)
if
!
result_obj
.
empty?
result_obj
[
:corrected_text
]
=
corrected_text
# NOTE this reflects the total results from ES, but does not consider
# any post-filtering that might happen (e.g. unread, flagged...) before
# results are shown to the user.
result_obj
[
:total_results
]
=
thread_ids
.
size
end
json_output
result_obj
.
to_json
end
end
...
...
config/application.yml
View file @
66482b54
...
...
@@ -3,3 +3,4 @@ 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
:
<%= ENV['SERVICE_LANGUAGE'] || 'en-US' %>
manual_pagination_batch_size
:
<%= ENV['MANUAL_PAGINATION_BATCH_SIZE'] || 500 %>
lib/helpers.rb
View file @
66482b54
...
...
@@ -116,72 +116,101 @@ helpers do
end
def
handle_threads_query
(
comment_threads
)
def
handle_threads_query
(
comment_threads
,
user_id
,
course_id
,
filter_flagged
,
filter_unread
,
filter_unanswered
,
sort_key
,
sort_order
,
page
,
per_page
)
if
params
[
:course_id
]
comment_threads
=
comment_threads
.
where
(
:course_id
=>
params
[
:course_id
])
if
params
[
:flagged
]
self
.
class
.
trace_execution_scoped
([
'Custom/handle_threads_query/find_flagged'
])
do
#get flagged threads and threads containing flagged responses
comment_ids
=
Comment
.
where
(
:course_id
=>
params
[
:course_id
]).
where
(
:abuse_flaggers
.
ne
=>
[],
:abuse_flaggers
.
exists
=>
true
).
collect
{
|
c
|
c
.
comment_thread_id
}.
uniq
thread_ids
=
comment_threads
.
where
(
:abuse_flaggers
.
ne
=>
[],
:abuse_flaggers
.
exists
=>
true
).
collect
{
|
c
|
c
.
id
}
comment_ids
+=
thread_ids
if
filter_flagged
self
.
class
.
trace_execution_scoped
([
'Custom/handle_threads_query/find_flagged'
])
do
# TODO replace with aggregate query?
comment_ids
=
Comment
.
where
(
:course_id
=>
course_id
).
where
(
:abuse_flaggers
.
ne
=>
[],
:abuse_flaggers
.
exists
=>
true
).
collect
{
|
c
|
c
.
comment_thread_id
}.
uniq
comment_threads
=
comment_threads
.
where
(
:id
.
in
=>
comment_ids
)
end
thread_ids
=
comment_threads
.
where
(
:abuse_flaggers
.
ne
=>
[],
:abuse_flaggers
.
exists
=>
true
).
collect
{
|
c
|
c
.
id
}
comment_threads
=
comment_threads
.
in
({
"_id"
=>
(
comment_ids
+
thread_ids
).
uniq
})
end
end
if
params
[
:commentable_ids
]
comment_threads
=
comment_threads
.
in
(
commentable_id:
params
[
:commentable_ids
].
split
(
","
))
if
filter_unanswered
self
.
class
.
trace_execution_scoped
([
'Custom/handle_threads_query/find_unanswered'
])
do
endorsed_thread_ids
=
Comment
.
where
(
:course_id
=>
course_id
).
where
(
:parent_id
.
exists
=>
false
,
:endorsed
=>
true
).
collect
{
|
c
|
c
.
comment_thread_id
}.
uniq
comment_threads
=
comment_threads
.
where
({
"thread_type"
=>
:question
}).
nin
({
"_id"
=>
endorsed_thread_ids
})
end
end
sort_criteria
=
get_sort_criteria
(
params
)
sort_criteria
=
get_sort_criteria
(
sort_key
,
sort_order
)
if
not
sort_criteria
{}
.
to_json
{}
else
page
=
(
params
[
"page"
]
||
DEFAULT_PAGE
).
to_i
per_page
=
(
params
[
"per_page"
]
||
DEFAULT_PER_PAGE
).
to_i
request_user
=
user_id
?
user
:
nil
page
=
(
page
||
DEFAULT_PAGE
).
to_i
per_page
=
(
per_page
||
DEFAULT_PER_PAGE
).
to_i
comment_threads
=
comment_threads
.
order_by
(
sort_criteria
)
num_pages
=
[
1
,
(
comment_threads
.
count
/
per_page
.
to_f
).
ceil
].
max
page
=
[
num_pages
,
[
1
,
page
].
max
].
min
# actual query happens here (by doing to_a)
threads
=
comment_threads
.
page
(
page
).
per
(
per_page
).
to_a
if
request_user
and
filter_unread
# Filter and paginate based on user read state. Requires joining a subdocument of the
# user object with documents in the contents collection, which has to be done in memory.
read_dates
=
{}
read_state
=
request_user
.
read_states
.
where
(
:course_id
=>
course_id
).
first
if
read_state
read_dates
=
read_state
[
"last_read_times"
].
to_hash
end
threads
=
[]
skipped
=
0
to_skip
=
(
page
-
1
)
*
per_page
has_more
=
false
# batch_size is used to cap the number of documents we might load into memory at any given time
# TODO: starting with Mongoid 3.1, you can just do comment_threads.batch_size(size).each()
comment_threads
.
query
.
batch_size
(
CommentService
.
config
[
"manual_pagination_batch_size"
].
to_i
)
Mongoid
.
unit_of_work
(
disable: :current
)
do
# this is to prevent Mongoid from memoizing every document we look at
comment_threads
.
each
do
|
thread
|
thread_key
=
thread
.
_id
.
to_s
if
!
read_dates
.
has_key?
(
thread_key
)
||
read_dates
[
thread_key
]
<
thread
.
last_activity_at
if
skipped
>=
to_skip
if
threads
.
length
==
per_page
has_more
=
true
break
end
threads
<<
thread
else
skipped
+=
1
end
end
end
end
# The following trick makes frontend pagers work without recalculating
# the number of all unread threads per user on every request (since the number
# of threads in a course could be tens or hundreds of thousands). It has the
# effect of showing that there's always just one more page of results, until
# there definitely are no more pages. This is really only acceptable for pagers
# that don't actually reveal the total number of pages to the user onscreen.
num_pages
=
has_more
?
page
+
1
:
page
else
# let the installed paginator library handle pagination
num_pages
=
[
1
,
(
comment_threads
.
count
/
per_page
.
to_f
).
ceil
].
max
page
=
[
1
,
page
].
max
threads
=
comment_threads
.
page
(
page
).
per
(
per_page
).
to_a
end
if
threads
.
length
==
0
collection
=
[]
else
pres_threads
=
ThreadListPresenter
.
new
(
threads
,
params
[
:user_id
]
?
user
:
nil
,
params
[
:course_id
]
||
threads
.
first
.
course_id
)
pres_threads
=
ThreadListPresenter
.
new
(
threads
,
request_user
,
course_id
)
collection
=
pres_threads
.
to_hash
end
json_output
=
nil
self
.
class
.
trace_execution_scoped
([
'Custom/handle_threads_query/json_serialize'
])
do
json_output
=
{
collection:
collection
,
num_pages:
num_pages
,
page:
page
,
}.
to_json
end
json_output
{
collection:
collection
,
num_pages:
num_pages
,
page:
page
}
end
end
# Given query params, return sort criteria appropriate for passing to the
# order_by function of a Mongoid query. Returns nil if params are not valid.
def
get_sort_criteria
(
params
)
def
get_sort_criteria
(
sort_key
,
sort_order
)
sort_key_mapper
=
{
"date"
=>
:created_at
,
"activity"
=>
:last_activity_at
,
...
...
models/user.rb
View file @
66482b54
...
...
@@ -31,7 +31,7 @@ class User
end
def
subscribed_threads
CommentThread
.
where
(
:id
.
in
=>
subscribed_thread_ids
)
CommentThread
.
in
({
"_id"
=>
subscribed_thread_ids
}
)
end
def
to_hash
(
params
=
{})
...
...
spec/api/comment_thread_spec.rb
View file @
66482b54
...
...
@@ -103,6 +103,59 @@ describe "app" do
rs
.
length
.
should
==
0
end
end
it
"filters unread posts"
do
user
=
create_test_user
(
Random
.
new
)
rs
=
thread_result
course_id:
DFLT_COURSE_ID
,
user_id:
user
.
id
rs
.
length
.
should
==
10
rs2
=
thread_result
course_id:
DFLT_COURSE_ID
,
user_id:
user
.
id
,
unread:
true
rs2
.
should
==
rs
user
.
mark_as_read
(
@threads
[
rs
.
first
[
"title"
]])
rs3
=
thread_result
course_id:
DFLT_COURSE_ID
,
user_id:
user
.
id
,
unread:
true
rs3
.
should
==
rs
[
1
..
9
]
rs
[
1
..
8
].
each
{
|
r
|
user
.
mark_as_read
(
@threads
[
r
[
"title"
]])
}
rs4
=
thread_result
course_id:
DFLT_COURSE_ID
,
user_id:
user
.
id
,
unread:
true
rs4
.
should
==
rs
[
9
,
1
]
user
.
mark_as_read
(
@threads
[
rs
.
last
[
"title"
]])
rs5
=
thread_result
course_id:
DFLT_COURSE_ID
,
user_id:
user
.
id
,
unread:
true
rs5
.
should
==
[]
make_comment
(
create_test_user
(
Random
.
new
),
@threads
[
rs
.
first
[
"title"
]],
"new activity"
)
rs6
=
thread_result
course_id:
DFLT_COURSE_ID
,
user_id:
user
.
id
,
unread:
true
rs6
.
length
.
should
==
1
rs6
.
first
[
"title"
].
should
==
rs
.
first
[
"title"
]
end
it
"filters unanswered questions"
do
%w[t9 t7 t5 t3 t1]
.
each
do
|
thread_key
|
@threads
[
thread_key
].
thread_type
=
:question
@threads
[
thread_key
].
save!
end
rs
=
thread_result
course_id:
DFLT_COURSE_ID
,
unanswered:
true
rs
.
length
.
should
==
5
@comments
[
"t1 c0"
].
endorsed
=
true
@comments
[
"t1 c0"
].
save!
rs2
=
thread_result
course_id:
DFLT_COURSE_ID
,
unanswered:
true
rs2
.
length
.
should
==
4
%w[t9 t7 t5]
.
each
do
|
thread_key
|
comment
=
@threads
[
thread_key
].
comments
.
first
comment
.
endorsed
=
true
comment
.
save!
end
rs3
=
thread_result
course_id:
DFLT_COURSE_ID
,
unanswered:
true
rs3
.
length
.
should
==
1
@comments
[
"t3 c0"
].
endorsed
=
true
@comments
[
"t3 c0"
].
save!
rs3
=
thread_result
course_id:
DFLT_COURSE_ID
,
unanswered:
true
rs3
.
length
.
should
==
0
end
it
"ignores endorsed comments that are not question responses"
do
thread
=
@threads
[
"t0"
]
thread
.
thread_type
=
:question
thread
.
save!
comment
=
make_comment
(
create_test_user
(
Random
.
new
),
thread
.
comments
.
first
,
"comment on a response"
)
comment
.
endorsed
=
true
comment
.
save!
rs
=
thread_result
course_id:
DFLT_COURSE_ID
,
unanswered:
true
rs
.
length
.
should
==
1
end
it
"correctly considers read state"
do
user
=
create_test_user
(
123
)
[
@threads
[
"t1"
],
@threads
[
"t2"
]].
each
do
|
t
|
...
...
@@ -259,8 +312,8 @@ describe "app" do
end
context
"pagination"
do
def
thread_result_page
(
sort_key
,
sort_order
,
page
,
per_page
)
get
"/api/v1/threads"
,
course_id:
DFLT_COURSE_ID
,
sort_key:
sort_key
,
sort_order:
sort_order
,
page:
page
,
per_page:
per_page
def
thread_result_page
(
sort_key
,
sort_order
,
page
,
per_page
,
user_id
=
nil
,
unread
=
false
)
get
"/api/v1/threads"
,
course_id:
DFLT_COURSE_ID
,
sort_key:
sort_key
,
sort_order:
sort_order
,
page:
page
,
per_page:
per_page
,
user_id:
user_id
,
unread:
unread
last_response
.
should
be_ok
parse
(
last_response
.
body
)
end
...
...
@@ -282,24 +335,60 @@ describe "app" do
result
[
"num_pages"
].
should
==
2
result
[
"page"
].
should
==
2
end
it
"orders correctly across pages"
do
make_comment
(
@threads
[
"t5"
].
author
,
@threads
[
"t5"
],
"extra comment"
)
@threads
[
"t7"
].
pinned
=
tru
e
@threads
[
"t7"
].
save!
expected_order
=
move_to_front
(
move_to_end
(
@default_order
,
"t5"
),
"t7"
)
def
test_paged_order
(
sort_spec
,
expected_order
,
filter_spec
=
[],
user_id
=
nil
)
# sort spec is a hash with keys: sort_key, sort_dir, per_pag
e
# filter spec is an array of filters to set, e.g. "unread", "flagged"
# expected order is an array of the expected titles of returned threads, in the expected order
actual_order
=
[]
per_page
=
3
num_pages
=
(
@threads
.
length
+
per_page
-
1
)
/
per_page
per_page
=
sort_spec
[
'per_page'
]
num_pages
=
(
expected_order
.
length
+
per_page
-
1
)
/
per_page
num_pages
.
times
do
|
i
|
page
=
i
+
1
result
=
thread_result_page
(
"comments"
,
"asc"
,
page
,
per_page
)
result
[
"collection"
].
length
.
should
==
(
page
*
per_page
<=
@threads
.
length
?
per_page
:
@threads
.
length
%
per_page
)
result
[
"num_pages"
].
should
==
num_pages
result
=
thread_result_page
(
sort_spec
[
'sort_key'
],
sort_spec
[
'sort_dir'
],
page
,
per_page
,
user_id
,
filter_spec
.
include?
(
"unread"
)
)
result
[
"collection"
].
length
.
should
==
(
page
*
per_page
<=
expected_order
.
length
?
per_page
:
expected_order
.
length
%
per_page
)
if
filter_spec
.
include?
(
"unread"
)
# because of the way we handle num_pages for the unread filter, this is a special case.
result
[
"num_pages"
].
should
==
(
page
==
num_pages
?
page
:
page
+
1
)
else
result
[
"num_pages"
].
should
==
num_pages
end
result
[
"page"
].
should
==
page
actual_order
+=
result
[
"collection"
].
map
{
|
v
|
v
[
"title"
]}
end
actual_order
.
should
==
expected_order
end
it
"orders correctly across pages"
do
make_comment
(
@threads
[
"t5"
].
author
,
@threads
[
"t5"
],
"extra comment"
)
@threads
[
"t7"
].
pinned
=
true
@threads
[
"t7"
].
save!
expected_order
=
move_to_front
(
move_to_end
(
@default_order
,
"t5"
),
"t7"
)
test_paged_order
({
'sort_key'
=>
'comments'
,
'sort_dir'
=>
'asc'
,
'per_page'
=>
3
},
expected_order
)
end
it
"orders correctly acrosss pages with unread filter"
do
user
=
create_test_user
(
Random
.
new
)
user
.
mark_as_read
(
@threads
[
"t0"
])
user
.
mark_as_read
(
@threads
[
"t9"
])
make_comment
(
@threads
[
"t5"
].
author
,
@threads
[
"t5"
],
"extra comment"
)
@threads
[
"t7"
].
pinned
=
true
@threads
[
"t7"
].
save!
expected_order
=
move_to_front
(
move_to_end
(
@default_order
[
1
..
8
],
"t5"
),
"t7"
)
test_paged_order
(
{
'sort_key'
=>
'comments'
,
'sort_dir'
=>
'asc'
,
'per_page'
=>
3
},
expected_order
,
[
"unread"
],
user
.
id
)
end
end
end
...
...
spec/api/notifications_and_subscriptions_spec.rb
0 → 100644
View file @
66482b54
require
'spec_helper'
describe
"app"
do
describe
"notifications and subscriptions"
do
let
(
:subscriber
)
{
create_test_user
(
42
)
}
before
(
:each
)
do
set_api_key_header
setup_10_threads
%w[t9 t7 t5 t3 t1]
.
each
{
|
t
|
subscriber
.
subscribe
(
@threads
[
t
])
}
end
describe
"GET /api/v1/users/:user_id/subscribed_threads"
do
def
thread_result
(
params
)
get
"/api/v1/users/
#{
subscriber
.
id
}
/subscribed_threads"
,
params
last_response
.
should
be_ok
parse
(
last_response
.
body
)[
"collection"
]
end
context
"when filtering flagged posts"
do
it
"returns threads that are flagged"
do
@threads
[
"t1"
].
abuse_flaggers
=
[
1
]
@threads
[
"t1"
].
save!
rs
=
thread_result
course_id:
DFLT_COURSE_ID
,
flagged:
true
rs
.
length
.
should
==
1
check_thread_result_json
(
nil
,
@threads
[
"t1"
],
rs
.
first
)
end
it
"returns threads that have flagged comments"
do
@comments
[
"t2 c3"
].
abuse_flaggers
=
[
1
]
# note: not subscribed
@comments
[
"t2 c3"
].
save!
@comments
[
"t3 c3"
].
abuse_flaggers
=
[
1
]
# subscribed
@comments
[
"t3 c3"
].
save!
rs
=
thread_result
course_id:
DFLT_COURSE_ID
,
flagged:
true
rs
.
length
.
should
==
1
check_thread_result_json
(
nil
,
@threads
[
"t3"
],
rs
.
first
)
end
it
"returns an empty result when no posts were flagged"
do
rs
=
thread_result
course_id:
DFLT_COURSE_ID
,
flagged:
true
rs
.
length
.
should
==
0
end
end
it
"filters unread posts"
do
rs
=
thread_result
course_id:
DFLT_COURSE_ID
rs
.
length
.
should
==
5
rs2
=
thread_result
course_id:
DFLT_COURSE_ID
,
unread:
true
rs2
.
should
==
rs
subscriber
.
mark_as_read
(
@threads
[
rs
.
first
[
"title"
]])
rs3
=
thread_result
course_id:
DFLT_COURSE_ID
,
unread:
true
rs3
.
should
==
rs
[
1
..
4
]
rs
[
1
..
3
].
each
{
|
r
|
subscriber
.
mark_as_read
(
@threads
[
r
[
"title"
]])
}
rs4
=
thread_result
course_id:
DFLT_COURSE_ID
,
unread:
true
rs4
.
should
==
rs
[
4
,
1
]
subscriber
.
mark_as_read
(
@threads
[
rs
.
last
[
"title"
]])
rs5
=
thread_result
course_id:
DFLT_COURSE_ID
,
unread:
true
rs5
.
should
==
[]
make_comment
(
create_test_user
(
Random
.
new
),
@threads
[
rs
.
first
[
"title"
]],
"new activity"
)
rs6
=
thread_result
course_id:
DFLT_COURSE_ID
,
unread:
true
rs6
.
length
.
should
==
1
rs6
.
first
[
"title"
].
should
==
rs
.
first
[
"title"
]
end
it
"filters unanswered questions"
do
%w[t9 t7]
.
each
do
|
thread_key
|
@threads
[
thread_key
].
thread_type
=
:question
@threads
[
thread_key
].
save!
end
rs
=
thread_result
course_id:
DFLT_COURSE_ID
,
unanswered:
true
rs
.
length
.
should
==
2
@comments
[
"t7 c0"
].
endorsed
=
true
@comments
[
"t7 c0"
].
save!
rs2
=
thread_result
course_id:
DFLT_COURSE_ID
,
unanswered:
true
rs2
.
length
.
should
==
1
@comments
[
"t9 c0"
].
endorsed
=
true
@comments
[
"t9 c0"
].
save!
rs3
=
thread_result
course_id:
DFLT_COURSE_ID
,
unanswered:
true
rs3
.
length
.
should
==
0
end
it
"ignores endorsed comments that are not question responses"
do
thread
=
@threads
[
"t1"
]
thread
.
thread_type
=
:question
thread
.
save!
rs
=
thread_result
course_id:
DFLT_COURSE_ID
,
unanswered:
true
rs
.
length
.
should
==
1
comment
=
make_comment
(
create_test_user
(
Random
.
new
),
thread
.
comments
.
first
,
"comment on a response"
)
comment
.
endorsed
=
true
comment
.
save!
rs2
=
thread_result
course_id:
DFLT_COURSE_ID
,
unanswered:
true
rs2
.
length
.
should
==
1
end
end
describe
"POST /api/v1/users/:user_id/subscriptions"
do
it
"subscribe a comment thread"
do
thread
=
@threads
[
"t0"
]
post
"/api/v1/users/
#{
subscriber
.
external_id
}
/subscriptions"
,
source_type:
"thread"
,
source_id:
thread
.
id
last_response
.
should
be_ok
thread
.
subscribers
.
length
.
should
==
1
thread
.
subscribers
[
0
].
should
==
subscriber
end
end
describe
"DELETE /api/v1/users/:user_id/subscriptions"
do
it
"unsubscribe a comment thread"
do
thread
=
@threads
[
"t2"
]
subscriber
.
subscribe
(
thread
)
thread
.
subscribers
.
length
.
should
==
1
thread
.
subscribers
[
0
].
should
==
subscriber
delete
"/api/v1/users/
#{
subscriber
.
external_id
}
/subscriptions"
,
source_type:
"thread"
,
source_id:
thread
.
id
last_response
.
should
be_ok
thread
.
subscribers
.
length
.
should
==
0
end
end
end
end
spec/api/search_spec.rb
View file @
66482b54
...
...
@@ -40,10 +40,21 @@ describe "app" do
let!
(
:threads
)
do
threads
=
(
0
..
29
).
map
do
|
i
|
thread
=
make_thread
(
author
,
"text"
,
course_id
+
(
i
%
2
).
to_s
,
"commentable"
+
(
i
%
3
).
to_s
)
if
i
<
2
comment
=
make_comment
(
author
,
thread
,
"objectionable"
)
comment
.
abuse_flaggers
=
[
1
]
comment
.
save!
end
if
i
%
5
!=
0
thread
.
group_id
=
i
%
5
thread
.
save!
end
if
[
0
,
2
,
4
].
include?
i
thread
.
thread_type
=
:question
thread
.
save!
comment
=
make_comment
(
author
,
thread
,
"response"
)
comment
.
save!
end
thread
end
refresh_es_index
...
...
@@ -63,6 +74,42 @@ describe "app" do
assert_response_contains
((
0
..
29
).
find_all
{
|
i
|
i
%
2
==
0
})
end
it
"with unread filter"
do
user
=
create_test_user
(
Random
.
new
)
user
.
mark_as_read
(
threads
[
0
])
get
"/api/v1/search/threads"
,
text:
"text"
,
course_id:
"test/course/id0"
,
user_id:
user
.
id
,
unread:
true
assert_response_contains
((
1
..
29
).
find_all
{
|
i
|
i
%
2
==
0
})
end
it
"with flagged filter"
do
get
"/api/v1/search/threads"
,
text:
"text"
,
course_id:
"test/course/id0"
,
flagged:
true
assert_response_contains
([
0
])
end
it
"with unanswered filter"
do
get
"/api/v1/search/threads"
,
text:
"text"
,
course_id:
"test/course/id0"
,
unanswered:
true
assert_response_contains
([
0
,
2
,
4
])
comment
=
threads
[
2
].
comments
.
first
comment
.
endorsed
=
true
comment
.
save!
get
"/api/v1/search/threads"
,
text:
"text"
,
course_id:
"test/course/id0"
,
unanswered:
true
assert_response_contains
([
0
,
4
])
end
it
"with unanswered filter and group_id"
do
get
"/api/v1/search/threads"
,
text:
"text"
,
course_id:
"test/course/id0"
,
unanswered:
true
assert_response_contains
([
0
,
2
,
4
])
get
"/api/v1/search/threads"
,
text:
"text"
,
course_id:
"test/course/id0"
,
unanswered:
true
,
group_id:
2
assert_response_contains
([
0
,
2
])
get
"/api/v1/search/threads"
,
text:
"text"
,
course_id:
"test/course/id0"
,
unanswered:
true
,
group_id:
4
assert_response_contains
([
0
,
4
])
comment
=
threads
[
2
].
comments
.
first
comment
.
endorsed
=
true
comment
.
save!
get
"/api/v1/search/threads"
,
text:
"text"
,
course_id:
"test/course/id0"
,
unanswered:
true
,
group_id:
2
assert_response_contains
([
0
])
end
it
"by commentable_id"
do
get
"/api/v1/search/threads"
,
text:
"text"
,
commentable_id:
"commentable0"
assert_response_contains
((
0
..
29
).
find_all
{
|
i
|
i
%
3
==
0
})
...
...
spec/api/subscription_and_notification_spec.rb
deleted
100644 → 0
View file @
3021d716
require
'spec_helper'
# Commenting out until notifications are used again.
#
#describe "app" do
# describe "subscriptions and notifications" do
# before(:each) { init_with_subscriptions }
# describe "GET /api/v1/users/:user_id/notifications" do
# it "get all notifications on the subscribed comment threads for the user" do
# user = User.find("1")
# get "/api/v1/users/#{user.external_id}/notifications"
# last_response.should be_ok
# notifications = parse last_response.body
# so_easy = Comment.all.select{|c| c.body == "this problem is so easy"}.first
# not_for_me_neither = Comment.all.select{|c| c.body == "not for me neither!"}.first
# notification_so_easy = notifications.select{|f| f["notification_type"] == "post_reply" and f["info"]["comment_id"] == so_easy.id.to_s}.first
# notification_so_easy.should_not be_nil
# notification_not_for_me_neither = notifications.select{|f| f["notification_type"] == "post_reply" and f["info"]["comment_id"] == not_for_me_neither.id.to_s}.first
# notification_not_for_me_neither.should_not be_nil
# end
# it "returns error if user does not exist" do #TODO may change later if have user service
# get "/api/v1/users/does_not_exist/notifications"
# last_response.status.should == 400
# end
# it "get all notifications on the subscribed commentable for the user" do
# user = User.find("1")
# get "/api/v1/users/#{user.external_id}/notifications"
# last_response.should be_ok
# notifications = parse last_response.body
# notifications.select{|f| f["notification_type"] == "post_topic"}.length.should == 1
# problem_wrong = notifications.select{|f| f["notification_type"] == "post_topic"}.first
# problem_wrong["info"]["thread_title"].should == "This problem is wrong"
# end
# it "get all notifications on the followed user for the user" do
# user = User.find("2")
# get "/api/v1/users/#{user.external_id}/notifications"
# last_response.should be_ok
# notifications = parse last_response.body
# notifications.select{|f| f["info"]["thread_title"] =~ /what to say/}.first.should_not be_nil
# end
# end
# describe "POST /api/v1/users/:user_id/subscriptions" do
# it "follow user" do
# user1 = User.find("1")
# user2 = User.find("2")
# post "/api/v1/users/#{user1.external_id}/subscriptions", source_type: "user", source_id: user2.external_id
# last_response.should be_ok
# User.find("2").followers.length.should == 1
# User.find("2").followers.should include user1
# end
# it "does not follow the same user twice" do
# user1 = User.find("1")
# user2 = User.find("2")
# post "/api/v1/users/#{user1.external_id}/subscriptions", source_type: "user", source_id: user2.external_id
# post "/api/v1/users/#{user1.external_id}/subscriptions", source_type: "user", source_id: user2.external_id
# last_response.should be_ok
# User.find("2").followers.length.should == 1
# end
# it "does not follow oneself" do
# user = create_test_user(3)
# post "/api/v1/users/#{user.external_id}/subscriptions", source_type: "user", source_id: user.external_id
# last_response.status.should == 400
# user.reload.followers.length.should == 0
# end
# it "unfollow user" do
# user1 = User.find("1")
# user2 = User.find("2")
# delete "/api/v1/users/#{user2.external_id}/subscriptions", source_type: "user", source_id: user1.external_id
# last_response.should be_ok
# User.find("1").followers.length.should == 0
# end
# it "respond ok when unfollowing user twice" do
# user1 = User.find("1")
# user2 = User.find("2")
# delete "/api/v1/users/#{user2.external_id}/subscriptions", source_type: "user", source_id: user1.external_id
# delete "/api/v1/users/#{user2.external_id}/subscriptions", source_type: "user", source_id: user1.external_id
# last_response.should be_ok
# User.find("1").followers.length.should == 0
# end
# it "subscribe a commentable" do
# user3 = create_test_user(3)
# post "/api/v1/users/#{user3.external_id}/subscriptions", source_type: "other", source_id: "question_1"
# last_response.should be_ok
# Commentable.find("question_1").subscribers.length.should == 3
# Commentable.find("question_1").subscribers.should include user3
# end
# it "unsubscribe a commentable" do
# user2 = User.find_by(external_id: "2")
# delete "/api/v1/users/#{user2.external_id}/subscriptions", source_type: "other", source_id: "question_1"
# last_response.should be_ok
# Commentable.find("question_1").subscribers.length.should == 1
# Commentable.find("question_1").subscribers.should_not include user2
# end
# it "subscribe a comment thread" do
# user1 = User.find_by(external_id: "1")
# thread = CommentThread.where(body: "it is unsolvable").first
# post "/api/v1/users/#{user1.external_id}/subscriptions", source_type: "thread", source_id: thread.id
# last_response.should be_ok
# thread = CommentThread.where(body: "it is unsolvable").first
# thread.subscribers.length.should == 2
# thread.subscribers.should include user1
# end
# it "unsubscribe a comment thread" do
# user2 = User.find_by(external_id: "2")
# thread = CommentThread.where(body: "it is unsolvable").first
# delete "/api/v1/users/#{user2.external_id}/subscriptions", source_type: "thread", source_id: thread.id
# last_response.should be_ok
# thread = CommentThread.where(body: "it is unsolvable").first
# thread.subscribers.length.should == 0
# end
# end
# end
#end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment