mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 15:48:43 -05:00
moderators now have teeth, more at http://meta.discourse.org/t/moderator-permission-set/6307/5
allow pms to be targetted at groups
This commit is contained in:
parent
e59ab32210
commit
65cd00cf25
27 changed files with 176 additions and 61 deletions
|
@ -12,10 +12,11 @@ Discourse.AdminDashboardController = Ember.Controller.extend({
|
|||
problemsCheckInterval: '1 minute ago',
|
||||
|
||||
foundProblems: function() {
|
||||
return(this.get('problems') && this.get('problems').length > 0);
|
||||
return(Discourse.currentUser.admin && this.get('problems') && this.get('problems').length > 0);
|
||||
}.property('problems'),
|
||||
|
||||
thereWereProblems: function() {
|
||||
if(!Discourse.currentUser.admin) { return false }
|
||||
if( this.get('foundProblems') ) {
|
||||
this.set('hadProblems', true);
|
||||
return true;
|
||||
|
|
|
@ -4,14 +4,18 @@
|
|||
|
||||
<ul class="nav nav-pills">
|
||||
<li>{{#linkTo 'admin.dashboard'}}{{i18n admin.dashboard.title}}{{/linkTo}}</li>
|
||||
<li>{{#linkTo 'admin.site_settings'}}{{i18n admin.site_settings.title}}{{/linkTo}}</li>
|
||||
<li>{{#linkTo 'adminSiteContents'}}{{i18n admin.site_content.title}}{{/linkTo}}</li>
|
||||
{{#if Discourse.currentUser.admin}}
|
||||
<li>{{#linkTo 'admin.site_settings'}}{{i18n admin.site_settings.title}}{{/linkTo}}</li>
|
||||
<li>{{#linkTo 'adminSiteContents'}}{{i18n admin.site_content.title}}{{/linkTo}}</li>
|
||||
{{/if}}
|
||||
<li>{{#linkTo 'adminUsersList.active'}}{{i18n admin.users.title}}{{/linkTo}}</li>
|
||||
<!--<li>{{#linkTo 'admin.groups'}}{{i18n admin.groups.title}}{{/linkTo}}</li>-->
|
||||
<li>{{#linkTo 'admin.email_logs'}}{{i18n admin.email_logs.title}}{{/linkTo}}</li>
|
||||
<li>{{#linkTo 'adminFlags.active'}}{{i18n admin.flags.title}}{{/linkTo}}</li>
|
||||
<li>{{#linkTo 'admin.customize'}}{{i18n admin.customize.title}}{{/linkTo}}</li>
|
||||
<li>{{#linkTo 'admin.api'}}{{i18n admin.api.title}}{{/linkTo}}</li>
|
||||
{{#if Discourse.currentUser.admin}}
|
||||
<li>{{#linkTo 'admin.customize'}}{{i18n admin.customize.title}}{{/linkTo}}</li>
|
||||
<li>{{#linkTo 'admin.api'}}{{i18n admin.api.title}}{{/linkTo}}</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
|
||||
<div class='boxed white admin-content'>
|
||||
|
|
|
@ -31,9 +31,11 @@
|
|||
<div class='field'>{{i18n user.ip_address.title}}</div>
|
||||
<div class='value'>{{content.ip_address}}</div>
|
||||
<div class='controls'>
|
||||
{{#if Discourse.currentUser.admin}}
|
||||
<button class='btn' {{action refreshBrowsers target="content"}}>
|
||||
{{i18n admin.user.refresh_browsers}}
|
||||
</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ Discourse = Ember.Application.createWithMixins({
|
|||
if (user) {
|
||||
bus.callbackInterval = Discourse.SiteSettings.polling_interval;
|
||||
bus.enableLongPolling = true;
|
||||
if (user.admin) {
|
||||
if (user.admin || user.moderator) {
|
||||
bus.subscribe("/flagged_counts", function(data) {
|
||||
user.set('site_flagged_posts_count', data.total);
|
||||
});
|
||||
|
|
|
@ -13,7 +13,7 @@ Discourse.UserController = Discourse.ObjectController.extend({
|
|||
}).property('content.username', 'Discourse.currentUser.username'),
|
||||
|
||||
canSeePrivateMessages: (function() {
|
||||
return this.get('viewingSelf') || Discourse.get('currentUser.admin');
|
||||
return this.get('viewingSelf') || Discourse.get('currentUser.moderator');
|
||||
}).property('viewingSelf', 'Discourse.currentUser')
|
||||
|
||||
});
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
<section class='d-dropdown' id='site-map-dropdown'>
|
||||
<ul>
|
||||
{{#if Discourse.currentUser.admin}}
|
||||
{{#if Discourse.currentUser.moderator}}
|
||||
<li><a href="/admin"><i class='icon-cog'></i>{{i18n admin_title}}</a></li>
|
||||
<li><a href="/admin/flags/active"><i class='icon-flag'></i>{{i18n flags_title}}</a></li>
|
||||
{{/if}}
|
||||
|
|
|
@ -134,6 +134,6 @@
|
|||
{{render share}}
|
||||
{{render quoteButton}}
|
||||
|
||||
{{#if Discourse.currentUser.admin}}
|
||||
{{#if Discourse.currentUser.moderator}}
|
||||
{{render topicAdminMenu content}}
|
||||
{{/if}}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
{{#if viewingSelf}}
|
||||
<button {{action "logout" target="Discourse"}} class='btn'>{{i18n user.log_out}}</button>
|
||||
{{/if}}
|
||||
{{#if Discourse.currentUser.admin}}
|
||||
{{#if Discourse.currentUser.moderator}}
|
||||
<a href="{{unbound content.adminPath}}" class='btn'><i class="icon-wrench"></i> {{i18n admin.user.show_admin_profile}}</a>
|
||||
{{/if}}
|
||||
<ul class="nav nav-pills">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Admin::AdminController < ApplicationController
|
||||
|
||||
before_filter :ensure_logged_in
|
||||
before_filter :ensure_is_admin
|
||||
before_filter :ensure_is_moderator
|
||||
|
||||
def index
|
||||
render nothing: true
|
||||
|
@ -9,8 +9,8 @@ class Admin::AdminController < ApplicationController
|
|||
|
||||
protected
|
||||
|
||||
def ensure_is_admin
|
||||
raise Discourse::InvalidAccess.new unless current_user.admin?
|
||||
def ensure_is_moderator
|
||||
raise Discourse::InvalidAccess.new unless current_user.moderator?
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -34,6 +34,10 @@ module ApplicationHelper
|
|||
current_user.try(:admin?)
|
||||
end
|
||||
|
||||
def moderator?
|
||||
current_user.try(:moderator?)
|
||||
end
|
||||
|
||||
# Creates open graph and twitter card meta data
|
||||
def crawlable_meta_data(opts=nil)
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@ class PostAction < ActiveRecord::Base
|
|||
'topics.deleted_at' => nil).count('DISTINCT posts.id')
|
||||
|
||||
$redis.set('posts_flagged_count', posts_flagged_count)
|
||||
admins = User.admins.select(:id).map {|u| u.id}
|
||||
MessageBus.publish('/flagged_counts', { total: posts_flagged_count }, { user_ids: admins })
|
||||
user_ids = User.where("admin = 't' or moderator = 't'").select(:id).map {|u| u.id}
|
||||
MessageBus.publish('/flagged_counts', { total: posts_flagged_count }, { user_ids: user_ids })
|
||||
end
|
||||
|
||||
def self.flagged_posts_count
|
||||
|
|
|
@ -60,8 +60,8 @@ class PostAlertObserver < ActiveRecord::Observer
|
|||
def after_create_post(post)
|
||||
if post.topic.private_message?
|
||||
# If it's a private message, notify the topic_allowed_users
|
||||
post.topic.topic_allowed_users.reject{ |a| a.user_id == post.user_id }.each do |a|
|
||||
create_notification(a.user, Notification.types[:private_message], post)
|
||||
post.topic.all_allowed_users.reject{ |a| a.id == post.user_id }.each do |a|
|
||||
create_notification(a, Notification.types[:private_message], post)
|
||||
end
|
||||
else
|
||||
# If it's not a private message, notify the users
|
||||
|
|
|
@ -38,6 +38,10 @@ class Topic < ActiveRecord::Base
|
|||
belongs_to :category
|
||||
has_many :posts
|
||||
has_many :topic_allowed_users
|
||||
has_many :topic_allowed_groups
|
||||
|
||||
has_many :allowed_group_users, through: :allowed_groups, source: :users
|
||||
has_many :allowed_groups, through: :topic_allowed_groups, source: :group
|
||||
has_many :allowed_users, through: :topic_allowed_users, source: :user
|
||||
|
||||
has_one :hot_topic
|
||||
|
@ -94,6 +98,12 @@ class Topic < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
# all users (in groups or directly targetted) that are going to get the pm
|
||||
def all_allowed_users
|
||||
# TODO we should probably change this from 3 queries to 1
|
||||
User.where('id in (?)', allowed_users.select('users.id').to_a + allowed_group_users.select('users.id').to_a)
|
||||
end
|
||||
|
||||
# Additional rate limits on topics: per day and private messages per day
|
||||
def limit_topics_per_day
|
||||
RateLimiter.new(user, "topics-per-day:#{Date.today.to_s}", SiteSetting.max_topics_per_day, 1.day.to_i)
|
||||
|
|
7
app/models/topic_allowed_group.rb
Normal file
7
app/models/topic_allowed_group.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class TopicAllowedGroup < ActiveRecord::Base
|
||||
belongs_to :topic
|
||||
belongs_to :group
|
||||
attr_accessible :group_id, :user_id
|
||||
|
||||
validates_uniqueness_of :topic_id, scope: :group_id
|
||||
end
|
|
@ -51,8 +51,8 @@ class TopicList
|
|||
|
||||
def has_rank_details?
|
||||
|
||||
# Only admins can see rank details
|
||||
return false unless @current_user.try(:admin?)
|
||||
# Only moderators can see rank details
|
||||
return false unless @current_user.try(:moderator?)
|
||||
|
||||
# Only show them on 'Hot'
|
||||
return @filter == :hot
|
||||
|
|
|
@ -15,8 +15,15 @@ class CurrentUserSerializer < BasicUserSerializer
|
|||
|
||||
# we probably want to move this into site, but that json is cached so hanging it off current user seems okish
|
||||
|
||||
def moderator
|
||||
# TODO we probably want better terminology
|
||||
#
|
||||
# we have admins / moderators and users who are either moderators or admins denoted by moderator?
|
||||
object.moderator?
|
||||
end
|
||||
|
||||
def include_site_flagged_posts_count?
|
||||
object.admin
|
||||
object.moderator?
|
||||
end
|
||||
|
||||
def topic_count
|
||||
|
|
|
@ -88,7 +88,7 @@ class PostSerializer < ApplicationSerializer
|
|||
end
|
||||
|
||||
def cooked
|
||||
if object.hidden && !scope.is_admin?
|
||||
if object.hidden && !scope.is_moderator?
|
||||
if scope.current_user && object.user_id == scope.current_user.id
|
||||
I18n.t('flagging.you_must_edit')
|
||||
else
|
||||
|
@ -154,7 +154,7 @@ class PostSerializer < ApplicationSerializer
|
|||
|
||||
# The following only applies if you're logged in
|
||||
if action_summary[:can_act] && scope.current_user.present?
|
||||
action_summary[:can_clear_flags] = scope.is_admin? && PostActionType.flag_types.values.include?(id)
|
||||
action_summary[:can_clear_flags] = scope.is_moderator? && PostActionType.flag_types.values.include?(id)
|
||||
end
|
||||
|
||||
if post_actions.present? && post_actions.has_key?(id)
|
||||
|
@ -163,7 +163,7 @@ class PostSerializer < ApplicationSerializer
|
|||
end
|
||||
|
||||
# anonymize flags
|
||||
if !scope.is_admin? && PostActionType.flag_types.values.include?(id)
|
||||
if !scope.is_moderator? && PostActionType.flag_types.values.include?(id)
|
||||
action_summary[:count] = action_summary[:acted] ? 1 : 0
|
||||
end
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<%# load the selected locale before any other scripts %>
|
||||
<%= javascript_include_tag "locales/#{I18n.locale}" %>
|
||||
<%= javascript_include_tag "application" %>
|
||||
<%- if admin? %>
|
||||
<%- if moderator? %>
|
||||
<%= javascript_include_tag "admin"%>
|
||||
<%- end %>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<%=stylesheet_link_tag "application"%>
|
||||
<%- end %>
|
||||
|
||||
<%- if admin? %>
|
||||
<%- if moderator? %>
|
||||
<%= stylesheet_link_tag "admin"%>
|
||||
<%-end%>
|
||||
<%=SiteCustomization.custom_stylesheet(session[:preview_style])%>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
require 'sidekiq/web'
|
||||
|
||||
require_dependency 'admin_constraint'
|
||||
require_dependency 'moderator_constraint'
|
||||
require_dependency 'homepage_constraint'
|
||||
|
||||
# This used to be User#username_format, but that causes a preload of the User object
|
||||
|
@ -21,13 +22,14 @@ Discourse::Application.routes.draw do
|
|||
end
|
||||
get 'srv/status' => 'forums#status'
|
||||
|
||||
namespace :admin, constraints: AdminConstraint.new do
|
||||
namespace :admin, constraints: ModeratorConstraint.new do
|
||||
get '' => 'admin#index'
|
||||
|
||||
resources :site_settings
|
||||
resources :site_settings, constraints: AdminConstraint.new
|
||||
|
||||
get 'reports/:type' => 'reports#show'
|
||||
|
||||
resources :groups
|
||||
resources :groups, constraints: AdminConstraint.new
|
||||
resources :users, id: USERNAME_ROUTE_FORMAT do
|
||||
collection do
|
||||
get 'list/:query' => 'users#index'
|
||||
|
@ -36,35 +38,35 @@ Discourse::Application.routes.draw do
|
|||
put 'ban'
|
||||
put 'delete_all_posts'
|
||||
put 'unban'
|
||||
put 'revoke_admin'
|
||||
put 'grant_admin'
|
||||
put 'revoke_moderation'
|
||||
put 'grant_moderation'
|
||||
put 'revoke_admin', constraints: AdminConstraint.new
|
||||
put 'grant_admin', constraints: AdminConstraint.new
|
||||
put 'revoke_moderation', constraints: AdminConstraint.new
|
||||
put 'grant_moderation', constraints: AdminConstraint.new
|
||||
put 'approve'
|
||||
post 'refresh_browsers'
|
||||
post 'refresh_browsers', constraints: AdminConstraint.new
|
||||
end
|
||||
|
||||
resources :impersonate
|
||||
resources :impersonate, constraints: AdminConstraint.new
|
||||
resources :email_logs do
|
||||
collection do
|
||||
post 'test'
|
||||
end
|
||||
end
|
||||
get 'customize' => 'site_customizations#index'
|
||||
get 'customize' => 'site_customizations#index', constraints: AdminConstraint.new
|
||||
get 'flags' => 'flags#index'
|
||||
get 'flags/:filter' => 'flags#index'
|
||||
post 'flags/clear/:id' => 'flags#clear'
|
||||
resources :site_customizations
|
||||
resources :site_contents
|
||||
resources :site_content_types
|
||||
resources :export
|
||||
resources :site_customizations, constraints: AdminConstraint.new
|
||||
resources :site_contents, constraints: AdminConstraint.new
|
||||
resources :site_content_types, constraints: AdminConstraint.new
|
||||
resources :export, constraints: AdminConstraint.new
|
||||
get 'version_check' => 'versions#show'
|
||||
resources :dashboard, only: [:index] do
|
||||
collection do
|
||||
get 'problems'
|
||||
end
|
||||
end
|
||||
resources :api, only: [:index] do
|
||||
resources :api, only: [:index], constraints: AdminConstraint.new do
|
||||
collection do
|
||||
post 'generate_key'
|
||||
end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
class AddTopicAllowedGroups < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :topic_allowed_groups do |t|
|
||||
# oops
|
||||
t.integer :group_id, :integer, null: false
|
||||
t.integer :topic_id, :integer, null: false
|
||||
end
|
||||
|
|
6
db/migrate/20130501105651_fix_topic_allowed_groups.rb
Normal file
6
db/migrate/20130501105651_fix_topic_allowed_groups.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
class FixTopicAllowedGroups < ActiveRecord::Migration
|
||||
def change
|
||||
# big oops
|
||||
remove_column :topic_allowed_groups, :integer
|
||||
end
|
||||
end
|
|
@ -207,7 +207,7 @@ class Guardian
|
|||
end
|
||||
|
||||
def can_see_private_messages?(user_id)
|
||||
return true if is_admin?
|
||||
return true if is_moderator?
|
||||
return false if @user.blank?
|
||||
@user.id == user_id
|
||||
end
|
||||
|
@ -263,7 +263,7 @@ class Guardian
|
|||
|
||||
def can_edit_user?(user)
|
||||
return true if user == @user
|
||||
@user.admin?
|
||||
@user.moderator?
|
||||
end
|
||||
|
||||
def can_edit_topic?(topic)
|
||||
|
@ -311,12 +311,12 @@ class Guardian
|
|||
return post_action.created_at > SiteSetting.post_undo_action_window_mins.minutes.ago
|
||||
end
|
||||
|
||||
def can_send_private_message?(target_user)
|
||||
return false unless User === target_user
|
||||
def can_send_private_message?(target)
|
||||
return false unless User === target || Group === target
|
||||
return false if @user.blank?
|
||||
|
||||
# Can't send message to yourself
|
||||
return false if @user.id == target_user.id
|
||||
return false if User === target && @user.id == target.id
|
||||
|
||||
# Have to be a basic level at least
|
||||
return false unless @user.has_trust_level?(:basic)
|
||||
|
@ -336,15 +336,15 @@ class Guardian
|
|||
return false unless topic
|
||||
|
||||
return true if @user && @user.moderator?
|
||||
return false if topic.deleted_at.present?
|
||||
return false if topic.deleted_at
|
||||
|
||||
if topic.category && topic.category.secure
|
||||
return false unless @user && can_see_category?(topic.category)
|
||||
end
|
||||
|
||||
if topic.private_message?
|
||||
return false if @user.blank?
|
||||
return true if topic.allowed_users.include?(@user)
|
||||
return false unless @user
|
||||
return true if topic.all_allowed_users.where(id: @user.id).exists?
|
||||
return is_admin?
|
||||
end
|
||||
true
|
||||
|
@ -375,11 +375,11 @@ class Guardian
|
|||
def post_can_act?(post, action_key, opts={})
|
||||
return false if @user.blank?
|
||||
return false if post.blank?
|
||||
return false if post.topic.archived?
|
||||
|
||||
taken = opts[:taken_actions]
|
||||
taken = taken.keys if taken
|
||||
|
||||
# we always allow flagging
|
||||
if PostActionType.is_flag?(action_key)
|
||||
return false unless @user.has_trust_level?(:basic)
|
||||
|
||||
|
@ -390,6 +390,9 @@ class Guardian
|
|||
return false if taken && taken.include?(PostActionType.types[action_key])
|
||||
end
|
||||
|
||||
# nothing else on archived posts
|
||||
return false if post.topic.archived?
|
||||
|
||||
case action_key
|
||||
when :like
|
||||
return false if post.user == @user
|
||||
|
|
10
lib/moderator_constraint.rb
Normal file
10
lib/moderator_constraint.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
require_dependency 'current_user'
|
||||
|
||||
class ModeratorConstraint
|
||||
|
||||
def matches?(request)
|
||||
return false unless request.session[:current_user_id].present?
|
||||
User.where("admin = 't' or moderator = 't'").where(id: request.session[:current_user_id].to_i).exists?
|
||||
end
|
||||
|
||||
end
|
|
@ -56,17 +56,14 @@ class PostCreator
|
|||
|
||||
topic.subtype = TopicSubtype.user_to_user unless topic.subtype
|
||||
|
||||
usernames = @opts[:target_usernames].split(',')
|
||||
User.where(username: usernames).each do |u|
|
||||
|
||||
unless guardian.can_send_private_message?(u)
|
||||
topic.errors.add(:archetype, :cant_send_pm)
|
||||
@errors = topic.errors
|
||||
raise ActiveRecord::Rollback.new
|
||||
end
|
||||
|
||||
topic.topic_allowed_users.build(user_id: u.id)
|
||||
unless @opts[:target_usernames].present? || @opts[:target_group_names].present?
|
||||
topic.errors.add(:archetype, :cant_send_pm)
|
||||
@errors = topic.errors
|
||||
raise ActiveRecord::Rollback.new
|
||||
end
|
||||
|
||||
add_users(topic,@opts[:target_usernames])
|
||||
add_groups(topic,@opts[:target_group_names])
|
||||
topic.topic_allowed_users.build(user_id: @user.id)
|
||||
end
|
||||
|
||||
|
@ -148,4 +145,35 @@ class PostCreator
|
|||
PostCreator.new(user, opts).create
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def add_users(topic, usernames)
|
||||
return unless usernames
|
||||
usernames = usernames.split(',')
|
||||
User.where(username: usernames).each do |u|
|
||||
|
||||
unless guardian.can_send_private_message?(u)
|
||||
topic.errors.add(:archetype, :cant_send_pm)
|
||||
@errors = topic.errors
|
||||
raise ActiveRecord::Rollback.new
|
||||
end
|
||||
|
||||
topic.topic_allowed_users.build(user_id: u.id)
|
||||
end
|
||||
end
|
||||
|
||||
def add_groups(topic, groups)
|
||||
return unless groups
|
||||
groups = groups.split(',')
|
||||
Group.where(name: groups).each do |g|
|
||||
|
||||
unless guardian.can_send_private_message?(g)
|
||||
topic.errors.add(:archetype, :cant_send_pm)
|
||||
@errors = topic.errors
|
||||
raise ActiveRecord::Rollback.new
|
||||
end
|
||||
|
||||
topic.topic_allowed_groups.build(group_id: g.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -485,8 +485,8 @@ describe Guardian do
|
|||
Guardian.new(user).can_edit?(user).should be_true
|
||||
end
|
||||
|
||||
it 'returns false as a moderator' do
|
||||
Guardian.new(moderator).can_edit?(user).should be_false
|
||||
it 'returns true as a moderator' do
|
||||
Guardian.new(moderator).can_edit?(user).should be_true
|
||||
end
|
||||
|
||||
it 'returns true as an admin' do
|
||||
|
|
|
@ -190,5 +190,35 @@ describe PostCreator do
|
|||
end
|
||||
end
|
||||
|
||||
context 'private message to group' do
|
||||
let(:target_user1) { Fabricate(:coding_horror) }
|
||||
let(:target_user2) { Fabricate(:moderator) }
|
||||
let(:group) do
|
||||
g = Fabricate.build(:group)
|
||||
g.add(target_user1)
|
||||
g.add(target_user2)
|
||||
g.save
|
||||
g
|
||||
end
|
||||
let(:unrelated) { Fabricate(:user) }
|
||||
let(:post) do
|
||||
PostCreator.create(user, title: 'hi there welcome to my topic',
|
||||
raw: "this is my awesome message @#{unrelated.username_lower}",
|
||||
archetype: Archetype.private_message,
|
||||
target_group_names: group.name)
|
||||
end
|
||||
|
||||
it 'acts correctly' do
|
||||
post.topic.archetype.should == Archetype.private_message
|
||||
post.topic.topic_allowed_users.count.should == 1
|
||||
post.topic.topic_allowed_groups.count.should == 1
|
||||
|
||||
# does not notify an unrelated user
|
||||
unrelated.notifications.count.should == 0
|
||||
post.topic.subtype.should == TopicSubtype.user_to_user
|
||||
target_user1.notifications.count.should == 1
|
||||
target_user2.notifications.count.should == 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue