[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:
Andy Zhao 2018-06-19 16:41:31 -04:00 committed by Ben Halpern
parent ec264bf802
commit ecbb9d4ab1
32 changed files with 572 additions and 96 deletions

View file

@ -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>\

View 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;
}

View file

@ -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

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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,
)

View file

@ -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>

View file

@ -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="&#x2713;" />
<%= 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 %>

View file

@ -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>

View 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>

View file

@ -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>

View 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>

View file

@ -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>

View file

@ -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>.

View file

@ -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.

View file

@ -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>

View file

@ -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"

View file

@ -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

View 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

View file

@ -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|

View file

@ -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="&#x2713;" />
<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>

View 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

View file

@ -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

View file

@ -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

View 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

View file

@ -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

View 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