diff --git a/app/assets/javascripts/admin/templates/user_index.js.handlebars b/app/assets/javascripts/admin/templates/user_index.js.handlebars
index 952fd8f9477..5a6ccc6c76e 100644
--- a/app/assets/javascripts/admin/templates/user_index.js.handlebars
+++ b/app/assets/javascripts/admin/templates/user_index.js.handlebars
@@ -354,6 +354,10 @@
{{i18n admin.user.flags_given_received_count}}
{{flags_given_count}} / {{flags_received_count}}
diff --git a/app/assets/javascripts/discourse/components/notification-item.js.es6 b/app/assets/javascripts/discourse/components/notification-item.js.es6
index c587e12b6d0..4942a90ca66 100644
--- a/app/assets/javascripts/discourse/components/notification-item.js.es6
+++ b/app/assets/javascripts/discourse/components/notification-item.js.es6
@@ -1,6 +1,6 @@
export default Ember.Component.extend({
tagName: 'li',
- classNameBindings: ['notification.read'],
+ classNameBindings: ['notification.read', 'notification.is_warning'],
_markRead: function(){
var self = this;
diff --git a/app/assets/javascripts/discourse/components/topic-status.js.es6 b/app/assets/javascripts/discourse/components/topic-status.js.es6
index 83ce68493ad..fe99221da52 100644
--- a/app/assets/javascripts/discourse/components/topic-status.js.es6
+++ b/app/assets/javascripts/discourse/components/topic-status.js.es6
@@ -9,8 +9,8 @@
export default Ember.Component.extend({
classNames: ['topic-statuses'],
- hasDisplayableStatus: Em.computed.or('topic.archived','topic.closed', 'topic.pinned', 'topic.unpinned', 'topic.invisible', 'topic.archetypeObject.notDefault'),
- shouldRerender: Discourse.View.renderIfChanged('topic.archived','topic.closed', 'topic.pinned', 'topic.visible', 'topic.unpinned'),
+ hasDisplayableStatus: Em.computed.or('topic.archived','topic.closed', 'topic.pinned', 'topic.unpinned', 'topic.invisible', 'topic.archetypeObject.notDefault', 'topic.is_warning'),
+ shouldRerender: Discourse.View.renderIfChanged('topic.archived', 'topic.closed', 'topic.pinned', 'topic.visible', 'topic.unpinned', 'topic.is_warning'),
didInsertElement: function(){
var self = this;
@@ -52,6 +52,7 @@ export default Ember.Component.extend({
// Allow a plugin to add a custom icon to a topic
this.trigger('addCustomIcon', buffer);
+ renderIconIf('topic.is_warning', 'envelope', 'warning');
renderIconIf('topic.closed', 'lock', 'locked');
renderIconIf('topic.archived', 'lock', 'archived');
renderIconIf('topic.pinned', 'thumb-tack', 'pinned', self.get("canAct") );
diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6
index 9567ba57ac1..702df16a936 100644
--- a/app/assets/javascripts/discourse/controllers/composer.js.es6
+++ b/app/assets/javascripts/discourse/controllers/composer.js.es6
@@ -15,6 +15,16 @@ export default DiscourseController.extend({
this.set('similarTopics', []);
}.on('init'),
+ showWarning: function() {
+ var usernames = this.get('model.targetUsernames');
+
+ // We need exactly one user to issue a warning
+ if (Em.empty(usernames) || usernames.split(',').length !== 1) {
+ return false;
+ }
+ return this.get('model.creatingPrivateMessage');
+ }.property('model.creatingPrivateMessage', 'model.targetUsernames'),
+
actions: {
// Toggle the reply view
toggle: function() {
@@ -103,6 +113,12 @@ export default DiscourseController.extend({
var composer = this.get('model'),
self = this;
+
+ // Clear the warning state if we're not showing the checkbox anymore
+ if (!this.get('showWarning')) {
+ this.set('model.isWarning', false);
+ }
+
if(composer.get('cantSubmitPost')) {
var now = Date.now();
this.setProperties({
@@ -345,6 +361,7 @@ export default DiscourseController.extend({
this.set('model', composerModel);
composerModel.set('composeState', Discourse.Composer.OPEN);
+ composerModel.set('isWarning', false);
var composerMessages = this.get('controllers.composer-messages');
composerMessages.queryFor(composerModel);
diff --git a/app/assets/javascripts/discourse/controllers/header.js.es6 b/app/assets/javascripts/discourse/controllers/header.js.es6
index 8701149d922..d7cebb23f01 100644
--- a/app/assets/javascripts/discourse/controllers/header.js.es6
+++ b/app/assets/javascripts/discourse/controllers/header.js.es6
@@ -10,6 +10,10 @@ export default DiscourseController.extend({
loginRequired: Em.computed.alias('controllers.application.loginRequired'),
canSignUp: Em.computed.alias('controllers.application.canSignUp'),
+ showPrivateMessageGlyph: function() {
+ return !this.get('topic.is_warning') && this.get('topic.isPrivateMessage');
+ }.property('topic.is_warning', 'topic.isPrivateMessage'),
+
showSignUpButton: function() {
return this.get('canSignUp') && !this.get('showExtraInfo');
}.property('canSignUp', 'showExtraInfo'),
diff --git a/app/assets/javascripts/discourse/models/_post.js b/app/assets/javascripts/discourse/models/_post.js
index 6fac98173f6..f2980e50d65 100644
--- a/app/assets/javascripts/discourse/models/_post.js
+++ b/app/assets/javascripts/discourse/models/_post.js
@@ -149,6 +149,7 @@ Discourse.Post = Discourse.Model.extend({
var data = {
raw: this.get('raw'),
topic_id: this.get('topic_id'),
+ is_warning: this.get('is_warning'),
reply_to_post_number: this.get('reply_to_post_number'),
category: this.get('category'),
archetype: this.get('archetype'),
diff --git a/app/assets/javascripts/discourse/models/composer.js b/app/assets/javascripts/discourse/models/composer.js
index 9cee7aa0026..9709b5529bc 100644
--- a/app/assets/javascripts/discourse/models/composer.js
+++ b/app/assets/javascripts/discourse/models/composer.js
@@ -494,6 +494,7 @@ Discourse.Composer = Discourse.Model.extend({
title: this.get('title'),
category: this.get('categoryId'),
topic_id: this.get('topic.id'),
+ is_warning: this.get('isWarning'),
imageSizes: opts.imageSizes,
cooked: this.getCookedHtml(),
reply_count: 0,
diff --git a/app/assets/javascripts/discourse/templates/composer.js.handlebars b/app/assets/javascripts/discourse/templates/composer.js.handlebars
index 322ab1feb0e..a907c32468a 100644
--- a/app/assets/javascripts/discourse/templates/composer.js.handlebars
+++ b/app/assets/javascripts/discourse/templates/composer.js.handlebars
@@ -35,6 +35,14 @@
placeholderKey="composer.users_placeholder"
tabindex="1"
usernames=model.targetUsernames}}
+ {{#if showWarning}}
+
+
+
+ {{/if}}
{{/if}}
{{bound-avatar model "huge"}}
diff --git a/app/assets/javascripts/discourse/views/topic.js.es6 b/app/assets/javascripts/discourse/views/topic.js.es6
index a15125343d1..c09130113a4 100644
--- a/app/assets/javascripts/discourse/views/topic.js.es6
+++ b/app/assets/javascripts/discourse/views/topic.js.es6
@@ -6,6 +6,7 @@ export default Discourse.View.extend(AddCategoryClass, Discourse.Scrolling, {
userFiltersBinding: 'controller.userFilters',
classNameBindings: ['controller.multiSelect:multi-select',
'topic.archetype',
+ 'topic.is_warning',
'topic.category.read_restricted:read_restricted',
'topic.deleted:deleted-topic',
'topic.categoryClass'],
diff --git a/app/assets/stylesheets/common/base/_topic-list.scss b/app/assets/stylesheets/common/base/_topic-list.scss
index 92a740058b6..26e0a4ac31b 100644
--- a/app/assets/stylesheets/common/base/_topic-list.scss
+++ b/app/assets/stylesheets/common/base/_topic-list.scss
@@ -308,4 +308,4 @@ ol.category-breadcrumb {
div.education {
color: scale-color($primary, $lightness: 50%);
-}
\ No newline at end of file
+}
diff --git a/app/assets/stylesheets/common/base/header.scss b/app/assets/stylesheets/common/base/header.scss
index a6121425fbe..c3342aeb300 100644
--- a/app/assets/stylesheets/common/base/header.scss
+++ b/app/assets/stylesheets/common/base/header.scss
@@ -208,6 +208,14 @@
overflow: hidden;
}
}
+ .is-warning {
+ i.fa-envelope-o {
+ &:before {
+ content: "\f0e0";
+ }
+ color: $danger;
+ }
+ }
.read {
background-color: $secondary;
}
diff --git a/app/assets/stylesheets/desktop/compose.scss b/app/assets/stylesheets/desktop/compose.scss
index 6d7535e2988..9cd2125e83b 100644
--- a/app/assets/stylesheets/desktop/compose.scss
+++ b/app/assets/stylesheets/desktop/compose.scss
@@ -3,6 +3,15 @@
// hack, this needs to be done cleaner
#private-message-users {
width: 400px;
+ float: left;
+}
+
+.add-warning {
+ width: 300px;
+ display: inline-block;
+ position: relative;
+ top: -30px;
+ margin-left: 20px;
}
.composer-popup-container {
diff --git a/app/assets/stylesheets/desktop/discourse.scss b/app/assets/stylesheets/desktop/discourse.scss
index 13b422b746d..015e5dade18 100644
--- a/app/assets/stylesheets/desktop/discourse.scss
+++ b/app/assets/stylesheets/desktop/discourse.scss
@@ -125,6 +125,10 @@ body {
font-size: 15px;
}
}
+
+ i.fa-envelope {
+ color: $danger;
+ }
}
/* bootstrap carryover */
diff --git a/app/assets/stylesheets/desktop/topic-post.scss b/app/assets/stylesheets/desktop/topic-post.scss
index d8653437add..5b0d6e789e6 100644
--- a/app/assets/stylesheets/desktop/topic-post.scss
+++ b/app/assets/stylesheets/desktop/topic-post.scss
@@ -527,6 +527,7 @@ iframe {
.topic-statuses {
i { color: $header_primary; }
+ i.fa-envelope { color: $danger; }
.unpinned { color: $header_primary; }
}
.topic-link { color: $header_primary;
diff --git a/app/assets/stylesheets/desktop/topic.scss b/app/assets/stylesheets/desktop/topic.scss
index 4edabbde490..785f8f923f7 100644
--- a/app/assets/stylesheets/desktop/topic.scss
+++ b/app/assets/stylesheets/desktop/topic.scss
@@ -65,7 +65,7 @@
color: scale-color($primary, $lightness: 75%);
float: left;
margin: 0 5px 0 0;
- }
+}
.private_message #topic-title .private-message-glyph { display: inline; }
a.reply-new {
diff --git a/app/assets/stylesheets/desktop/user.scss b/app/assets/stylesheets/desktop/user.scss
index 35f372a2797..fe6f7144399 100644
--- a/app/assets/stylesheets/desktop/user.scss
+++ b/app/assets/stylesheets/desktop/user.scss
@@ -395,6 +395,9 @@
.flagged-posts {
background-color: #E49735;
}
+ .warnings-received {
+ background-color: #EC441B;
+ }
.deleted-posts {
background-color: #EC441B;
}
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 86a57e216a3..8febcf7962d 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -331,12 +331,21 @@ class PostsController < ApplicationController
permitted << :embed_url
end
+
params.require(:raw)
- params.permit(*permitted).tap do |whitelisted|
- whitelisted[:image_sizes] = params[:image_sizes]
- # TODO this does not feel right, we should name what meta_data is allowed
- whitelisted[:meta_data] = params[:meta_data]
+ result = params.permit(*permitted).tap do |whitelisted|
+ whitelisted[:image_sizes] = params[:image_sizes]
+ # TODO this does not feel right, we should name what meta_data is allowed
+ whitelisted[:meta_data] = params[:meta_data]
end
+
+ # Staff are allowed to pass `is_warning`
+ if current_user.staff?
+ params.permit(:is_warning)
+ result[:is_warning] = (params[:is_warning] == "true")
+ end
+
+ result
end
def too_late_to(action, post)
diff --git a/app/models/notification.rb b/app/models/notification.rb
index 55ebdcae66b..c5f6eb7ec46 100644
--- a/app/models/notification.rb
+++ b/app/models/notification.rb
@@ -98,7 +98,7 @@ class Notification < ActiveRecord::Base
def self.recent_report(user, count = nil)
count ||= 10
- notifications = user.notifications.recent(count).includes(:topic).to_a
+ notifications = user.notifications.recent(count).includes({:topic => :warning}).to_a
if notifications.present?
notifications += user.notifications
diff --git a/app/models/topic.rb b/app/models/topic.rb
index 8e9533fd4e8..9b35c05debb 100644
--- a/app/models/topic.rb
+++ b/app/models/topic.rb
@@ -100,6 +100,7 @@ class Topic < ActiveRecord::Base
has_many :invites, through: :topic_invites, source: :invite
has_many :revisions, foreign_key: :topic_id, class_name: 'TopicRevision'
+ has_one :warning
# When we want to temporarily attach some data to a forum topic (usually before serialization)
attr_accessor :user_data
diff --git a/app/models/user.rb b/app/models/user.rb
index 59b73c735f2..d07a02123aa 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -35,6 +35,7 @@ class User < ActiveRecord::Base
has_many :invites, dependent: :destroy
has_many :topic_links, dependent: :destroy
has_many :uploads
+ has_many :warnings
has_one :user_avatar, dependent: :destroy
has_one :facebook_user_info, dependent: :destroy
@@ -393,6 +394,10 @@ class User < ActiveRecord::Base
PostAction.where(user_id: id, post_action_type_id: PostActionType.flag_types.values).count
end
+ def warnings_received_count
+ warnings.count
+ end
+
def flags_received_count
posts.includes(:post_actions).where('post_actions.post_action_type_id' => PostActionType.flag_types.values).count
end
diff --git a/app/models/warning.rb b/app/models/warning.rb
new file mode 100644
index 00000000000..7d60d2deb50
--- /dev/null
+++ b/app/models/warning.rb
@@ -0,0 +1,5 @@
+class Warning < ActiveRecord::Base
+ belongs_to :user
+ belongs_to :topic
+ belongs_to :created_by, class_name: 'User'
+end
diff --git a/app/serializers/admin_detailed_user_serializer.rb b/app/serializers/admin_detailed_user_serializer.rb
index b24d2d126ea..1df1089ef28 100644
--- a/app/serializers/admin_detailed_user_serializer.rb
+++ b/app/serializers/admin_detailed_user_serializer.rb
@@ -17,7 +17,8 @@ class AdminDetailedUserSerializer < AdminUserSerializer
:can_be_deleted,
:suspend_reason,
:primary_group_id,
- :badge_count
+ :badge_count,
+ :warnings_received_count
has_one :approved_by, serializer: BasicUserSerializer, embed: :objects
has_one :api_key, serializer: ApiKeySerializer, embed: :objects
diff --git a/app/serializers/listable_topic_serializer.rb b/app/serializers/listable_topic_serializer.rb
index b89c05aeaa6..99f2aff8bb9 100644
--- a/app/serializers/listable_topic_serializer.rb
+++ b/app/serializers/listable_topic_serializer.rb
@@ -19,6 +19,7 @@ class ListableTopicSerializer < BasicTopicSerializer
:visible,
:closed,
:archived,
+ :is_warning,
:notification_level
has_one :last_poster, serializer: BasicUserSerializer, embed: :objects
@@ -37,6 +38,14 @@ class ListableTopicSerializer < BasicTopicSerializer
false
end
+ def is_warning
+ object.private_message? && object.warning.present?
+ end
+
+ def include_is_warning?
+ is_warning
+ end
+
def unseen
!seen
end
diff --git a/app/serializers/notification_serializer.rb b/app/serializers/notification_serializer.rb
index c6eb8412722..c73bfa903b7 100644
--- a/app/serializers/notification_serializer.rb
+++ b/app/serializers/notification_serializer.rb
@@ -6,12 +6,21 @@ class NotificationSerializer < ApplicationSerializer
:post_number,
:topic_id,
:slug,
- :data
+ :data,
+ :is_warning
def slug
Slug.for(object.topic.title) if object.topic.present?
end
+ def is_warning
+ object.topic.present? && object.topic.warning.present?
+ end
+
+ def include_is_warning?
+ is_warning
+ end
+
def data
object.data_hash
end
diff --git a/app/serializers/topic_view_serializer.rb b/app/serializers/topic_view_serializer.rb
index 23313c29daa..b9d3a4737a7 100644
--- a/app/serializers/topic_view_serializer.rb
+++ b/app/serializers/topic_view_serializer.rb
@@ -41,7 +41,9 @@ class TopicViewSerializer < ApplicationSerializer
:deleted_by,
:has_deleted,
:actions_summary,
- :expandable_first_post
+ :expandable_first_post,
+ :is_warning
+
# Define a delegator for each attribute of the topic we want
attributes(*topic_attributes)
@@ -109,6 +111,14 @@ class TopicViewSerializer < ApplicationSerializer
result
end
+
+ def is_warning
+ object.topic.private_message? && object.topic.warning.present?
+ end
+
+ def include_is_warning?
+ is_warning
+ end
def draft
object.draft
end
diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb
index 15b871a8a3c..1edb4034d2f 100644
--- a/app/serializers/user_serializer.rb
+++ b/app/serializers/user_serializer.rb
@@ -55,7 +55,8 @@ class UserSerializer < BasicUserSerializer
staff_attributes :number_of_deleted_posts,
:number_of_flagged_posts,
:number_of_flags_given,
- :number_of_suspensions
+ :number_of_suspensions,
+ :number_of_warnings
private_attributes :email,
@@ -193,6 +194,10 @@ class UserSerializer < BasicUserSerializer
.count
end
+ def number_of_warnings
+ object.warnings.count
+ end
+
def number_of_suspensions
UserHistory.for(object, :suspend_user).count
end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 220c34c3c96..ecddbc6db06 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -336,6 +336,7 @@ en:
flagged_posts: "flagged posts"
deleted_posts: "deleted posts"
suspensions: "suspensions"
+ warnings_received: "warnings received"
messages:
all: "All"
@@ -624,6 +625,7 @@ en:
message: "Authenticating with GitHub (make sure pop up blockers are not enabled)"
composer:
+ add_warning: "This is an official warning."
posting_not_on_topic: "Which topic do you want to reply to?"
saving_draft_tip: "saving"
saved_draft_tip: "saved"
@@ -1318,6 +1320,8 @@ en:
other: "%{count} clicks"
topic_statuses:
+ warning:
+ help: "This is an official warning."
locked:
help: "This topic is closed; it no longer accepts new replies"
archived:
@@ -1898,6 +1902,7 @@ en:
topics_entered: Topics Viewed
flags_given_count: Flags Given
flags_received_count: Flags Received
+ warnings_received_count: Warnings Received
flags_given_received_count: 'Flags Given / Received'
approve: 'Approve'
approved_by: "approved by"
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 639ce4097eb..1f7d17923ac 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -211,6 +211,9 @@ en:
models:
topic:
attributes:
+ base:
+ warning_requires_pm: "You can only attach warnings to private messages."
+ too_many_users: "You can only send warnings to one user at a time."
archetype:
cant_send_pm: "Sorry, you cannot send a private message to that user."
user:
diff --git a/db/migrate/20140905171733_create_warnings.rb b/db/migrate/20140905171733_create_warnings.rb
new file mode 100644
index 00000000000..90d38725b6e
--- /dev/null
+++ b/db/migrate/20140905171733_create_warnings.rb
@@ -0,0 +1,12 @@
+class CreateWarnings < ActiveRecord::Migration
+ def change
+ create_table :warnings do |t|
+ t.references :topic, null: false
+ t.references :user, null: false
+ t.integer :created_by_id, null: false
+ t.timestamps
+ end
+ add_index :warnings, :user_id
+ add_index :warnings, :topic_id, unique: true
+ end
+end
diff --git a/lib/post_creator.rb b/lib/post_creator.rb
index c4de0707c2f..ee777a26e2a 100644
--- a/lib/post_creator.rb
+++ b/lib/post_creator.rb
@@ -28,6 +28,7 @@ class PostCreator
# When creating a topic:
# title - New topic title
# archetype - Topic archetype
+ # is_warning - Is the topic a warning?
# category - Category to assign to topic
# target_usernames - comma delimited list of usernames for membership (private message)
# target_group_names - comma delimited list of groups for membership (private message)
diff --git a/lib/topic_creator.rb b/lib/topic_creator.rb
index 9209ec85cab..cf25144b17f 100644
--- a/lib/topic_creator.rb
+++ b/lib/topic_creator.rb
@@ -10,6 +10,7 @@ class TopicCreator
@user = user
@guardian = guardian
@opts = opts
+ @added_users = []
end
def create
@@ -18,6 +19,7 @@ class TopicCreator
setup_auto_close_time
process_private_message
save_topic
+ create_warning
watch_topic
@topic
@@ -25,6 +27,27 @@ class TopicCreator
private
+ def create_warning
+ return unless @opts[:is_warning]
+
+ # We can only attach warnings to PMs
+ unless @topic.private_message?
+ @topic.errors.add(:base, :warning_requires_pm)
+ @errors = @topic.errors
+ raise ActiveRecord::Rollback.new
+ end
+
+ # Don't create it if there is more than one user
+ if @added_users.size != 1
+ @topic.errors.add(:base, :too_many_users)
+ @errors = @topic.errors
+ raise ActiveRecord::Rollback.new
+ end
+
+ # Create a warning record
+ Warning.create(topic: @topic, user: @added_users.first, created_by: @user)
+ end
+
def watch_topic
unless @opts[:auto_track] == false
@topic.notifier.watch_topic!(@topic.user_id)
@@ -108,7 +131,8 @@ class TopicCreator
def add_users(topic, usernames)
return unless usernames
User.where(username: usernames.split(',')).each do |user|
- check_can_send_permission!(topic,user)
+ check_can_send_permission!(topic, user)
+ @added_users << user
topic.topic_allowed_users.build(user_id: user.id)
end
end
diff --git a/lib/topic_query.rb b/lib/topic_query.rb
index ceb341ba5ca..022806db329 100644
--- a/lib/topic_query.rb
+++ b/lib/topic_query.rb
@@ -165,7 +165,7 @@ class TopicQuery
options.reverse_merge!(per_page: SiteSetting.topics_per_page)
# Start with a list of all topics
- result = Topic.includes(:allowed_users)
+ result = Topic.includes(:allowed_users).includes(:warning)
.where("topics.id IN (SELECT topic_id FROM topic_allowed_users WHERE user_id = #{user.id.to_i})")
.joins("LEFT OUTER JOIN topic_users AS tu ON (topics.id = tu.topic_id AND tu.user_id = #{user.id.to_i})")
.order(TopicQuerySQL.order_nocategory_basic_bumped)
diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb
index 7b02d7747a9..bf7ee76bcd3 100644
--- a/spec/components/post_creator_spec.rb
+++ b/spec/components/post_creator_spec.rb
@@ -350,6 +350,9 @@ describe PostCreator do
end
it 'acts correctly' do
+ # It's not a warning
+ post.topic.warning.should be_blank
+
post.topic.archetype.should == Archetype.private_message
post.topic.topic_allowed_users.count.should == 3
@@ -370,6 +373,43 @@ describe PostCreator do
end
end
+ context "warnings" do
+ let(:target_user1) { Fabricate(:coding_horror) }
+ let(:target_user2) { Fabricate(:moderator) }
+ let(:base_args) do
+ { title: 'you need a warning buddy!',
+ raw: "you did something bad and I'm telling you about it!",
+ is_warning: true,
+ target_usernames: target_user1.username,
+ category: 1 }
+ end
+
+ it "works as expected" do
+ # Invalid archetype
+ creator = PostCreator.new(user, base_args)
+ creator.create
+ creator.errors.should be_present
+
+ # Too many users
+ creator = PostCreator.new(user, base_args.merge(archetype: Archetype.private_message,
+ target_usernames: [target_user1.username, target_user2.username].join(',')))
+ creator.create
+ creator.errors.should be_present
+
+ # Success
+ creator = PostCreator.new(user, base_args.merge(archetype: Archetype.private_message))
+ post = creator.create
+ creator.errors.should be_blank
+
+ topic = post.topic
+ topic.should be_present
+ topic.warning.should be_present
+ topic.warning.user.should == target_user1
+ topic.warning.created_by.should == user
+ target_user1.warnings.count.should == 1
+ end
+ end
+
context 'private message to group' do
let(:target_user1) { Fabricate(:coding_horror) }
let(:target_user2) { Fabricate(:moderator) }
diff --git a/spec/controllers/posts_controller_spec.rb b/spec/controllers/posts_controller_spec.rb
index 23fde8ccd80..9fe83fec40c 100644
--- a/spec/controllers/posts_controller_spec.rb
+++ b/spec/controllers/posts_controller_spec.rb
@@ -384,6 +384,7 @@ describe PostsController do
describe 'when logged in' do
let!(:user) { log_in }
+ let(:moderator) { log_in(:moderator) }
let(:new_post) { Fabricate.build(:post, user: user) }
it "raises an exception without a raw parameter" do
@@ -492,6 +493,24 @@ describe PostsController do
xhr :post, :create, {raw: 'hello', meta_data: {xyz: 'abc'}}
end
+ context "is_warning" do
+ it "doesn't pass `is_warning` through if you're not staff" do
+ PostCreator.expects(:new).with(user, Not(has_entries('is_warning' => true))).returns(post_creator)
+ xhr :post, :create, {raw: 'hello', archetype: 'private_message', is_warning: 'true'}
+ end
+
+ it "passes `is_warning` through if you're staff" do
+ PostCreator.expects(:new).with(moderator, has_entries('is_warning' => true)).returns(post_creator)
+ xhr :post, :create, {raw: 'hello', archetype: 'private_message', is_warning: 'true'}
+ end
+
+ it "passes `is_warning` as false through if you're staff" do
+ PostCreator.expects(:new).with(moderator, has_entries('is_warning' => false)).returns(post_creator)
+ xhr :post, :create, {raw: 'hello', archetype: 'private_message', is_warning: 'false'}
+ end
+
+ end
+
end
end