Add subtype to topics to classify private messages

This commit is contained in:
Neil Lalonde 2013-04-16 16:56:18 -04:00
parent 2b5a2b5fce
commit 3b6aeb14c7
16 changed files with 223 additions and 43 deletions

View file

@ -130,7 +130,28 @@
{{ render 'admin_report_counts' likes }}
{{ render 'admin_report_counts' flags }}
{{ render 'admin_report_counts' emails }}
{{ render 'admin_report_counts' private_messages }}
{{/unless}}
</table>
</div>
<div class="dashboard-stats">
<table class="table table-condensed table-hover">
<thead>
<tr>
<th>&nbsp;</th>
<th>{{i18n admin.dashboard.reports.today}}</th>
<th>{{i18n admin.dashboard.reports.yesterday}}</th>
<th>{{i18n admin.dashboard.reports.last_7_days}}</th>
<th>{{i18n admin.dashboard.reports.last_30_days}}</th>
<th>{{i18n admin.dashboard.reports.all}}</th>
</tr>
</thead>
{{#unless loading}}
{{ render 'admin_report_counts' user_to_user_private_messages }}
{{ render 'admin_report_counts' system_private_messages }}
{{ render 'admin_report_counts' notify_moderators_private_messages }}
{{ render 'admin_report_counts' notify_user_private_messages }}
{{ render 'admin_report_counts' moderator_warning_private_messages }}
{{/unless}}
</table>
</div>

View file

@ -336,8 +336,8 @@ table {
.dashboard-stats {
margin-top: 30px;
width: 450px;
margin-left: 40px;
width: 460px;
margin-left: 30px;
table {
width: 100%;

View file

@ -2,7 +2,21 @@ require_dependency 'mem_info'
class AdminDashboardData
REPORTS = ['visits', 'signups', 'topics', 'posts', 'flags', 'users_by_trust_level', 'likes', 'emails', 'private_messages']
REPORTS = [
'visits',
'signups',
'topics',
'posts',
'flags',
'users_by_trust_level',
'likes',
'emails',
'user_to_user_private_messages',
'system_private_messages',
'moderator_warning_private_messages',
'notify_moderators_private_messages',
'notify_user_private_messages'
]
def self.fetch_all
AdminDashboardData.new

View file

@ -42,6 +42,7 @@ class Post < ActiveRecord::Base
scope :with_user, includes(:user)
scope :public_posts, -> { joins(:topic).where('topics.archetype <> ?', Archetype.private_message) }
scope :private_posts, -> { joins(:topic).where('topics.archetype = ?', Archetype.private_message) }
scope :with_topic_subtype, ->(subtype) { joins(:topic).where('topics.subtype = ?', subtype) }
def self.hidden_reasons
@hidden_reasons ||= Enum.new(:flag_threshold_reached, :flag_threshold_reached_again)
@ -393,11 +394,11 @@ class Post < ActiveRecord::Base
Jobs.enqueue(:process_post, args)
end
def self.public_posts_count_per_day(sinceDaysAgo=30)
public_posts.where('posts.created_at > ?', sinceDaysAgo.days.ago).group('date(posts.created_at)').order('date(posts.created_at)').count
def self.public_posts_count_per_day(since_days_ago=30)
public_posts.where('posts.created_at > ?', since_days_ago.days.ago).group('date(posts.created_at)').order('date(posts.created_at)').count
end
def self.private_messages_count_per_day(sinceDaysAgo=30)
private_posts.where('posts.created_at > ?', sinceDaysAgo.days.ago).group('date(posts.created_at)').order('date(posts.created_at)').count
def self.private_messages_count_per_day(since_days_ago, topic_subtype)
private_posts.with_topic_subtype(topic_subtype).where('posts.created_at > ?', since_days_ago.days.ago).group('date(posts.created_at)').order('date(posts.created_at)').count
end
end

View file

@ -73,7 +73,7 @@ class PostAction < ActiveRecord::Base
def self.act(user, post, post_action_type_id, message = nil)
begin
title, target_usernames,body = nil
title, target_usernames, subtype, body = nil
if message
[:notify_moderators, :notify_user].each do |k|
@ -84,6 +84,7 @@ class PostAction < ActiveRecord::Base
body = I18n.t("post_action_types.#{k}.email_body",
message: message,
link: "#{Discourse.base_url}#{post.url}")
subtype = k == :notify_moderators ? TopicSubtype.notify_moderators : TopicSubtype.notify_user
end
end
end
@ -92,6 +93,7 @@ class PostAction < ActiveRecord::Base
PostCreator.new(user,
target_usernames: target_usernames,
archetype: Archetype.private_message,
subtype: subtype,
title: title,
raw: body
).create

View file

@ -1,3 +1,5 @@
require_dependency 'topic_subtype'
class Report
attr_accessor :type, :data, :total, :prev30Days
@ -51,12 +53,6 @@ class Report
report.prev30Days = Post.public_posts.where('posts.created_at > ? and posts.created_at < ?', 60.days.ago, 30.days.ago).count
end
def self.report_private_messages(report)
basic_report_about report, Post, :private_messages_count_per_day
report.total = Post.private_posts.count
report.prev30Days = Post.private_posts.where('posts.created_at > ? and posts.created_at < ?', 60.days.ago, 30.days.ago).count
end
def self.report_emails(report)
report_about report, EmailLog
end
@ -66,9 +62,9 @@ class Report
add_counts(report, subject_class)
end
def self.basic_report_about(report, subject_class, report_method)
def self.basic_report_about(report, subject_class, report_method, *args)
report.data = []
subject_class.send(report_method, 30).each do |date, count|
subject_class.send(report_method, 30, *args).each do |date, count|
report.data << {x: date, y: count}
end
end
@ -109,4 +105,30 @@ class Report
report.total = likesQuery.count
report.prev30Days = likesQuery.where('created_at > ? and created_at < ?', 60.days.ago, 30.days.ago).count
end
def self.private_messages_report(report, topic_subtype)
basic_report_about report, Post, :private_messages_count_per_day, topic_subtype
report.total = Post.private_posts.with_topic_subtype(topic_subtype).count
report.prev30Days = Post.private_posts.with_topic_subtype(topic_subtype).where('posts.created_at > ? and posts.created_at < ?', 60.days.ago, 30.days.ago).count
end
def self.report_user_to_user_private_messages(report)
private_messages_report report, TopicSubtype.user_to_user
end
def self.report_system_private_messages(report)
private_messages_report report, TopicSubtype.system_message
end
def self.report_moderator_warning_private_messages(report)
private_messages_report report, TopicSubtype.moderator_warning
end
def self.report_notify_moderators_private_messages(report)
private_messages_report report, TopicSubtype.notify_moderators
end
def self.report_notify_user_private_messages(report)
private_messages_report report, TopicSubtype.notify_user
end
end

View file

@ -305,8 +305,24 @@ en:
title: "Emails Sent"
xaxis: "Day"
yaxis: "Number of Emails"
private_messages:
title: "Private Messages"
user_to_user_private_messages:
title: "User-to-User Messages"
xaxis: "Day"
yaxis: "Number of private messages"
system_private_messages:
title: "System Messages"
xaxis: "Day"
yaxis: "Number of private messages"
moderator_warning_private_messages:
title: "Moderator Warning Messages"
xaxis: "Day"
yaxis: "Number of private messages"
notify_moderators_private_messages:
title: "Notify Moderators Messages"
xaxis: "Day"
yaxis: "Number of private messages"
notify_user_private_messages:
title: "Nofity User Messages"
xaxis: "Day"
yaxis: "Number of private messages"

View file

@ -0,0 +1,10 @@
class AddSubtypeToTopics < ActiveRecord::Migration
def up
add_column :topics, :subtype, :string
execute "update topics set subtype = 'user_to_user' where archetype = 'private_message'"
end
def down
remove_column :topics, :subtype
end
end

View file

@ -42,6 +42,7 @@ class PostCreator
if @opts[:topic_id].blank?
topic_params = {title: @opts[:title], user_id: @user.id, last_post_user_id: @user.id}
topic_params[:archetype] = @opts[:archetype] if @opts[:archetype].present?
topic_params[:subtype] = @opts[:subtype] if @opts[:subtype].present?
guardian.ensure_can_create!(Topic)
@ -53,6 +54,8 @@ class PostCreator
if @opts[:archetype] == Archetype.private_message
topic.subtype = TopicSubtype.user_to_user unless topic.subtype
usernames = @opts[:target_usernames].split(',')
User.where(username: usernames).each do |u|

View file

@ -1,5 +1,6 @@
# Handle sending a message to a user from the system.
require_dependency 'post_creator'
require_dependency 'topic_subtype'
class SystemMessage
@ -33,6 +34,7 @@ class SystemMessage
raw: raw_body,
title: title,
archetype: Archetype.private_message,
subtype: TopicSubtype.system_message,
target_usernames: @recipient.username)
end

52
lib/topic_subtype.rb Normal file
View file

@ -0,0 +1,52 @@
class TopicSubtype
include ActiveModel::Serialization
attr_accessor :id, :options
def initialize(id, options)
@id = id
@options = options
end
def attributes
{'id' => @id,
'options' => @options}
end
def self.list
return [] unless @archetypes.present?
@archetypes.values
end
def self.user_to_user
'user_to_user'
end
def self.system_message
'system_message'
end
def self.moderator_warning
'moderator_warning'
end
def self.notify_moderators
'notify_moderators'
end
def self.notify_user
'notify_user'
end
def self.register(name, options={})
@subtypes ||= {}
@subtypes[name] = TopicSubtype.new(name, options)
end
register 'user_to_user'
register 'system_message'
register 'moderator_warning'
register 'notify_moderators'
register 'notify_user'
end

View file

@ -1,5 +1,6 @@
require 'spec_helper'
require 'post_creator'
require 'topic_subtype'
describe PostCreator do
@ -173,22 +174,28 @@ describe PostCreator do
context 'private message' do
let(:target_user1) { Fabricate(:coding_horror) }
let(:target_user2) { Fabricate(:moderator) }
let(:post) do
PostCreator.create(user, title: 'hi there welcome to my topic',
raw: 'this is my awesome message',
archetype: Archetype.private_message,
target_usernames: [target_user1.username, target_user2.username].join(','))
end
it 'has the right archetype' do
post.topic.archetype.should == Archetype.private_message
end
describe 'regular user to user' do
let(:post) do
PostCreator.create(user, title: 'hi there welcome to my topic',
raw: 'this is my awesome message',
archetype: Archetype.private_message,
target_usernames: [target_user1.username, target_user2.username].join(','))
end
it 'has the right count (me and 2 other users)' do
post.topic.topic_allowed_users.count.should == 3
it 'has the right archetype' do
post.topic.archetype.should == Archetype.private_message
end
it 'has the right count (me and 2 other users)' do
post.topic.topic_allowed_users.count.should == 3
end
it 'has the right subtype' do
post.topic.subtype.should == TopicSubtype.user_to_user
end
end
end
end

View file

@ -1,5 +1,6 @@
require 'spec_helper'
require 'system_message'
require 'topic_subtype'
describe SystemMessage do
@ -20,6 +21,10 @@ describe SystemMessage do
topic.should be_private_message
end
it 'should have the correct topic subtype' do
topic.subtype.should == TopicSubtype.system_message
end
it 'should be visible by the user' do
topic.allowed_users.include?(user).should be_true
end

View file

@ -68,6 +68,7 @@ Fabricator(:private_message_post, from: :post) do
Fabricate( :private_message_topic,
user: attrs[:user],
created_at: attrs[:created_at],
subtype: TopicSubtype.user_to_user,
topic_allowed_users: [
Fabricate.build(:topic_allowed_user, user_id: attrs[:user].id),
Fabricate.build(:topic_allowed_user, user_id: Fabricate(:user).id)

View file

@ -18,19 +18,43 @@ describe PostAction do
let(:bookmark) { PostAction.new(user_id: post.user_id, post_action_type_id: PostActionType.types[:bookmark] , post_id: post.id) }
describe "messaging" do
it "sends an email to all moderators if selected" do
PostAction.stubs(:create)
PostAction.expects(:target_moderators).returns("bob")
PostCreator.any_instance.expects(:create).returns(nil)
PostAction.act(build(:user), build(:post), PostActionType.types[:notify_moderators], "this is my special message");
describe 'notify_moderators' do
before do
PostAction.stubs(:create)
PostAction.expects(:target_moderators).returns("bob")
end
it "sends an email to all moderators if selected" do
PostCreator.any_instance.expects(:create).returns(nil)
PostAction.act(build(:user), build(:post), PostActionType.types[:notify_moderators], "this is my special message");
end
it "uses the correct topic subtype" do
PostCreator.expects(:new).with do |user, opts|
opts[:subtype] == TopicSubtype.notify_moderators
end.returns(stub_everything)
PostAction.act(build(:user), build(:post), PostActionType.types[:notify_moderators], "this is my special message");
end
end
it "sends an email to user if selected" do
PostAction.stubs(:create)
PostCreator.any_instance.expects(:create).returns(nil)
post = build(:post)
post.user = build(:user)
PostAction.act(build(:user), post, PostActionType.types[:notify_user], "this is my special message");
describe "notify_user" do
before do
PostAction.stubs(:create)
post = build(:post)
post.user = build(:user)
end
it "sends an email to user if selected" do
PostCreator.any_instance.expects(:create).returns(nil)
PostAction.act(build(:user), post, PostActionType.types[:notify_user], "this is my special message");
end
it "uses the correct topic subtype" do
PostCreator.expects(:new).with do |user, opts|
opts[:subtype] == TopicSubtype.notify_user
end.returns(stub_everything)
PostAction.act(build(:user), post, PostActionType.types[:notify_user], "this is my special message");
end
end
end

View file

@ -61,7 +61,7 @@ describe Report do
end
describe 'private messages' do
let(:report) { Report.find('private_messages') }
let(:report) { Report.find('user_to_user_private_messages') }
it 'topic report should not include private messages' do
Fabricate(:private_message_topic, created_at: 1.hour.ago)