[Done] New Reporting System MVP (#408)
* Move validations from controller to model * Add new columns to feedback message model * Use polymorphic notes relationship * MVP of ticketing system * Use new URL for reported_url param * Add missing files * Add validations and tests for feedback_messages * Clean up some html * Update create spec and add update spec * Add mail tests and lint * Add link to user profile
This commit is contained in:
parent
ec264bf802
commit
ecbb9d4ab1
32 changed files with 572 additions and 96 deletions
|
|
@ -45,7 +45,7 @@ function buildCommentHTML(comment) {
|
|||
<a href="'+comment.url+'">\
|
||||
Permalink\
|
||||
</a>\
|
||||
<a href="/report-abuse">Report Abuse</a>\
|
||||
<a href="/report-abuse?url=https://dev.to'+comment.url+'">Report Abuse</a>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
|
|
|
|||
24
app/assets/stylesheets/feedback_messages.scss
Normal file
24
app/assets/stylesheets/feedback_messages.scss
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
.dialog{
|
||||
background: rgb(236, 236, 236);
|
||||
border: 1px solid rgb(217, 217, 217);
|
||||
text-align: center;
|
||||
padding: 20px 30px;
|
||||
margin: 20vh auto;
|
||||
max-width: 60%;
|
||||
height: 100%;
|
||||
color: rgb(44, 46, 50);
|
||||
border-radius: 5px;
|
||||
@media screen and (max-width: 321px) {
|
||||
h1,h2,h3,h4,h5,h6{
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
h3{
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
.blankmessage{
|
||||
font-style: italic;
|
||||
}
|
||||
|
|
@ -3,23 +3,24 @@ class FeedbackMessagesController < ApplicationController
|
|||
|
||||
def create
|
||||
flash.clear
|
||||
@feedback = FeedbackMessage.new(feedback_message_params.merge(user_id: current_user&.id))
|
||||
if authorize_send?
|
||||
@feedback_message = FeedbackMessage.new(
|
||||
feedback_message_params.merge(reporter_id: current_user&.id))
|
||||
if recaptcha_verified? && @feedback_message.save
|
||||
send_slack_message
|
||||
@feedback.save
|
||||
render :index
|
||||
NotifyMailer.new_report_email(@feedback_message).deliver if @feedback_message.reporter_id?
|
||||
redirect_to @feedback_message.path
|
||||
elsif feedback_message_params[:feedback_type] == "bug-reports"
|
||||
flash.now[:notice] = "Make sure the forms are filled 🤖 "
|
||||
flash[:notice] = "Make sure the forms are filled 🤖 "
|
||||
render file: "public/500.html", status: 500, layout: false
|
||||
else
|
||||
flash.now[:notice] = "Make sure the forms are filled 🤖 "
|
||||
flash[:notice] = "Make sure the forms are filled 🤖 "
|
||||
@previous_message = feedback_message_params[:message]
|
||||
render "pages/report-abuse.html.erb"
|
||||
end
|
||||
end
|
||||
|
||||
def authorize_send?
|
||||
recaptcha_verified? && form_filled?
|
||||
def show
|
||||
@feedback_message = FeedbackMessage.find_by(slug: params[:slug])
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -40,7 +41,7 @@ class FeedbackMessagesController < ApplicationController
|
|||
def generate_message
|
||||
<<~HEREDOC
|
||||
#{generate_user_detail}
|
||||
Category: #{feedback_message_params[:category_selection]}
|
||||
Category: #{feedback_message_params[:category]}
|
||||
Message: #{feedback_message_params[:message]}
|
||||
URL: #{params[:url]}
|
||||
HEREDOC
|
||||
|
|
@ -50,22 +51,13 @@ class FeedbackMessagesController < ApplicationController
|
|||
return "" unless current_user
|
||||
<<~HEREDOC
|
||||
*Logged in user:*
|
||||
username: #{current_user.username}
|
||||
email: #{current_user.email}
|
||||
username: #{current_user.username} - https://dev.to/#{current_user.username}
|
||||
email: <mailto:#{current_user.email}|#{current_user.email}>
|
||||
twitter: #{current_user.twitter_username}
|
||||
github: #{current_user.github_username}
|
||||
HEREDOC
|
||||
end
|
||||
|
||||
def form_filled?
|
||||
if feedback_message_params[:feedback_type] == "abuse-reports"
|
||||
feedback_message_params[:category_selection].present?
|
||||
else
|
||||
feedback_message_params[:message].present? ||
|
||||
feedback_message_params[:category_selection].present?
|
||||
end
|
||||
end
|
||||
|
||||
def emoji_for_feedback(feedback_type)
|
||||
case feedback_type
|
||||
when "abuse-reports"
|
||||
|
|
@ -78,6 +70,6 @@ class FeedbackMessagesController < ApplicationController
|
|||
end
|
||||
|
||||
def feedback_message_params
|
||||
params[:feedback_message].permit(:message, :feedback_type, :category_selection)
|
||||
params[:feedback_message].permit(:message, :feedback_type, :category, :reported_url)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
37
app/controllers/internal/feedback_messages_controller.rb
Normal file
37
app/controllers/internal/feedback_messages_controller.rb
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
class Internal::FeedbackMessagesController < Internal::ApplicationController
|
||||
layout "internal"
|
||||
|
||||
def index
|
||||
@feedback_type = params[:state] || "abuse-reports"
|
||||
@feedback_messages = FeedbackMessage.
|
||||
where(feedback_type: @feedback_type).
|
||||
order("created_at DESC").
|
||||
page(params[:page] || 1).per(25)
|
||||
end
|
||||
|
||||
def update
|
||||
@feedback_message = FeedbackMessage.find(params[:id])
|
||||
@feedback_message.status = feedback_message_params[:status]
|
||||
@feedback_message.reviewer_id = feedback_message_params[:reviewer_id]
|
||||
note = @feedback_message.find_or_create_note(@feedback_message.feedback_type)
|
||||
note.content = feedback_message_params[:note][:content]
|
||||
if @feedback_message.save! && note.save!
|
||||
@feedback_message.touch(:last_reviewed_at)
|
||||
flash[:success] = "Report ##{@feedback_message.id} saved. Remember to send emails!"
|
||||
redirect_to "/internal/reports?state=#{@feedback_message.feedback_type}"
|
||||
else
|
||||
@feedback_messages = FeedbackMessage.where(feedback_type: @feedback_type)
|
||||
flash[:error] = @feedback_message.errors.full_messages
|
||||
render "index.html.erb", state: @feedback_message.feedback_type
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def feedback_message_params
|
||||
params[:feedback_message].permit(
|
||||
:status, :reviewer_id,
|
||||
note: [:content, :reason],
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
@ -24,6 +24,13 @@ class PagesController < ApplicationController
|
|||
render "membership_form", layout: false
|
||||
end
|
||||
|
||||
def report_abuse
|
||||
@feedback_message = FeedbackMessage.new(
|
||||
reported_url: params[:reported_url] || params[:url] || request.referrer,
|
||||
)
|
||||
render "pages/report-abuse"
|
||||
end
|
||||
|
||||
def rlyweb
|
||||
set_surrogate_key_header "rlyweb"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class FeedbackMessageDashboard < Administrate::BaseDashboard
|
|||
id: Field::Number,
|
||||
message: Field::Text,
|
||||
feedback_type: Field::String,
|
||||
category_selection: Field::String,
|
||||
category: Field::String,
|
||||
}.freeze
|
||||
|
||||
# COLLECTION_ATTRIBUTES
|
||||
|
|
@ -34,7 +34,7 @@ class FeedbackMessageDashboard < Administrate::BaseDashboard
|
|||
:id,
|
||||
:message,
|
||||
:feedback_type,
|
||||
:category_selection,
|
||||
:category,
|
||||
].freeze
|
||||
|
||||
# FORM_ATTRIBUTES
|
||||
|
|
@ -44,7 +44,7 @@ class FeedbackMessageDashboard < Administrate::BaseDashboard
|
|||
:user,
|
||||
:message,
|
||||
:feedback_type,
|
||||
:category_selection,
|
||||
:category,
|
||||
].freeze
|
||||
|
||||
# Overwrite this method to customize how feedback messages are displayed
|
||||
|
|
|
|||
|
|
@ -48,4 +48,15 @@ class NotifyMailer < ApplicationMailer
|
|||
@badge = @badge_achievement.badge
|
||||
mail(to: @user.email, subject: "You just got a badge")
|
||||
end
|
||||
|
||||
def new_report_email(report)
|
||||
@feedback_message = report
|
||||
@user = report.reporter
|
||||
mail(to: @user.email, subject: "Thank you for your report")
|
||||
end
|
||||
|
||||
def reporter_resolution_email(report)
|
||||
@feedback_message = report
|
||||
@user = report.reporter
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,41 @@
|
|||
class FeedbackMessage < ApplicationRecord
|
||||
belongs_to :user, optional: true
|
||||
belongs_to :offender, foreign_key: "offender_id", class_name: "User", optional: true
|
||||
belongs_to :reviewer, foreign_key: "reviewer_id", class_name: "User", optional: true
|
||||
belongs_to :reporter, foreign_key: "reporter_id", class_name: "User", optional: true
|
||||
belongs_to :victim, foreign_key: "victim_id", class_name: "User", optional: true
|
||||
has_one :note, as: :noteable, dependent: :destroy
|
||||
|
||||
validates_presence_of :feedback_type, :message
|
||||
validates_presence_of :reported_url, :category, if: :abuse_report?
|
||||
validates :category,
|
||||
inclusion: {
|
||||
in: ["spam", "other", "rude or vulgar", "harassment", "bug"],
|
||||
}
|
||||
|
||||
before_validation :generate_slug
|
||||
|
||||
def abuse_report?
|
||||
feedback_type == "abuse-reports"
|
||||
end
|
||||
|
||||
def generate_slug
|
||||
self.slug = SecureRandom.hex(10) unless slug?
|
||||
end
|
||||
|
||||
def capitalize_status
|
||||
self.status = status.capitalize unless status.blank?
|
||||
end
|
||||
|
||||
def to_eastern_strftime(time)
|
||||
return if time.nil?
|
||||
time.in_time_zone("America/New_York").strftime("%A, %b %d %Y - %I:%M %p %Z")
|
||||
end
|
||||
|
||||
def path
|
||||
"/reports/#{slug}"
|
||||
end
|
||||
|
||||
def find_or_create_note(reason)
|
||||
note || Note.new(reason: reason, noteable_id: id, noteable_type: "FeedbackMessage")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
class Note < ApplicationRecord
|
||||
belongs_to :user
|
||||
validates :user_id, :reason, :content, presence: true
|
||||
validates :user_id, uniqueness:
|
||||
{ scope: :reason, message: "limited to one note per user per reason" }
|
||||
belongs_to :noteable, polymorphic: true
|
||||
validates :reason, :content, presence: true
|
||||
validates :noteable_id, uniqueness:
|
||||
{ scope: :reason, message: "limited to one note per noteable per reason" }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,13 +22,14 @@ class User < ApplicationRecord
|
|||
has_many :identities
|
||||
has_many :mentions
|
||||
has_many :messages
|
||||
has_many :notes
|
||||
has_many :notes, as: :noteable
|
||||
has_many :notifications
|
||||
has_many :reactions
|
||||
has_many :tweets
|
||||
has_many :chat_channel_memberships
|
||||
has_many :chat_channels, through: :chat_channel_memberships
|
||||
has_many :notification_subscriptions
|
||||
has_many :feedback_messages
|
||||
|
||||
mount_uploader :profile_image, ProfileImageUploader
|
||||
|
||||
|
|
@ -224,12 +225,12 @@ class User < ApplicationRecord
|
|||
|
||||
def reason_for_ban
|
||||
return if notes.where(reason: "banned").blank?
|
||||
Note.find_by(user_id: id, reason: "banned").content
|
||||
Note.find_by(noteable_id: id, noteable_type: "User", reason: "banned").content
|
||||
end
|
||||
|
||||
def reason_for_warning
|
||||
return if notes.where(reason: "warned").blank?
|
||||
Note.find_by(user_id: id, reason: "warned").content
|
||||
Note.find_by(noteable_id: id, noteable_type: "User", reason: "warned").content
|
||||
end
|
||||
|
||||
def scholar
|
||||
|
|
|
|||
|
|
@ -67,10 +67,11 @@ class UserRoleService
|
|||
end
|
||||
|
||||
def create_or_update_note(reason, content)
|
||||
note = Note.find_by(user_id: @user.id, reason: reason)
|
||||
note = Note.find_by(noteable_id: @user.id, noteable_type: "User", reason: reason)
|
||||
if note.nil?
|
||||
Note.create(
|
||||
user_id: @user.id,
|
||||
noteable_id: @user.id,
|
||||
noteable_type: "User",
|
||||
reason: reason,
|
||||
content: content,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
<span class="mod-actions hidden" style="display:none">
|
||||
<a href="<%=comment.path%>/mod" class="edit-butt" rel="nofollow" style="color:#0a0a0a">Moderate</a>
|
||||
</span>
|
||||
<a href="/report-abuse">Report Abuse</a>
|
||||
<a href="/report-abuse?url=https://dev.to<%= comment.path %>">Report Abuse</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,31 +1,51 @@
|
|||
<%= form_for FeedbackMessage.new do |f| %>
|
||||
<style>
|
||||
.reportedurlfield{
|
||||
max-width: 99%;
|
||||
border-radius: 3px;
|
||||
font-size: 18px;
|
||||
background-color: white;
|
||||
padding: 2px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.messagefield{
|
||||
width: 100%;
|
||||
resize: none;
|
||||
font-size: 18px;
|
||||
height: 100px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
</style>
|
||||
<%= form_for feedback_message do |f| %>
|
||||
<input name="utf8" type="hidden" value="✓" />
|
||||
<%= f.hidden_field :feedback_type, value:"abuse-reports" %>
|
||||
<input name="url" type="hidden" value="<%= request.referrer %>" />
|
||||
<div class="field">
|
||||
<ul style="list-style-type:none; margin-left:0px;">
|
||||
<li>
|
||||
<%= f.radio_button :category_selection, "rude or vulgar", required: 'required' %>
|
||||
<%= label_tag(:category_selection_rude, "Rude or vulgar") %>
|
||||
<%= f.radio_button :category, "rude or vulgar", required: 'required' %>
|
||||
<%= label_tag(:category_rude, "Rude or vulgar") %>
|
||||
</li>
|
||||
<li>
|
||||
<%= f.radio_button :category_selection, "harassment" %>
|
||||
<%= label_tag(:category_selection_harassment, "Harassment or hate speech") %>
|
||||
<%= f.radio_button :category, "harassment" %>
|
||||
<%= label_tag(:category_harassment, "Harassment or hate speech") %>
|
||||
</li>
|
||||
<li>
|
||||
<%= f.radio_button :category_selection, "spam" %>
|
||||
<%= label_tag(:category_selection_spam, "Spam or copyright issue") %>
|
||||
<%= f.radio_button :category, "spam" %>
|
||||
<%= label_tag(:category_spam, "Spam or copyright issue") %>
|
||||
</li>
|
||||
<li>
|
||||
<%= f.radio_button :category_selection, "other" %>
|
||||
<%= label_tag(:category_selection_other, "Other") %>
|
||||
<%= f.radio_button :category, "other" %>
|
||||
<%= label_tag(:category_other, "Other") %>
|
||||
</li>
|
||||
</ul>
|
||||
Reported URL:
|
||||
<%= f.text_field :reported_url, class: "reportedurlfield", value: feedback_message.reported_url, style: "width:100%;font-size: 18px; border-radius:3px;", required: true %>
|
||||
<p style="margin-bottom:0px;">
|
||||
<%= f.text_area :message, style:"width:100%;resize:none;font-size:18px;height:100px;border-radius:3px;", placeholder:"Please provide any additional information, such as an URL, that will help us understand and handle the situation.", value: @previous_message %>
|
||||
<%= f.label :message %>:
|
||||
<%= f.text_area :message, class: "messagefield", placeholder:"Please provide any additional information or context that will help us understand and handle the situation.", value: @previous_message %>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<% if flash[:notice] %>
|
||||
<div class="notice" id="notice">
|
||||
|
|
@ -33,6 +53,6 @@
|
|||
</div>
|
||||
<% end %>
|
||||
<%= recaptcha_tags site_key: ENV['RECAPTCHA_SITE'] %>
|
||||
<input type="submit" name="commit" value="Send Feedback" style="color:white;background:#424874;margin-top:50px;margin-bottom:25px;border:0px;cursor:pointer;padding:5px 14px;font-size:18px;border-radius:3px;" />
|
||||
<input type="submit" name="commit" value="Send Feedback" style="margin-top: 40px;" />
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -1,25 +1,6 @@
|
|||
<style>
|
||||
body {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||||
font-weight: 300;
|
||||
}
|
||||
.dialog{
|
||||
background:rgb(236, 236, 236);
|
||||
border:1px solid rgb(217, 217, 217);
|
||||
text-align:center;
|
||||
padding:20px 0px;
|
||||
margin:10% auto;
|
||||
width:80%;
|
||||
max-width:600px;
|
||||
color:rgb(44, 46, 50);
|
||||
border-radius:5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="dialog">
|
||||
<div>
|
||||
<h1>Thank you.</h1>
|
||||
<h2><a href="/">Return to home page</a></h2>
|
||||
<h2>Thank you for your report. You can view the <br><a href="<%= @feedback_message.path %>">status of your report here.</a></h2>
|
||||
<h3><a href="/">Return to home page</a></h3>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
30
app/views/feedback_messages/show.html.erb
Normal file
30
app/views/feedback_messages/show.html.erb
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<meta name="robots" content="noindex" />
|
||||
<div class="dialog">
|
||||
<h1>Thank you for your report. You can use this link to check for any updates on your report:</h1>
|
||||
<h3>https://dev.to<%= @feedback_message.path %></h3>
|
||||
<p style="color: white;background-color:#d10000;">Note that the link above is public, but secret.</p>
|
||||
<div class="report-body">
|
||||
<h3>Current Status: <%= @feedback_message.status %></h3>
|
||||
<% if @feedback_message.feedback_type == "abuse-reports" %>
|
||||
<h3>
|
||||
Reported URL: <%= link_to @feedback_message.reported_url, @feedback_message.reported_url, target: "_blank" %>
|
||||
<br>
|
||||
<small>(Opens in a new tab)</small>
|
||||
</h3>
|
||||
<hr>
|
||||
<h4>Category: <%= @feedback_message.category %></h4>
|
||||
<% end %>
|
||||
<h4>Message:</h4>
|
||||
<p>
|
||||
<% if @feedback_message.message.blank? %>
|
||||
<span class="blankmessage">No message was left.</span>
|
||||
<% else %>
|
||||
<%= @feedback_message.message %>
|
||||
<% end %>
|
||||
</p>
|
||||
</div>
|
||||
<hr>
|
||||
<p>
|
||||
Questions? Send an email to <a href="mailto:yo@dev.to">yo@dev.to</a>
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<style>
|
||||
.notefield{
|
||||
width: 100%;
|
||||
resize: none;
|
||||
font-size: 18px;
|
||||
height: 100px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.blankmessage{
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h2>
|
||||
Report #<%= feedback_message.id %> - Submitted on: <%= feedback_message.to_eastern_strftime(feedback_message.created_at) %>
|
||||
<hr>
|
||||
Reporter:
|
||||
<% if feedback_message.reporter_id? %>
|
||||
<%= feedback_message.reporter.name %>
|
||||
<a href="<%= feedback_message.reporter.path %>">@<%= feedback_message.reporter.username %></a>
|
||||
--
|
||||
Email: <a href="mailto:<%= feedback_message.reporter.email %>"><%= feedback_message.reporter.email %></a>
|
||||
<% else %>
|
||||
Anonymous
|
||||
<% end %>
|
||||
</h2>
|
||||
<h3>
|
||||
Reported URL (new tab):
|
||||
<br>
|
||||
<a href="<%= feedback_message.reported_url %>" target="_blank"><%= feedback_message.reported_url %></a>
|
||||
</h3>
|
||||
<h3>Category: <%= feedback_message.category %></h3>
|
||||
<h3>
|
||||
Message:
|
||||
</h3>
|
||||
<p>
|
||||
<% if feedback_message.message.blank? %>
|
||||
<span class="blankmessage">No message was left.</span>
|
||||
<% else %>
|
||||
<%= feedback_message.message %>
|
||||
<% end %>
|
||||
</p>
|
||||
<hr>
|
||||
<h3>
|
||||
Status: <%= f.select :status, ['Open', 'Closed', 'Resolved'] %>
|
||||
</h3>
|
||||
<h3>Note:</h3>
|
||||
<%= f.fields_for :note do |note| %>
|
||||
<%= note.hidden_field :reason, value: feedback_message.feedback_type %>
|
||||
<%= note.text_area :content, value: feedback_message.note&.content, placeholder: "Leave some notes about the status and context of this report.", class: "notefield" %>
|
||||
<% end %>
|
||||
<%= f.hidden_field :reviewer_id, value: current_user.id %>
|
||||
<% if feedback_message.reviewer_id %>
|
||||
<h4>Last reviewed by: <%= feedback_message.reviewer.name %></h4>
|
||||
<h4>Last reviewed on: <%= feedback_message.to_eastern_strftime(feedback_message.last_reviewed_at) %></h4>
|
||||
<% else %>
|
||||
<h4>Last reviewed by: No one yet</h4>
|
||||
<% end %>
|
||||
<br>
|
||||
<button class="btn btn-primary" type="submit">SUBMIT</button>
|
||||
31
app/views/internal/feedback_messages/index.html.erb
Normal file
31
app/views/internal/feedback_messages/index.html.erb
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<style>
|
||||
.top-nav{
|
||||
line-height: 1.4em;
|
||||
}
|
||||
.top-nav a {
|
||||
display: inline-block;
|
||||
padding: 10px;
|
||||
}
|
||||
.active-state {
|
||||
background-color:#89ffba;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h3 class="top-nav">
|
||||
<a href="/internal/reports?state=abuse-reports" class="<%= "active-state" if @feedback_type == "abuse-reports" %>">Abuse Reports</a> |
|
||||
<a href="/internal/reports?state=bug-reports" class="<%= "active-state" if @feedback_type == "bug-reports" %>">Bug Reports</a>
|
||||
</h3>
|
||||
|
||||
<h1><%= @feedback_type.titleize %></h1>
|
||||
|
||||
<%= paginate @feedback_messages %>
|
||||
|
||||
<% @feedback_messages.each do |feedback_message| %>
|
||||
<div class="row main-group">
|
||||
<%= form_for [:internal, feedback_message] do |f| %>
|
||||
<%= render "feedback_message", f: f, feedback_message: feedback_message %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<br>
|
||||
|
|
@ -89,14 +89,10 @@
|
|||
</div>
|
||||
<div id="navbar" class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="<%= "active" if controller_name == "comments"%>"><a href="/internal/comments">comments</a></li>
|
||||
<li class="<%= "active" if controller_name == "articles"%>"><a href="/internal/articles">articles</a></li>
|
||||
<li class="<%= "active" if controller_name == "users"%>"><a href="/internal/users">users</a></li>
|
||||
<li class="<%= "active" if controller_name == "members"%>"><a href="/internal/members">members</a></li>
|
||||
<li class="<%= "active" if controller_name == "dogfood"%>"><a href="/internal/dogfood">dog food</a></li>
|
||||
<li class="<%= "active" if controller_name == "tags"%>"><a href="/internal/tags">tags</a></li>
|
||||
<li class="<%= "active" if controller_name == "welcome"%>"><a href="/internal/welcome">welcome</a></li>
|
||||
<li class="<%= "active" if controller_name == "broadcasts"%>"><a href="/internal/broadcasts">broadcasts</a></li>
|
||||
<% controller_names = %w(comments articles users members dogfood tags welcome broadcasts reports) %>
|
||||
<% controller_names.each do |name| %>
|
||||
<li class="<%= "active" if controller_name == name %>"><a href="/internal/<%= name %>"><%= name %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
Thank you for your report. You can check the status of your report here:
|
||||
<br>
|
||||
<a href="https://dev.to<%= @feedback_message.path %>">https://dev.to<%= @feedback_message.path %></a>
|
||||
<br>
|
||||
<br>
|
||||
If you have any questions, feel free to reply to this email, or send an email to <a href="mailto:yo@dev.to">yo@dev.to</a>.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Thank you for your report. You can check the status of your report here:
|
||||
https://dev.to<%= @feedback_message.path %>
|
||||
|
||||
If you have any questions, feel free to reply to this email, or send an email to yo@dev.to.
|
||||
|
|
@ -24,6 +24,6 @@
|
|||
<p>
|
||||
Thank you for reporting any abuse that violates our <a href="/code-of-conduct">code of conduct</a> or <a href="/terms">terms and conditions</a>. We continue to try to make this environment a great one for everybody.
|
||||
</p>
|
||||
<%= render 'feedback_messages/form' %>
|
||||
<%= render 'feedback_messages/form', feedback_message: @feedback_message %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ Rails.application.routes.draw do
|
|||
end
|
||||
resources :members, only: [:index]
|
||||
resources :events
|
||||
resources :feedback_messages, only: [:update]
|
||||
resources :reports, only: [:index, :update], controller: "feedback_messages"
|
||||
mount Flipflop::Engine => "/features"
|
||||
end
|
||||
|
||||
|
|
@ -72,10 +74,11 @@ Rails.application.routes.draw do
|
|||
resources :messages, only: [:create]
|
||||
resources :chat_channels, only: [:index, :show]
|
||||
resources :articles, only: [:update,:create,:destroy]
|
||||
resources :comments, only:[:create,:update,:destroy]
|
||||
resources :users, only:[:update]
|
||||
resources :reactions, only: [:index,:create]
|
||||
resources :comments, only: [:create,:update,:destroy]
|
||||
resources :users, only: [:update]
|
||||
resources :reactions, only: [:index, :create]
|
||||
resources :feedback_messages, only: [:create]
|
||||
get "/reports/:slug", to: "feedback_messages#show"
|
||||
resources :organizations, only: [:update, :create]
|
||||
resources :followed_articles, only: [:index]
|
||||
resources :follows, only: [:index,:show,:create]
|
||||
|
|
@ -158,7 +161,7 @@ Rails.application.routes.draw do
|
|||
get "/rlyweb" => "pages#rlyweb"
|
||||
get "/rly" => "pages#rlyweb"
|
||||
get "/code-of-conduct" => "pages#code_of_conduct"
|
||||
get "/report-abuse" => "pages#report-abuse"
|
||||
get "/report-abuse" => "pages#report_abuse"
|
||||
get "/infiniteloop" => "pages#infinite_loop"
|
||||
get "/faq" => "pages#faq"
|
||||
get "/live" => "pages#live"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
class AddColumnsToFeedbackMessages < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
add_column :feedback_messages, :created_at, :datetime
|
||||
add_column :feedback_messages, :updated_at, :datetime
|
||||
add_column :feedback_messages, :last_reviewed_at, :datetime
|
||||
add_column :feedback_messages, :status, :string, default: "Open"
|
||||
add_column :feedback_messages, :victim_email_sent?, :boolean, default: false
|
||||
add_column :feedback_messages, :reporter_email_sent?, :boolean, default: false
|
||||
add_column :feedback_messages, :offender_email_sent?, :boolean, default: false
|
||||
add_column :feedback_messages, :slug, :string
|
||||
add_column :feedback_messages, :reported_url, :string
|
||||
rename_column :feedback_messages, :user_id, :reporter_id
|
||||
rename_column :feedback_messages, :category_selection, :category
|
||||
add_column :feedback_messages, :reviewer_id, :integer
|
||||
add_column :feedback_messages, :offender_id, :integer
|
||||
add_column :feedback_messages, :victim_id, :integer
|
||||
end
|
||||
end
|
||||
6
db/migrate/20180608195204_change_notes_to_polymorphic.rb
Normal file
6
db/migrate/20180608195204_change_notes_to_polymorphic.rb
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class ChangeNotesToPolymorphic < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
rename_column :notes, :user_id, :noteable_id
|
||||
add_column :notes, :noteable_type, :string
|
||||
end
|
||||
end
|
||||
19
db/schema.rb
19
db/schema.rb
|
|
@ -272,10 +272,22 @@ ActiveRecord::Schema.define(version: 20180612214259) do
|
|||
end
|
||||
|
||||
create_table "feedback_messages", force: :cascade do |t|
|
||||
t.string "category_selection"
|
||||
t.string "category"
|
||||
t.datetime "created_at"
|
||||
t.string "feedback_type"
|
||||
t.datetime "last_reviewed_at"
|
||||
t.text "message"
|
||||
t.integer "user_id"
|
||||
t.boolean "offender_email_sent?", default: false
|
||||
t.integer "offender_id"
|
||||
t.string "reported_url"
|
||||
t.boolean "reporter_email_sent?", default: false
|
||||
t.integer "reporter_id"
|
||||
t.integer "reviewer_id"
|
||||
t.string "slug"
|
||||
t.string "status", default: "Open"
|
||||
t.datetime "updated_at"
|
||||
t.boolean "victim_email_sent?", default: false
|
||||
t.integer "victim_id"
|
||||
end
|
||||
|
||||
create_table "flipflop_features", force: :cascade do |t|
|
||||
|
|
@ -373,9 +385,10 @@ ActiveRecord::Schema.define(version: 20180612214259) do
|
|||
create_table "notes", id: :serial, force: :cascade do |t|
|
||||
t.text "content"
|
||||
t.datetime "created_at", null: false
|
||||
t.integer "noteable_id"
|
||||
t.string "noteable_type"
|
||||
t.string "reason"
|
||||
t.datetime "updated_at", null: false
|
||||
t.integer "user_id"
|
||||
end
|
||||
|
||||
create_table "notifications", id: :serial, force: :cascade do |t|
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
</style>
|
||||
<script src='https://www.google.com/recaptcha/api.js'></script>
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
<!-- This file lives in public/500.html -->
|
||||
<div class="dialog">
|
||||
|
|
@ -67,6 +67,8 @@
|
|||
<form action="/feedback_messages" accept-charset="UTF-8" method="post">
|
||||
<input name="utf8" type="hidden" value="✓" />
|
||||
<input name="feedback_message[feedback_type]" type="hidden" value="bug-reports" />
|
||||
<input type="hidden" name="feedback_message[reported_url]" value="">
|
||||
<input type="hidden" name="feedback_message[category]" value="bug">
|
||||
<div class="field">
|
||||
<textarea name="feedback_message[message]" placeholder="If you would like to describe the situation that lead to this error, it would be appreciated :)" required></textarea>
|
||||
</div>
|
||||
|
|
|
|||
25
spec/factories/feedback_messages.rb
Normal file
25
spec/factories/feedback_messages.rb
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
FactoryBot.define do
|
||||
factory :feedback_message do
|
||||
transient do
|
||||
reporter_id 1
|
||||
end
|
||||
|
||||
after(:create) do |feedback_message, evaluator|
|
||||
feedback_message.update(reporter_id: evaluator.reporter_id)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
trait :abuse_report do
|
||||
feedback_type { "abuse-reports" }
|
||||
message { "this is spam" }
|
||||
category { "spam" }
|
||||
reported_url { "https://dev.to" }
|
||||
end
|
||||
|
||||
trait :bug_report do
|
||||
feedback_type { "bug-reports" }
|
||||
message { "i clicked something and this happened" }
|
||||
category { "bugs" }
|
||||
end
|
||||
end
|
||||
|
|
@ -12,6 +12,7 @@ RSpec.describe NotifyMailer, type: :mailer do
|
|||
new_reply_email = described_class.new_reply_email(comment)
|
||||
expect(new_reply_email.subject).to include("replied to your")
|
||||
end
|
||||
|
||||
it "renders proper receiver" do
|
||||
new_reply_email = described_class.new_reply_email(comment)
|
||||
expect(new_reply_email.to).to eq([comment.user.email])
|
||||
|
|
@ -24,6 +25,7 @@ RSpec.describe NotifyMailer, type: :mailer do
|
|||
new_follower_email = described_class.new_follower_email(Follow.last)
|
||||
expect(new_follower_email.subject).to eq("#{user2.name} just followed you on dev.to")
|
||||
end
|
||||
|
||||
it "renders proper receiver" do
|
||||
user2.follow(user)
|
||||
new_follower_email = described_class.new_follower_email(Follow.last)
|
||||
|
|
@ -37,11 +39,48 @@ RSpec.describe NotifyMailer, type: :mailer do
|
|||
new_mention_email = described_class.new_mention_email(mention)
|
||||
expect(new_mention_email.subject).to include("#{comment.user.name} just mentioned you")
|
||||
end
|
||||
|
||||
it "renders proper receiver" do
|
||||
mention = create(:mention, user_id: user2.id, mentionable_id: comment.id)
|
||||
new_mention_email = described_class.new_mention_email(mention)
|
||||
expect(new_mention_email.to).to eq([user2.email])
|
||||
end
|
||||
end
|
||||
|
||||
describe "#new_badge_email" do
|
||||
let(:badge) { create(:badge) }
|
||||
|
||||
it "renders proper subject" do
|
||||
badge_achievement = BadgeAchievement.create(user_id: user.id,
|
||||
badge_id: badge.id,
|
||||
rewarder_id: user2.id,
|
||||
rewarding_context_message_markdown: "Hello [Yoho](/hey)")
|
||||
new_badge_email = described_class.new_badge_email(badge_achievement)
|
||||
expect(new_badge_email.subject).to eq("You just got a badge")
|
||||
end
|
||||
|
||||
it "renders proper receiver" do
|
||||
badge_achievement = BadgeAchievement.create(user_id: user.id,
|
||||
badge_id: badge.id,
|
||||
rewarder_id: user2.id,
|
||||
rewarding_context_message_markdown: "Hello [Yoho](/hey)")
|
||||
new_badge_email = described_class.new_badge_email(badge_achievement)
|
||||
expect(new_badge_email.to).to eq([user.email])
|
||||
end
|
||||
end
|
||||
|
||||
describe "#new_report_email" do
|
||||
it "renders proper subject" do
|
||||
feedback_message = create(:feedback_message, :abuse_report, reporter_id: user.id)
|
||||
new_report_email = described_class.new_report_email(feedback_message)
|
||||
expect(new_report_email.subject).to eq("Thank you for your report")
|
||||
end
|
||||
|
||||
it "renders proper receiver" do
|
||||
feedback_message = create(:feedback_message, :abuse_report, reporter_id: user.id)
|
||||
new_report_email = described_class.new_report_email(feedback_message)
|
||||
expect(new_report_email.to).to eq([user.email])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,4 +23,8 @@ class NotifyMailerPreview < ActionMailer::Preview
|
|||
def new_badge_email
|
||||
NotifyMailer.new_badge_email(BadgeAchievement.first)
|
||||
end
|
||||
|
||||
def new_report_email
|
||||
NotifyMailer.new_report_email(FeedbackMessage.first)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
49
spec/models/feedback_message_spec.rb
Normal file
49
spec/models/feedback_message_spec.rb
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe FeedbackMessage, type: :model do
|
||||
let(:user) { create(:user) }
|
||||
let(:abuse_report) { create(:feedback_message, :abuse_report) }
|
||||
|
||||
describe "validations for an abuse report" do
|
||||
subject do
|
||||
FeedbackMessage.new(
|
||||
feedback_type: "abuse-reports",
|
||||
reported_url: "https://dev.to",
|
||||
category: "spam",
|
||||
message: "something",
|
||||
)
|
||||
end
|
||||
|
||||
it { is_expected.to validate_presence_of(:feedback_type) }
|
||||
it { is_expected.to validate_presence_of(:reported_url) }
|
||||
it { is_expected.to validate_presence_of(:message) }
|
||||
|
||||
it do
|
||||
is_expected.to validate_inclusion_of(:category).
|
||||
in_array(["spam", "other", "rude or vulgar", "harassment", "bug"])
|
||||
end
|
||||
end
|
||||
|
||||
describe "validations for a bug report" do
|
||||
subject do
|
||||
FeedbackMessage.new(
|
||||
feedback_type: "bug-reports",
|
||||
category: "bug",
|
||||
message: "something",
|
||||
)
|
||||
end
|
||||
|
||||
it { is_expected.to validate_presence_of(:feedback_type) }
|
||||
it { is_expected.to validate_presence_of(:message) }
|
||||
it { is_expected.not_to validate_presence_of(:reported_url) }
|
||||
|
||||
it do
|
||||
is_expected.to validate_inclusion_of(:category).
|
||||
in_array(["spam", "other", "rude or vulgar", "harassment", "bug"])
|
||||
end
|
||||
end
|
||||
|
||||
it "always generates a slug" do
|
||||
expect(abuse_report.slug).not_to be_nil
|
||||
end
|
||||
end
|
||||
|
|
@ -3,17 +3,53 @@ require "rails_helper"
|
|||
RSpec.describe "feedback_messages", type: :request do
|
||||
describe "POST /feedback_messages" do
|
||||
before do
|
||||
allow_any_instance_of(FeedbackMessagesController).to receive(:recaptcha_verified?).and_return(true)
|
||||
allow_any_instance_of(FeedbackMessagesController).
|
||||
to receive(:recaptcha_verified?).and_return(true)
|
||||
allow_any_instance_of(Slack::Notifier).to receive(:ping).and_return(true)
|
||||
end
|
||||
it "creates feedback message with filled form" do
|
||||
new_body = "NEW BODY #{rand(100)}"
|
||||
post "/feedback_messages", params: {
|
||||
feedback_message: { feedback_type: "abuse-reports",
|
||||
category_selection: "other",
|
||||
message: new_body },
|
||||
}
|
||||
expect(FeedbackMessage.last.message).to eq(new_body)
|
||||
|
||||
valid_abuse_report_params = {
|
||||
feedback_message: {
|
||||
feedback_type: "abuse-reports",
|
||||
category: "rude or vulgar",
|
||||
reported_url: "https://dev.to",
|
||||
message: "this was vulgar",
|
||||
},
|
||||
}
|
||||
|
||||
context "with valid params" do
|
||||
before do
|
||||
post "/feedback_messages", params: valid_abuse_report_params
|
||||
end
|
||||
|
||||
it "creates feedback message with filled form" do
|
||||
expect(FeedbackMessage.last.message).to eq(
|
||||
valid_abuse_report_params[:feedback_message][:message],
|
||||
)
|
||||
end
|
||||
|
||||
it "redirects to the ticket page" do
|
||||
expect(response).to redirect_to(FeedbackMessage.last.path)
|
||||
end
|
||||
end
|
||||
|
||||
context "when a logged in user submits report" do
|
||||
let!(:user) { create(:user) }
|
||||
let(:mail_message) { instance_double(Mail::Message, deliver: true) }
|
||||
|
||||
before do
|
||||
allow(NotifyMailer).to receive(:new_report_email).and_return(mail_message)
|
||||
login_as(user)
|
||||
post "/feedback_messages", params: valid_abuse_report_params
|
||||
end
|
||||
|
||||
it "adds the logged in user as as the reporter" do
|
||||
expect(FeedbackMessage.find_by(reporter_id: user.id)).not_to eq(nil)
|
||||
end
|
||||
|
||||
it "sends an email to the reporter" do
|
||||
expect(NotifyMailer).to have_received(:new_report_email)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
42
spec/requests/internal_feedback_messages_update_spec.rb
Normal file
42
spec/requests/internal_feedback_messages_update_spec.rb
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe "/internal/feedback_messages", type: :request do
|
||||
describe "PUTS /internal/feedback_messages" do
|
||||
context "with a valid request" do
|
||||
let(:feedback_message) { create(:feedback_message, :abuse_report) }
|
||||
let(:admin) { create(:user, :super_admin) }
|
||||
|
||||
valid_abuse_report_params = {
|
||||
feedback_message: {
|
||||
id: 1,
|
||||
status: "Resolved",
|
||||
note: {
|
||||
content: "this is valid",
|
||||
reason: "abuse-reports",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
before do
|
||||
login_as(admin)
|
||||
valid_abuse_report_params[:feedback_message][:reviewer_id] = admin.id
|
||||
patch "/internal/feedback_messages/#{feedback_message.id}", params:
|
||||
valid_abuse_report_params
|
||||
end
|
||||
|
||||
it "adds a note to a report" do
|
||||
expect(FeedbackMessage.last.note.content).to eq(
|
||||
valid_abuse_report_params[:feedback_message][:note][:content],
|
||||
)
|
||||
end
|
||||
|
||||
it "adds the current user as the reviewer" do
|
||||
expect(FeedbackMessage.find_by(reviewer_id: admin.id)).not_to eq(nil)
|
||||
end
|
||||
|
||||
it "updates the last_reviewed_at timestamp" do
|
||||
expect(FeedbackMessage.last.last_reviewed_at).not_to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue