Merge pull request #4781 from Zauberstuhl/report_feature
It is now possible to report posts and comments
This commit is contained in:
commit
63c44d9f6b
47 changed files with 615 additions and 276 deletions
|
|
@ -49,7 +49,7 @@ Read more in [#4249](https://github.com/diaspora/diaspora/pull/4249) and [#4883]
|
|||
* Redirect to the stream when switching the mobile publisher to desktop [#4806](https://github.com/diaspora/diaspora/issues/4806)
|
||||
|
||||
## Features
|
||||
* You can report a single post by clicking the correct icon in the controler section [#4517](https://github.com/diaspora/diaspora/pull/4517)
|
||||
* You can report a single post or comment by clicking the correct icon in the controler section [#4517](https://github.com/diaspora/diaspora/pull/4517) [#4781](https://github.com/diaspora/diaspora/pull/4781)
|
||||
* Add permalinks for comments [#4577](https://github.com/diaspora/diaspora/pull/4577)
|
||||
* New menu for the mobile version [#4673](https://github.com/diaspora/diaspora/pull/4673)
|
||||
* Added comment count to statistic to enable calculations of posts/comments ratios [#4799](https://github.com/diaspora/diaspora/pull/4799)
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 173 B After Width: | Height: | Size: 173 B |
|
|
@ -1,3 +0,0 @@
|
|||
app.models.PostReport = Backbone.Model.extend({
|
||||
urlRoot: '/post_report'
|
||||
});
|
||||
4
app/assets/javascripts/app/models/report.js
Normal file
4
app/assets/javascripts/app/models/report.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
app.models.Report = Backbone.Model.extend({
|
||||
urlRoot: '/report',
|
||||
type: 'POST'
|
||||
});
|
||||
|
|
@ -81,6 +81,37 @@ app.views.Base = Backbone.View.extend({
|
|||
}
|
||||
},
|
||||
|
||||
report: function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
var msg = prompt(Diaspora.I18n.t('report.prompt'), Diaspora.I18n.t('report.prompt_default'));
|
||||
if (msg == null) {
|
||||
return;
|
||||
}
|
||||
var data = {
|
||||
report: {
|
||||
item_id: this.model.id,
|
||||
item_type: $(evt.currentTarget).data("type"),
|
||||
text: msg
|
||||
}
|
||||
};
|
||||
|
||||
var report = new app.models.Report();
|
||||
report.save(data, {
|
||||
success: function(model, response) {
|
||||
Diaspora.page.flashMessages.render({
|
||||
success: true,
|
||||
notice: Diaspora.I18n.t('report.status.created')
|
||||
});
|
||||
},
|
||||
error: function(model, response) {
|
||||
Diaspora.page.flashMessages.render({
|
||||
success: false,
|
||||
notice: Diaspora.I18n.t('report.status.exists')
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
destroyModel: function(evt) {
|
||||
evt && evt.preventDefault();
|
||||
var self = this;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ app.views.Comment = app.views.Content.extend({
|
|||
|
||||
events : function() {
|
||||
return _.extend({}, app.views.Content.prototype.events, {
|
||||
"click .comment_delete": "destroyModel"
|
||||
"click .comment_delete": "destroyModel",
|
||||
"click .comment_report": "report"
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ app.views.Feedback = app.views.Base.extend({
|
|||
events: {
|
||||
"click *[rel='auth-required']" : "requireAuth",
|
||||
"click .like" : "toggleLike",
|
||||
"click .reshare" : "resharePost"
|
||||
"click .reshare" : "resharePost",
|
||||
"click .post_report" : "report"
|
||||
},
|
||||
|
||||
tooltipSelector : ".label",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ app.views.StreamPost = app.views.Post.extend({
|
|||
|
||||
"click .remove_post": "destroyModel",
|
||||
"click .hide_post": "hidePost",
|
||||
"click .post_report": "postReport",
|
||||
"click .post_report": "report",
|
||||
"click .block_user": "blockUser"
|
||||
},
|
||||
|
||||
|
|
@ -108,21 +108,6 @@ app.views.StreamPost = app.views.Post.extend({
|
|||
this.remove();
|
||||
},
|
||||
|
||||
postReport : function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
var text = prompt(Diaspora.I18n.t('post_report_prompt'),
|
||||
Diaspora.I18n.t('post_report_prompt_default'));
|
||||
|
||||
var postReport = new app.models.PostReport();
|
||||
postReport.fetch({
|
||||
data: {
|
||||
post_id: this.model.id,
|
||||
text: text
|
||||
},
|
||||
type: 'POST'
|
||||
});
|
||||
},
|
||||
|
||||
focusCommentTextarea: function(evt){
|
||||
evt.preventDefault();
|
||||
this.$(".new_comment_form_wrapper").removeClass("hidden");
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
@import 'facebox'
|
||||
@import 'aspects'
|
||||
@import 'popover'
|
||||
@import 'post_report'
|
||||
@import 'stream_element'
|
||||
@import 'report'
|
||||
|
||||
/* ====== media ====== */
|
||||
.media
|
||||
|
|
@ -211,10 +211,10 @@ ul.as-selections
|
|||
:z-index 6
|
||||
:float right
|
||||
|
||||
.post_report
|
||||
.post_report, .comment_report
|
||||
:display inline-block
|
||||
|
||||
.icons-postreport
|
||||
.icons-report
|
||||
:height 14px
|
||||
:width 14px
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
#post_report {
|
||||
#reports {
|
||||
padding-top: 2em;
|
||||
.content {
|
||||
float: left;
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
.content {
|
||||
float: left;
|
||||
}
|
||||
.options {
|
||||
float: right;
|
||||
}
|
||||
.clear {
|
||||
clear: both;
|
||||
border-bottom: 1px solid #808080;
|
||||
padding-bottom: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
|
@ -61,6 +61,9 @@
|
|||
i.comment:hover {
|
||||
color: #424242;
|
||||
}
|
||||
.post_report i.gray:hover {
|
||||
color: $red;
|
||||
}
|
||||
i.heart.gray:hover {
|
||||
color: $red;
|
||||
}
|
||||
|
|
@ -204,6 +207,13 @@
|
|||
&:hover {
|
||||
@include opacity(1);
|
||||
}
|
||||
.comment_report {
|
||||
display: inline-block;
|
||||
.icons-report {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
}
|
||||
}
|
||||
.delete {
|
||||
display: inline-block;
|
||||
.icons-deletelabel {
|
||||
|
|
|
|||
|
|
@ -133,17 +133,17 @@
|
|||
padding-top: 10px;
|
||||
|
||||
.controls {
|
||||
.comment_delete {
|
||||
.comment_delete, .comment_report {
|
||||
@include transition(opacity);
|
||||
@include opacity(0);
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.controls {
|
||||
.comment_delete {
|
||||
.comment_delete, .comment_report {
|
||||
@include opacity(0.3);
|
||||
}
|
||||
.comment_delete:hover {
|
||||
.comment_delete:hover, .comment_report:hover {
|
||||
@include opacity(1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,17 @@
|
|||
</div>
|
||||
|
||||
<div class="bd">
|
||||
{{#if canRemove}}
|
||||
<div class="controls">
|
||||
{{#if canRemove}}
|
||||
<a href="#" class="delete comment_delete" title="{{t "delete"}}">
|
||||
<div alt="Deletelabel" class="icons-deletelabel" />
|
||||
<a/>
|
||||
</div>
|
||||
{{else}}
|
||||
<a href="#" data-type="comment" class="comment_report" title="{{t "report.name"}}">
|
||||
<div class="icons-report"/>
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#with author}}
|
||||
<a href="/people/{{guid}}" class="author author-name {{hovercardable this}}">
|
||||
|
|
|
|||
|
|
@ -22,5 +22,9 @@
|
|||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<a href="#" rel="auth-required" data-type="post" class="post_report" title="{{t "report.name"}}">
|
||||
<i class="entypo gray large">!</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
{{#if loggedIn}}
|
||||
<div class="controls">
|
||||
{{#unless authorIsCurrentUser}}
|
||||
<a href="#" rel="nofollow" class="post_report" title="{{t "post_report"}}">
|
||||
<div class="icons-postreport control_icon"/>
|
||||
<a href="#" rel="nofollow" data-type="post" class="post_report" title="{{t "report.name"}}">
|
||||
<div class="icons-report control_icon"/>
|
||||
</a>
|
||||
<a href="#" rel="nofollow" class="block_user" title="{{t "ignore"}}">
|
||||
<div class="icons-ignoreuser control_icon"></div>
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
class PostReportController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
before_filter :redirect_unless_admin, :except => [:create]
|
||||
|
||||
def index
|
||||
@post_report = PostReport.where(reviewed: false).all
|
||||
end
|
||||
|
||||
def update
|
||||
if PostReport.exists?(post_id: params[:id])
|
||||
mark_as_reviewed
|
||||
end
|
||||
redirect_to :action => :index and return
|
||||
end
|
||||
|
||||
def destroy
|
||||
if Post.exists?(params[:id])
|
||||
delete_post
|
||||
mark_as_reviewed
|
||||
end
|
||||
redirect_to :action => :index and return
|
||||
end
|
||||
|
||||
def create
|
||||
username = current_user.username
|
||||
unless PostReport.where(post_id: params[:post_id]).exists?(user_id: username)
|
||||
post = PostReport.new(
|
||||
:post_id => params[:post_id],
|
||||
:user_id => username,
|
||||
:text => params[:text])
|
||||
result = post.save
|
||||
status(( 200 if result ) || ( 422 if !result ))
|
||||
else
|
||||
status(409)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def delete_post
|
||||
post = Post.find(params[:id])
|
||||
current_user.retract(post)
|
||||
flash[:notice] = I18n.t 'post_report.status.destroyed'
|
||||
end
|
||||
|
||||
def mark_as_reviewed id = params[:id]
|
||||
posts = PostReport.where(post_id: id)
|
||||
posts.each do |post|
|
||||
post.update_attributes(reviewed: true)
|
||||
end
|
||||
flash[:notice] = I18n.t 'post_report.status.marked'
|
||||
end
|
||||
|
||||
def status(code)
|
||||
if code == 200
|
||||
flash[:notice] = I18n.t 'post_report.status.created'
|
||||
else
|
||||
flash[:error] = I18n.t 'post_report.status.failed'
|
||||
end
|
||||
render :nothing => true, :status => code
|
||||
end
|
||||
end
|
||||
42
app/controllers/report_controller.rb
Normal file
42
app/controllers/report_controller.rb
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
class ReportController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
before_filter :redirect_unless_admin, :except => [:create]
|
||||
|
||||
def index
|
||||
@reports = Report.where(reviewed: false).all
|
||||
end
|
||||
|
||||
def update
|
||||
if report = Report.where(id: params[:id]).first
|
||||
report.mark_as_reviewed
|
||||
end
|
||||
redirect_to :action => :index
|
||||
end
|
||||
|
||||
def destroy
|
||||
if (report = Report.where(id: params[:id]).first) && report.destroy_reported_item
|
||||
flash[:notice] = I18n.t 'report.status.destroyed'
|
||||
else
|
||||
flash[:error] = I18n.t 'report.status.failed'
|
||||
end
|
||||
redirect_to :action => :index
|
||||
end
|
||||
|
||||
def create
|
||||
report = current_user.reports.new(report_params)
|
||||
if report.save
|
||||
render :json => true, :status => 200
|
||||
else
|
||||
render :nothing => true, :status => 409
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def report_params
|
||||
params.require(:report).permit(:item_id, :item_type, :text)
|
||||
end
|
||||
end
|
||||
|
|
@ -179,6 +179,7 @@ class UsersController < ApplicationController
|
|||
:remember_me,
|
||||
:getting_started,
|
||||
email_preferences: [
|
||||
:someone_reported,
|
||||
:also_commented,
|
||||
:mentioned,
|
||||
:comment_on_post,
|
||||
|
|
|
|||
16
app/helpers/report_helper.rb
Normal file
16
app/helpers/report_helper.rb
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Copyright (c) 2012, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
module ReportHelper
|
||||
def report_content(id, type)
|
||||
raw case type
|
||||
when 'post'
|
||||
t('report.post_label', title: link_to(post_page_title(Post.find_by_id(id)), post_path(id)))
|
||||
when 'comment'
|
||||
# comment_message is not html_safe. To prevent
|
||||
# cross-site-scripting we have to escape html
|
||||
t('report.comment_label', data: h(comment_message(Comment.find_by_id(id))))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
class PostReportMailer < ActionMailer::Base
|
||||
default :from => AppConfig.mail.sender_address
|
||||
|
||||
def new_report
|
||||
Role.admins.each do |role|
|
||||
email = User.find_by_id(role.person_id).email
|
||||
format(email).deliver
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def format(email)
|
||||
mail(to: email, subject: I18n.t('notifier.post_report_email.subject')) do |format|
|
||||
format.text { render 'post_report/post_report_email' }
|
||||
format.html { render 'post_report/post_report_email' }
|
||||
end
|
||||
end
|
||||
end
|
||||
26
app/mailers/report_mailer.rb
Normal file
26
app/mailers/report_mailer.rb
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
class ReportMailer < ActionMailer::Base
|
||||
default :from => AppConfig.mail.sender_address
|
||||
|
||||
def new_report(type, id)
|
||||
resource = {
|
||||
:url => report_index_url,
|
||||
:type => I18n.t('notifier.report_email.type.' + type),
|
||||
:id => id
|
||||
}
|
||||
Role.admins.each do |role|
|
||||
user = User.find_by_id(role.person_id)
|
||||
unless user.user_preferences.exists?(:email_type => :someone_reported)
|
||||
resource[:email] = user.email
|
||||
format(resource).deliver
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def format(resource)
|
||||
mail(to: resource[:email], subject: I18n.t('notifier.report_email.subject', :type => resource[:type])) do |format|
|
||||
format.html { render 'report/report_email', :locals => { :resource => resource } }
|
||||
format.text { render 'report/report_email', :locals => { :resource => resource } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
class PostReport < ActiveRecord::Base
|
||||
validates :user_id, presence: true
|
||||
validates :post_id, presence: true
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :post
|
||||
|
||||
has_many :post_reports
|
||||
|
||||
after_create :send_report_notification
|
||||
|
||||
def send_report_notification
|
||||
Workers::Mail::PostReportWorker.perform_async
|
||||
end
|
||||
end
|
||||
60
app/models/report.rb
Normal file
60
app/models/report.rb
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
class Report < ActiveRecord::Base
|
||||
validates :user_id, presence: true
|
||||
validates :item_id, presence: true
|
||||
validates :item_type, presence: true, :inclusion => { :in => %w(post comment),
|
||||
:message => 'Type should match `post` or `comment`!'}
|
||||
validates :text, presence: true
|
||||
|
||||
validate :entry_does_not_exist, :on => :create
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :post
|
||||
belongs_to :comment
|
||||
|
||||
after_commit :send_report_notification, :on => :create
|
||||
|
||||
def entry_does_not_exist
|
||||
if Report.where(item_id: item_id, item_type: item_type).exists?(user_id: user_id)
|
||||
errors[:base] << 'You cannot report the same post twice.'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_reported_item
|
||||
if item_type == 'post'
|
||||
delete_post
|
||||
elsif item_type == 'comment'
|
||||
delete_comment
|
||||
end
|
||||
mark_as_reviewed
|
||||
end
|
||||
|
||||
def delete_post
|
||||
if post = Post.where(id: item_id).first
|
||||
if post.author.local?
|
||||
post.author.owner.retract(post)
|
||||
else
|
||||
post.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def delete_comment
|
||||
if comment = Comment.where(id: item_id).first
|
||||
if comment.author.local?
|
||||
comment.author.owner.retract(comment)
|
||||
elsif comment.parent.author.local?
|
||||
comment.parent.author.owner.retract(comment)
|
||||
else
|
||||
comment.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def mark_as_reviewed
|
||||
Report.where(item_id: item_id, item_type: item_type).update_all(reviewed: true)
|
||||
end
|
||||
|
||||
def send_report_notification
|
||||
Workers::Mail::ReportWorker.perform_async(self.item_type, self.item_id)
|
||||
end
|
||||
end
|
||||
|
|
@ -69,6 +69,8 @@ class User < ActiveRecord::Base
|
|||
|
||||
has_many :notifications, :foreign_key => :recipient_id
|
||||
|
||||
has_many :reports
|
||||
|
||||
before_save :guard_unconfirmed_email,
|
||||
:save_person!
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ class UserPreference < ActiveRecord::Base
|
|||
validate :must_be_valid_email_type
|
||||
|
||||
VALID_EMAIL_TYPES =
|
||||
["mentioned",
|
||||
["someone_reported",
|
||||
"mentioned",
|
||||
"comment_on_post",
|
||||
"private_message",
|
||||
"started_sharing",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
%li= link_to t('.user_search'), user_search_path
|
||||
%li= link_to t('.weekly_user_stats'), weekly_user_stats_path
|
||||
%li= link_to t('.pod_stats'), pod_stats_path
|
||||
%li= link_to t('.post_report'), post_report_index_path
|
||||
%li= link_to t('.report'), report_index_path
|
||||
%li= link_to t('.correlations'), correlations_path
|
||||
%li= link_to t('.sidekiq_monitor'), sidekiq_path
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
.span-24
|
||||
= render :partial => 'admins/admin_bar'
|
||||
|
||||
.span-24.last
|
||||
%h1
|
||||
= t('post_report.title')
|
||||
%div#post_report
|
||||
- @post_report.each do |report|
|
||||
%div.content
|
||||
%span
|
||||
= raw t('post_report.post_label', title: link_to(post_page_title(Post.find_by_id(report.post_id)), post_path(report.post_id)))
|
||||
%span
|
||||
= raw t('post_report.reported_label', person: link_to(report.user_id, user_profile_path(report.user_id)))
|
||||
%span
|
||||
= t('post_report.reason_label', text: report.text)
|
||||
%div.options
|
||||
%span
|
||||
= link_to t('post_report.review_link'), post_report_path(report.post_id), method: :put
|
||||
%span
|
||||
= link_to t('post_report.delete_link'), post_report_path(report.post_id), method: :delete
|
||||
%div.clear
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<%= t('notifier.post_report_email.body') %>
|
||||
|
||||
27
app/views/report/index.html.haml
Normal file
27
app/views/report/index.html.haml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
.span-24
|
||||
= render :partial => 'admins/admin_bar'
|
||||
|
||||
.span-24.last
|
||||
%h1
|
||||
= t('report.title')
|
||||
%div#reports
|
||||
- @reports.each do |r|
|
||||
- username = User.find_by_id(r.user_id).username
|
||||
%div.content
|
||||
%span
|
||||
= report_content(r.item_id, r.item_type)
|
||||
%span
|
||||
= raw t('report.reported_label', person: link_to(username, user_profile_path(username)))
|
||||
%span
|
||||
= t('report.reason_label', text: r.text)
|
||||
%div.options
|
||||
%span
|
||||
= button_to t('report.review_link'), report_path(r.id, :type => r.item_type),
|
||||
:class => "button",
|
||||
method: :put
|
||||
%span
|
||||
= button_to t('report.delete_link'), report_path(r.id, :type => r.item_type),
|
||||
:data => { :confirm => t('report.confirm_deletion') },
|
||||
:class => "button delete",
|
||||
method: :delete
|
||||
%div.clear
|
||||
2
app/views/report/report_email.markerb
Normal file
2
app/views/report/report_email.markerb
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<%= t('notifier.report_email.body', url: resource[:url], type: resource[:type], id: resource[:id]) %>
|
||||
|
||||
|
|
@ -125,11 +125,22 @@
|
|||
|
||||
= f.fields_for :email_preferences do |type|
|
||||
#email_prefs
|
||||
- if current_user.admin?
|
||||
%p.checkbox_select
|
||||
= type.label :someone_reported, t('.someone_reported')
|
||||
= type.check_box :someone_reported, {:checked => @email_prefs['someone_reported']}, false, true
|
||||
|
||||
%br
|
||||
%p.checkbox_select
|
||||
= type.label :started_sharing, t('.started_sharing')
|
||||
= type.check_box :started_sharing, {:checked => @email_prefs['started_sharing']}, false, true
|
||||
%br
|
||||
|
||||
%p.checkbox_select
|
||||
= type.label :also_commented, t('.also_commented')
|
||||
= type.check_box :also_commented, {:checked => @email_prefs['also_commented']}, false, true
|
||||
%br
|
||||
|
||||
%p.checkbox_select
|
||||
= type.label :mentioned, t('.mentioned')
|
||||
= type.check_box :mentioned, {:checked => @email_prefs['mentioned']}, false, true
|
||||
|
|
|
|||
|
|
@ -113,11 +113,22 @@
|
|||
|
||||
= f.fields_for :email_preferences do |type|
|
||||
#email_prefs
|
||||
- if current_user.admin?
|
||||
%p.checkbox_select
|
||||
= type.label :someone_reported, t('.someone_reported')
|
||||
= type.check_box :someone_reported, {:checked => @email_prefs['someone_reported']}, false, true
|
||||
|
||||
%br
|
||||
%p.checkbox_select
|
||||
= type.label :started_sharing, t('.started_sharing')
|
||||
= type.check_box :started_sharing, {:checked => @email_prefs['started_sharing']}, false, true
|
||||
%br
|
||||
|
||||
%p.checkbox_select
|
||||
= type.label :also_commented, t('.also_commented')
|
||||
= type.check_box :also_commented, {:checked => @email_prefs['also_commented']}, false, true
|
||||
%br
|
||||
|
||||
%p.checkbox_select
|
||||
= type.label :mentioned, t('.mentioned')
|
||||
= type.check_box :mentioned, {:checked => @email_prefs['mentioned']}, false, true
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
module Workers
|
||||
module Mail
|
||||
class PostReportWorker < Base
|
||||
sidekiq_options queue: :mail
|
||||
|
||||
def perform
|
||||
PostReportMailer.new_report
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
12
app/workers/mail/report_worker.rb
Normal file
12
app/workers/mail/report_worker.rb
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
module Workers
|
||||
module Mail
|
||||
class ReportWorker < Base
|
||||
sidekiq_options queue: :mail
|
||||
|
||||
def perform(type, id)
|
||||
ReportMailer.new_report(type, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ en:
|
|||
user_search: "User Search"
|
||||
weekly_user_stats: "Weekly User Stats"
|
||||
pod_stats: "Pod Stats"
|
||||
post_report: "Reported Posts"
|
||||
report: "Reports"
|
||||
correlations: "Correlations"
|
||||
sidekiq_monitor: "Sidekiq monitor"
|
||||
correlations:
|
||||
|
|
@ -736,9 +736,26 @@ en:
|
|||
confirm_email:
|
||||
subject: "Please activate your new email address %{unconfirmed_email}"
|
||||
click_link: "To activate your new email address %{unconfirmed_email}, please follow this link:"
|
||||
post_report_email:
|
||||
subject: "A new post was marked as offensive"
|
||||
body: "Please review as soon as possible!"
|
||||
report_email:
|
||||
type:
|
||||
post: "post"
|
||||
comment: "comment"
|
||||
subject: "A new %{type} was marked as offensive"
|
||||
body: |-
|
||||
Hello,
|
||||
|
||||
the %{type} with ID %{id} was marked as offensive.
|
||||
|
||||
[%{url}][1]
|
||||
|
||||
Please review as soon as possible!
|
||||
|
||||
|
||||
Cheers,
|
||||
|
||||
The diaspora* email robot!
|
||||
|
||||
[1]: %{url}
|
||||
accept_invite: "Accept Your diaspora* invite!"
|
||||
invited_you: "%{name} invited you to diaspora*"
|
||||
invite:
|
||||
|
|
@ -868,13 +885,15 @@ en:
|
|||
other: "%{count} photos by %{author}"
|
||||
reshare_by: "Reshare by %{author}"
|
||||
|
||||
post_report:
|
||||
title: "Marked Reports Overview"
|
||||
report:
|
||||
title: "Reports Overview"
|
||||
post_label: "<b>Post</b>: %{title}"
|
||||
comment_label: "<b>Comment</b>:<br>%{data}"
|
||||
reported_label: "<b>Reported by</b> %{person}"
|
||||
reason_label: "Reason: %{text}"
|
||||
review_link: "Mark as reviewed"
|
||||
delete_link: "Delete post"
|
||||
delete_link: "Delete item"
|
||||
confirm_deletion: "Are you sure to delete the item?"
|
||||
status:
|
||||
marked: "The report was marked as reviewed"
|
||||
destroyed: "The post was destroyed"
|
||||
|
|
@ -1206,6 +1225,7 @@ en:
|
|||
edit_account: "Edit account"
|
||||
receive_email_notifications: "Receive email notifications when:"
|
||||
started_sharing: "someone starts sharing with you"
|
||||
someone_reported: "someone sent a report"
|
||||
mentioned: "you are mentioned in a post"
|
||||
liked: "someone likes your post"
|
||||
reshared: "someone reshares your post"
|
||||
|
|
|
|||
|
|
@ -6,11 +6,15 @@
|
|||
en:
|
||||
javascripts:
|
||||
confirm_dialog: "Are you sure?"
|
||||
post_report_prompt: "Please enter a reason:"
|
||||
post_report_prompt_default: "offensive content"
|
||||
delete: "Delete"
|
||||
ignore: "Ignore"
|
||||
post_report: "Report"
|
||||
report:
|
||||
prompt: "Please enter a reason:"
|
||||
prompt_default: "offensive content"
|
||||
name: "Report"
|
||||
status:
|
||||
created: "The report was successfully created"
|
||||
exists: "The report already exists"
|
||||
ignore_user: "Ignore this user?"
|
||||
and: "and"
|
||||
comma: ","
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
require 'sidekiq/web'
|
||||
|
||||
Diaspora::Application.routes.draw do
|
||||
resources :post_report, :except => [:edit]
|
||||
resources :report, :except => [:edit, :new]
|
||||
|
||||
if Rails.env.production?
|
||||
mount RailsAdmin::Engine => '/admin_panel', :as => 'rails_admin'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
class AddPostTypeToPostReport < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :post_reports, :post_type, :string, :null => false, :after => :post_id, :default => 'post'
|
||||
change_column_default :post_reports, :post_type, nil
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
class RenamePostReportToReport < ActiveRecord::Migration
|
||||
def self.up
|
||||
rename_table :post_reports, :reports
|
||||
end
|
||||
def self.down
|
||||
rename_table :reports, :post_reports
|
||||
end
|
||||
end
|
||||
11
db/migrate/20140422134050_rename_post_columns_to_item.rb
Normal file
11
db/migrate/20140422134050_rename_post_columns_to_item.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
class RenamePostColumnsToItem < ActiveRecord::Migration
|
||||
def up
|
||||
rename_column :reports, :post_id, :item_id
|
||||
rename_column :reports, :post_type, :item_type
|
||||
end
|
||||
|
||||
def down
|
||||
rename_column :reports, :item_id, :post_id
|
||||
rename_column :reports, :item_type, :post_type
|
||||
end
|
||||
end
|
||||
12
db/migrate/20140422134627_change_user_id_type_to_integer.rb
Normal file
12
db/migrate/20140422134627_change_user_id_type_to_integer.rb
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
class ChangeUserIdTypeToInteger < ActiveRecord::Migration
|
||||
def up
|
||||
remove_column :reports, :user_id
|
||||
add_column :reports, :user_id, :integer, :null => false, :default => 1
|
||||
change_column_default :reports, :user_id, nil
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :reports, :user_id
|
||||
add_column :reports, :user_id, :string
|
||||
end
|
||||
end
|
||||
25
db/schema.rb
25
db/schema.rb
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20140308154022) do
|
||||
ActiveRecord::Schema.define(:version => 20140422134627) do
|
||||
|
||||
create_table "account_deletions", :force => true do |t|
|
||||
t.string "diaspora_handle"
|
||||
|
|
@ -316,17 +316,6 @@ ActiveRecord::Schema.define(:version => 20140308154022) do
|
|||
|
||||
add_index "polls", ["status_message_id"], :name => "index_polls_on_status_message_id"
|
||||
|
||||
create_table "post_reports", :force => true do |t|
|
||||
t.integer "post_id", :null => false
|
||||
t.string "user_id"
|
||||
t.boolean "reviewed", :default => false
|
||||
t.text "text"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
add_index "post_reports", ["post_id"], :name => "index_post_reports_on_post_id"
|
||||
|
||||
create_table "posts", :force => true do |t|
|
||||
t.integer "author_id", :null => false
|
||||
t.boolean "public", :default => false, :null => false
|
||||
|
|
@ -410,6 +399,18 @@ ActiveRecord::Schema.define(:version => 20140308154022) do
|
|||
|
||||
add_index "rails_admin_histories", ["item", "table", "month", "year"], :name => "index_rails_admin_histories"
|
||||
|
||||
create_table "reports", :force => true do |t|
|
||||
t.integer "item_id", :null => false
|
||||
t.string "item_type", :null => false
|
||||
t.boolean "reviewed", :default => false
|
||||
t.text "text"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.integer "user_id", :null => false
|
||||
end
|
||||
|
||||
add_index "reports", ["item_id"], :name => "index_post_reports_on_post_id"
|
||||
|
||||
create_table "roles", :force => true do |t|
|
||||
t.integer "person_id"
|
||||
t.string "name"
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class AccountDeleter
|
|||
end
|
||||
|
||||
def ignored_ar_user_associations
|
||||
[:followed_tags, :invited_by, :contact_people, :aspect_memberships, :ignored_people, :conversation_visibilities, :conversations]
|
||||
[:followed_tags, :invited_by, :contact_people, :aspect_memberships, :ignored_people, :conversation_visibilities, :conversations, :reports]
|
||||
end
|
||||
|
||||
def delete_standard_user_associations
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe PostReportController do
|
||||
before do
|
||||
sign_in alice
|
||||
@message = alice.post(:status_message, :text => "hey", :to => alice.aspects.first.id)
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
context 'admin not signed in' do
|
||||
it 'is behind redirect_unless_admin' do
|
||||
get :index
|
||||
response.should redirect_to stream_path
|
||||
end
|
||||
end
|
||||
|
||||
context 'admin signed in' do
|
||||
before do
|
||||
Role.add_admin(alice.person)
|
||||
end
|
||||
it 'succeeds and renders index' do
|
||||
get :index
|
||||
response.should render_template('index')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
context 'report offensive content' do
|
||||
it 'succeeds' do
|
||||
put :create, :post_id => @message.id, :text => 'offensive content'
|
||||
response.status.should == 200
|
||||
PostReport.exists?(:post_id => @message.id).should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
context 'mark report as user' do
|
||||
it 'is behind redirect_unless_admin' do
|
||||
put :update, :id => @message.id
|
||||
response.should redirect_to stream_path
|
||||
PostReport.where(:reviewed => false, :post_id => @message.id).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context 'mark report as admin' do
|
||||
before do
|
||||
Role.add_admin(alice.person)
|
||||
end
|
||||
it 'succeeds' do
|
||||
put :update, :id => @message.id
|
||||
response.status.should == 302
|
||||
PostReport.where(:reviewed => true, :post_id => @message.id).should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#destroy' do
|
||||
context 'destroy post as user' do
|
||||
it 'is behind redirect_unless_admin' do
|
||||
delete :destroy, :id => @message.id
|
||||
response.should redirect_to stream_path
|
||||
PostReport.where(:reviewed => false, :post_id => @message.id).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context 'destroy post as admin' do
|
||||
before do
|
||||
Role.add_admin(alice.person)
|
||||
end
|
||||
it 'succeeds' do
|
||||
delete :destroy, :id => @message.id
|
||||
response.status.should == 302
|
||||
PostReport.where(:reviewed => true, :post_id => @message.id).should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
130
spec/controllers/report_controller_spec.rb
Normal file
130
spec/controllers/report_controller_spec.rb
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe ReportController do
|
||||
before do
|
||||
sign_in alice
|
||||
@message = alice.post(:status_message, :text => "hey", :to => alice.aspects.first.id)
|
||||
@comment = alice.comment!(@message, "flying pigs, everywhere")
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
context 'admin not signed in' do
|
||||
it 'is behind redirect_unless_admin' do
|
||||
get :index
|
||||
response.should redirect_to stream_path
|
||||
end
|
||||
end
|
||||
|
||||
context 'admin signed in' do
|
||||
before do
|
||||
Role.add_admin(alice.person)
|
||||
end
|
||||
it 'succeeds and renders index' do
|
||||
get :index
|
||||
response.should render_template('index')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
let(:comment_hash) {
|
||||
{:text =>"facebook, is that you?",
|
||||
:item_id =>"#{@post.id}"}
|
||||
}
|
||||
|
||||
context 'report offensive post' do
|
||||
it 'succeeds' do
|
||||
put :create, :report => { :item_id => @message.id, :item_type => 'post', :text => 'offensive content' }
|
||||
response.status.should == 200
|
||||
Report.exists?(:item_id => @message.id, :item_type => 'post').should be_true
|
||||
end
|
||||
end
|
||||
context 'report offensive comment' do
|
||||
it 'succeeds' do
|
||||
put :create, :report => { :item_id => @comment.id, :item_type => 'comment', :text => 'offensive content' }
|
||||
response.status.should == 200
|
||||
Report.exists?(:item_id => @comment.id, :item_type => 'comment').should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
context 'mark post report as user' do
|
||||
it 'is behind redirect_unless_admin' do
|
||||
put :update, :id => @message.id, :type => 'post'
|
||||
response.should redirect_to stream_path
|
||||
Report.where(:reviewed => false, :item_id => @message.id, :item_type => 'post').should be_true
|
||||
end
|
||||
end
|
||||
context 'mark comment report as user' do
|
||||
it 'is behind redirect_unless_admin' do
|
||||
put :update, :id => @comment.id, :type => 'comment'
|
||||
response.should redirect_to stream_path
|
||||
Report.where(:reviewed => false, :item_id => @comment.id, :item_type => 'comment').should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context 'mark post report as admin' do
|
||||
before do
|
||||
Role.add_admin(alice.person)
|
||||
end
|
||||
it 'succeeds' do
|
||||
put :update, :id => @message.id, :type => 'post'
|
||||
response.status.should == 302
|
||||
Report.where(:reviewed => true, :item_id => @message.id, :item_type => 'post').should be_true
|
||||
end
|
||||
end
|
||||
context 'mark comment report as admin' do
|
||||
before do
|
||||
Role.add_admin(alice.person)
|
||||
end
|
||||
it 'succeeds' do
|
||||
put :update, :id => @comment.id, :type => 'comment'
|
||||
response.status.should == 302
|
||||
Report.where(:reviewed => true, :item_id => @comment.id, :item_type => 'comment').should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#destroy' do
|
||||
context 'destroy post as user' do
|
||||
it 'is behind redirect_unless_admin' do
|
||||
delete :destroy, :id => @message.id, :type => 'post'
|
||||
response.should redirect_to stream_path
|
||||
Report.where(:reviewed => false, :item_id => @message.id, :item_type => 'post').should be_true
|
||||
end
|
||||
end
|
||||
context 'destroy comment as user' do
|
||||
it 'is behind redirect_unless_admin' do
|
||||
delete :destroy, :id => @comment.id, :type => 'comment'
|
||||
response.should redirect_to stream_path
|
||||
Report.where(:reviewed => false, :item_id => @comment.id, :item_type => 'comment').should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context 'destroy post as admin' do
|
||||
before do
|
||||
Role.add_admin(alice.person)
|
||||
end
|
||||
it 'succeeds' do
|
||||
delete :destroy, :id => @message.id, :type => 'post'
|
||||
response.status.should == 302
|
||||
Report.where(:reviewed => true, :item_id => @message.id, :item_type => 'post').should be_true
|
||||
end
|
||||
end
|
||||
context 'destroy comment as admin' do
|
||||
before do
|
||||
Role.add_admin(alice.person)
|
||||
end
|
||||
it 'succeeds' do
|
||||
delete :destroy, :id => @comment.id, :type => 'comment'
|
||||
response.status.should == 302
|
||||
Report.where(:reviewed => true, :item_id => @comment.id, :item_type => 'comment').should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
26
spec/mailers/report_spec.rb
Normal file
26
spec/mailers/report_spec.rb
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Report do
|
||||
describe '#make_notification' do
|
||||
before do
|
||||
@user = bob
|
||||
Role.add_admin(@user)
|
||||
end
|
||||
|
||||
it "should deliver successfully" do
|
||||
expect {
|
||||
ReportMailer.new_report('post', 666)
|
||||
}.to_not raise_error
|
||||
end
|
||||
|
||||
it "should be added to the delivery queue" do
|
||||
expect {
|
||||
ReportMailer.new_report('post', 666)
|
||||
}.to change(ActionMailer::Base.deliveries, :size).by(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
79
spec/models/report_spec.rb
Normal file
79
spec/models/report_spec.rb
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Report do
|
||||
before do
|
||||
#:report => { :item_id => @message.id, :item_type => 'post', :text => 'offensive content' }
|
||||
@user = bob
|
||||
@bob_post = @user.post(:status_message, :text => "hello", :to => @user.aspects.first.id)
|
||||
@bob_comment = @user.comment!(@bob_post, "welcome")
|
||||
|
||||
@valid_post_report = {
|
||||
:item_id => @bob_post.id,
|
||||
:item_type => 'post',
|
||||
:text => 'offensive content'
|
||||
}
|
||||
@valid_comment_report = {
|
||||
:item_id => @bob_comment.id,
|
||||
:item_type => 'comment',
|
||||
:text => 'offensive content'
|
||||
}
|
||||
end
|
||||
|
||||
describe '#validation' do
|
||||
it 'validates that post ID is required' do
|
||||
@user.reports.build(:item_type => 'post', :text => 'blub').should_not be_valid
|
||||
end
|
||||
|
||||
it 'validates that post type is required' do
|
||||
@user.reports.build(:item_id => 666, :text => 'blub').should_not be_valid
|
||||
end
|
||||
|
||||
it 'validates that entry does not exist' do
|
||||
@user.reports.build(@valid_post_report).should be_valid
|
||||
end
|
||||
|
||||
it 'validates that entry does exist' do
|
||||
@user.reports.create(@valid_post_report)
|
||||
@user.reports.build(@valid_post_report).should_not be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe '#destroy_reported_item' do
|
||||
before(:each) do
|
||||
@post_report = @user.reports.create(@valid_post_report)
|
||||
@comment_report = @user.reports.create(@valid_comment_report)
|
||||
end
|
||||
|
||||
describe '.post' do
|
||||
it 'should destroy it' do
|
||||
expect {
|
||||
@post_report.destroy_reported_item
|
||||
}.to change { Post.count }.by(-1)
|
||||
end
|
||||
|
||||
it 'should be marked' do
|
||||
expect {
|
||||
@post_report.destroy_reported_item
|
||||
}.to change { Report.where(@valid_post_report).first.reviewed }.to(true).from(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.comment' do
|
||||
it 'should destroy it' do
|
||||
expect {
|
||||
@comment_report.destroy_reported_item
|
||||
}.to change { Comment.count }.by(-1)
|
||||
end
|
||||
|
||||
it 'should be marked' do
|
||||
expect {
|
||||
@comment_report.destroy_reported_item
|
||||
}.to change { Report.where(@valid_comment_report).first.reviewed }.to(true).from(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue