mirror of
https://github.com/discourse/discourse.git
synced 2025-06-08 00:27:32 +08:00
FEATURE: Whisper posts
This commit is contained in:
@ -3,6 +3,7 @@ import DiscourseURL from 'discourse/lib/url';
|
|||||||
import Quote from 'discourse/lib/quote';
|
import Quote from 'discourse/lib/quote';
|
||||||
import Draft from 'discourse/models/draft';
|
import Draft from 'discourse/models/draft';
|
||||||
import Composer from 'discourse/models/composer';
|
import Composer from 'discourse/models/composer';
|
||||||
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
function loadDraft(store, opts) {
|
function loadDraft(store, opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
@ -64,6 +65,11 @@ export default Ember.Controller.extend({
|
|||||||
this.set('similarTopics', []);
|
this.set('similarTopics', []);
|
||||||
}.on('init'),
|
}.on('init'),
|
||||||
|
|
||||||
|
@computed('model.action')
|
||||||
|
canWhisper(action) {
|
||||||
|
return this.siteSettings.enable_whispers && action === Composer.REPLY;
|
||||||
|
},
|
||||||
|
|
||||||
showWarning: function() {
|
showWarning: function() {
|
||||||
if (!Discourse.User.currentProp('staff')) { return false; }
|
if (!Discourse.User.currentProp('staff')) { return false; }
|
||||||
|
|
||||||
@ -132,7 +138,6 @@ export default Ember.Controller.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
hitEsc() {
|
hitEsc() {
|
||||||
|
|
||||||
const messages = this.get('controllers.composer-messages.model');
|
const messages = this.get('controllers.composer-messages.model');
|
||||||
if (messages.length) {
|
if (messages.length) {
|
||||||
messages.popObject();
|
messages.popObject();
|
||||||
|
@ -24,6 +24,7 @@ const CLOSED = 'closed',
|
|||||||
category: 'categoryId',
|
category: 'categoryId',
|
||||||
topic_id: 'topic.id',
|
topic_id: 'topic.id',
|
||||||
is_warning: 'isWarning',
|
is_warning: 'isWarning',
|
||||||
|
whisper: 'whisper',
|
||||||
archetype: 'archetypeId',
|
archetype: 'archetypeId',
|
||||||
target_usernames: 'targetUsernames',
|
target_usernames: 'targetUsernames',
|
||||||
typing_duration_msecs: 'typingTime',
|
typing_duration_msecs: 'typingTime',
|
||||||
@ -557,6 +558,9 @@ const Composer = RestModel.extend({
|
|||||||
|
|
||||||
let addedToStream = false;
|
let addedToStream = false;
|
||||||
|
|
||||||
|
const postTypes = this.site.get('post_types');
|
||||||
|
const postType = this.get('whisper') ? postTypes.whisper : postTypes.regular;
|
||||||
|
|
||||||
// Build the post object
|
// Build the post object
|
||||||
const createdPost = this.store.createRecord('post', {
|
const createdPost = this.store.createRecord('post', {
|
||||||
imageSizes: opts.imageSizes,
|
imageSizes: opts.imageSizes,
|
||||||
@ -569,7 +573,7 @@ const Composer = RestModel.extend({
|
|||||||
user_title: user.get('title'),
|
user_title: user.get('title'),
|
||||||
avatar_template: user.get('avatar_template'),
|
avatar_template: user.get('avatar_template'),
|
||||||
user_custom_fields: user.get('custom_fields'),
|
user_custom_fields: user.get('custom_fields'),
|
||||||
post_type: this.site.get('post_types.regular'),
|
post_type: postType,
|
||||||
actions_summary: [],
|
actions_summary: [],
|
||||||
moderator: user.get('moderator'),
|
moderator: user.get('moderator'),
|
||||||
admin: user.get('admin'),
|
admin: user.get('admin'),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import RestModel from 'discourse/models/rest';
|
import RestModel from 'discourse/models/rest';
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
import ActionSummary from 'discourse/models/action-summary';
|
import ActionSummary from 'discourse/models/action-summary';
|
||||||
import { url, fmt, propertyEqual } from 'discourse/lib/computed';
|
import { url, propertyEqual } from 'discourse/lib/computed';
|
||||||
import Quote from 'discourse/lib/quote';
|
import Quote from 'discourse/lib/quote';
|
||||||
import computed from 'ember-addons/ember-computed-decorators';
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
@ -77,7 +77,6 @@ const Post = RestModel.extend({
|
|||||||
|
|
||||||
topicOwner: propertyEqual('topic.details.created_by.id', 'user_id'),
|
topicOwner: propertyEqual('topic.details.created_by.id', 'user_id'),
|
||||||
hasHistory: Em.computed.gt('version', 1),
|
hasHistory: Em.computed.gt('version', 1),
|
||||||
postElementId: fmt('post_number', 'post_%@'),
|
|
||||||
|
|
||||||
canViewRawEmail: function() {
|
canViewRawEmail: function() {
|
||||||
return this.get("user_id") === Discourse.User.currentProp("id") || Discourse.User.currentProp('staff');
|
return this.get("user_id") === Discourse.User.currentProp("id") || Discourse.User.currentProp('staff');
|
||||||
|
@ -60,6 +60,16 @@
|
|||||||
{{/unless}}
|
{{/unless}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if canWhisper}}
|
||||||
|
<div class='form-element clearfix'>
|
||||||
|
<label>
|
||||||
|
{{input type="checkbox" checked=model.whisper tabindex="3"}}
|
||||||
|
{{i18n "composer.add_whisper"}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{plugin-outlet "composer-fields"}}
|
{{plugin-outlet "composer-fields"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
{{view 'reply-history' content=replyHistory}}
|
{{view 'reply-history' content=replyHistory}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<article {{bind-attr class=":boxed via_email" id="postElementId" data-post-id="id" data-user-id="user_id"}}>
|
<article class="boxed {{if via_email 'via-email'}}" id={{postElementId}} data-post-id={{id}} data-user-id={{user_id}}>
|
||||||
<div class='row'>
|
<div class='row'>
|
||||||
|
|
||||||
<div class='topic-avatar'>
|
<div class='topic-avatar'>
|
||||||
@ -45,15 +45,20 @@
|
|||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if wiki}}
|
{{#if wiki}}
|
||||||
<div class="post-info wiki" title="{{i18n 'post.wiki.about'}}" {{action "editPost" this}}>{{fa-icon "pencil-square-o"}}</div>
|
<div class="post-info wiki" title={{i18n 'post.wiki.about'}} {{action "editPost" this}}>{{fa-icon "pencil-square-o"}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if via_email}}
|
{{#if via_email}}
|
||||||
{{#if canViewRawEmail}}
|
{{#if canViewRawEmail}}
|
||||||
<div class="post-info via-email raw-email" title="{{i18n 'post.via_email'}}" {{action "showRawEmail" this}}>{{fa-icon "envelope-o"}}</div>
|
<div class="post-info via-email raw-email" title={{i18n 'post.via_email'}} {{action "showRawEmail" this}}>{{fa-icon "envelope-o"}}</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="post-info via-email" title="{{i18n 'post.via_email'}}">{{fa-icon "envelope-o"}}</div>
|
<div class="post-info via-email" title={{i18n 'post.via_email'}}>{{fa-icon "envelope-o"}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if view.whisper}}
|
||||||
|
<div class="post-info whisper" title={{i18n 'post.whisper'}}>{{fa-icon "user-secret"}}</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#if showUserReplyTab}}
|
{{#if showUserReplyTab}}
|
||||||
<a href {{action "toggleReplyHistory" this target="view"}} class='reply-to-tab'>
|
<a href {{action "toggleReplyHistory" this target="view"}} class='reply-to-tab'>
|
||||||
{{#if loadingReplyHistory}}
|
{{#if loadingReplyHistory}}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import ScreenTrack from 'discourse/lib/screen-track';
|
import ScreenTrack from 'discourse/lib/screen-track';
|
||||||
import { number } from 'discourse/lib/formatter';
|
import { number } from 'discourse/lib/formatter';
|
||||||
import DiscourseURL from 'discourse/lib/url';
|
import DiscourseURL from 'discourse/lib/url';
|
||||||
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
import { fmt } from 'discourse/lib/computed';
|
||||||
|
|
||||||
const DAY = 60 * 50 * 1000;
|
const DAY = 60 * 50 * 1000;
|
||||||
|
|
||||||
@ -12,10 +14,18 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
|
|||||||
'post.deleted:deleted',
|
'post.deleted:deleted',
|
||||||
'post.topicOwner:topic-owner',
|
'post.topicOwner:topic-owner',
|
||||||
'groupNameClass',
|
'groupNameClass',
|
||||||
'post.wiki:wiki'],
|
'post.wiki:wiki',
|
||||||
|
'whisper'],
|
||||||
|
|
||||||
post: Ember.computed.alias('content'),
|
post: Ember.computed.alias('content'),
|
||||||
|
|
||||||
|
postElementId: fmt('post.post_number', 'post_%@'),
|
||||||
|
|
||||||
|
@computed('post.post_type')
|
||||||
|
whisper(postType) {
|
||||||
|
return postType === this.site.get('post_types.whisper');
|
||||||
|
},
|
||||||
|
|
||||||
templateName: function() {
|
templateName: function() {
|
||||||
return (this.get('post.post_type') === this.site.get('post_types.small_action')) ? 'post-small-action' : 'post';
|
return (this.get('post.post_type') === this.site.get('post_types.small_action')) ? 'post-small-action' : 'post';
|
||||||
}.property('post.post_type'),
|
}.property('post.post_type'),
|
||||||
|
@ -147,7 +147,7 @@ aside.quote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.post-info {
|
.post-info {
|
||||||
&.wiki, &.via-email {
|
&.wiki, &.via-email, &.whisper {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
i.fa {
|
i.fa {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
@ -582,6 +582,15 @@ a.mention {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.whisper {
|
||||||
|
.topic-body {
|
||||||
|
.cooked {
|
||||||
|
font-style: italic;
|
||||||
|
color: dark-light-diff($primary, $secondary, 55%, -40%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#share-link {
|
#share-link {
|
||||||
width: 365px;
|
width: 365px;
|
||||||
margin-left: -4px;
|
margin-left: -4px;
|
||||||
|
@ -465,6 +465,10 @@ class PostsController < ApplicationController
|
|||||||
result[:is_warning] = false
|
result[:is_warning] = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if SiteSetting.enable_whispers? && params[:whisper] == "true"
|
||||||
|
result[:post_type] = Post.types[:whisper]
|
||||||
|
end
|
||||||
|
|
||||||
PostRevisor.tracked_topic_fields.each_key do |f|
|
PostRevisor.tracked_topic_fields.each_key do |f|
|
||||||
params.permit(f => [])
|
params.permit(f => [])
|
||||||
result[f] = params[f] if params.has_key?(f)
|
result[f] = params[f] if params.has_key?(f)
|
||||||
|
@ -74,7 +74,7 @@ class Post < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.types
|
def self.types
|
||||||
@types ||= Enum.new(:regular, :moderator_action, :small_action)
|
@types ||= Enum.new(:regular, :moderator_action, :small_action, :whisper)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.cook_methods
|
def self.cook_methods
|
||||||
@ -96,15 +96,24 @@ class Post < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def publish_change_to_clients!(type)
|
def publish_change_to_clients!(type)
|
||||||
# special failsafe for posts missing topics
|
|
||||||
# consistency checks should fix, but message
|
channel = "/topic/#{topic_id}"
|
||||||
# is safe to skip
|
msg = { id: id,
|
||||||
MessageBus.publish("/topic/#{topic_id}", {
|
|
||||||
id: id,
|
|
||||||
post_number: post_number,
|
post_number: post_number,
|
||||||
updated_at: Time.now,
|
updated_at: Time.now,
|
||||||
type: type
|
type: type }
|
||||||
}, group_ids: topic.secure_group_ids) if topic
|
|
||||||
|
# special failsafe for posts missing topics consistency checks should fix, but message
|
||||||
|
# is safe to skip
|
||||||
|
return unless topic
|
||||||
|
|
||||||
|
# Whispers should not be published to everyone
|
||||||
|
if post_type == Post.types[:whisper]
|
||||||
|
user_ids = User.where('admin or moderator or id = ?', user_id).pluck(:id)
|
||||||
|
MessageBus.publish(channel, msg, user_ids: user_ids)
|
||||||
|
else
|
||||||
|
MessageBus.publish(channel, msg, group_ids: topic.secure_group_ids)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def trash!(trashed_by=nil)
|
def trash!(trashed_by=nil)
|
||||||
|
@ -218,6 +218,13 @@ class Topic < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def visible_post_types(viewed_by=nil)
|
||||||
|
types = Post.types
|
||||||
|
result = [types[:regular], types[:moderator_action], types[:small_action]]
|
||||||
|
result << types[:whisper] if viewed_by.try(:staff?)
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
def self.top_viewed(max = 10)
|
def self.top_viewed(max = 10)
|
||||||
Topic.listable_topics.visible.secured.order('views desc').limit(max)
|
Topic.listable_topics.visible.secured.order('views desc').limit(max)
|
||||||
end
|
end
|
||||||
|
@ -809,6 +809,7 @@ en:
|
|||||||
emoji: "Emoji :smile:"
|
emoji: "Emoji :smile:"
|
||||||
|
|
||||||
add_warning: "This is an official warning."
|
add_warning: "This is an official warning."
|
||||||
|
add_whisper: "This is a whisper only visible to moderators"
|
||||||
posting_not_on_topic: "Which topic do you want to reply to?"
|
posting_not_on_topic: "Which topic do you want to reply to?"
|
||||||
saving_draft_tip: "saving..."
|
saving_draft_tip: "saving..."
|
||||||
saved_draft_tip: "saved"
|
saved_draft_tip: "saved"
|
||||||
@ -1349,6 +1350,7 @@ en:
|
|||||||
yes_value: "Yes, abandon"
|
yes_value: "Yes, abandon"
|
||||||
|
|
||||||
via_email: "this post arrived via email"
|
via_email: "this post arrived via email"
|
||||||
|
whisper: "this post is a private whisper for moderators"
|
||||||
|
|
||||||
wiki:
|
wiki:
|
||||||
about: "this post is a wiki; basic users can edit it"
|
about: "this post is a wiki; basic users can edit it"
|
||||||
|
@ -880,6 +880,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 users to whisper to moderators"
|
||||||
|
|
||||||
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"
|
||||||
|
@ -182,6 +182,9 @@ basic:
|
|||||||
enable_badges:
|
enable_badges:
|
||||||
client: true
|
client: true
|
||||||
default: true
|
default: true
|
||||||
|
enable_whispers:
|
||||||
|
client: true
|
||||||
|
default: false
|
||||||
|
|
||||||
login:
|
login:
|
||||||
invite_only:
|
invite_only:
|
||||||
|
@ -144,10 +144,13 @@ module PostGuardian
|
|||||||
end
|
end
|
||||||
|
|
||||||
def can_see_post?(post)
|
def can_see_post?(post)
|
||||||
post.present? &&
|
return false if post.blank?
|
||||||
(is_admin? ||
|
return true if is_admin?
|
||||||
((is_moderator? || !post.deleted_at.present?) &&
|
return false unless can_see_topic?(post.topic)
|
||||||
can_see_topic?(post.topic)))
|
return false unless post.user == @user || post.topic.visible_post_types(@user).include?(post.post_type)
|
||||||
|
return false if !is_moderator? && post.deleted_at.present?
|
||||||
|
|
||||||
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_view_edit_history?(post)
|
def can_view_edit_history?(post)
|
||||||
|
@ -191,11 +191,9 @@ class TopicView
|
|||||||
|
|
||||||
# Find the sort order for a post in the topic
|
# Find the sort order for a post in the topic
|
||||||
def sort_order_for_post_number(post_number)
|
def sort_order_for_post_number(post_number)
|
||||||
Post.where(topic_id: @topic.id, post_number: post_number)
|
posts = Post.where(topic_id: @topic.id, post_number: post_number).with_deleted
|
||||||
.with_deleted
|
posts = filter_post_types(posts)
|
||||||
.select(:sort_order)
|
posts.select(:sort_order).first.try(:sort_order)
|
||||||
.first
|
|
||||||
.try(:sort_order)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Filter to all posts near a particular post number
|
# Filter to all posts near a particular post number
|
||||||
@ -332,11 +330,22 @@ class TopicView
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def filter_post_types(posts)
|
||||||
|
visible_types = @topic.visible_post_types(@user)
|
||||||
|
|
||||||
|
if @user.present?
|
||||||
|
posts.where("user_id = ? OR post_type IN (?)", @user.id, visible_types)
|
||||||
|
else
|
||||||
|
posts.where(post_type: visible_types)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def filter_posts_by_ids(post_ids)
|
def filter_posts_by_ids(post_ids)
|
||||||
# TODO: Sort might be off
|
# TODO: Sort might be off
|
||||||
@posts = Post.where(id: post_ids, topic_id: @topic.id)
|
@posts = Post.where(id: post_ids, topic_id: @topic.id)
|
||||||
.includes(:user, :reply_to_user)
|
.includes(:user, :reply_to_user)
|
||||||
.order('sort_order')
|
.order('sort_order')
|
||||||
|
@posts = filter_post_types(@posts)
|
||||||
@posts = @posts.with_deleted if @guardian.can_see_deleted_posts?
|
@posts = @posts.with_deleted if @guardian.can_see_deleted_posts?
|
||||||
@posts
|
@posts
|
||||||
end
|
end
|
||||||
@ -361,7 +370,7 @@ class TopicView
|
|||||||
end
|
end
|
||||||
|
|
||||||
def unfiltered_posts
|
def unfiltered_posts
|
||||||
result = @topic.posts
|
result = filter_post_types(@topic.posts)
|
||||||
result = result.with_deleted if @guardian.can_see_deleted_posts?
|
result = result.with_deleted if @guardian.can_see_deleted_posts?
|
||||||
result = @topic.posts.where("user_id IS NOT NULL") if @exclude_deleted_users
|
result = @topic.posts.where("user_id IS NOT NULL") if @exclude_deleted_users
|
||||||
result
|
result
|
||||||
|
@ -437,6 +437,32 @@ describe Guardian do
|
|||||||
expect(Guardian.new(user).can_see?(post)).to be_falsey
|
expect(Guardian.new(user).can_see?(post)).to be_falsey
|
||||||
expect(Guardian.new(admin).can_see?(post)).to be_truthy
|
expect(Guardian.new(admin).can_see?(post)).to be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'respects whispers' do
|
||||||
|
regular_post = Fabricate.build(:post)
|
||||||
|
whisper_post = Fabricate.build(:post, post_type: Post.types[:whisper])
|
||||||
|
|
||||||
|
anon_guardian = Guardian.new
|
||||||
|
expect(anon_guardian.can_see?(regular_post)).to eq(true)
|
||||||
|
expect(anon_guardian.can_see?(whisper_post)).to eq(false)
|
||||||
|
|
||||||
|
regular_user = Fabricate.build(:user)
|
||||||
|
regular_guardian = Guardian.new(regular_user)
|
||||||
|
expect(regular_guardian.can_see?(regular_post)).to eq(true)
|
||||||
|
expect(regular_guardian.can_see?(whisper_post)).to eq(false)
|
||||||
|
|
||||||
|
# can see your own whispers
|
||||||
|
regular_whisper = Fabricate.build(:post, post_type: Post.types[:whisper], user: regular_user)
|
||||||
|
expect(regular_guardian.can_see?(regular_whisper)).to eq(true)
|
||||||
|
|
||||||
|
mod_guardian = Guardian.new(Fabricate.build(:moderator))
|
||||||
|
expect(mod_guardian.can_see?(regular_post)).to eq(true)
|
||||||
|
expect(mod_guardian.can_see?(whisper_post)).to eq(true)
|
||||||
|
|
||||||
|
admin_guardian = Guardian.new(Fabricate.build(:admin))
|
||||||
|
expect(admin_guardian.can_see?(regular_post)).to eq(true)
|
||||||
|
expect(admin_guardian.can_see?(whisper_post)).to eq(true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'a PostRevision' do
|
describe 'a PostRevision' do
|
||||||
|
@ -251,6 +251,23 @@ describe TopicView do
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'whispers' do
|
||||||
|
it "handles their visibility properly" do
|
||||||
|
p1 = Fabricate(:post, topic: topic, user: coding_horror)
|
||||||
|
p2 = Fabricate(:post, topic: topic, user: coding_horror, post_type: Post.types[:whisper])
|
||||||
|
p3 = Fabricate(:post, topic: topic, user: coding_horror)
|
||||||
|
|
||||||
|
ch_posts = TopicView.new(topic.id, coding_horror).posts
|
||||||
|
expect(ch_posts.map(&:id)).to eq([p1.id, p2.id, p3.id])
|
||||||
|
|
||||||
|
anon_posts = TopicView.new(topic.id).posts
|
||||||
|
expect(anon_posts.map(&:id)).to eq([p1.id, p3.id])
|
||||||
|
|
||||||
|
admin_posts = TopicView.new(topic.id, Fabricate(:moderator)).posts
|
||||||
|
expect(admin_posts.map(&:id)).to eq([p1.id, p2.id, p3.id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context '.posts' do
|
context '.posts' do
|
||||||
|
|
||||||
# Create the posts in a different order than the sort_order
|
# Create the posts in a different order than the sort_order
|
||||||
|
@ -11,6 +11,40 @@ describe Topic do
|
|||||||
|
|
||||||
it { is_expected.to rate_limit }
|
it { is_expected.to rate_limit }
|
||||||
|
|
||||||
|
context '#visible_post_types' do
|
||||||
|
let(:types) { Post.types }
|
||||||
|
|
||||||
|
it "returns the appropriate types for anonymous users" do
|
||||||
|
topic = Fabricate.build(:topic)
|
||||||
|
post_types = topic.visible_post_types
|
||||||
|
|
||||||
|
expect(post_types).to include(types[:regular])
|
||||||
|
expect(post_types).to include(types[:moderator_action])
|
||||||
|
expect(post_types).to include(types[:small_action])
|
||||||
|
expect(post_types).to_not include(types[:whisper])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the appropriate types for regular users" do
|
||||||
|
topic = Fabricate.build(:topic)
|
||||||
|
post_types = topic.visible_post_types(Fabricate.build(:user))
|
||||||
|
|
||||||
|
expect(post_types).to include(types[:regular])
|
||||||
|
expect(post_types).to include(types[:moderator_action])
|
||||||
|
expect(post_types).to include(types[:small_action])
|
||||||
|
expect(post_types).to_not include(types[:whisper])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the appropriate types for staff users" do
|
||||||
|
topic = Fabricate.build(:topic)
|
||||||
|
post_types = topic.visible_post_types(Fabricate.build(:moderator))
|
||||||
|
|
||||||
|
expect(post_types).to include(types[:regular])
|
||||||
|
expect(post_types).to include(types[:moderator_action])
|
||||||
|
expect(post_types).to include(types[:small_action])
|
||||||
|
expect(post_types).to include(types[:whisper])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'slug' do
|
context 'slug' do
|
||||||
let(:title) { "hello world topic" }
|
let(:title) { "hello world topic" }
|
||||||
let(:slug) { "hello-world-topic" }
|
let(:slug) { "hello-world-topic" }
|
||||||
|
Reference in New Issue
Block a user