Merge remote-tracking branch 'upstream/pull/1576'
This commit is contained in:
commit
7441f15b4f
40 changed files with 1887 additions and 5 deletions
|
@ -67,7 +67,7 @@ Metrics/AbcSize:
|
|||
# Offense count: 41
|
||||
# Configuration parameters: CountComments, ExcludedMethods.
|
||||
Metrics/BlockLength:
|
||||
Max: 247
|
||||
Max: 257
|
||||
|
||||
# Offense count: 12
|
||||
# Configuration parameters: CountBlocks.
|
||||
|
|
3
Gemfile
3
Gemfile
|
@ -73,6 +73,9 @@ gem "omniauth-windowslive"
|
|||
# Markdown formatting support
|
||||
gem "redcarpet"
|
||||
|
||||
# For status transitions of Issues
|
||||
gem "aasm"
|
||||
|
||||
# Load libxml support for XML parsing and generation
|
||||
gem "libxml-ruby", ">= 2.0.5", :require => "libxml"
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ GEM
|
|||
remote: https://rubygems.org/
|
||||
specs:
|
||||
SystemTimer (1.2.3)
|
||||
aasm (4.1.0)
|
||||
actioncable (5.1.5)
|
||||
actionpack (= 5.1.5)
|
||||
nio4r (~> 2.0)
|
||||
|
@ -361,6 +362,7 @@ PLATFORMS
|
|||
|
||||
DEPENDENCIES
|
||||
SystemTimer (>= 1.1.3)
|
||||
aasm
|
||||
actionpack-page_caching
|
||||
annotate
|
||||
autoprefixer-rails
|
||||
|
|
|
@ -2820,3 +2820,59 @@ input.richtext_title[type="text"] {
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.read-reports {
|
||||
background: #eee;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.report-related-block {
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.report-block {
|
||||
width:475px;
|
||||
float:left;
|
||||
margin-right:100px;
|
||||
}
|
||||
|
||||
.related-reports {
|
||||
width: 280px;
|
||||
float: right;
|
||||
|
||||
ul {
|
||||
padding-left: $lineheight;
|
||||
margin-bottom: 0;
|
||||
|
||||
li {
|
||||
list-style: disc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.issue-comments {
|
||||
width:475px;
|
||||
}
|
||||
|
||||
.issues-list {
|
||||
td:nth-child(2) {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.report-disclaimer {
|
||||
background: #fff1f0;
|
||||
color: #d85030;
|
||||
border-color: rgba(216, 80, 48, 0.3);
|
||||
padding: 10px 20px;
|
||||
margin-bottom: $lineheight;
|
||||
|
||||
ul {
|
||||
padding-left: $lineheight;
|
||||
margin-bottom: 0;
|
||||
|
||||
li {
|
||||
list-style: disc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
37
app/controllers/issue_comments_controller.rb
Normal file
37
app/controllers/issue_comments_controller.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
class IssueCommentsController < ApplicationController
|
||||
layout "site"
|
||||
|
||||
before_action :authorize_web
|
||||
before_action :require_user
|
||||
before_action :check_permission
|
||||
|
||||
def create
|
||||
@issue = Issue.find(params[:issue_id])
|
||||
comment = @issue.comments.build(issue_comment_params)
|
||||
comment.user = current_user
|
||||
comment.save!
|
||||
notice = t(".comment_created")
|
||||
reassign_issue(@issue) if params[:reassign]
|
||||
redirect_to @issue, :notice => notice
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def issue_comment_params
|
||||
params.require(:issue_comment).permit(:body)
|
||||
end
|
||||
|
||||
def check_permission
|
||||
unless current_user.administrator? || current_user.moderator?
|
||||
flash[:error] = t("application.require_moderator_or_admin.not_a_moderator_or_admin")
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
|
||||
# This sort of assumes there are only two roles
|
||||
def reassign_issue(issue)
|
||||
role = (Issue::ASSIGNED_ROLES - [issue.assigned_role]).first
|
||||
issue.assigned_role = role
|
||||
issue.save!
|
||||
end
|
||||
end
|
90
app/controllers/issues_controller.rb
Normal file
90
app/controllers/issues_controller.rb
Normal file
|
@ -0,0 +1,90 @@
|
|||
class IssuesController < ApplicationController
|
||||
layout "site"
|
||||
|
||||
before_action :authorize_web
|
||||
before_action :require_user
|
||||
before_action :check_permission
|
||||
before_action :find_issue, :only => [:show, :resolve, :reopen, :ignore]
|
||||
|
||||
def index
|
||||
@title = t ".title"
|
||||
|
||||
@issue_types = []
|
||||
@issue_types.concat %w[Note] if current_user.moderator?
|
||||
@issue_types.concat %w[DiaryEntry DiaryComment User] if current_user.administrator?
|
||||
|
||||
@users = User.joins(:roles).where(:user_roles => { :role => current_user.roles.map(&:role) }).distinct
|
||||
@issues = Issue.where(:assigned_role => current_user.roles.map(&:role))
|
||||
|
||||
# If search
|
||||
if params[:search_by_user] && params[:search_by_user].present?
|
||||
@find_user = User.find_by(:display_name => params[:search_by_user])
|
||||
if @find_user
|
||||
@issues = @issues.where(:reported_user_id => @find_user.id)
|
||||
else
|
||||
@issues = @issues.none
|
||||
flash.now[:warning] = t(".user_not_found")
|
||||
end
|
||||
end
|
||||
|
||||
@issues = @issues.where(:status => params[:status]) if params[:status] && params[:status].present?
|
||||
|
||||
@issues = @issues.where(:reportable_type => params[:issue_type]) if params[:issue_type] && params[:issue_type].present?
|
||||
|
||||
if params[:last_updated_by] && params[:last_updated_by].present?
|
||||
last_updated_by = params[:last_updated_by].to_s == "nil" ? nil : params[:last_updated_by].to_i
|
||||
@issues = @issues.where(:updated_by => last_updated_by)
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@read_reports = @issue.read_reports
|
||||
@unread_reports = @issue.unread_reports
|
||||
@comments = @issue.comments
|
||||
@related_issues = @issue.reported_user.issues.where(:assigned_role => current_user.roles.map(&:role)) if @issue.reported_user
|
||||
@new_comment = IssueComment.new(:issue => @issue)
|
||||
end
|
||||
|
||||
# Status Transistions
|
||||
def resolve
|
||||
if @issue.resolve
|
||||
@issue.save!
|
||||
redirect_to @issue, :notice => t(".resolved")
|
||||
else
|
||||
render :show
|
||||
end
|
||||
end
|
||||
|
||||
def ignore
|
||||
if @issue.ignore
|
||||
@issue.updated_by = current_user.id
|
||||
@issue.save!
|
||||
redirect_to @issue, :notice => t(".ignored")
|
||||
else
|
||||
render :show
|
||||
end
|
||||
end
|
||||
|
||||
def reopen
|
||||
if @issue.reopen
|
||||
@issue.updated_by = current_user.id
|
||||
@issue.save!
|
||||
redirect_to @issue, :notice => t(".reopened")
|
||||
else
|
||||
render :show
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_issue
|
||||
@issue = Issue.find(params[:id])
|
||||
end
|
||||
|
||||
def check_permission
|
||||
unless current_user.administrator? || current_user.moderator?
|
||||
flash[:error] = t("application.require_moderator_or_admin.not_a_moderator_or_admin")
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
end
|
42
app/controllers/reports_controller.rb
Normal file
42
app/controllers/reports_controller.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
class ReportsController < ApplicationController
|
||||
layout "site"
|
||||
|
||||
before_action :authorize_web
|
||||
before_action :require_user
|
||||
|
||||
def new
|
||||
if required_new_report_params_present?
|
||||
@report = Report.new
|
||||
@report.issue = Issue.find_or_initialize_by(create_new_report_params)
|
||||
else
|
||||
redirect_to root_path, :notice => t(".missing_params")
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@report = current_user.reports.new(report_params)
|
||||
@report.issue = Issue.find_or_initialize_by(:reportable_id => params[:report][:issue][:reportable_id], :reportable_type => params[:report][:issue][:reportable_type])
|
||||
|
||||
if @report.save
|
||||
@report.issue.save
|
||||
@report.issue.reopen! unless @report.issue.open?
|
||||
redirect_to helpers.reportable_url(@report.issue.reportable), :notice => t(".successful_report")
|
||||
else
|
||||
redirect_to new_report_path(:reportable_type => @report.issue.reportable_type, :reportable_id => @report.issue.reportable_id), :notice => t(".provide_details")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def required_new_report_params_present?
|
||||
create_new_report_params["reportable_id"].present? && create_new_report_params["reportable_type"].present?
|
||||
end
|
||||
|
||||
def create_new_report_params
|
||||
params.permit(:reportable_id, :reportable_type)
|
||||
end
|
||||
|
||||
def report_params
|
||||
params[:report].permit(:details, :category)
|
||||
end
|
||||
end
|
27
app/helpers/issues_helper.rb
Normal file
27
app/helpers/issues_helper.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
module IssuesHelper
|
||||
def reportable_url(reportable)
|
||||
case reportable
|
||||
when DiaryEntry
|
||||
url_for(:controller => reportable.class.name.underscore, :action => :view, :display_name => reportable.user.display_name, :id => reportable.id)
|
||||
when User
|
||||
url_for(:controller => reportable.class.name.underscore, :action => :view, :display_name => reportable.display_name)
|
||||
when DiaryComment
|
||||
url_for(:controller => reportable.diary_entry.class.name.underscore, :action => :view, :display_name => reportable.diary_entry.user.display_name, :id => reportable.diary_entry.id, :anchor => "comment#{reportable.id}")
|
||||
when Note
|
||||
url_for(:controller => :browse, :action => :note, :id => reportable.id)
|
||||
end
|
||||
end
|
||||
|
||||
def reportable_title(reportable)
|
||||
case reportable
|
||||
when DiaryEntry
|
||||
reportable.title
|
||||
when User
|
||||
reportable.display_name
|
||||
when DiaryComment
|
||||
I18n.t("issues.helper.reportable_title.diary_comment", :entry_title => reportable.diary_entry.title, :comment_id => reportable.id)
|
||||
when Note
|
||||
I18n.t("issues.helper.reportable_title.note", :note_id => reportable.id)
|
||||
end
|
||||
end
|
||||
end
|
5
app/helpers/reports_helper.rb
Normal file
5
app/helpers/reports_helper.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
module ReportsHelper
|
||||
def report_link(name, reportable)
|
||||
link_to name, new_report_url(:reportable_id => reportable.id, :reportable_type => reportable.class.name)
|
||||
end
|
||||
end
|
104
app/models/issue.rb
Normal file
104
app/models/issue.rb
Normal file
|
@ -0,0 +1,104 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: issues
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# reportable_type :string not null
|
||||
# reportable_id :integer not null
|
||||
# reported_user_id :integer
|
||||
# status :enum default("open"), not null
|
||||
# assigned_role :enum not null
|
||||
# resolved_at :datetime
|
||||
# resolved_by :integer
|
||||
# updated_by :integer
|
||||
# reports_count :integer default(0)
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_issues_on_assigned_role (assigned_role)
|
||||
# index_issues_on_reportable_type_and_reportable_id (reportable_type,reportable_id)
|
||||
# index_issues_on_reported_user_id (reported_user_id)
|
||||
# index_issues_on_status (status)
|
||||
# index_issues_on_updated_by (updated_by)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# issues_reported_user_id_fkey (reported_user_id => users.id)
|
||||
# issues_resolved_by_fkey (resolved_by => users.id)
|
||||
# issues_updated_by_fkey (updated_by => users.id)
|
||||
#
|
||||
|
||||
class Issue < ActiveRecord::Base
|
||||
belongs_to :reportable, :polymorphic => true
|
||||
belongs_to :reported_user, :class_name => "User", :foreign_key => :reported_user_id
|
||||
belongs_to :user_resolved, :class_name => "User", :foreign_key => :resolved_by
|
||||
belongs_to :user_updated, :class_name => "User", :foreign_key => :updated_by
|
||||
|
||||
has_many :reports, :dependent => :destroy
|
||||
has_many :comments, :class_name => "IssueComment", :dependent => :destroy
|
||||
|
||||
validates :reportable_id, :uniqueness => { :scope => [:reportable_type] }
|
||||
|
||||
ASSIGNED_ROLES = %w[administrator moderator].freeze
|
||||
validates :assigned_role, :presence => true, :inclusion => ASSIGNED_ROLES
|
||||
|
||||
before_validation :set_default_assigned_role
|
||||
before_validation :set_reported_user
|
||||
|
||||
scope :with_status, ->(issue_status) { where(:status => statuses[issue_status]) }
|
||||
|
||||
def read_reports
|
||||
resolved_at.present? ? reports.where("updated_at < ?", resolved_at) : nil
|
||||
end
|
||||
|
||||
def unread_reports
|
||||
resolved_at.present? ? reports.where("updated_at >= ?", resolved_at) : reports
|
||||
end
|
||||
|
||||
include AASM
|
||||
aasm :column => :status, :no_direct_assignment => true do
|
||||
state :open, :initial => true
|
||||
state :ignored
|
||||
state :resolved
|
||||
|
||||
event :ignore do
|
||||
transitions :from => :open, :to => :ignored
|
||||
end
|
||||
|
||||
event :resolve do
|
||||
transitions :from => :open, :to => :resolved
|
||||
after do
|
||||
self.resolved_at = Time.now.getutc
|
||||
end
|
||||
end
|
||||
|
||||
event :reopen do
|
||||
transitions :from => :resolved, :to => :open
|
||||
transitions :from => :ignored, :to => :open
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_reported_user
|
||||
self.reported_user = case reportable.class.name
|
||||
when "User"
|
||||
reportable
|
||||
when "Note"
|
||||
reportable.author
|
||||
else
|
||||
reportable.user
|
||||
end
|
||||
end
|
||||
|
||||
def set_default_assigned_role
|
||||
if assigned_role.blank?
|
||||
self.assigned_role = case reportable
|
||||
when Note then "moderator"
|
||||
else "administrator"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
30
app/models/issue_comment.rb
Normal file
30
app/models/issue_comment.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: issue_comments
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# issue_id :integer not null
|
||||
# user_id :integer not null
|
||||
# body :text not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_issue_comments_on_issue_id (issue_id)
|
||||
# index_issue_comments_on_user_id (user_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# issue_comments_issue_id_fkey (issue_id => issues.id)
|
||||
# issue_comments_user_id_fkey (user_id => users.id)
|
||||
#
|
||||
|
||||
class IssueComment < ActiveRecord::Base
|
||||
belongs_to :issue
|
||||
belongs_to :user
|
||||
|
||||
validates :body, :presence => true
|
||||
validates :user, :presence => true
|
||||
validates :issue, :presence => true
|
||||
end
|
42
app/models/report.rb
Normal file
42
app/models/report.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: reports
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# issue_id :integer not null
|
||||
# user_id :integer not null
|
||||
# details :text not null
|
||||
# category :string not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_reports_on_issue_id (issue_id)
|
||||
# index_reports_on_user_id (user_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# reports_issue_id_fkey (issue_id => issues.id)
|
||||
# reports_user_id_fkey (user_id => users.id)
|
||||
#
|
||||
|
||||
class Report < ActiveRecord::Base
|
||||
belongs_to :issue, :counter_cache => true
|
||||
belongs_to :user
|
||||
|
||||
validates :issue, :presence => true
|
||||
validates :user, :presence => true
|
||||
validates :details, :presence => true
|
||||
validates :category, :presence => true
|
||||
|
||||
def self.categories_for(reportable)
|
||||
case reportable.class.name
|
||||
when "DiaryEntry" then %w[spam offensive threat other]
|
||||
when "DiaryComment" then %w[spam offensive threat other]
|
||||
when "User" then %w[spam offensive threat vandal other]
|
||||
when "Note" then %w[spam personal abusive other]
|
||||
else %w[other]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -75,6 +75,11 @@ class User < ActiveRecord::Base
|
|||
|
||||
has_many :roles, :class_name => "UserRole"
|
||||
|
||||
has_many :issues, :class_name => "Issue", :foreign_key => :reported_user_id
|
||||
has_many :issue_comments
|
||||
|
||||
has_many :reports
|
||||
|
||||
scope :visible, -> { where(:status => %w[pending active confirmed]) }
|
||||
scope :active, -> { where(:status => %w[active confirmed]) }
|
||||
scope :identifiable, -> { where(:data_public => true) }
|
||||
|
|
|
@ -23,6 +23,10 @@
|
|||
<p class='warning'><%= t "javascripts.notes.show.anonymous_warning" %></p>
|
||||
<% end -%>
|
||||
|
||||
<% if current_user && current_user != @note.author %>
|
||||
<p class="deemphasize"><%= report_link(t(".report"), @note) %></p>
|
||||
<% end %>
|
||||
|
||||
<% if @note_comments.length > 1 %>
|
||||
<div class='note-comments'>
|
||||
<ul>
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
<div class="clearfix diary-comment">
|
||||
<%= user_thumbnail diary_comment.user %>
|
||||
<p class="deemphasize comment-heading" id="comment<%= diary_comment.id %>"><%= raw(t('.comment_from', :link_user => (link_to h(diary_comment.user.display_name), user_path(diary_comment.user)), :comment_created_at => link_to(l(diary_comment.created_at, :format => :friendly), :anchor => "comment#{diary_comment.id}"))) %></p>
|
||||
<p class="deemphasize comment-heading" id="comment<%= diary_comment.id %>"><%= raw(t('.comment_from', :link_user => (link_to h(diary_comment.user.display_name), user_path(diary_comment.user)), :comment_created_at => link_to(l(diary_comment.created_at, :format => :friendly), :anchor => "comment#{diary_comment.id}"))) %>
|
||||
<% if current_user and diary_comment.user.id != current_user.id %>
|
||||
| <%= report_link(t(".report"), diary_comment) %>
|
||||
<% end %>
|
||||
</p>
|
||||
|
||||
<div class="richtext"><%= diary_comment.body.to_html %></div>
|
||||
<% if current_user && current_user.administrator? %>
|
||||
<span>
|
||||
|
|
|
@ -31,8 +31,16 @@
|
|||
<li><%= link_to t('.edit_link'), :action => 'edit', :display_name => diary_entry.user.display_name, :id => diary_entry.id %></li>
|
||||
<% end %>
|
||||
|
||||
<% if current_user and diary_entry.user != current_user %>
|
||||
<li>
|
||||
<%= report_link(t(".report"), diary_entry) %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if current_user && current_user.administrator? %>
|
||||
<li><%= link_to t('.hide_link'), hide_diary_entry_path(:display_name => diary_entry.user.display_name, :id => diary_entry.id), :method => :post, :data => { :confirm => t('.confirm') } %></li>
|
||||
<li>
|
||||
<%= link_to t('.hide_link'), hide_diary_entry_path(:display_name => diary_entry.user.display_name, :id => diary_entry.id), :method => :post, :data => { :confirm => t('.confirm') } %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
25
app/views/issues/_comments.html.erb
Normal file
25
app/views/issues/_comments.html.erb
Normal file
|
@ -0,0 +1,25 @@
|
|||
<div class="issue-comments">
|
||||
<% comments.each do |comment| %>
|
||||
<div class="comment">
|
||||
<div style="float:left">
|
||||
<%= link_to user_thumbnail(comment.user), user_path(comment.user.display_name) %>
|
||||
</div>
|
||||
<b> <%= link_to comment.user.display_name, user_path(comment.user.display_name) %> </b> <br/>
|
||||
<%= comment.body %>
|
||||
</div>
|
||||
<span class="deemphasize">
|
||||
<%= t(".created_at", :datetime => l(comment.created_at.to_datetime, :format => :friendly)) %>
|
||||
</span>
|
||||
<hr>
|
||||
<% end %>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="comment">
|
||||
<%= form_for @new_comment, url: issue_comments_path(@issue) do |f| %>
|
||||
<%= richtext_area :issue_comment, :body, :cols => 10, :rows => 8, :required => true %>
|
||||
<%= label_tag :reassign, t('.reassign_param') %> <%= check_box_tag :reassign, true %>
|
||||
<br/>
|
||||
<br/>
|
||||
<%= submit_tag 'Submit' %>
|
||||
<% end %>
|
||||
</div>
|
16
app/views/issues/_reports.html.erb
Normal file
16
app/views/issues/_reports.html.erb
Normal file
|
@ -0,0 +1,16 @@
|
|||
<% reports.each do |report| %>
|
||||
<div class="report">
|
||||
<div style="float:left">
|
||||
<%= link_to user_thumbnail(report.user), user_path(report.user.display_name) %>
|
||||
</div>
|
||||
<%= t ".reported_by_html", :category => report.category, :user => link_to(report.user.display_name, user_path(report.user.display_name)) %>
|
||||
<br/>
|
||||
<span class="deemphasize">
|
||||
<%= t(".updated_at", :datetime => l(report.updated_at.to_datetime, :format => :friendly)) %>
|
||||
</span>
|
||||
<br/>
|
||||
<%= report.details %>
|
||||
<br/>
|
||||
</div>
|
||||
<hr>
|
||||
<% end %>
|
51
app/views/issues/index.html.erb
Normal file
51
app/views/issues/index.html.erb
Normal file
|
@ -0,0 +1,51 @@
|
|||
<% content_for :heading do %>
|
||||
<h1><%= t ".title" %></h1>
|
||||
<% end %>
|
||||
|
||||
<%= form_tag(issues_path, :method => :get) do %>
|
||||
<p><%= t ".search_guidance" %></p>
|
||||
<%= select_tag :status, options_for_select(Issue.aasm.states.map(&:name).map{|state| [t(".states.#{state}"), state]}, params[:status]), :include_blank => t(".select_status"), :data => { :behavior => 'category_dropdown' } %>
|
||||
<%= select_tag :issue_type, options_for_select(@issue_types, params[:issue_type]), :include_blank => t(".select_type"), :data => { :behavior => 'category_dropdown' } %>
|
||||
<%= text_field_tag :search_by_user, params[:search_by_user], placeholder: t(".reported_user") %>
|
||||
<%= select_tag :last_updated_by, options_for_select(@users.all.collect{|f| [f.display_name, f.id]} << [ t(".not_updated"), "nil"], params[:last_updated_by]), :include_blank => t(".select_last_updated_by"), :data => { :behavior => 'category_dropdown' } %>
|
||||
<%= submit_tag t(".search"), :name => nil %>
|
||||
<% end %>
|
||||
<br/>
|
||||
|
||||
<% if @issues.length == 0 %>
|
||||
<p><%= t ".issues_not_found" %></p>
|
||||
<% end %>
|
||||
|
||||
<br/>
|
||||
|
||||
<table class="issues-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t ".status" %></th>
|
||||
<th><%= t ".reports" %></th>
|
||||
<th><%= t ".reported_item" %></th>
|
||||
<th><%= t ".reported_user" %></th>
|
||||
<th><%= t ".last_updated" %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @issues.each do |issue| %>
|
||||
<tr>
|
||||
<td><%= t ".states.#{issue.status}" %></td>
|
||||
<td><%= link_to t(".reports_count", :count => issue.reports_count), issue %></td>
|
||||
<td><%= link_to reportable_title(issue.reportable), reportable_url(issue.reportable) %></td>
|
||||
<td><%= link_to issue.reported_user.display_name, user_path(issue.reported_user.display_name) if issue.reported_user %></td>
|
||||
<td>
|
||||
<% if issue.user_updated %>
|
||||
<%= t ".last_updated_time_user_html", :user => link_to(issue.user_updated.display_name, user_path(issue.user_updated.display_name)),
|
||||
:time => distance_of_time_in_words_to_now(issue.updated_at),
|
||||
:title => l(issue.updated_at) %>
|
||||
<% else %>
|
||||
<%= t ".last_updated_time_html", :time => distance_of_time_in_words_to_now(issue.updated_at),
|
||||
:title => l(issue.updated_at) %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
62
app/views/issues/show.html.erb
Normal file
62
app/views/issues/show.html.erb
Normal file
|
@ -0,0 +1,62 @@
|
|||
<% content_for :heading do %>
|
||||
<h2><%= t ".title", :status => @issue.status.humanize, :issue_id => @issue.id %></h2>
|
||||
<p><%= @issue.reportable.model_name.human %> : <%= link_to reportable_title(@issue.reportable), reportable_url(@issue.reportable) %></p>
|
||||
<p class="deemphasize">
|
||||
<small>
|
||||
<%= @issue.assigned_role %>
|
||||
| <%= t ".reports", :count => @issue.reports.count %>
|
||||
| <%= t ".report_created_at", :datetime => l(@issue.created_at.to_datetime, :format => :friendly) %>
|
||||
<%= " | " + t(".last_resolved_at", :datetime => l(@issue.resolved_at.to_datetime, :format =>:friendly)) if @issue.resolved_at? %>
|
||||
<%= " | " + t(".last_updated_at", :datetime => l(@issue.updated_at.to_datetime, :format => :friendly), :displayname => @issue.user_updated.display_name ) if @issue.user_updated %>
|
||||
</small>
|
||||
</p>
|
||||
<p>
|
||||
<%= link_to t('.resolve'), resolve_issue_url(@issue), :method => :post if @issue.may_resolve? %>
|
||||
<% if @issue.may_ignore? %>
|
||||
| <%= link_to t('.ignore'), ignore_issue_url(@issue), :method => :post %>
|
||||
<% end %>
|
||||
</p>
|
||||
<p><%= link_to t('.reopen'), reopen_issue_url(@issue), :method => :post if @issue.may_reopen? %></p>
|
||||
<% end %>
|
||||
|
||||
<div class="report-related-block">
|
||||
|
||||
<div class="report-block">
|
||||
<h3><%= t ".reports_of_this_issue" %></h3>
|
||||
|
||||
<% if @read_reports.present? %>
|
||||
<div class="read-reports">
|
||||
<h4><%= t ".read_reports" %></h4>
|
||||
<%= render 'reports', reports: @read_reports %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @unread_reports.any? %>
|
||||
<div class="unread-reports">
|
||||
<h4><%= t ".new_reports" %></h4>
|
||||
<%= render 'reports', reports: @unread_reports %>
|
||||
</div>
|
||||
<% end %>
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
<% if @issue.reported_user %>
|
||||
<div class="related-reports">
|
||||
<h3><%= t ".other_issues_against_this_user" %></h3>
|
||||
<% if @related_issues.count > 1 %>
|
||||
<ul>
|
||||
<% @related_issues.each do |issue| %>
|
||||
<% if issue.id != @issue.id %>
|
||||
<li><%= link_to reportable_title(issue.reportable), issue %></li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% else %>
|
||||
<p><%= t ".no_other_issues" %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<h3><%= t ".comments_on_this_issue" %></h3>
|
||||
<%= render 'comments', comments: @comments %>
|
|
@ -38,6 +38,9 @@
|
|||
</nav>
|
||||
<nav class='secondary'>
|
||||
<ul>
|
||||
<% if current_user and ( current_user.administrator? or current_user.moderator? ) %>
|
||||
<li class="compact-hide <%= current_page_class(issues_path) %>"><%= link_to t('layouts.issues'), issues_path(:status => 'open') %></li>
|
||||
<% end %>
|
||||
<li class="compact-hide <%= current_page_class(traces_path) %>"><%= link_to t('layouts.gps_traces'), traces_path %></li>
|
||||
<li class="compact-hide <%= current_page_class(diary_path) %>"><%= link_to t('layouts.user_diaries'), diary_path %></li>
|
||||
<li class="compact-hide <%= current_page_class(copyright_path) %>"><%= link_to t('layouts.copyright'), copyright_path %></li>
|
||||
|
|
42
app/views/reports/new.html.erb
Normal file
42
app/views/reports/new.html.erb
Normal file
|
@ -0,0 +1,42 @@
|
|||
<% content_for :heading do %>
|
||||
<h1><%= t ".title_html", :link => link_to(reportable_title(@report.issue.reportable), reportable_url(@report.issue.reportable)) %></h1>
|
||||
<% end %>
|
||||
|
||||
<div class="report-disclaimer">
|
||||
<%= t('.disclaimer.intro') %>
|
||||
<ul>
|
||||
<li> <%= t('.disclaimer.not_just_mistake') %> </li>
|
||||
<li> <%= t('.disclaimer.unable_to_fix') %> </li>
|
||||
<li> <%= t('.disclaimer.resolve_with_user') %> </li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<%= form_for(@report) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<fieldset>
|
||||
<%= f.fields_for @report.issue do |issue_form| %>
|
||||
<%= issue_form.hidden_field :reportable_id %>
|
||||
<%= issue_form.hidden_field :reportable_type %>
|
||||
<% end %>
|
||||
|
||||
<div class='form-row'>
|
||||
<p><%= t('.select') %></p>
|
||||
<ul>
|
||||
<% Report.categories_for(@report.issue.reportable).each do |c| %>
|
||||
<li>
|
||||
<%= radio_button :report, :category, c, :required => true %>
|
||||
<%= label_tag "report_category_#{c}", t(".categories.#{@report.issue.reportable.class.name.underscore}.#{c}") %> <br/>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class='form-row'>
|
||||
<%= text_area :report, :details, :cols => 20, :rows => 5, placeholder: t('.details'), :required => true %>
|
||||
</div>
|
||||
|
||||
<div class='buttons'>
|
||||
<%= f.submit %>
|
||||
</div>
|
||||
</fieldset>
|
||||
<% end %>
|
|
@ -102,6 +102,11 @@
|
|||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if current_user and @user.id != current_user.id %>
|
||||
<li>
|
||||
<%= report_link(t(".report"), @user) %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
<% end %>
|
||||
|
|
|
@ -207,6 +207,7 @@ en:
|
|||
reopened_by: "Reactivated by %{user} <abbr title='%{exact_time}'>%{when} ago</abbr>"
|
||||
reopened_by_anonymous: "Reactivated by anonymous <abbr title='%{exact_time}'>%{when} ago</abbr>"
|
||||
hidden_by: "Hidden by %{user} <abbr title='%{exact_time}'>%{when} ago</abbr>"
|
||||
report: Report this note
|
||||
query:
|
||||
title: "Query Features"
|
||||
introduction: "Click on the map to find nearby features."
|
||||
|
@ -297,10 +298,12 @@ en:
|
|||
edit_link: Edit this entry
|
||||
hide_link: Hide this entry
|
||||
confirm: Confirm
|
||||
report: Report this entry
|
||||
diary_comment:
|
||||
comment_from: "Comment from %{link_user} on %{comment_created_at}"
|
||||
hide_link: Hide this comment
|
||||
confirm: Confirm
|
||||
report: Report this comment
|
||||
location:
|
||||
location: "Location:"
|
||||
view: "View"
|
||||
|
@ -918,6 +921,110 @@ en:
|
|||
results:
|
||||
no_results: "No results found"
|
||||
more_results: "More results"
|
||||
issues:
|
||||
index:
|
||||
title: Issues
|
||||
select_status: Select Status
|
||||
select_type: Select Type
|
||||
select_last_updated_by: Select Last Updated By
|
||||
reported_user: Reported User
|
||||
not_updated: Not Updated
|
||||
search: Search
|
||||
search_guidance: "Search Issues:"
|
||||
user_not_found: User does not exist
|
||||
issues_not_found: No such issues found
|
||||
status: Status
|
||||
reports: Reports
|
||||
last_updated: Last Updated
|
||||
last_updated_time_html: "<abbr title='%{title}'>%{time} ago</abbr>"
|
||||
last_updated_time_user_html: "<abbr title='%{title}'>%{time} ago</abbr> by %{user}"
|
||||
link_to_reports: View Reports
|
||||
reported_user: Reported User
|
||||
reports_count:
|
||||
one: "1 Report"
|
||||
other: "%{count} Reports"
|
||||
reported_item: Reported Item
|
||||
states:
|
||||
ignored: Ignored
|
||||
open: Open
|
||||
resolved: Resolved
|
||||
update:
|
||||
new_report: Your report has been registered sucessfully
|
||||
successful_update: Your report has been updated successfully
|
||||
provide_details: Please provide the required details
|
||||
show:
|
||||
title: "%{status} Issue #%{issue_id}"
|
||||
reports:
|
||||
zero: No reports
|
||||
one: 1 report
|
||||
other: "%{count} reports"
|
||||
report_created_at: "First reported at %{datetime}"
|
||||
last_resolved_at: "Last resolved at %{datetime}"
|
||||
last_updated_at: "Last updated at %{datetime} by %{displayname}"
|
||||
resolve: Resolve
|
||||
ignore: Ignore
|
||||
reopen: Reopen
|
||||
reports_of_this_issue: Reports of this Issue
|
||||
read_reports: Read Reports
|
||||
new_reports: New Reports
|
||||
other_issues_against_this_user: Other issues against this user
|
||||
no_other_issues: No other issues against this user.
|
||||
comments_on_this_issue: Comments on this issue
|
||||
resolve:
|
||||
resolved: Issue status has been set to 'Resolved'
|
||||
ignore:
|
||||
ignored: Issue status has been set to 'Ignored'
|
||||
reopen:
|
||||
reopened: Issue status has been set to 'Open'
|
||||
comments:
|
||||
created_at: "On %{datetime}"
|
||||
reassign_param: Reassign Issue?
|
||||
reports:
|
||||
updated_at: "On %{datetime}"
|
||||
reported_by_html: "Reported as %{category} by %{user}"
|
||||
helper:
|
||||
reportable_title:
|
||||
diary_comment: "%{entry_title}, comment #%{comment_id}"
|
||||
note: "Note #{note_id}"
|
||||
issue_comments:
|
||||
create:
|
||||
comment_created: Your comment was successfully created
|
||||
reports:
|
||||
new:
|
||||
title_html: "Report %{link}"
|
||||
missing_params: "Cannot create a new report"
|
||||
details: Please provide some more details about the problem (required).
|
||||
select: "Select a reason for your report:"
|
||||
disclaimer:
|
||||
intro: "Before sending your report to the site moderators, please ensure that:"
|
||||
not_just_mistake: You are certain that the problem is not just a mistake
|
||||
unable_to_fix: You are unable to fix the problem yourself or with the help of your fellow community members
|
||||
resolve_with_user: You have already tried to resolve the problem with the user concerned
|
||||
categories:
|
||||
diary_entry:
|
||||
spam: This diary entry is/contains spam
|
||||
offensive: This diary entry is obscene/offensive
|
||||
threat: This diary entry contains a threat
|
||||
other: Other
|
||||
diary_comment:
|
||||
spam: This diary comment is/contains spam
|
||||
offensive: This diary comment is obscene/offensive
|
||||
threat: This diary comment contains a threat
|
||||
other: Other
|
||||
user:
|
||||
spam: This user profile is/contains spam
|
||||
offensive: This user profile is obscene/offensive
|
||||
threat: This user profile contains a threat
|
||||
vandal: This user is a vandal
|
||||
other: Other
|
||||
note:
|
||||
spam: This note is spam
|
||||
personal: This note contains personal data
|
||||
abusive: This note is abusive
|
||||
other: Other
|
||||
create:
|
||||
successful_report: Your report has been registered sucessfully
|
||||
provide_details: Please provide the required details
|
||||
layouts:
|
||||
project_name:
|
||||
# in <title>
|
||||
|
@ -936,6 +1043,7 @@ en:
|
|||
edit: Edit
|
||||
history: History
|
||||
export: Export
|
||||
issues: Issues
|
||||
data: Data
|
||||
export_data: Export Data
|
||||
gps_traces: GPS Traces
|
||||
|
@ -1684,8 +1792,12 @@ en:
|
|||
application:
|
||||
require_cookies:
|
||||
cookies_needed: "You appear to have cookies disabled - please enable cookies in your browser before continuing."
|
||||
require_admin:
|
||||
not_an_admin: You need to be an admin to perform that action.
|
||||
require_moderator:
|
||||
not_a_moderator: "You need to be a moderator to perform that action."
|
||||
require_moderator_or_admin:
|
||||
not_a_moderator_or_admin: You need to be a moderator or an admin to perform that action
|
||||
setup_user_auth:
|
||||
blocked_zero_hour: "You have an urgent message on the OpenStreetMap web site. You need to read the message before you will be able to save your edits."
|
||||
blocked: "Your access to the API has been blocked. Please log-in to the web interface to find out more."
|
||||
|
@ -1955,6 +2067,7 @@ en:
|
|||
friends_diaries: "friends' diary entries"
|
||||
nearby_changesets: "nearby user changesets"
|
||||
nearby_diaries: "nearby user diary entries"
|
||||
report: Report this User
|
||||
popup:
|
||||
your location: "Your location"
|
||||
nearby mapper: "Nearby mapper"
|
||||
|
|
|
@ -297,6 +297,19 @@ OpenStreetMap::Application.routes.draw do
|
|||
resources :user_blocks
|
||||
match "/blocks/:id/revoke" => "user_blocks#revoke", :via => [:get, :post], :as => "revoke_user_block"
|
||||
|
||||
# issues and reports
|
||||
resources :issues do
|
||||
resources :comments, :controller => :issue_comments
|
||||
member do
|
||||
post "resolve"
|
||||
post "assign"
|
||||
post "ignore"
|
||||
post "reopen"
|
||||
end
|
||||
end
|
||||
|
||||
resources :reports
|
||||
|
||||
# redactions
|
||||
resources :redactions
|
||||
end
|
||||
|
|
64
db/migrate/20160822153055_create_issues_and_reports.rb
Normal file
64
db/migrate/20160822153055_create_issues_and_reports.rb
Normal file
|
@ -0,0 +1,64 @@
|
|||
require "migrate"
|
||||
|
||||
class CreateIssuesAndReports < ActiveRecord::Migration[5.0]
|
||||
def up
|
||||
create_enumeration :issue_status_enum, %w[open ignored resolved]
|
||||
|
||||
create_table :issues do |t|
|
||||
t.string :reportable_type, :null => false
|
||||
t.integer :reportable_id, :null => false
|
||||
t.integer :reported_user_id
|
||||
t.column :status, :issue_status_enum, :null => false, :default => "open"
|
||||
t.column :assigned_role, :user_role_enum, :null => false
|
||||
t.datetime :resolved_at
|
||||
t.integer :resolved_by
|
||||
t.integer :updated_by
|
||||
t.integer :reports_count, :default => 0
|
||||
t.timestamps :null => false
|
||||
end
|
||||
|
||||
add_foreign_key :issues, :users, :column => :reported_user_id, :name => "issues_reported_user_id_fkey"
|
||||
add_foreign_key :issues, :users, :column => :resolved_by, :name => "issues_resolved_by_fkey"
|
||||
add_foreign_key :issues, :users, :column => :updated_by, :name => "issues_updated_by_fkey"
|
||||
|
||||
add_index :issues, [:reportable_type, :reportable_id]
|
||||
add_index :issues, [:reported_user_id]
|
||||
add_index :issues, [:status]
|
||||
add_index :issues, [:assigned_role]
|
||||
add_index :issues, [:updated_by]
|
||||
|
||||
create_table :reports do |t|
|
||||
t.integer :issue_id, :null => false
|
||||
t.integer :user_id, :null => false
|
||||
t.text :details, :null => false
|
||||
t.string :category, :null => false
|
||||
t.timestamps :null => false
|
||||
end
|
||||
|
||||
add_foreign_key :reports, :issues, :name => "reports_issue_id_fkey"
|
||||
add_foreign_key :reports, :users, :column => :user_id, :name => "reports_user_id_fkey"
|
||||
|
||||
add_index :reports, :issue_id
|
||||
add_index :reports, :user_id
|
||||
|
||||
create_table :issue_comments do |t|
|
||||
t.integer :issue_id, :null => false
|
||||
t.integer :user_id, :null => false
|
||||
t.text :body, :null => false
|
||||
t.timestamps :null => false
|
||||
end
|
||||
|
||||
add_foreign_key :issue_comments, :issues, :name => "issue_comments_issue_id_fkey"
|
||||
add_foreign_key :issue_comments, :users, :column => :user_id, :name => "issue_comments_user_id_fkey"
|
||||
|
||||
add_index :issue_comments, :issue_id
|
||||
add_index :issue_comments, :user_id
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :issue_comments
|
||||
drop_table :reports
|
||||
drop_table :issues
|
||||
drop_enumeration :issue_status_enum
|
||||
end
|
||||
end
|
284
db/structure.sql
284
db/structure.sql
|
@ -60,6 +60,17 @@ CREATE TYPE gpx_visibility_enum AS ENUM (
|
|||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issue_status_enum; Type: TYPE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TYPE issue_status_enum AS ENUM (
|
||||
'open',
|
||||
'ignored',
|
||||
'resolved'
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: note_event_enum; Type: TYPE; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -679,6 +690,78 @@ CREATE SEQUENCE gpx_files_id_seq
|
|||
ALTER SEQUENCE gpx_files_id_seq OWNED BY gpx_files.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: issue_comments; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE issue_comments (
|
||||
id integer NOT NULL,
|
||||
issue_id integer NOT NULL,
|
||||
user_id integer NOT NULL,
|
||||
body text NOT NULL,
|
||||
created_at timestamp without time zone NOT NULL,
|
||||
updated_at timestamp without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issue_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE issue_comments_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: issue_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE issue_comments_id_seq OWNED BY issue_comments.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: issues; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE issues (
|
||||
id integer NOT NULL,
|
||||
reportable_type character varying NOT NULL,
|
||||
reportable_id integer NOT NULL,
|
||||
reported_user_id integer,
|
||||
status issue_status_enum DEFAULT 'open'::public.issue_status_enum NOT NULL,
|
||||
assigned_role user_role_enum NOT NULL,
|
||||
resolved_at timestamp without time zone,
|
||||
resolved_by integer,
|
||||
updated_by integer,
|
||||
reports_count integer DEFAULT 0,
|
||||
created_at timestamp without time zone NOT NULL,
|
||||
updated_at timestamp without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issues_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE issues_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: issues_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE issues_id_seq OWNED BY issues.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: languages; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -980,6 +1063,40 @@ CREATE TABLE relations (
|
|||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reports; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE reports (
|
||||
id integer NOT NULL,
|
||||
issue_id integer NOT NULL,
|
||||
user_id integer NOT NULL,
|
||||
details text NOT NULL,
|
||||
category character varying NOT NULL,
|
||||
created_at timestamp without time zone NOT NULL,
|
||||
updated_at timestamp without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reports_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE reports_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: reports_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE reports_id_seq OWNED BY reports.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1283,6 +1400,20 @@ ALTER TABLE ONLY gpx_file_tags ALTER COLUMN id SET DEFAULT nextval('gpx_file_tag
|
|||
ALTER TABLE ONLY gpx_files ALTER COLUMN id SET DEFAULT nextval('gpx_files_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issue_comments id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY issue_comments ALTER COLUMN id SET DEFAULT nextval('issue_comments_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issues id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY issues ALTER COLUMN id SET DEFAULT nextval('issues_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: messages id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1325,6 +1456,13 @@ ALTER TABLE ONLY oauth_tokens ALTER COLUMN id SET DEFAULT nextval('oauth_tokens_
|
|||
ALTER TABLE ONLY redactions ALTER COLUMN id SET DEFAULT nextval('redactions_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reports id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY reports ALTER COLUMN id SET DEFAULT nextval('reports_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: user_blocks id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1505,6 +1643,22 @@ ALTER TABLE ONLY gpx_files
|
|||
ADD CONSTRAINT gpx_files_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issue_comments issue_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY issue_comments
|
||||
ADD CONSTRAINT issue_comments_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issues issues_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY issues
|
||||
ADD CONSTRAINT issues_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: languages languages_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1601,6 +1755,14 @@ ALTER TABLE ONLY relations
|
|||
ADD CONSTRAINT relations_pkey PRIMARY KEY (relation_id, version);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reports reports_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY reports
|
||||
ADD CONSTRAINT reports_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: user_blocks user_blocks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1875,6 +2037,55 @@ CREATE INDEX index_client_applications_on_user_id ON client_applications USING b
|
|||
CREATE INDEX index_diary_entry_subscriptions_on_diary_entry_id ON diary_entry_subscriptions USING btree (diary_entry_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_issue_comments_on_issue_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_issue_comments_on_issue_id ON issue_comments USING btree (issue_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_issue_comments_on_user_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_issue_comments_on_user_id ON issue_comments USING btree (user_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_issues_on_assigned_role; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_issues_on_assigned_role ON issues USING btree (assigned_role);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_issues_on_reportable_type_and_reportable_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_issues_on_reportable_type_and_reportable_id ON issues USING btree (reportable_type, reportable_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_issues_on_reported_user_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_issues_on_reported_user_id ON issues USING btree (reported_user_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_issues_on_status; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_issues_on_status ON issues USING btree (status);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_issues_on_updated_by; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_issues_on_updated_by ON issues USING btree (updated_by);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_note_comments_on_body; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1910,6 +2121,20 @@ CREATE UNIQUE INDEX index_oauth_tokens_on_token ON oauth_tokens USING btree (tok
|
|||
CREATE INDEX index_oauth_tokens_on_user_id ON oauth_tokens USING btree (user_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_reports_on_issue_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_reports_on_issue_id ON reports USING btree (issue_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_reports_on_user_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_reports_on_user_id ON reports USING btree (user_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_user_blocks_on_user_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2329,6 +2554,46 @@ ALTER TABLE ONLY gpx_files
|
|||
ADD CONSTRAINT gpx_files_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issue_comments issue_comments_issue_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY issue_comments
|
||||
ADD CONSTRAINT issue_comments_issue_id_fkey FOREIGN KEY (issue_id) REFERENCES issues(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issue_comments issue_comments_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY issue_comments
|
||||
ADD CONSTRAINT issue_comments_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issues issues_reported_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY issues
|
||||
ADD CONSTRAINT issues_reported_user_id_fkey FOREIGN KEY (reported_user_id) REFERENCES users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issues issues_resolved_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY issues
|
||||
ADD CONSTRAINT issues_resolved_by_fkey FOREIGN KEY (resolved_by) REFERENCES users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: issues issues_updated_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY issues
|
||||
ADD CONSTRAINT issues_updated_by_fkey FOREIGN KEY (updated_by) REFERENCES users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: messages messages_from_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2441,6 +2706,22 @@ ALTER TABLE ONLY relations
|
|||
ADD CONSTRAINT relations_redaction_id_fkey FOREIGN KEY (redaction_id) REFERENCES redactions(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reports reports_issue_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY reports
|
||||
ADD CONSTRAINT reports_issue_id_fkey FOREIGN KEY (issue_id) REFERENCES issues(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reports reports_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY reports
|
||||
ADD CONSTRAINT reports_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: user_blocks user_blocks_moderator_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2584,6 +2865,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('20150111192335'),
|
||||
('20150222101847'),
|
||||
('20150818224516'),
|
||||
('20160822153055'),
|
||||
('20161002153425'),
|
||||
('20161011010929'),
|
||||
('20170222134109'),
|
||||
|
@ -2632,5 +2914,3 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('7'),
|
||||
('8'),
|
||||
('9');
|
||||
|
||||
|
||||
|
|
27
test/controllers/issue_comments_controller_test.rb
Normal file
27
test/controllers/issue_comments_controller_test.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
require "test_helper"
|
||||
|
||||
class IssueCommentsControllerTest < ActionController::TestCase
|
||||
def test_comment_by_normal_user
|
||||
issue = create(:issue)
|
||||
|
||||
# Login as normal user
|
||||
session[:user] = create(:user).id
|
||||
|
||||
post :create, :params => { :issue_id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
assert_equal 0, issue.comments.length
|
||||
end
|
||||
|
||||
def test_comment
|
||||
issue = create(:issue)
|
||||
|
||||
# Login as administrator
|
||||
session[:user] = create(:administrator_user).id
|
||||
|
||||
post :create, :params => { :issue_id => issue.id, :issue_comment => { :body => "test comment" } }
|
||||
assert_response :redirect
|
||||
assert_redirected_to issue
|
||||
assert_equal 1, issue.comments.length
|
||||
end
|
||||
end
|
144
test/controllers/issues_controller_test.rb
Normal file
144
test/controllers/issues_controller_test.rb
Normal file
|
@ -0,0 +1,144 @@
|
|||
require "test_helper"
|
||||
|
||||
class IssuesControllerTest < ActionController::TestCase
|
||||
def test_index
|
||||
# Access issues list without login
|
||||
get :index
|
||||
assert_response :redirect
|
||||
assert_redirected_to login_path(:referer => issues_path)
|
||||
|
||||
# Access issues list as normal user
|
||||
session[:user] = create(:user).id
|
||||
get :index
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
|
||||
# Access issues list as administrator
|
||||
session[:user] = create(:administrator_user).id
|
||||
get :index
|
||||
assert_response :success
|
||||
|
||||
# Access issues list as moderator
|
||||
session[:user] = create(:moderator_user).id
|
||||
get :index
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
def test_show
|
||||
target_user = create(:user)
|
||||
issue = create(:issue, :reportable => target_user, :reported_user => target_user)
|
||||
|
||||
# Access issue without login
|
||||
get :show, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_redirected_to login_path(:referer => issue_path(issue))
|
||||
|
||||
# Access issue as normal user
|
||||
session[:user] = create(:user).id
|
||||
get :show, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
|
||||
# Access issue as administrator
|
||||
session[:user] = create(:administrator_user).id
|
||||
get :show, :params => { :id => issue.id }
|
||||
assert_response :success
|
||||
|
||||
# Access issue as moderator
|
||||
session[:user] = create(:moderator_user).id
|
||||
get :show, :params => { :id => issue.id }
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
def test_resolve
|
||||
target_user = create(:user)
|
||||
issue = create(:issue, :reportable => target_user, :reported_user => target_user)
|
||||
|
||||
# Resolve issue without login
|
||||
get :resolve, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_redirected_to login_path(:referer => resolve_issue_path(issue))
|
||||
|
||||
# Resolve issue as normal user
|
||||
session[:user] = create(:user).id
|
||||
get :resolve, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
|
||||
# Resolve issue as administrator
|
||||
session[:user] = create(:administrator_user).id
|
||||
get :resolve, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_equal true, issue.reload.resolved?
|
||||
|
||||
issue.reopen!
|
||||
|
||||
# Resolve issue as moderator
|
||||
session[:user] = create(:moderator_user).id
|
||||
get :resolve, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_equal true, issue.reload.resolved?
|
||||
end
|
||||
|
||||
def test_ignore
|
||||
target_user = create(:user)
|
||||
issue = create(:issue, :reportable => target_user, :reported_user => target_user)
|
||||
|
||||
# Ignore issue without login
|
||||
get :ignore, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_redirected_to login_path(:referer => ignore_issue_path(issue))
|
||||
|
||||
# Ignore issue as normal user
|
||||
session[:user] = create(:user).id
|
||||
get :ignore, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
|
||||
# Ignore issue as administrator
|
||||
session[:user] = create(:administrator_user).id
|
||||
get :ignore, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_equal true, issue.reload.ignored?
|
||||
|
||||
issue.reopen!
|
||||
|
||||
# Ignore issue as moderator
|
||||
session[:user] = create(:moderator_user).id
|
||||
get :ignore, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_equal true, issue.reload.ignored?
|
||||
end
|
||||
|
||||
def test_reopen
|
||||
target_user = create(:user)
|
||||
issue = create(:issue, :reportable => target_user, :reported_user => target_user)
|
||||
|
||||
issue.resolve!
|
||||
|
||||
# Reopen issue without login
|
||||
get :reopen, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_redirected_to login_path(:referer => reopen_issue_path(issue))
|
||||
|
||||
# Reopen issue as normal user
|
||||
session[:user] = create(:user).id
|
||||
get :reopen, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
|
||||
# Reopen issue as administrator
|
||||
session[:user] = create(:administrator_user).id
|
||||
get :reopen, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_equal true, issue.reload.open?
|
||||
|
||||
issue.resolve!
|
||||
|
||||
# Reopen issue as moderator
|
||||
session[:user] = create(:moderator_user).id
|
||||
get :reopen, :params => { :id => issue.id }
|
||||
assert_response :redirect
|
||||
assert_equal true, issue.reload.open?
|
||||
end
|
||||
end
|
131
test/controllers/reports_controller_test.rb
Normal file
131
test/controllers/reports_controller_test.rb
Normal file
|
@ -0,0 +1,131 @@
|
|||
require "test_helper"
|
||||
|
||||
class ReportsControllerTest < ActionController::TestCase
|
||||
def test_new_report_without_login
|
||||
target_user = create(:user)
|
||||
get :new, :params => { :reportable_id => target_user.id, :reportable_type => "User" }
|
||||
assert_response :redirect
|
||||
assert_redirected_to login_path(:referer => new_report_path(:reportable_id => target_user.id, :reportable_type => "User"))
|
||||
end
|
||||
|
||||
def test_new_report_after_login
|
||||
target_user = create(:user)
|
||||
|
||||
session[:user] = create(:user).id
|
||||
|
||||
# Create an Issue and a report
|
||||
get :new, :params => { :reportable_id => target_user.id, :reportable_type => "User" }
|
||||
assert_response :success
|
||||
assert_difference "Issue.count", 1 do
|
||||
details = "Details of a report"
|
||||
category = "other"
|
||||
post :create,
|
||||
:params => {
|
||||
:report => {
|
||||
:details => details,
|
||||
:category => category,
|
||||
:issue => { :reportable_id => target_user.id, :reportable_type => "User" }
|
||||
}
|
||||
}
|
||||
end
|
||||
assert_response :redirect
|
||||
assert_redirected_to user_path(target_user.display_name)
|
||||
end
|
||||
|
||||
def test_new_report_with_incomplete_details
|
||||
# Test creation of a new issue and a new report
|
||||
target_user = create(:user)
|
||||
|
||||
# Login
|
||||
session[:user] = create(:user).id
|
||||
|
||||
# Create an Issue and a report
|
||||
get :new, :params => { :reportable_id => target_user.id, :reportable_type => "User" }
|
||||
assert_response :success
|
||||
assert_difference "Issue.count", 1 do
|
||||
details = "Details of a report"
|
||||
category = "other"
|
||||
post :create,
|
||||
:params => {
|
||||
:report => {
|
||||
:details => details,
|
||||
:category => category,
|
||||
:issue => { :reportable_id => target_user.id, :reportable_type => "User" }
|
||||
}
|
||||
}
|
||||
end
|
||||
assert_response :redirect
|
||||
assert_redirected_to user_path(target_user.display_name)
|
||||
|
||||
issue = Issue.last
|
||||
|
||||
assert_equal 1, issue.reports.count
|
||||
|
||||
get :new, :params => { :reportable_id => target_user.id, :reportable_type => "User" }
|
||||
assert_response :success
|
||||
|
||||
# Report without details
|
||||
assert_no_difference "Issue.count" do
|
||||
category = "other"
|
||||
post :create,
|
||||
:params => {
|
||||
:report => {
|
||||
:category => category,
|
||||
:issue => { :reportable_id => 1, :reportable_type => "User" }
|
||||
}
|
||||
}
|
||||
end
|
||||
assert_response :redirect
|
||||
|
||||
assert_equal 1, issue.reports.count
|
||||
end
|
||||
|
||||
def test_new_report_with_complete_details
|
||||
# Test creation of a new issue and a new report
|
||||
target_user = create(:user)
|
||||
|
||||
# Login
|
||||
session[:user] = create(:user).id
|
||||
|
||||
# Create an Issue and a report
|
||||
get :new, :params => { :reportable_id => target_user.id, :reportable_type => "User" }
|
||||
assert_response :success
|
||||
assert_difference "Issue.count", 1 do
|
||||
details = "Details of a report"
|
||||
category = "other"
|
||||
post :create,
|
||||
:params => {
|
||||
:report => {
|
||||
:details => details,
|
||||
:category => category,
|
||||
:issue => { :reportable_id => target_user.id, :reportable_type => "User" }
|
||||
}
|
||||
}
|
||||
end
|
||||
assert_response :redirect
|
||||
assert_redirected_to user_path(target_user.display_name)
|
||||
|
||||
issue = Issue.last
|
||||
|
||||
assert_equal 1, issue.reports.count
|
||||
|
||||
# Create a report for an existing Issue
|
||||
get :new, :params => { :reportable_id => target_user.id, :reportable_type => "User" }
|
||||
assert_response :success
|
||||
assert_no_difference "Issue.count" do
|
||||
details = "Details of another report under the same issue"
|
||||
category = "other"
|
||||
post :create,
|
||||
:params => {
|
||||
:report => {
|
||||
:details => details,
|
||||
:category => category,
|
||||
:issue => { :reportable_id => target_user.id, :reportable_type => "User" }
|
||||
}
|
||||
}
|
||||
end
|
||||
assert_response :redirect
|
||||
|
||||
assert_equal 2, issue.reports.count
|
||||
end
|
||||
end
|
7
test/factories/issues.rb
Normal file
7
test/factories/issues.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
FactoryBot.define do
|
||||
factory :issue do
|
||||
# Default to reporting users
|
||||
association :reportable, :factory => :user
|
||||
association :reported_user, :factory => :user
|
||||
end
|
||||
end
|
8
test/factories/reports.rb
Normal file
8
test/factories/reports.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
FactoryBot.define do
|
||||
factory :report do
|
||||
sequence(:details) { |n| "Report details #{n}" }
|
||||
category "other"
|
||||
issue
|
||||
user
|
||||
end
|
||||
end
|
7
test/models/issue_comment_test.rb
Normal file
7
test/models/issue_comment_test.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
require "test_helper"
|
||||
|
||||
class IssueCommentTest < ActiveSupport::TestCase
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
88
test/models/issue_test.rb
Normal file
88
test/models/issue_test.rb
Normal file
|
@ -0,0 +1,88 @@
|
|||
require "test_helper"
|
||||
|
||||
class IssueTest < ActiveSupport::TestCase
|
||||
def test_assigned_role
|
||||
issue = create(:issue)
|
||||
|
||||
assert issue.valid?
|
||||
issue.assigned_role = "bogus"
|
||||
assert_not issue.valid?
|
||||
end
|
||||
|
||||
def test_reported_user
|
||||
create(:language, :code => "en")
|
||||
user = create(:user)
|
||||
note = create(:note_comment, :author => create(:user)).note
|
||||
anonymous_note = create(:note_comment, :author => nil).note
|
||||
diary_entry = create(:diary_entry)
|
||||
diary_comment = create(:diary_comment, :diary_entry => diary_entry)
|
||||
|
||||
issue = Issue.new(:reportable => user)
|
||||
issue.save!
|
||||
assert_equal issue.reported_user, user
|
||||
|
||||
issue = Issue.new(:reportable => note)
|
||||
issue.save!
|
||||
assert_equal issue.reported_user, note.author
|
||||
|
||||
issue = Issue.new(:reportable => anonymous_note)
|
||||
issue.save!
|
||||
assert_nil issue.reported_user
|
||||
|
||||
issue = Issue.new(:reportable => diary_entry)
|
||||
issue.save!
|
||||
assert_equal issue.reported_user, diary_entry.user
|
||||
|
||||
issue = Issue.new(:reportable => diary_comment)
|
||||
issue.save!
|
||||
assert_equal issue.reported_user, diary_comment.user
|
||||
end
|
||||
|
||||
def test_default_assigned_role
|
||||
create(:language, :code => "en")
|
||||
user = create(:user)
|
||||
note = create(:note_with_comments)
|
||||
diary_entry = create(:diary_entry)
|
||||
diary_comment = create(:diary_comment, :diary_entry => diary_entry)
|
||||
|
||||
issue = Issue.new(:reportable => user)
|
||||
issue.save!
|
||||
assert_equal "administrator", issue.assigned_role
|
||||
|
||||
issue = Issue.new(:reportable => note)
|
||||
issue.save!
|
||||
assert_equal "moderator", issue.assigned_role
|
||||
|
||||
issue = Issue.new(:reportable => diary_entry)
|
||||
issue.save!
|
||||
assert_equal "administrator", issue.assigned_role
|
||||
|
||||
issue = Issue.new(:reportable => diary_comment)
|
||||
issue.save!
|
||||
assert_equal "administrator", issue.assigned_role
|
||||
end
|
||||
|
||||
def test_no_default_explicit_role
|
||||
create(:language, :code => "en")
|
||||
user = create(:user)
|
||||
note = create(:note_with_comments)
|
||||
diary_entry = create(:diary_entry)
|
||||
diary_comment = create(:diary_comment, :diary_entry => diary_entry)
|
||||
|
||||
issue = Issue.new(:reportable => user, :assigned_role => "moderator")
|
||||
issue.save!
|
||||
assert_equal "moderator", issue.reload.assigned_role
|
||||
|
||||
issue = Issue.new(:reportable => note, :assigned_role => "administrator")
|
||||
issue.save!
|
||||
assert_equal "administrator", issue.reload.assigned_role
|
||||
|
||||
issue = Issue.new(:reportable => diary_entry, :assigned_role => "moderator")
|
||||
issue.save!
|
||||
assert_equal "moderator", issue.reload.assigned_role
|
||||
|
||||
issue = Issue.new(:reportable => diary_comment, :assigned_role => "moderator")
|
||||
issue.save!
|
||||
assert_equal "moderator", issue.reload.assigned_role
|
||||
end
|
||||
end
|
35
test/models/report_test.rb
Normal file
35
test/models/report_test.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
require "test_helper"
|
||||
|
||||
class ReportTest < ActiveSupport::TestCase
|
||||
def test_issue_required
|
||||
report = create(:report)
|
||||
|
||||
assert report.valid?
|
||||
report.issue = nil
|
||||
assert_not report.valid?
|
||||
end
|
||||
|
||||
def test_user_required
|
||||
report = create(:report)
|
||||
|
||||
assert report.valid?
|
||||
report.user = nil
|
||||
assert_not report.valid?
|
||||
end
|
||||
|
||||
def test_details_required
|
||||
report = create(:report)
|
||||
|
||||
assert report.valid?
|
||||
report.details = ""
|
||||
assert_not report.valid?
|
||||
end
|
||||
|
||||
def test_category_required
|
||||
report = create(:report)
|
||||
|
||||
assert report.valid?
|
||||
report.category = ""
|
||||
assert_not report.valid?
|
||||
end
|
||||
end
|
119
test/system/issues_test.rb
Normal file
119
test/system/issues_test.rb
Normal file
|
@ -0,0 +1,119 @@
|
|||
require "application_system_test_case"
|
||||
|
||||
class IssuesTest < ApplicationSystemTestCase
|
||||
include IssuesHelper
|
||||
|
||||
def test_view_issues_not_logged_in
|
||||
visit issues_path
|
||||
assert page.has_content?(I18n.t("user.login.title"))
|
||||
end
|
||||
|
||||
def test_view_issues_normal_user
|
||||
sign_in_as(create(:user))
|
||||
|
||||
visit issues_path
|
||||
assert page.has_content?(I18n.t("application.require_moderator_or_admin.not_a_moderator_or_admin"))
|
||||
end
|
||||
|
||||
def test_view_no_issues
|
||||
sign_in_as(create(:moderator_user))
|
||||
|
||||
visit issues_path
|
||||
assert page.has_content?(I18n.t("issues.index.issues_not_found"))
|
||||
end
|
||||
|
||||
def test_view_issues
|
||||
sign_in_as(create(:moderator_user))
|
||||
issues = create_list(:issue, 3, :assigned_role => "moderator")
|
||||
|
||||
visit issues_path
|
||||
assert page.has_content?(issues.first.reported_user.display_name)
|
||||
end
|
||||
|
||||
def test_view_issues_with_no_reported_user
|
||||
sign_in_as(create(:moderator_user))
|
||||
anonymous_note = create(:note_with_comments)
|
||||
issue = create(:issue, :reportable => anonymous_note)
|
||||
|
||||
visit issues_path
|
||||
assert page.has_content?(reportable_title(anonymous_note))
|
||||
|
||||
visit issue_path(issue)
|
||||
assert page.has_content?(reportable_title(anonymous_note))
|
||||
end
|
||||
|
||||
def test_search_issues_by_user
|
||||
good_user = create(:user)
|
||||
bad_user = create(:user)
|
||||
create(:issue, :reportable => bad_user, :reported_user => bad_user, :assigned_role => "administrator")
|
||||
|
||||
sign_in_as(create(:administrator_user))
|
||||
|
||||
# No issues against the user
|
||||
visit issues_path
|
||||
fill_in "search_by_user", :with => good_user.display_name
|
||||
click_on "Search"
|
||||
assert_not page.has_content?(I18n.t("issues.index.user_not_found"))
|
||||
assert page.has_content?(I18n.t("issues.index.issues_not_found"))
|
||||
|
||||
# User doesn't exist
|
||||
visit issues_path
|
||||
fill_in "search_by_user", :with => "Nonexistant User"
|
||||
click_on "Search"
|
||||
assert page.has_content?(I18n.t("issues.index.user_not_found"))
|
||||
assert page.has_content?(I18n.t("issues.index.issues_not_found"))
|
||||
|
||||
# Find Issue against bad_user
|
||||
visit issues_path
|
||||
fill_in "search_by_user", :with => bad_user.display_name
|
||||
click_on "Search"
|
||||
assert_not page.has_content?(I18n.t("issues.index.user_not_found"))
|
||||
assert_not page.has_content?(I18n.t("issues.index.issues_not_found"))
|
||||
end
|
||||
|
||||
def test_commenting
|
||||
issue = create(:issue)
|
||||
sign_in_as(create(:moderator_user))
|
||||
|
||||
visit issue_path(issue)
|
||||
|
||||
fill_in :issue_comment_body, :with => "test comment"
|
||||
click_on "Submit"
|
||||
assert page.has_content?(I18n.t("issue_comments.create.comment_created"))
|
||||
assert page.has_content?("test comment")
|
||||
|
||||
issue.reload
|
||||
assert_equal issue.comments.first.body, "test comment"
|
||||
end
|
||||
|
||||
def test_reassign_issue
|
||||
issue = create(:issue)
|
||||
assert_equal "administrator", issue.assigned_role
|
||||
sign_in_as(create(:administrator_user))
|
||||
|
||||
visit issue_path(issue)
|
||||
|
||||
fill_in :issue_comment_body, :with => "reassigning to moderators"
|
||||
check :reassign
|
||||
click_on "Submit"
|
||||
|
||||
issue.reload
|
||||
assert_equal "moderator", issue.assigned_role
|
||||
end
|
||||
|
||||
def test_issue_index_with_multiple_roles
|
||||
user1 = create(:user)
|
||||
user2 = create(:user)
|
||||
issue1 = create(:issue, :reportable => user1, :assigned_role => "administrator")
|
||||
issue2 = create(:issue, :reportable => user2, :assigned_role => "moderator")
|
||||
|
||||
user = create(:administrator_user)
|
||||
create(:user_role, :user => user, :role => "moderator")
|
||||
sign_in_as(user)
|
||||
|
||||
visit issues_path
|
||||
|
||||
assert page.has_link?(I18n.t("issues.index.reports_count", :count => issue1.reports_count), :href => issue_path(issue1))
|
||||
assert page.has_link?(I18n.t("issues.index.reports_count", :count => issue2.reports_count), :href => issue_path(issue2))
|
||||
end
|
||||
end
|
36
test/system/report_diary_comment_test.rb
Normal file
36
test/system/report_diary_comment_test.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
require "application_system_test_case"
|
||||
|
||||
class ReportDiaryCommentTest < ApplicationSystemTestCase
|
||||
def setup
|
||||
create(:language, :code => "en")
|
||||
@diary_entry = create(:diary_entry)
|
||||
@comment = create(:diary_comment, :diary_entry => @diary_entry)
|
||||
end
|
||||
|
||||
def test_no_link_when_not_logged_in
|
||||
visit diary_entry_path(@diary_entry.user.display_name, @diary_entry)
|
||||
assert page.has_content?(@comment.body)
|
||||
|
||||
assert_not page.has_content?(I18n.t("diary_entry.diary_comment.report"))
|
||||
end
|
||||
|
||||
def test_it_works
|
||||
sign_in_as(create(:user))
|
||||
visit diary_entry_path(@diary_entry.user.display_name, @diary_entry)
|
||||
assert page.has_content? @diary_entry.title
|
||||
|
||||
click_on I18n.t("diary_entry.diary_comment.report")
|
||||
assert page.has_content? "Report"
|
||||
assert page.has_content? I18n.t("reports.new.disclaimer.intro")
|
||||
|
||||
choose I18n.t("reports.new.categories.diary_comment.spam")
|
||||
fill_in "report_details", :with => "This comment is spam"
|
||||
assert_difference "Issue.count", 1 do
|
||||
click_on "Create Report"
|
||||
end
|
||||
|
||||
assert page.has_content? "Your report has been registered sucessfully"
|
||||
|
||||
assert_equal @comment, Issue.last.reportable
|
||||
end
|
||||
end
|
64
test/system/report_diary_entry_test.rb
Normal file
64
test/system/report_diary_entry_test.rb
Normal file
|
@ -0,0 +1,64 @@
|
|||
require "application_system_test_case"
|
||||
|
||||
class ReportDiaryEntryTest < ApplicationSystemTestCase
|
||||
def setup
|
||||
create(:language, :code => "en")
|
||||
@diary_entry = create(:diary_entry)
|
||||
end
|
||||
|
||||
def test_no_link_when_not_logged_in
|
||||
visit diary_entry_path(@diary_entry.user.display_name, @diary_entry)
|
||||
assert page.has_content?(@diary_entry.title)
|
||||
|
||||
assert_not page.has_content?(I18n.t("diary_entry.diary_entry.report"))
|
||||
end
|
||||
|
||||
def test_it_works
|
||||
sign_in_as(create(:user))
|
||||
visit diary_entry_path(@diary_entry.user.display_name, @diary_entry)
|
||||
assert page.has_content? @diary_entry.title
|
||||
|
||||
click_on I18n.t("diary_entry.diary_entry.report")
|
||||
assert page.has_content? "Report"
|
||||
assert page.has_content? I18n.t("reports.new.disclaimer.intro")
|
||||
|
||||
choose I18n.t("reports.new.categories.diary_entry.spam")
|
||||
fill_in "report_details", :with => "This is advertising"
|
||||
assert_difference "Issue.count", 1 do
|
||||
click_on "Create Report"
|
||||
end
|
||||
|
||||
assert page.has_content? "Your report has been registered sucessfully"
|
||||
|
||||
assert_equal @diary_entry, Issue.last.reportable
|
||||
end
|
||||
|
||||
def test_it_reopens_issue
|
||||
issue = create(:issue, :reportable => @diary_entry)
|
||||
issue.resolve!
|
||||
|
||||
sign_in_as(create(:user))
|
||||
visit diary_entry_path(@diary_entry.user.display_name, @diary_entry)
|
||||
assert page.has_content? @diary_entry.title
|
||||
|
||||
click_on I18n.t("diary_entry.diary_entry.report")
|
||||
assert page.has_content? "Report"
|
||||
assert page.has_content? I18n.t("reports.new.disclaimer.intro")
|
||||
|
||||
choose I18n.t("reports.new.categories.diary_entry.spam")
|
||||
fill_in "report_details", :with => "This is advertising"
|
||||
assert_no_difference "Issue.count" do
|
||||
click_on "Create Report"
|
||||
end
|
||||
|
||||
issue.reload
|
||||
assert_not issue.resolved?
|
||||
assert issue.open?
|
||||
end
|
||||
|
||||
def test_missing_report_params
|
||||
sign_in_as(create(:user))
|
||||
visit new_report_path
|
||||
assert page.has_content? I18n.t("reports.new.missing_params")
|
||||
end
|
||||
end
|
51
test/system/report_note_test.rb
Normal file
51
test/system/report_note_test.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
require "application_system_test_case"
|
||||
|
||||
class ReportNoteTest < ApplicationSystemTestCase
|
||||
def test_no_link_when_not_logged_in
|
||||
note = create(:note_with_comments)
|
||||
visit browse_note_path(note)
|
||||
assert page.has_content?(note.comments.first.body)
|
||||
|
||||
assert_not page.has_content?(I18n.t("browse.note.report"))
|
||||
end
|
||||
|
||||
def test_can_report_anonymous_notes
|
||||
note = create(:note_with_comments)
|
||||
sign_in_as(create(:user))
|
||||
visit browse_note_path(note)
|
||||
|
||||
click_on I18n.t("browse.note.report")
|
||||
assert page.has_content? "Report"
|
||||
assert page.has_content? I18n.t("reports.new.disclaimer.intro")
|
||||
|
||||
choose I18n.t("reports.new.categories.note.spam")
|
||||
fill_in "report_details", :with => "This is spam"
|
||||
assert_difference "Issue.count", 1 do
|
||||
click_on "Create Report"
|
||||
end
|
||||
|
||||
assert page.has_content? "Your report has been registered sucessfully"
|
||||
|
||||
assert_equal note, Issue.last.reportable
|
||||
end
|
||||
|
||||
def test_can_report_notes_with_author
|
||||
note = create(:note_comment, :author => create(:user)).note
|
||||
sign_in_as(create(:user))
|
||||
visit browse_note_path(note)
|
||||
|
||||
click_on I18n.t("browse.note.report")
|
||||
assert page.has_content? "Report"
|
||||
assert page.has_content? I18n.t("reports.new.disclaimer.intro")
|
||||
|
||||
choose I18n.t("reports.new.categories.note.spam")
|
||||
fill_in "report_details", :with => "This is spam"
|
||||
assert_difference "Issue.count", 1 do
|
||||
click_on "Create Report"
|
||||
end
|
||||
|
||||
assert page.has_content? "Your report has been registered sucessfully"
|
||||
|
||||
assert_equal note, Issue.last.reportable
|
||||
end
|
||||
end
|
31
test/system/report_user_test.rb
Normal file
31
test/system/report_user_test.rb
Normal file
|
@ -0,0 +1,31 @@
|
|||
require "application_system_test_case"
|
||||
|
||||
class ReportUserTest < ApplicationSystemTestCase
|
||||
def test_no_link_when_not_logged_in
|
||||
note = create(:note_with_comments)
|
||||
visit browse_note_path(note)
|
||||
assert page.has_content?(note.comments.first.body)
|
||||
|
||||
assert_not page.has_content?(I18n.t("user.view.report"))
|
||||
end
|
||||
|
||||
def test_can_report_user
|
||||
user = create(:user)
|
||||
sign_in_as(create(:user))
|
||||
visit user_path(user.display_name)
|
||||
|
||||
click_on I18n.t("user.view.report")
|
||||
assert page.has_content? "Report"
|
||||
assert page.has_content? I18n.t("reports.new.disclaimer.intro")
|
||||
|
||||
choose I18n.t("reports.new.categories.user.vandal")
|
||||
fill_in "report_details", :with => "This user is a vandal"
|
||||
assert_difference "Issue.count", 1 do
|
||||
click_on "Create Report"
|
||||
end
|
||||
|
||||
assert page.has_content? "Your report has been registered sucessfully"
|
||||
|
||||
assert_equal user, Issue.last.reportable
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue