Merge branch 'fix_whisper'
This commit is contained in:
commit
33d0a23d84
|
@ -98,3 +98,7 @@ pre code {
|
||||||
#offscreen-content {
|
#offscreen-content {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
|
@ -382,7 +382,7 @@ class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
def preload_current_user_data
|
def preload_current_user_data
|
||||||
store_preloaded("currentUser", MultiJson.dump(CurrentUserSerializer.new(current_user, scope: guardian, root: false)))
|
store_preloaded("currentUser", MultiJson.dump(CurrentUserSerializer.new(current_user, scope: guardian, root: false)))
|
||||||
report = TopicTrackingState.report(current_user.id)
|
report = TopicTrackingState.report(current_user)
|
||||||
serializer = ActiveModel::ArraySerializer.new(report, each_serializer: TopicTrackingStateSerializer)
|
serializer = ActiveModel::ArraySerializer.new(report, each_serializer: TopicTrackingStateSerializer)
|
||||||
store_preloaded("topicTrackingStates", MultiJson.dump(serializer))
|
store_preloaded("topicTrackingStates", MultiJson.dump(serializer))
|
||||||
end
|
end
|
||||||
|
|
|
@ -152,7 +152,7 @@ class UsersController < ApplicationController
|
||||||
user = fetch_user_from_params
|
user = fetch_user_from_params
|
||||||
guardian.ensure_can_edit!(user)
|
guardian.ensure_can_edit!(user)
|
||||||
|
|
||||||
report = TopicTrackingState.report(user.id)
|
report = TopicTrackingState.report(user)
|
||||||
serializer = ActiveModel::ArraySerializer.new(report, each_serializer: TopicTrackingStateSerializer)
|
serializer = ActiveModel::ArraySerializer.new(report, each_serializer: TopicTrackingStateSerializer)
|
||||||
|
|
||||||
render json: MultiJson.dump(serializer)
|
render json: MultiJson.dump(serializer)
|
||||||
|
|
|
@ -24,7 +24,7 @@ class Post < ActiveRecord::Base
|
||||||
rate_limit :limit_posts_per_day
|
rate_limit :limit_posts_per_day
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :topic, counter_cache: :posts_count
|
belongs_to :topic
|
||||||
|
|
||||||
belongs_to :reply_to_user, class_name: "User"
|
belongs_to :reply_to_user, class_name: "User"
|
||||||
|
|
||||||
|
|
|
@ -435,8 +435,10 @@ SQL
|
||||||
post_action_type: post_action_type_key)
|
post_action_type: post_action_type_key)
|
||||||
end
|
end
|
||||||
|
|
||||||
topic_count = Post.where(topic_id: topic_id).sum(column)
|
if column == "like_count"
|
||||||
Topic.where(id: topic_id).update_all ["#{column} = ?", topic_count]
|
topic_count = Post.where(topic_id: topic_id).sum(column)
|
||||||
|
Topic.where(id: topic_id).update_all ["#{column} = ?", topic_count]
|
||||||
|
end
|
||||||
|
|
||||||
if PostActionType.notify_flag_type_ids.include?(post_action_type_id)
|
if PostActionType.notify_flag_type_ids.include?(post_action_type_id)
|
||||||
PostAction.update_flagged_posts_count
|
PostAction.update_flagged_posts_count
|
||||||
|
|
|
@ -466,23 +466,103 @@ class Topic < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
# Atomically creates the next post number
|
# Atomically creates the next post number
|
||||||
def self.next_post_number(topic_id, reply = false)
|
def self.next_post_number(topic_id, reply = false, whisper = false)
|
||||||
highest = exec_sql("select coalesce(max(post_number),0) as max from posts where topic_id = ?", topic_id).first['max'].to_i
|
highest = exec_sql("select coalesce(max(post_number),0) as max from posts where topic_id = ?", topic_id).first['max'].to_i
|
||||||
|
|
||||||
reply_sql = reply ? ", reply_count = reply_count + 1" : ""
|
if whisper
|
||||||
result = exec_sql("UPDATE topics SET highest_post_number = ? + 1#{reply_sql}
|
|
||||||
WHERE id = ? RETURNING highest_post_number", highest, topic_id)
|
result = exec_sql("UPDATE topics
|
||||||
result.first['highest_post_number'].to_i
|
SET highest_staff_post_number = ? + 1
|
||||||
|
WHERE id = ?
|
||||||
|
RETURNING highest_staff_post_number", highest, topic_id)
|
||||||
|
|
||||||
|
result.first['highest_staff_post_number'].to_i
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
reply_sql = reply ? ", reply_count = reply_count + 1" : ""
|
||||||
|
|
||||||
|
result = exec_sql("UPDATE topics
|
||||||
|
SET highest_staff_post_number = :highest + 1,
|
||||||
|
highest_post_number = :highest + 1#{reply_sql},
|
||||||
|
posts_count = posts_count + 1
|
||||||
|
WHERE id = :topic_id
|
||||||
|
RETURNING highest_post_number", highest: highest, topic_id: topic_id)
|
||||||
|
|
||||||
|
result.first['highest_post_number'].to_i
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def self.reset_all_highest!
|
||||||
|
exec_sql <<SQL
|
||||||
|
WITH
|
||||||
|
X as (
|
||||||
|
SELECT topic_id,
|
||||||
|
COALESCE(MAX(post_number), 0) highest_post_number
|
||||||
|
FROM posts
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
GROUP BY topic_id
|
||||||
|
),
|
||||||
|
Y as (
|
||||||
|
SELECT topic_id,
|
||||||
|
coalesce(MAX(post_number), 0) highest_post_number,
|
||||||
|
count(*) posts_count,
|
||||||
|
max(created_at) last_posted_at
|
||||||
|
FROM posts
|
||||||
|
WHERE deleted_at IS NULL AND post_type <> 4
|
||||||
|
GROUP BY topic_id
|
||||||
|
)
|
||||||
|
UPDATE topics
|
||||||
|
SET
|
||||||
|
highest_staff_post_number = X.highest_post_number,
|
||||||
|
highest_post_number = Y.highest_post_number,
|
||||||
|
last_posted_at = Y.last_posted_at,
|
||||||
|
posts_count = Y.posts_count
|
||||||
|
FROM X, Y
|
||||||
|
WHERE
|
||||||
|
X.topic_id = topics.id AND
|
||||||
|
Y.topic_id = topics.id AND (
|
||||||
|
topics.highest_staff_post_number <> X.highest_post_number OR
|
||||||
|
topics.highest_post_number <> Y.highest_post_number OR
|
||||||
|
topics.last_posted_at <> Y.last_posted_at OR
|
||||||
|
topics.posts_count <> Y.posts_count
|
||||||
|
)
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
# If a post is deleted we have to update our highest post counters
|
# If a post is deleted we have to update our highest post counters
|
||||||
def self.reset_highest(topic_id)
|
def self.reset_highest(topic_id)
|
||||||
result = exec_sql "UPDATE topics
|
result = exec_sql "UPDATE topics
|
||||||
SET highest_post_number = (SELECT COALESCE(MAX(post_number), 0) FROM posts WHERE topic_id = :topic_id AND deleted_at IS NULL),
|
SET
|
||||||
posts_count = (SELECT count(*) FROM posts WHERE deleted_at IS NULL AND topic_id = :topic_id),
|
highest_staff_post_number = (
|
||||||
last_posted_at = (SELECT MAX(created_at) FROM POSTS WHERE topic_id = :topic_id AND deleted_at IS NULL)
|
SELECT COALESCE(MAX(post_number), 0) FROM posts
|
||||||
|
WHERE topic_id = :topic_id AND
|
||||||
|
deleted_at IS NULL
|
||||||
|
),
|
||||||
|
highest_post_number = (
|
||||||
|
SELECT COALESCE(MAX(post_number), 0) FROM posts
|
||||||
|
WHERE topic_id = :topic_id AND
|
||||||
|
deleted_at IS NULL AND
|
||||||
|
post_type <> 4
|
||||||
|
),
|
||||||
|
posts_count = (
|
||||||
|
SELECT count(*) FROM posts
|
||||||
|
WHERE deleted_at IS NULL AND
|
||||||
|
topic_id = :topic_id AND
|
||||||
|
post_type <> 4
|
||||||
|
),
|
||||||
|
|
||||||
|
last_posted_at = (
|
||||||
|
SELECT MAX(created_at) FROM posts
|
||||||
|
WHERE topic_id = :topic_id AND
|
||||||
|
deleted_at IS NULL AND
|
||||||
|
post_type <> 4
|
||||||
|
)
|
||||||
WHERE id = :topic_id
|
WHERE id = :topic_id
|
||||||
RETURNING highest_post_number", topic_id: topic_id
|
RETURNING highest_post_number", topic_id: topic_id
|
||||||
|
|
||||||
highest_post_number = result.first['highest_post_number'].to_i
|
highest_post_number = result.first['highest_post_number'].to_i
|
||||||
|
|
||||||
# Update the forum topic user records
|
# Update the forum topic user records
|
||||||
|
@ -724,10 +804,7 @@ class Topic < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_action_counts
|
def update_action_counts
|
||||||
PostActionType.types.each_key do |type|
|
update_column(:like_count, Post.where(topic_id: id).sum(:like_count))
|
||||||
count_field = "#{type}_count"
|
|
||||||
update_column(count_field, Post.where(topic_id: id).sum(count_field))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def posters_summary(options = {})
|
def posters_summary(options = {})
|
||||||
|
|
|
@ -38,7 +38,7 @@ class TopicTrackingState
|
||||||
publish_read(topic.id, 1, topic.user_id)
|
publish_read(topic.id, 1, topic.user_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.publish_latest(topic)
|
def self.publish_latest(topic, staff_only=false)
|
||||||
return unless topic.archetype == "regular"
|
return unless topic.archetype == "regular"
|
||||||
|
|
||||||
message = {
|
message = {
|
||||||
|
@ -52,15 +52,25 @@ class TopicTrackingState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
group_ids = topic.category && topic.category.secure_group_ids
|
group_ids =
|
||||||
|
if staff_only
|
||||||
|
[Group::AUTO_GROUPS[:staff]]
|
||||||
|
else
|
||||||
|
topic.category && topic.category.secure_group_ids
|
||||||
|
end
|
||||||
MessageBus.publish("/latest", message.as_json, group_ids: group_ids)
|
MessageBus.publish("/latest", message.as_json, group_ids: group_ids)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.publish_unread(post)
|
def self.publish_unread(post)
|
||||||
# TODO at high scale we are going to have to defer this,
|
# TODO at high scale we are going to have to defer this,
|
||||||
# perhaps cut down to users that are around in the last 7 days as well
|
# perhaps cut down to users that are around in the last 7 days as well
|
||||||
#
|
|
||||||
group_ids = post.topic.category && post.topic.category.secure_group_ids
|
group_ids =
|
||||||
|
if post.post_type == Post.types[:whisper]
|
||||||
|
[Group::AUTO_GROUPS[:staff]]
|
||||||
|
else
|
||||||
|
post.topic.category && post.topic.category.secure_group_ids
|
||||||
|
end
|
||||||
|
|
||||||
TopicUser
|
TopicUser
|
||||||
.tracking(post.topic_id)
|
.tracking(post.topic_id)
|
||||||
|
@ -148,7 +158,7 @@ class TopicTrackingState
|
||||||
).where_values[0]
|
).where_values[0]
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.report(user_id, topic_id = nil)
|
def self.report(user, topic_id = nil)
|
||||||
|
|
||||||
# Sam: this is a hairy report, in particular I need custom joins and fancy conditions
|
# Sam: this is a hairy report, in particular I need custom joins and fancy conditions
|
||||||
# Dropping to sql_builder so I can make sense of it.
|
# Dropping to sql_builder so I can make sense of it.
|
||||||
|
@ -160,12 +170,12 @@ class TopicTrackingState
|
||||||
# cycles from usual requests
|
# cycles from usual requests
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
sql = report_raw_sql(topic_id: topic_id, skip_unread: true, skip_order: true)
|
sql = report_raw_sql(topic_id: topic_id, skip_unread: true, skip_order: true, staff: user.staff?)
|
||||||
sql << "\nUNION ALL\n\n"
|
sql << "\nUNION ALL\n\n"
|
||||||
sql << report_raw_sql(topic_id: topic_id, skip_new: true, skip_order: true)
|
sql << report_raw_sql(topic_id: topic_id, skip_new: true, skip_order: true, staff: user.staff?)
|
||||||
|
|
||||||
SqlBuilder.new(sql)
|
SqlBuilder.new(sql)
|
||||||
.map_exec(TopicTrackingState, user_id: user_id, topic_id: topic_id)
|
.map_exec(TopicTrackingState, user_id: user.id, topic_id: topic_id)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -176,7 +186,7 @@ class TopicTrackingState
|
||||||
if opts && opts[:skip_unread]
|
if opts && opts[:skip_unread]
|
||||||
"1=0"
|
"1=0"
|
||||||
else
|
else
|
||||||
TopicQuery.unread_filter(Topic).where_values.join(" AND ")
|
TopicQuery.unread_filter(Topic, staff: opts && opts[:staff]).where_values.join(" AND ")
|
||||||
end
|
end
|
||||||
|
|
||||||
new =
|
new =
|
||||||
|
@ -190,7 +200,7 @@ class TopicTrackingState
|
||||||
u.id AS user_id,
|
u.id AS user_id,
|
||||||
topics.id AS topic_id,
|
topics.id AS topic_id,
|
||||||
topics.created_at,
|
topics.created_at,
|
||||||
highest_post_number,
|
#{opts && opts[:staff] ? "highest_staff_post_number highest_post_number" : "highest_post_number"},
|
||||||
last_read_post_number,
|
last_read_post_number,
|
||||||
c.id AS category_id,
|
c.id AS category_id,
|
||||||
tu.notification_level"
|
tu.notification_level"
|
||||||
|
|
|
@ -236,6 +236,8 @@ SQL
|
||||||
topic_users.notification_level, tu.notification_level old_level, tu.last_read_post_number
|
topic_users.notification_level, tu.notification_level old_level, tu.last_read_post_number
|
||||||
"
|
"
|
||||||
|
|
||||||
|
UPDATE_TOPIC_USER_SQL_STAFF = UPDATE_TOPIC_USER_SQL.gsub("highest_post_number", "highest_staff_post_number")
|
||||||
|
|
||||||
INSERT_TOPIC_USER_SQL = "INSERT INTO topic_users (user_id, topic_id, last_read_post_number, highest_seen_post_number, last_visited_at, first_visited_at, notification_level)
|
INSERT_TOPIC_USER_SQL = "INSERT INTO topic_users (user_id, topic_id, last_read_post_number, highest_seen_post_number, last_visited_at, first_visited_at, notification_level)
|
||||||
SELECT :user_id, :topic_id, :post_number, ft.highest_post_number, :now, :now, :new_status
|
SELECT :user_id, :topic_id, :post_number, ft.highest_post_number, :now, :now, :new_status
|
||||||
FROM topics AS ft
|
FROM topics AS ft
|
||||||
|
@ -245,6 +247,8 @@ SQL
|
||||||
FROM topic_users AS ftu
|
FROM topic_users AS ftu
|
||||||
WHERE ftu.user_id = :user_id and ftu.topic_id = :topic_id)"
|
WHERE ftu.user_id = :user_id and ftu.topic_id = :topic_id)"
|
||||||
|
|
||||||
|
INSERT_TOPIC_USER_SQL_STAFF = INSERT_TOPIC_USER_SQL.gsub("highest_post_number", "highest_staff_post_number")
|
||||||
|
|
||||||
def update_last_read(user, topic_id, post_number, msecs, opts={})
|
def update_last_read(user, topic_id, post_number, msecs, opts={})
|
||||||
return if post_number.blank?
|
return if post_number.blank?
|
||||||
msecs = 0 if msecs.to_i < 0
|
msecs = 0 if msecs.to_i < 0
|
||||||
|
@ -265,7 +269,11 @@ SQL
|
||||||
# ... user visited the topic but did not read the posts
|
# ... user visited the topic but did not read the posts
|
||||||
#
|
#
|
||||||
# 86400000 = 1 day
|
# 86400000 = 1 day
|
||||||
rows = exec_sql(UPDATE_TOPIC_USER_SQL,args).values
|
rows = if user.staff?
|
||||||
|
exec_sql(UPDATE_TOPIC_USER_SQL_STAFF,args).values
|
||||||
|
else
|
||||||
|
exec_sql(UPDATE_TOPIC_USER_SQL,args).values
|
||||||
|
end
|
||||||
|
|
||||||
if rows.length == 1
|
if rows.length == 1
|
||||||
before = rows[0][1].to_i
|
before = rows[0][1].to_i
|
||||||
|
@ -295,7 +303,11 @@ SQL
|
||||||
user.update_posts_read!(post_number, mobile: opts[:mobile])
|
user.update_posts_read!(post_number, mobile: opts[:mobile])
|
||||||
|
|
||||||
begin
|
begin
|
||||||
exec_sql(INSERT_TOPIC_USER_SQL, args)
|
if user.staff?
|
||||||
|
exec_sql(INSERT_TOPIC_USER_SQL_STAFF, args)
|
||||||
|
else
|
||||||
|
exec_sql(INSERT_TOPIC_USER_SQL, args)
|
||||||
|
end
|
||||||
rescue PG::UniqueViolation
|
rescue PG::UniqueViolation
|
||||||
# if record is inserted between two statements this can happen
|
# if record is inserted between two statements this can happen
|
||||||
# we retry once to avoid failing the req
|
# we retry once to avoid failing the req
|
||||||
|
|
|
@ -109,7 +109,7 @@ class ListableTopicSerializer < BasicTopicSerializer
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def unread_helper
|
def unread_helper
|
||||||
@unread_helper ||= Unread.new(object, object.user_data)
|
@unread_helper ||= Unread.new(object, object.user_data, scope)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -967,7 +967,7 @@ en:
|
||||||
email_token_grace_period_hours: "Forgot password / activate account tokens are still valid for a grace period of (n) hours after being redeemed."
|
email_token_grace_period_hours: "Forgot password / activate account tokens are still valid for a grace period of (n) hours after being redeemed."
|
||||||
|
|
||||||
enable_badges: "Enable the badge system"
|
enable_badges: "Enable the badge system"
|
||||||
enable_whispers: "Allow staff private communication within topic. (experimental)"
|
enable_whispers: "Allow staff private communication within topics."
|
||||||
|
|
||||||
allow_index_in_robots_txt: "Specify in robots.txt that this site is allowed to be indexed by web search engines."
|
allow_index_in_robots_txt: "Specify in robots.txt that this site is allowed to be indexed by web search engines."
|
||||||
email_domains_blacklist: "A pipe-delimited list of email domains that users are not allowed to register accounts with. Example: mailinator.com|trashmail.net"
|
email_domains_blacklist: "A pipe-delimited list of email domains that users are not allowed to register accounts with. Example: mailinator.com|trashmail.net"
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
class AddWhisperSupportToTopics < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
remove_column :topics, :bookmark_count
|
||||||
|
remove_column :topics, :off_topic_count
|
||||||
|
remove_column :topics, :illegal_count
|
||||||
|
remove_column :topics, :inappropriate_count
|
||||||
|
remove_column :topics, :notify_user_count
|
||||||
|
|
||||||
|
add_column :topics, :highest_staff_post_number, :int, default: 0, null: false
|
||||||
|
execute "UPDATE topics SET highest_staff_post_number = highest_post_number"
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
raise ActiveRecord::IrreversibleMigration
|
||||||
|
end
|
||||||
|
end
|
|
@ -146,6 +146,9 @@ class PostCreator
|
||||||
end
|
end
|
||||||
|
|
||||||
if @post && errors.blank?
|
if @post && errors.blank?
|
||||||
|
# update counters etc.
|
||||||
|
@post.topic.reload
|
||||||
|
|
||||||
publish
|
publish
|
||||||
|
|
||||||
track_latest_on_category
|
track_latest_on_category
|
||||||
|
@ -199,7 +202,9 @@ class PostCreator
|
||||||
set_reply_info(post)
|
set_reply_info(post)
|
||||||
|
|
||||||
post.word_count = post.raw.scan(/[[:word:]]+/).size
|
post.word_count = post.raw.scan(/[[:word:]]+/).size
|
||||||
post.post_number ||= Topic.next_post_number(post.topic_id, post.reply_to_post_number.present?)
|
|
||||||
|
whisper = post.post_type == Post.types[:whisper]
|
||||||
|
post.post_number ||= Topic.next_post_number(post.topic_id, post.reply_to_post_number.present?, whisper)
|
||||||
|
|
||||||
cooking_options = post.cooking_options || {}
|
cooking_options = post.cooking_options || {}
|
||||||
cooking_options[:topic_id] = post.topic_id
|
cooking_options[:topic_id] = post.topic_id
|
||||||
|
|
|
@ -35,7 +35,7 @@ class PostJobsEnqueuer
|
||||||
|
|
||||||
def after_post_create
|
def after_post_create
|
||||||
TopicTrackingState.publish_unread(@post) if @post.post_number > 1
|
TopicTrackingState.publish_unread(@post) if @post.post_number > 1
|
||||||
TopicTrackingState.publish_latest(@topic)
|
TopicTrackingState.publish_latest(@topic, @post.post_type == Post.types[:whisper])
|
||||||
|
|
||||||
Jobs.enqueue_in(
|
Jobs.enqueue_in(
|
||||||
SiteSetting.email_time_window_mins.minutes,
|
SiteSetting.email_time_window_mins.minutes,
|
||||||
|
|
|
@ -242,9 +242,12 @@ class TopicQuery
|
||||||
.where("COALESCE(tu.notification_level, :tracking) >= :tracking", tracking: TopicUser.notification_levels[:tracking])
|
.where("COALESCE(tu.notification_level, :tracking) >= :tracking", tracking: TopicUser.notification_levels[:tracking])
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.unread_filter(list)
|
def self.unread_filter(list, opts)
|
||||||
list.where("tu.last_read_post_number < topics.highest_post_number")
|
col_name = opts[:staff] ? "highest_staff_post_number" : "highest_post_number"
|
||||||
.where("COALESCE(tu.notification_level, :regular) >= :tracking", regular: TopicUser.notification_levels[:regular], tracking: TopicUser.notification_levels[:tracking])
|
|
||||||
|
list.where("tu.last_read_post_number < topics.#{col_name}")
|
||||||
|
.where("COALESCE(tu.notification_level, :regular) >= :tracking",
|
||||||
|
regular: TopicUser.notification_levels[:regular], tracking: TopicUser.notification_levels[:tracking])
|
||||||
end
|
end
|
||||||
|
|
||||||
def prioritize_pinned_topics(topics, options)
|
def prioritize_pinned_topics(topics, options)
|
||||||
|
@ -320,7 +323,7 @@ class TopicQuery
|
||||||
end
|
end
|
||||||
|
|
||||||
def unread_results(options={})
|
def unread_results(options={})
|
||||||
result = TopicQuery.unread_filter(default_results(options.reverse_merge(:unordered => true)))
|
result = TopicQuery.unread_filter(default_results(options.reverse_merge(:unordered => true)), staff: @user.try(:staff?))
|
||||||
.order('CASE WHEN topics.user_id = tu.user_id THEN 1 ELSE 2 END')
|
.order('CASE WHEN topics.user_id = tu.user_id THEN 1 ELSE 2 END')
|
||||||
|
|
||||||
self.class.results_filter_callbacks.each do |filter_callback|
|
self.class.results_filter_callbacks.each do |filter_callback|
|
||||||
|
@ -656,7 +659,7 @@ class TopicQuery
|
||||||
end
|
end
|
||||||
|
|
||||||
def unread_messages(params)
|
def unread_messages(params)
|
||||||
TopicQuery.unread_filter(messages_for_groups_or_user(params[:my_group_ids]))
|
TopicQuery.unread_filter(messages_for_groups_or_user(params[:my_group_ids]), staff: @user.try(:staff?))
|
||||||
.limit(params[:count])
|
.limit(params[:count])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,8 @@ class Unread
|
||||||
|
|
||||||
# This module helps us calculate unread and new post counts
|
# This module helps us calculate unread and new post counts
|
||||||
|
|
||||||
def initialize(topic, topic_user)
|
def initialize(topic, topic_user, guardian)
|
||||||
|
@guardian = guardian
|
||||||
@topic = topic
|
@topic = topic
|
||||||
@topic_user = topic_user
|
@topic_user = topic_user
|
||||||
end
|
end
|
||||||
|
@ -18,9 +19,12 @@ class Unread
|
||||||
def new_posts
|
def new_posts
|
||||||
return 0 if @topic_user.highest_seen_post_number.blank?
|
return 0 if @topic_user.highest_seen_post_number.blank?
|
||||||
return 0 if do_not_notify?(@topic_user.notification_level)
|
return 0 if do_not_notify?(@topic_user.notification_level)
|
||||||
return 0 if (@topic_user.last_read_post_number||0) > @topic.highest_post_number
|
|
||||||
|
|
||||||
new_posts = (@topic.highest_post_number - @topic_user.highest_seen_post_number)
|
highest_post_number = @guardian.is_staff? ? @topic.highest_staff_post_number : @topic.highest_post_number
|
||||||
|
|
||||||
|
return 0 if (@topic_user.last_read_post_number||0) > highest_post_number
|
||||||
|
|
||||||
|
new_posts = (highest_post_number - @topic_user.highest_seen_post_number)
|
||||||
new_posts = 0 if new_posts < 0
|
new_posts = 0 if new_posts < 0
|
||||||
return new_posts
|
return new_posts
|
||||||
end
|
end
|
||||||
|
|
|
@ -334,7 +334,12 @@ describe PostCreator do
|
||||||
context 'whisper' do
|
context 'whisper' do
|
||||||
let!(:topic) { Fabricate(:topic, user: user) }
|
let!(:topic) { Fabricate(:topic, user: user) }
|
||||||
|
|
||||||
it 'forces replies to whispers to be whispers' do
|
it 'whispers do not mess up the public view' do
|
||||||
|
|
||||||
|
first = PostCreator.new(user,
|
||||||
|
topic_id: topic.id,
|
||||||
|
raw: 'this is the first post').create
|
||||||
|
|
||||||
whisper = PostCreator.new(user,
|
whisper = PostCreator.new(user,
|
||||||
topic_id: topic.id,
|
topic_id: topic.id,
|
||||||
reply_to_post_number: 1,
|
reply_to_post_number: 1,
|
||||||
|
@ -344,6 +349,7 @@ describe PostCreator do
|
||||||
expect(whisper).to be_present
|
expect(whisper).to be_present
|
||||||
expect(whisper.post_type).to eq(Post.types[:whisper])
|
expect(whisper.post_type).to eq(Post.types[:whisper])
|
||||||
|
|
||||||
|
|
||||||
whisper_reply = PostCreator.new(user,
|
whisper_reply = PostCreator.new(user,
|
||||||
topic_id: topic.id,
|
topic_id: topic.id,
|
||||||
reply_to_post_number: whisper.post_number,
|
reply_to_post_number: whisper.post_number,
|
||||||
|
@ -352,6 +358,29 @@ describe PostCreator do
|
||||||
|
|
||||||
expect(whisper_reply).to be_present
|
expect(whisper_reply).to be_present
|
||||||
expect(whisper_reply.post_type).to eq(Post.types[:whisper])
|
expect(whisper_reply.post_type).to eq(Post.types[:whisper])
|
||||||
|
|
||||||
|
|
||||||
|
first.reload
|
||||||
|
# does not leak into the OP
|
||||||
|
expect(first.reply_count).to eq(0)
|
||||||
|
|
||||||
|
topic.reload
|
||||||
|
|
||||||
|
# cause whispers should not muck up that number
|
||||||
|
expect(topic.highest_post_number).to eq(1)
|
||||||
|
expect(topic.reply_count).to eq(0)
|
||||||
|
expect(topic.posts_count).to eq(1)
|
||||||
|
expect(topic.highest_staff_post_number).to eq(3)
|
||||||
|
|
||||||
|
topic.update_columns(highest_staff_post_number:0, highest_post_number:0, posts_count: 0, last_posted_at: 1.year.ago)
|
||||||
|
|
||||||
|
Topic.reset_highest(topic.id)
|
||||||
|
|
||||||
|
topic.reload
|
||||||
|
expect(topic.highest_post_number).to eq(1)
|
||||||
|
expect(topic.posts_count).to eq(1)
|
||||||
|
expect(topic.last_posted_at).to eq(first.created_at)
|
||||||
|
expect(topic.highest_staff_post_number).to eq(3)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -624,6 +653,8 @@ describe PostCreator do
|
||||||
_post2 = create_post(user: post1.user, topic_id: post1.topic_id)
|
_post2 = create_post(user: post1.user, topic_id: post1.topic_id)
|
||||||
|
|
||||||
post1.topic.reload
|
post1.topic.reload
|
||||||
|
|
||||||
|
expect(post1.topic.posts_count).to eq(3)
|
||||||
expect(post1.topic.closed).to eq(true)
|
expect(post1.topic.closed).to eq(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -409,6 +409,29 @@ describe TopicQuery do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with whispers' do
|
||||||
|
|
||||||
|
it 'correctly shows up in unread for staff' do
|
||||||
|
|
||||||
|
first = create_post(raw: 'this is the first post', title: 'super amazing title')
|
||||||
|
|
||||||
|
_whisper = create_post(topic_id: first.topic.id,
|
||||||
|
post_type: Post.types[:whisper],
|
||||||
|
raw: 'this is a whispered reply')
|
||||||
|
|
||||||
|
topic_id = first.topic.id
|
||||||
|
|
||||||
|
TopicUser.update_last_read(user, topic_id, first.post_number, 1)
|
||||||
|
TopicUser.update_last_read(admin, topic_id, first.post_number, 1)
|
||||||
|
|
||||||
|
TopicUser.change(user.id, topic_id, notification_level: TopicUser.notification_levels[:tracking])
|
||||||
|
TopicUser.change(admin.id, topic_id, notification_level: TopicUser.notification_levels[:tracking])
|
||||||
|
|
||||||
|
expect(TopicQuery.new(user).list_unread.topics).to eq([])
|
||||||
|
expect(TopicQuery.new(admin).list_unread.topics).to eq([first.topic])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with read data' do
|
context 'with read data' do
|
||||||
let!(:partially_read) { Fabricate(:post, user: creator).topic }
|
let!(:partially_read) { Fabricate(:post, user: creator).topic }
|
||||||
let!(:fully_read) { Fabricate(:post, user: creator).topic }
|
let!(:fully_read) { Fabricate(:post, user: creator).topic }
|
||||||
|
@ -419,8 +442,9 @@ describe TopicQuery do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'list_unread' do
|
context 'list_unread' do
|
||||||
it 'contains no topics' do
|
it 'lists topics correctly' do
|
||||||
expect(topic_query.list_unread.topics).to eq([])
|
expect(topic_query.list_unread.topics).to eq([])
|
||||||
|
expect(topic_query.list_read.topics).to match_array([fully_read, partially_read])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -435,11 +459,6 @@ describe TopicQuery do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'list_read' do
|
|
||||||
it 'contain both topics ' do
|
|
||||||
expect(topic_query.list_read.topics).to match_array([fully_read, partially_read])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -630,7 +649,6 @@ describe TopicQuery do
|
||||||
related_by_group_pm = create_pm(sender, target_group_names: [group_with_user.name])
|
related_by_group_pm = create_pm(sender, target_group_names: [group_with_user.name])
|
||||||
read(user, related_by_group_pm, 1)
|
read(user, related_by_group_pm, 1)
|
||||||
|
|
||||||
|
|
||||||
expect(TopicQuery.new(user).list_suggested_for(pm_to_group).topics.map(&:id)).to(
|
expect(TopicQuery.new(user).list_suggested_for(pm_to_group).topics.map(&:id)).to(
|
||||||
eq([related_by_group_pm.id, related_by_user_pm.id, pm_to_user.id])
|
eq([related_by_group_pm.id, related_by_user_pm.id, pm_to_user.id])
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,62 +3,86 @@ require 'unread'
|
||||||
|
|
||||||
describe Unread do
|
describe Unread do
|
||||||
|
|
||||||
|
let (:user) { Fabricate.build(:user, id: 1) }
|
||||||
before do
|
let (:topic) do
|
||||||
@topic = Fabricate(:topic, posts_count: 13, highest_post_number: 13)
|
Fabricate.build(:topic,
|
||||||
@topic.notifier.watch_topic!(@topic.user_id)
|
posts_count: 13,
|
||||||
@topic_user = TopicUser.get(@topic, @topic.user)
|
highest_staff_post_number: 15,
|
||||||
@topic_user.stubs(:notification_level).returns(TopicUser.notification_levels[:tracking])
|
highest_post_number: 13,
|
||||||
@topic_user.notification_level = TopicUser.notification_levels[:tracking]
|
id: 1)
|
||||||
@unread = Unread.new(@topic, @topic_user)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let (:topic_user) do
|
||||||
|
Fabricate.build(:topic_user,
|
||||||
|
notification_level: TopicUser.notification_levels[:tracking],
|
||||||
|
topic_id: topic.id,
|
||||||
|
user_id: user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def unread
|
||||||
|
Unread.new(topic, topic_user, Guardian.new(user))
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'staff counts' do
|
||||||
|
it 'shoule correctly return based on staff post number' do
|
||||||
|
|
||||||
|
user.admin = true
|
||||||
|
|
||||||
|
topic_user.last_read_post_number = 13
|
||||||
|
topic_user.highest_seen_post_number = 13
|
||||||
|
|
||||||
|
expect(unread.unread_posts).to eq(0)
|
||||||
|
expect(unread.new_posts).to eq(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
describe 'unread_posts' do
|
describe 'unread_posts' do
|
||||||
it 'should have 0 unread posts if the user has seen all posts' do
|
it 'should have 0 unread posts if the user has seen all posts' do
|
||||||
@topic_user.stubs(:last_read_post_number).returns(13)
|
topic_user.last_read_post_number = 13
|
||||||
@topic_user.stubs(:highest_seen_post_number).returns(13)
|
topic_user.highest_seen_post_number = 13
|
||||||
expect(@unread.unread_posts).to eq(0)
|
expect(unread.unread_posts).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should have 6 unread posts if the user has seen all but 6 posts' do
|
it 'should have 6 unread posts if the user has seen all but 6 posts' do
|
||||||
@topic_user.stubs(:last_read_post_number).returns(5)
|
topic_user.last_read_post_number = 5
|
||||||
@topic_user.stubs(:highest_seen_post_number).returns(11)
|
topic_user.highest_seen_post_number = 11
|
||||||
expect(@unread.unread_posts).to eq(6)
|
expect(unread.unread_posts).to eq(6)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should have 0 unread posts if the user has seen more posts than exist (deleted)' do
|
it 'should have 0 unread posts if the user has seen more posts than exist (deleted)' do
|
||||||
@topic_user.stubs(:last_read_post_number).returns(100)
|
topic_user.last_read_post_number = 100
|
||||||
@topic_user.stubs(:highest_seen_post_number).returns(13)
|
topic_user.highest_seen_post_number = 13
|
||||||
expect(@unread.unread_posts).to eq(0)
|
expect(unread.unread_posts).to eq(0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'new_posts' do
|
describe 'new_posts' do
|
||||||
it 'should have 0 new posts if the user has read all posts' do
|
it 'should have 0 new posts if the user has read all posts' do
|
||||||
@topic_user.stubs(:last_read_post_number).returns(13)
|
topic_user.last_read_post_number = 13
|
||||||
expect(@unread.new_posts).to eq(0)
|
expect(unread.new_posts).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns 0 when the topic is the same length as when you last saw it' do
|
it 'returns 0 when the topic is the same length as when you last saw it' do
|
||||||
@topic_user.stubs(:highest_seen_post_number).returns(13)
|
topic_user.highest_seen_post_number = 13
|
||||||
expect(@unread.new_posts).to eq(0)
|
expect(unread.new_posts).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has 3 new posts if the user has read 10 posts' do
|
it 'has 3 new posts if the user has read 10 posts' do
|
||||||
@topic_user.stubs(:highest_seen_post_number).returns(10)
|
topic_user.highest_seen_post_number = 10
|
||||||
expect(@unread.new_posts).to eq(3)
|
expect(unread.new_posts).to eq(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has 0 new posts if the user has read 10 posts but is not tracking' do
|
it 'has 0 new posts if the user has read 10 posts but is not tracking' do
|
||||||
@topic_user.stubs(:highest_seen_post_number).returns(10)
|
topic_user.highest_seen_post_number = 10
|
||||||
@topic_user.stubs(:notification_level).returns(TopicUser.notification_levels[:regular])
|
topic_user.notification_level = TopicUser.notification_levels[:regular]
|
||||||
expect(@unread.new_posts).to eq(0)
|
expect(unread.new_posts).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has 0 new posts if the user read more posts than exist (deleted)' do
|
it 'has 0 new posts if the user read more posts than exist (deleted)' do
|
||||||
@topic_user.stubs(:highest_seen_post_number).returns(16)
|
topic_user.highest_seen_post_number = 16
|
||||||
expect(@unread.new_posts).to eq(0)
|
expect(unread.new_posts).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Fabricator(:topic_user) do
|
||||||
|
user
|
||||||
|
topic
|
||||||
|
end
|
|
@ -199,10 +199,6 @@ describe PostAction do
|
||||||
expect { bookmark.save; post.reload }.to change(post, :bookmark_count).by(1)
|
expect { bookmark.save; post.reload }.to change(post, :bookmark_count).by(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "increases the forum topic's bookmark count when saved" do
|
|
||||||
expect { bookmark.save; post.topic.reload }.to change(post.topic, :bookmark_count).by(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'when deleted' do
|
describe 'when deleted' do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -218,9 +214,6 @@ describe PostAction do
|
||||||
expect { post.reload }.to change(post, :bookmark_count).by(-1)
|
expect { post.reload }.to change(post, :bookmark_count).by(-1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'reduces the bookmark count of the forum topic' do
|
|
||||||
expect { @topic.reload }.to change(post.topic, :bookmark_count).by(-1)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -291,19 +284,24 @@ describe PostAction do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'when a user votes for something' do
|
describe 'when a user likes something' do
|
||||||
it 'should increase the vote counts when a user votes' do
|
it 'should increase the like counts when a user votes' do
|
||||||
expect {
|
expect {
|
||||||
PostAction.act(codinghorror, post, PostActionType.types[:vote])
|
PostAction.act(codinghorror, post, PostActionType.types[:like])
|
||||||
post.reload
|
post.reload
|
||||||
}.to change(post, :vote_count).by(1)
|
}.to change(post, :like_count).by(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should increase the forum topic vote count when a user votes' do
|
it 'should increase the forum topic vote count when a user votes' do
|
||||||
expect {
|
expect {
|
||||||
PostAction.act(codinghorror, post, PostActionType.types[:vote])
|
PostAction.act(codinghorror, post, PostActionType.types[:like])
|
||||||
post.topic.reload
|
post.topic.reload
|
||||||
}.to change(post.topic, :vote_count).by(1)
|
}.to change(post.topic, :like_count).by(1)
|
||||||
|
|
||||||
|
expect {
|
||||||
|
PostAction.remove_act(codinghorror, post, PostActionType.types[:like])
|
||||||
|
post.topic.reload
|
||||||
|
}.to change(post.topic, :like_count).by(-1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1724,4 +1724,21 @@ describe Topic do
|
||||||
|
|
||||||
expect(@topic_status_event_triggered).to eq(true)
|
expect(@topic_status_event_triggered).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
it 'allows users to normalize counts' do
|
||||||
|
|
||||||
|
topic = Fabricate(:topic, last_posted_at: 1.year.ago)
|
||||||
|
post1 = Fabricate(:post, topic: topic, post_number: 1)
|
||||||
|
post2 = Fabricate(:post, topic: topic, post_type: Post.types[:whisper], post_number: 2)
|
||||||
|
|
||||||
|
Topic.reset_all_highest!
|
||||||
|
topic.reload
|
||||||
|
|
||||||
|
expect(topic.posts_count).to eq(1)
|
||||||
|
expect(topic.highest_post_number).to eq(post1.post_number)
|
||||||
|
expect(topic.highest_staff_post_number).to eq(post2.post_number)
|
||||||
|
expect(topic.last_posted_at).to be_within(1.second).of (post1.created_at)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,7 +20,7 @@ describe TopicTrackingState do
|
||||||
user = Fabricate(:user)
|
user = Fabricate(:user)
|
||||||
post
|
post
|
||||||
|
|
||||||
report = TopicTrackingState.report(user.id)
|
report = TopicTrackingState.report(user)
|
||||||
expect(report.length).to eq(1)
|
expect(report.length).to eq(1)
|
||||||
|
|
||||||
CategoryUser.create!(user_id: user.id,
|
CategoryUser.create!(user_id: user.id,
|
||||||
|
@ -30,12 +30,12 @@ describe TopicTrackingState do
|
||||||
|
|
||||||
create_post(topic_id: post.topic_id)
|
create_post(topic_id: post.topic_id)
|
||||||
|
|
||||||
report = TopicTrackingState.report(user.id)
|
report = TopicTrackingState.report(user)
|
||||||
expect(report.length).to eq(0)
|
expect(report.length).to eq(0)
|
||||||
|
|
||||||
TopicUser.create!(user_id: user.id, topic_id: post.topic_id, last_read_post_number: 1, notification_level: 3)
|
TopicUser.create!(user_id: user.id, topic_id: post.topic_id, last_read_post_number: 1, notification_level: 3)
|
||||||
|
|
||||||
report = TopicTrackingState.report(user.id)
|
report = TopicTrackingState.report(user)
|
||||||
expect(report.length).to eq(1)
|
expect(report.length).to eq(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -62,18 +62,18 @@ describe TopicTrackingState do
|
||||||
TopicUser.change(user.id, post2.topic_id, tracking)
|
TopicUser.change(user.id, post2.topic_id, tracking)
|
||||||
TopicUser.change(user.id, post3.topic_id, tracking)
|
TopicUser.change(user.id, post3.topic_id, tracking)
|
||||||
|
|
||||||
report = TopicTrackingState.report(user.id)
|
report = TopicTrackingState.report(user)
|
||||||
expect(report.length).to eq(3)
|
expect(report.length).to eq(3)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "correctly gets the tracking state" do
|
it "correctly gets the tracking state" do
|
||||||
report = TopicTrackingState.report(user.id)
|
report = TopicTrackingState.report(user)
|
||||||
expect(report.length).to eq(0)
|
expect(report.length).to eq(0)
|
||||||
|
|
||||||
post.topic.notifier.watch_topic!(post.topic.user_id)
|
post.topic.notifier.watch_topic!(post.topic.user_id)
|
||||||
|
|
||||||
report = TopicTrackingState.report(user.id)
|
report = TopicTrackingState.report(user)
|
||||||
|
|
||||||
expect(report.length).to eq(1)
|
expect(report.length).to eq(1)
|
||||||
row = report[0]
|
row = report[0]
|
||||||
|
@ -84,18 +84,18 @@ describe TopicTrackingState do
|
||||||
expect(row.user_id).to eq(user.id)
|
expect(row.user_id).to eq(user.id)
|
||||||
|
|
||||||
# lets not leak out random users
|
# lets not leak out random users
|
||||||
expect(TopicTrackingState.report(post.user_id)).to be_empty
|
expect(TopicTrackingState.report(post.user)).to be_empty
|
||||||
|
|
||||||
# lets not return anything if we scope on non-existing topic
|
# lets not return anything if we scope on non-existing topic
|
||||||
expect(TopicTrackingState.report(user.id, post.topic_id + 1)).to be_empty
|
expect(TopicTrackingState.report(user, post.topic_id + 1)).to be_empty
|
||||||
|
|
||||||
# when we reply the poster should have an unread row
|
# when we reply the poster should have an unread row
|
||||||
create_post(user: user, topic: post.topic)
|
create_post(user: user, topic: post.topic)
|
||||||
|
|
||||||
report = TopicTrackingState.report(user.id)
|
report = TopicTrackingState.report(user)
|
||||||
expect(report.length).to eq(0)
|
expect(report.length).to eq(0)
|
||||||
|
|
||||||
report = TopicTrackingState.report(post.user_id)
|
report = TopicTrackingState.report(post.user)
|
||||||
expect(report.length).to eq(1)
|
expect(report.length).to eq(1)
|
||||||
|
|
||||||
row = report[0]
|
row = report[0]
|
||||||
|
@ -111,7 +111,7 @@ describe TopicTrackingState do
|
||||||
post.topic.category_id = category.id
|
post.topic.category_id = category.id
|
||||||
post.topic.save
|
post.topic.save
|
||||||
|
|
||||||
expect(TopicTrackingState.report(post.user_id)).to be_empty
|
expect(TopicTrackingState.report(post.user)).to be_empty
|
||||||
expect(TopicTrackingState.report(user.id)).to be_empty
|
expect(TopicTrackingState.report(user)).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue