Revert "FEATURE: Publish read state on group messages. (#7989)"

This reverts commit 1630dae2dbf26b2a0eec639c69ff60643cf6f8d1.
This commit is contained in:
romanrizzi 2019-08-20 10:24:34 -03:00
parent 1630dae2db
commit 67f5cc1ce8
35 changed files with 21 additions and 524 deletions

View File

@ -40,8 +40,7 @@ export default MountWidget.extend({
"gaps", "gaps",
"selectedQuery", "selectedQuery",
"selectedPostsCount", "selectedPostsCount",
"searchService", "searchService"
"showReadIndicator"
); );
}, },
@ -292,12 +291,6 @@ export default MountWidget.extend({
onRefresh: "refreshLikes" onRefresh: "refreshLikes"
}); });
} }
if (args.refreshReaders) {
this.dirtyKeys.keyDirty(`post-menu-${args.id}`, {
onRefresh: "refreshReaders"
});
}
} else if (args.force) { } else if (args.force) {
this.dirtyKeys.forceAll(); this.dirtyKeys.forceAll();
} }

View File

@ -35,42 +35,6 @@ export const ListItemDefaults = {
attributeBindings: ["data-topic-id"], attributeBindings: ["data-topic-id"],
"data-topic-id": Ember.computed.alias("topic.id"), "data-topic-id": Ember.computed.alias("topic.id"),
didInsertElement() {
this._super(...arguments);
if (typeof this.get("topic.read_by_group_member") !== "undefined") {
this.messageBus.subscribe(this.readIndicatorChannel, data => {
const nodeClassList = document.querySelector(
`.indicator-topic-${data.topic_id}`
).classList;
if (data.show_indicator) {
nodeClassList.remove("unread");
} else {
nodeClassList.add("unread");
}
});
}
},
willDestroyElement() {
this._super(...arguments);
if (typeof this.get("topic.read_by_group_member") !== "undefined") {
this.messageBus.unsubscribe(this.readIndicatorChannel);
}
},
@computed("topic.id")
readIndicatorChannel(topicId) {
return `/private-messages/group-read/${topicId}`;
},
@computed("topic.read_by_group_member")
unreadClass(readByGroupMember) {
return readByGroupMember ? "" : "unread";
},
@computed @computed
newDotText() { newDotText() {
return this.currentUser && this.currentUser.trust_level > 0 return this.currentUser && this.currentUser.trust_level > 0

View File

@ -1348,17 +1348,6 @@ export default Ember.Controller.extend(bufferedProperty("model"), {
}) })
.then(() => refresh({ id: data.id, refreshLikes: true })); .then(() => refresh({ id: data.id, refreshLikes: true }));
break; break;
case "read":
postStream
.triggerChangedPost(data.id, data.updated_at, {
preserveCooked: true
})
.then(() =>
refresh({
id: data.id,
refreshReaders: topic.show_read_indicator
})
);
case "revised": case "revised":
case "rebaked": { case "rebaked": {
postStream postStream

View File

@ -71,8 +71,7 @@ export function transformBasicPost(post) {
expandablePost: false, expandablePost: false,
replyCount: post.reply_count, replyCount: post.reply_count,
locked: post.locked, locked: post.locked,
userCustomFields: post.user_custom_fields, userCustomFields: post.user_custom_fields
readCount: post.readers_count
}; };
_additionalAttributes.forEach(a => (postAtts[a] = post[a])); _additionalAttributes.forEach(a => (postAtts[a] = post[a]));

View File

@ -178,8 +178,7 @@ const Group = RestModel.extend({
allow_membership_requests: this.allow_membership_requests, allow_membership_requests: this.allow_membership_requests,
full_name: this.full_name, full_name: this.full_name,
default_notification_level: this.default_notification_level, default_notification_level: this.default_notification_level,
membership_request_template: this.membership_request_template, membership_request_template: this.membership_request_template
publish_read_state: this.publish_read_state
}; };
if (!this.id) { if (!this.id) {

View File

@ -52,16 +52,6 @@
class="groups-form-messageable-level"}} class="groups-form-messageable-level"}}
</div> </div>
<div class="control-group">
<label>
{{input type="checkbox"
checked=model.publish_read_state
class="groups-form-publish-read-state"}}
{{i18n 'admin.groups.manage.interaction.publish_read_state'}}
</label>
</div>
{{#if showEmailSettings}} {{#if showEmailSettings}}
<div class="control-group"> <div class="control-group">
<label class="control-label">{{i18n 'admin.groups.manage.interaction.email'}}</label> <label class="control-label">{{i18n 'admin.groups.manage.interaction.email'}}</label>

View File

@ -23,9 +23,6 @@
{{~#if showTopicPostBadges}} {{~#if showTopicPostBadges}}
{{~raw "topic-post-badges" unread=topic.unread newPosts=topic.displayNewPosts unseen=topic.unseen url=topic.lastUnreadUrl newDotText=newDotText}} {{~raw "topic-post-badges" unread=topic.unread newPosts=topic.displayNewPosts unseen=topic.unseen url=topic.lastUnreadUrl newDotText=newDotText}}
{{~/if}} {{~/if}}
<span class='read-indicator indicator-topic-{{topic.id}} {{readStatus}}'>
{{~d-icon "far-eye"}}
</span>
</span> </span>
<div class="link-bottom-line"> <div class="link-bottom-line">
{{#unless hideCategory}} {{#unless hideCategory}}

View File

@ -177,7 +177,6 @@
selectedPostsCount=selectedPostsCount selectedPostsCount=selectedPostsCount
selectedQuery=selectedQuery selectedQuery=selectedQuery
gaps=model.postStream.gaps gaps=model.postStream.gaps
showReadIndicator=model.show_read_indicator
showFlags=(action "showPostFlags") showFlags=(action "showPostFlags")
editPost=(action "editPost") editPost=(action "editPost")
showHistory=(route-action "showHistory") showHistory=(route-action "showHistory")

View File

@ -52,36 +52,6 @@ export function buildButton(name, widget) {
} }
} }
registerButton("read-count", attrs => {
if (attrs.showReadIndicator) {
const count = attrs.readCount;
if (count > 0) {
return {
action: "toggleWhoRead",
title: "post.controls.read_indicator",
className: "button-count read-indicator",
contents: count,
iconRight: true,
addContainer: false
};
}
}
});
registerButton("read", attrs => {
const disabled = attrs.readCount === 0;
if (attrs.showReadIndicator) {
return {
action: "toggleWhoRead",
title: "post.controls.read_indicator",
icon: "far-eye",
before: "read-count",
addContainer: false,
disabled
};
}
});
function likeCount(attrs) { function likeCount(attrs) {
const count = attrs.likeCount; const count = attrs.likeCount;
@ -371,12 +341,7 @@ export default createWidget("post-menu", {
}, },
defaultState() { defaultState() {
return { return { collapsed: true, likedUsers: [], adminVisible: false };
collapsed: true,
likedUsers: [],
readers: [],
adminVisible: false
};
}, },
buildKey: attrs => `post-menu-${attrs.id}`, buildKey: attrs => `post-menu-${attrs.id}`,
@ -543,19 +508,6 @@ export default createWidget("post-menu", {
); );
} }
if (state.readers.length) {
const remaining = state.totalReaders - state.readers.length;
contents.push(
this.attach("small-user-list", {
users: state.readers,
addSelf: false,
listClassName: "who-read",
description: "post.actions.people.read",
count: remaining
})
);
}
return contents; return contents;
}, },
@ -573,15 +525,9 @@ export default createWidget("post-menu", {
showMoreActions() { showMoreActions() {
this.state.collapsed = false; this.state.collapsed = false;
const likesPromise = !this.state.likedUsers.length if (!this.state.likedUsers.length) {
? this.getWhoLiked() return this.getWhoLiked();
: Ember.RSVP.resolve();
return likesPromise.then(() => {
if (!this.state.readers.length) {
return this.getWhoRead();
} }
});
}, },
like() { like() {
@ -616,12 +562,6 @@ export default createWidget("post-menu", {
} }
}, },
refreshReaders() {
if (this.state.readers.length) {
return this.getWhoRead();
}
},
getWhoLiked() { getWhoLiked() {
const { attrs, state } = this; const { attrs, state } = this;
@ -636,15 +576,6 @@ export default createWidget("post-menu", {
}); });
}, },
getWhoRead() {
const { attrs, state } = this;
return this.store.find("post-reader", { id: attrs.id }).then(users => {
state.readers = users.map(avatarAtts);
state.totalReaders = users.totalRows;
});
},
toggleWhoLiked() { toggleWhoLiked() {
const state = this.state; const state = this.state;
if (state.likedUsers.length) { if (state.likedUsers.length) {
@ -652,14 +583,5 @@ export default createWidget("post-menu", {
} else { } else {
return this.getWhoLiked(); return this.getWhoLiked();
} }
},
toggleWhoRead() {
const state = this.state;
if (this.state.readers.length) {
state.readers = [];
} else {
return this.getWhoRead();
}
} }
}); });

View File

@ -136,7 +136,6 @@ export default createWidget("post-stream", {
this.attach("post-small-action", transformed, { model: post }) this.attach("post-small-action", transformed, { model: post })
); );
} else { } else {
transformed.showReadIndicator = attrs.showReadIndicator;
result.push(this.attach("post", transformed, { model: post })); result.push(this.attach("post", transformed, { model: post }));
} }

View File

@ -133,12 +133,6 @@
.raw-topic-link > * { .raw-topic-link > * {
pointer-events: none; pointer-events: none;
} }
.read-indicator {
&.unread {
display: none;
}
}
} }
.link-bottom-line { .link-bottom-line {

View File

@ -641,8 +641,7 @@ blockquote > *:last-child {
font-size: $font-down-1; font-size: $font-down-1;
} }
.who-liked, .who-liked {
.who-read {
transition: height 0.5s; transition: height 0.5s;
a { a {
margin: 0 0.25em 0.5em 0; margin: 0 0.25em 0.5em 0;

View File

@ -66,7 +66,6 @@ nav.post-controls {
margin-left: 0; margin-left: 0;
margin-right: 0; margin-right: 0;
&.my-likes, &.my-likes,
&.read-indicator,
&.regular-likes { &.regular-likes {
// Like count on posts // Like count on posts
.d-icon { .d-icon {
@ -839,8 +838,7 @@ a.attachment:before {
} }
} }
.who-liked, .who-liked {
.who-read {
margin-top: 20px; margin-top: 20px;
margin-bottom: 0; margin-bottom: 0;
width: 100%; width: 100%;

View File

@ -38,7 +38,6 @@ span.badge-posts {
flex: 0 1 auto; flex: 0 1 auto;
button { button {
&.like, &.like,
&.read-indicator,
&.create-flag { &.create-flag {
flex: 1 1 auto; flex: 1 1 auto;
} }

View File

@ -153,8 +153,7 @@ class Admin::GroupsController < Admin::AdminController
:default_notification_level, :default_notification_level,
:membership_request_template, :membership_request_template,
:owner_usernames, :owner_usernames,
:usernames, :usernames
:publish_read_state
] ]
custom_fields = Group.editable_group_custom_fields custom_fields = Group.editable_group_custom_fields
permitted << { custom_fields: custom_fields } unless custom_fields.blank? permitted << { custom_fields: custom_fields } unless custom_fields.blank?

View File

@ -552,8 +552,7 @@ class GroupsController < ApplicationController
:name, :name,
:grant_trust_level, :grant_trust_level,
:automatic_membership_email_domains, :automatic_membership_email_domains,
:automatic_membership_retroactive, :automatic_membership_retroactive
:publish_read_state
]) ])
custom_fields = Group.editable_group_custom_fields custom_fields = Group.editable_group_custom_fields

View File

@ -1,26 +0,0 @@
# frozen_string_literal: true
class PostReadersController < ApplicationController
requires_login
def index
post = Post.includes(topic: %i[allowed_groups]).find(params[:id])
read_state = post.topic.allowed_groups.any? { |g| g.publish_read_state? && g.users.include?(current_user) }
raise Discourse::InvalidAccess unless read_state
readers = User
.joins(:topic_users)
.where('topic_users.topic_id = ? AND COALESCE(topic_users.last_read_post_number, 1) >= ?', post.topic_id, post.post_number)
.where.not(id: [current_user.id, post.user_id])
readers = readers.map do |r|
{
id: r.id, avatar_template: r.avatar_template,
username: r.username,
username_lower: r.username_lower
}
end
render_json_dump(post_readers: readers)
end
end

View File

@ -897,7 +897,6 @@ end
# visibility_level :integer default(0), not null # visibility_level :integer default(0), not null
# public_exit :boolean default(FALSE), not null # public_exit :boolean default(FALSE), not null
# public_admission :boolean default(FALSE), not null # public_admission :boolean default(FALSE), not null
# publish_read_state :boolean default(FALSE), not null
# membership_request_template :text # membership_request_template :text
# messageable_level :integer default(0) # messageable_level :integer default(0)
# mentionable_level :integer default(0) # mentionable_level :integer default(0)

View File

@ -41,8 +41,7 @@ class TopicList
:current_user, :current_user,
:tags, :tags,
:shared_drafts, :shared_drafts,
:category, :category
:publish_read_state
) )
def initialize(filter, current_user, topics, opts = nil) def initialize(filter, current_user, topics, opts = nil)
@ -58,8 +57,6 @@ class TopicList
if @opts[:tags] if @opts[:tags]
@tags = Tag.where(id: @opts[:tags]).all @tags = Tag.where(id: @opts[:tags]).all
end end
@publish_read_state = !!@opts[:publish_read_state]
end end
def top_tags def top_tags

View File

@ -128,26 +128,19 @@ class TopicTrackingState
end end
def self.publish_read(topic_id, last_read_post_number, user_id, notification_level = nil) def self.publish_read(topic_id, last_read_post_number, user_id, notification_level = nil)
topic = Topic.select(:highest_post_number, :archetype, :id).find_by(id: topic_id) highest_post_number = Topic.where(id: topic_id).pluck(:highest_post_number).first
message = { message = {
topic_id: topic_id, topic_id: topic_id,
message_type: "read", message_type: "read",
payload: { payload: {
last_read_post_number: last_read_post_number, last_read_post_number: last_read_post_number,
highest_post_number: topic.highest_post_number, highest_post_number: highest_post_number,
topic_id: topic_id, topic_id: topic_id,
notification_level: notification_level notification_level: notification_level
} }
} }
if topic.private_message?
groups = read_allowed_groups_of(topic)
post = Post.find_by(topic_id: topic.id, post_number: last_read_post_number)
trigger_post_read_count_update(post, groups)
update_topic_list_read_indicator(topic, groups, last_read_post_number, user_id, true)
end
MessageBus.publish(self.unread_channel_key(user_id), message.as_json, user_ids: [user_id]) MessageBus.publish(self.unread_channel_key(user_id), message.as_json, user_ids: [user_id])
end end
@ -339,8 +332,6 @@ SQL
message = { message = {
topic_id: topic.id topic_id: topic.id
} }
groups = read_allowed_groups_of(topic)
update_topic_list_read_indicator(topic, groups, topic.highest_post_number, topic.last_post_user_id, false)
channels.each do |channel, ids| channels.each do |channel, ids|
MessageBus.publish( MessageBus.publish(
@ -350,27 +341,4 @@ SQL
) )
end end
end end
def self.read_allowed_groups_of(topic)
topic.allowed_groups
.joins(:group_users)
.select('ARRAY_AGG(group_users.user_id) AS members', :name, :publish_read_state)
.group('groups.id')
end
def self.update_topic_list_read_indicator(topic, groups, last_read_post_number, user_id, read_event)
groups.each do |group|
member = group.members.include?(user_id)
next unless group.publish_read_state? && last_read_post_number == topic.highest_post_number
next if (read_event && !member) || (!read_event && member)
message = { topic_id: topic.id, show_indicator: read_event }.as_json
MessageBus.publish("/private-messages/group-read/#{topic.id}", message, user_ids: group.members)
end
end
def self.trigger_post_read_count_update(post, groups)
return if groups.none?(&:publish_read_state?)
post.publish_change_to_clients!(:read)
end
end end

View File

@ -31,8 +31,7 @@ class BasicGroupSerializer < ApplicationSerializer
:is_group_user, :is_group_user,
:is_group_owner, :is_group_owner,
:members_visibility_level, :members_visibility_level,
:can_see_members, :can_see_members
:publish_read_state
def include_display_name? def include_display_name?
object.automatic object.automatic

View File

@ -25,8 +25,7 @@ class ListableTopicSerializer < BasicTopicSerializer
:notification_level, :notification_level,
:bookmarked, :bookmarked,
:liked, :liked,
:unicode_title, :unicode_title
:read_by_group_member
has_one :last_poster, serializer: BasicUserSerializer, embed: :objects has_one :last_poster, serializer: BasicUserSerializer, embed: :objects
@ -122,18 +121,6 @@ class ListableTopicSerializer < BasicTopicSerializer
PinnedCheck.unpinned?(object, object.user_data) PinnedCheck.unpinned?(object, object.user_data)
end end
def read_by_group_member
# object#minimum_unread_count is a dynamically generated attribute.
# See TopicQuery#append_read_state for more information.
return false unless object.respond_to?(:minimum_unread_count)
object.minimum_unread_count && object.minimum_unread_count <= 0
end
def include_read_by_group_member?
!!object.topic_list&.publish_read_state
end
protected protected
def unread_helper def unread_helper

View File

@ -26,7 +26,6 @@ class PostSerializer < BasicPostSerializer
:quote_count, :quote_count,
:incoming_link_count, :incoming_link_count,
:reads, :reads,
:readers_count,
:score, :score,
:yours, :yours,
:topic_id, :topic_id,
@ -459,13 +458,6 @@ class PostSerializer < BasicPostSerializer
can_review_topic? can_review_topic?
end end
def readers_count
read_count = object.reads - 1 # Exclude logged user
read_count -= 1 unless yours
read_count < 0 ? 0 : read_count
end
private private
def can_review_topic? def can_review_topic?

View File

@ -71,8 +71,7 @@ class TopicViewSerializer < ApplicationSerializer
:participant_count, :participant_count,
:destination_category_id, :destination_category_id,
:pm_with_non_human_user, :pm_with_non_human_user,
:queued_posts_count, :queued_posts_count
:show_read_indicator
) )
has_one :details, serializer: TopicViewDetailsSerializer, root: false, embed: :objects has_one :details, serializer: TopicViewDetailsSerializer, root: false, embed: :objects
@ -249,8 +248,4 @@ class TopicViewSerializer < ApplicationSerializer
def include_queued_posts_count? def include_queued_posts_count?
scope.is_staff? && object.queued_posts_enabled scope.is_staff? && object.queued_posts_enabled
end end
def show_read_indicator
object.show_read_indicator?
end
end end

View File

@ -32,7 +32,4 @@ class WebHookPostSerializer < PostSerializer
object.topic ? object.topic.posts_count : 0 object.topic ? object.topic.posts_count : 0
end end
def include_readers_count?
false
end
end end

View File

@ -28,10 +28,6 @@ class WebHookTopicViewSerializer < TopicViewSerializer
end end
end end
def include_show_read_indicator?
false
end
def created_by def created_by
BasicUserSerializer.new(object.topic.user, scope: scope, root: false) BasicUserSerializer.new(object.topic.user, scope: scope, root: false)
end end

View File

@ -2421,7 +2421,6 @@ en:
reply: "begin composing a reply to this post" reply: "begin composing a reply to this post"
like: "like this post" like: "like this post"
has_liked: "you've liked this post" has_liked: "you've liked this post"
read_indicator: "members who read this post"
undo_like: "undo like" undo_like: "undo like"
edit: "edit this post" edit: "edit this post"
edit_action: "Edit" edit_action: "Edit"
@ -2479,7 +2478,6 @@ en:
notify_user: "sent a message" notify_user: "sent a message"
bookmark: "bookmarked this" bookmark: "bookmarked this"
like: "liked this" like: "liked this"
read: "read this"
like_capped: like_capped:
one: "and {{count}} other liked this" one: "and {{count}} other liked this"
other: "and {{count}} others liked this" other: "and {{count}} others liked this"
@ -3219,7 +3217,6 @@ en:
members_visibility_levels: members_visibility_levels:
title: "Who can see this group members?" title: "Who can see this group members?"
description: "Admins can see members of all groups." description: "Admins can see members of all groups."
publish_read_state: "On group messages publish group read state"
membership: membership:
automatic: Automatic automatic: Automatic

View File

@ -614,7 +614,6 @@ Discourse::Application.routes.draw do
get "excerpt" => "excerpt#show" get "excerpt" => "excerpt#show"
resources :post_action_users resources :post_action_users
resources :post_readers, only: %i[index]
resources :post_actions do resources :post_actions do
collection do collection do
get "users" get "users"

View File

@ -191,10 +191,9 @@ basic:
post_menu: post_menu:
client: true client: true
type: list type: list
default: "read|like|share|flag|edit|bookmark|delete|admin|reply" default: "like|share|flag|edit|bookmark|delete|admin|reply"
allow_any: false allow_any: false
choices: choices:
- read
- like - like
- edit - edit
- flag - flag

View File

@ -1,7 +0,0 @@
# frozen_string_literal: true
class GroupsPublishReadState < ActiveRecord::Migration[5.2]
def change
add_column :groups, :publish_read_state, :boolean, null: false, default: false
end
end

View File

@ -344,13 +344,11 @@ class TopicQuery
def list_private_messages_group(user) def list_private_messages_group(user)
list = private_messages_for(user, :group) list = private_messages_for(user, :group)
group = Group.where('name ilike ?', @options[:group_name]).select(:id, :publish_read_state).first group_id = Group.where('name ilike ?', @options[:group_name]).pluck(:id).first
publish_read_state = !!group&.publish_read_state
list = list.joins("LEFT JOIN group_archived_messages gm ON gm.topic_id = topics.id AND list = list.joins("LEFT JOIN group_archived_messages gm ON gm.topic_id = topics.id AND
gm.group_id = #{group&.id&.to_i}") gm.group_id = #{group_id.to_i}")
list = list.where("gm.id IS NULL") list = list.where("gm.id IS NULL")
list = append_read_state(list, group) if publish_read_state create_list(:private_messages, {}, list)
create_list(:private_messages, { publish_read_state: publish_read_state }, list)
end end
def list_private_messages_group_archive(user) def list_private_messages_group_archive(user)
@ -1059,23 +1057,4 @@ class TopicQuery
def sanitize_sql_array(input) def sanitize_sql_array(input)
ActiveRecord::Base.public_send(:sanitize_sql_array, input.join(',')) ActiveRecord::Base.public_send(:sanitize_sql_array, input.join(','))
end end
def append_read_state(list, group)
group_id = group&.id
return list if group_id.nil?
selected_values = list.select_values.empty? ? ['topics.*'] : list.select_values
selected_values << "tuig.minimum_unread_count"
# The calculation was borrowed from lib/unread.rb
minimum_unread_count = TopicUser
.joins(:topic)
.joins("INNER JOIN group_users ON group_users.user_id = topic_users.user_id")
.where(group_users: { group_id: group_id })
.select(
"MIN(COALESCE(topics.highest_post_number, 0) - COALESCE(highest_seen_post_number, 0)) AS minimum_unread_count, topic_id"
).group(:topic_id).to_sql
list.joins("LEFT OUTER JOIN (#{minimum_unread_count}) tuig ON topics.id = tuig.topic_id").select(*selected_values)
end
end end

View File

@ -109,14 +109,6 @@ class TopicView
@personal_message = @topic.private_message? @personal_message = @topic.private_message?
end end
def show_read_indicator?
return false unless @user || topic.private_message?
topic.allowed_groups.any? do |group|
group.publish_read_state? && group.users.include?(@user)
end
end
def canonical_path def canonical_path
path = relative_url.dup path = relative_url.dup
path << path <<

View File

@ -1020,49 +1020,6 @@ describe TopicQuery do
expect(topics).to eq([]) expect(topics).to eq([])
end end
context "Calculating minimum unread count for a topic" do
before { group.update!(publish_read_state: true) }
let(:listed_message) do
TopicQuery.new(nil, group_name: group.name)
.list_private_messages_group(creator)
.topics.first
end
it 'returns a positive number when noone has read the last message' do
group_message.update!(highest_post_number: 1)
TopicUser.create!(user: creator, topic: group_message)
expect(listed_message.minimum_unread_count).to eq(1)
end
it 'returns 0 when all posts were read' do
group_message.update!(highest_post_number: 1)
TopicUser.create!(user: creator, topic: group_message, highest_seen_post_number: 1)
expect(listed_message.minimum_unread_count).to eq(0)
end
it 'returns the minimum number of unread posts when there are more than one user' do
new_user = Fabricate(:user)
group.add(new_user)
group_message.update!(highest_post_number: 3)
TopicUser.create!(user: creator, topic: group_message, highest_seen_post_number: 1)
TopicUser.create!(user: new_user, topic: group_message, highest_seen_post_number: 2)
expect(listed_message.minimum_unread_count).to eq(1)
end
it 'returns the minimum number of unread posts when there are more than one user' do
new_user = Fabricate(:topic_allowed_user, topic: group_message).user
group_message.update!(highest_post_number: 3)
TopicUser.create!(user: creator, topic: group_message, highest_seen_post_number: 1)
TopicUser.create!(user: new_user, topic: group_message, highest_seen_post_number: 2)
expect(listed_message.minimum_unread_count).to eq(2)
end
end
end end
context "shared drafts" do context "shared drafts" do

View File

@ -254,78 +254,6 @@ describe TopicTrackingState do
end end
end end
describe '#publish_read' do
fab!(:group) { Fabricate(:group) }
let(:read_topic_key) { "/private-messages/group-read/#{@group_message.id}" }
let(:read_post_key) { "/topic/#{@group_message.id}" }
let(:latest_post_number) { 3 }
before do
group.add(user)
@group_message = Fabricate(:private_message_topic,
allowed_groups: [group],
topic_allowed_users: [Fabricate.build(:topic_allowed_user, user: user)],
highest_post_number: latest_post_number
)
@post = Fabricate(:post, topic: @group_message, post_number: latest_post_number)
end
it 'does not publish the read indicator if the option is disabled' do
messages = MessageBus.track_publish(read_topic_key) do
TopicTrackingState.publish_read(@group_message.id, latest_post_number, user.id)
end
expect(messages).to be_empty
end
it 'does not trigger a read count update if no allowed groups have the option enabled' do
messages = MessageBus.track_publish(read_post_key) do
TopicTrackingState.publish_read(@group_message.id, latest_post_number, user.id)
end
expect(messages).to be_empty
end
context 'when the read indicator is enabled' do
before { group.update!(publish_read_state: true) }
it 'does publish the read indicator' do
message = MessageBus.track_publish(read_topic_key) do
TopicTrackingState.publish_read(@group_message.id, latest_post_number, user.id)
end.first
expect(message.data['topic_id']).to eq @group_message.id
end
it 'does not publish the read indicator if the message is not the last one' do
not_last_post_number = latest_post_number - 1
Fabricate(:post, topic: @group_message, post_number: not_last_post_number)
messages = MessageBus.track_publish(read_topic_key) do
TopicTrackingState.publish_read(@group_message.id, not_last_post_number, user.id)
end
expect(messages).to be_empty
end
it 'does not publish the read indicator if the user is not a group member' do
allowed_user = Fabricate(:topic_allowed_user, topic: @group_message)
messages = MessageBus.track_publish(read_topic_key) do
TopicTrackingState.publish_read(@group_message.id, latest_post_number, allowed_user.user_id)
end
expect(messages).to be_empty
end
it 'publish a read count update to every client' do
message = MessageBus.track_publish(read_post_key) do
TopicTrackingState.publish_read(@group_message.id, latest_post_number, user.id)
end.first
expect(message.data[:type]).to eq :read
end
end
end
it "correctly handles muted categories" do it "correctly handles muted categories" do
user = Fabricate(:user) user = Fabricate(:user)

View File

@ -1,90 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe PostReadersController do
describe '#index' do
fab!(:admin) { Fabricate(:admin) }
fab!(:reader) { Fabricate(:user) }
before { sign_in(admin) }
before do
@group = Fabricate(:group)
@group_message = Fabricate(:private_message_topic, allowed_groups: [@group])
@post = Fabricate(:post, topic: @group_message, post_number: 3)
end
context 'When the user has access to readers data' do
before do
@group.update!(publish_read_state: true)
@group.add(admin)
@group.add(reader)
end
it 'returns an empty list when nobody has read the topic' do
get '/post_readers.json', params: { id: @post.id }
readers = JSON.parse(response.body)['post_readers']
expect(readers).to be_empty
end
it 'returns an user who read until that post' do
TopicUser.create!(user: reader, topic: @group_message, last_read_post_number: 3)
get '/post_readers.json', params: { id: @post.id }
reader_data = JSON.parse(response.body)['post_readers'].first
assert_reader_is_correctly_serialized(reader_data, reader, @post)
end
it 'returns an user who read pass that post' do
TopicUser.create!(user: reader, topic: @group_message, last_read_post_number: 4)
get '/post_readers.json', params: { id: @post.id }
reader_data = JSON.parse(response.body)['post_readers'].first
assert_reader_is_correctly_serialized(reader_data, reader, @post)
end
it 'return an empty list when nodobody read unti that post' do
TopicUser.create!(user: reader, topic: @group_message, last_read_post_number: 1)
get '/post_readers.json', params: { id: @post.id }
readers = JSON.parse(response.body)['post_readers']
expect(readers).to be_empty
end
it "doesn't include current_user in the readers list" do
TopicUser.create!(user: admin, topic: @group_message, last_read_post_number: 3)
get '/post_readers.json', params: { id: @post.id }
reader = JSON.parse(response.body)['post_readers'].detect { |r| r['username'] == admin.username }
expect(reader).to be_nil
end
end
def assert_reader_is_correctly_serialized(reader_data, reader, post)
expect(reader_data['avatar_template']).to eq reader.avatar_template
expect(reader_data['username']).to eq reader.username
expect(reader_data['username_lower']).to eq reader.username_lower
end
it 'returns forbidden if no group has publish_read_state enabled' do
get '/post_readers.json', params: { id: @post.id }
expect(response).to be_forbidden
end
it 'returns forbidden if current_user is not a member of a group with publish_read_state enabled' do
@group.update!(publish_read_state: true)
get '/post_readers.json', params: { id: @post.id }
expect(response).to be_forbidden
end
end
end