diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 000000000..e69de29bb diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index c57a88f43..4a8240e81 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -2,7 +2,7 @@ module Admin class UsersController < Admin::ApplicationController def update user = User.find(params[:id]) - UserRoleService.new(user).check_for_roles(params[:user]) + UserRoleService.new(user, current_user.id).check_for_roles(params[:user]) if user.errors.messages.blank? && user.update(user_params) flash[:notice] = "User successfully updated" redirect_to "/admin/users/#{params[:id]}" diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index d1fa99c8b..904e103bb 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -102,7 +102,7 @@ class CommentsController < ApplicationController authorize @comment if @comment.update(permitted_attributes(@comment).merge(edited_at: Time.zone.now)) Mention.create_all(@comment) - redirect_to "#{@comment.commentable.path}/comments/#{@comment.id_code_generated}", notice: "Comment was successfully updated." + redirect_to @comment.path, notice: "Comment was successfully updated." else @commentable = @comment.commentable render :edit diff --git a/app/controllers/feedback_messages_controller.rb b/app/controllers/feedback_messages_controller.rb index fcc7dfaf3..426dcea89 100644 --- a/app/controllers/feedback_messages_controller.rb +++ b/app/controllers/feedback_messages_controller.rb @@ -9,7 +9,6 @@ class FeedbackMessagesController < ApplicationController ) if recaptcha_verified? && @feedback_message.save send_slack_message - # NotifyMailer.new_report_email(@feedback_message).deliver if @feedback_message.reporter_id? redirect_to "/feedback_messages" elsif feedback_message_params[:feedback_type] == "bug-reports" flash[:notice] = "Make sure the forms are filled 🤖 " @@ -21,10 +20,6 @@ class FeedbackMessagesController < ApplicationController end end - def show - @feedback_message = FeedbackMessage.find_by(slug: params[:slug]) - end - private def recaptcha_verified? diff --git a/app/controllers/internal/feedback_messages_controller.rb b/app/controllers/internal/feedback_messages_controller.rb index 693b1ac5b..bad0dcc30 100644 --- a/app/controllers/internal/feedback_messages_controller.rb +++ b/app/controllers/internal/feedback_messages_controller.rb @@ -3,26 +3,50 @@ class Internal::FeedbackMessagesController < Internal::ApplicationController def index @feedback_type = params[:state] || "abuse-reports" + @status = params[:status] || "Open" @feedback_messages = FeedbackMessage. - where(feedback_type: @feedback_type). + where(feedback_type: @feedback_type, status: @status). 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}" + def save_status + feedback_message = FeedbackMessage.find(params[:id]) + if feedback_message.update(status: params[:status]) + render json: { outcome: "Success" } 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 + render json: { outcome: feedback_message.errors.full_messages } + end + end + + def show + @feedback_message = FeedbackMessage.find_by(id: params[:id]) + end + + def send_email + if NotifyMailer.feedback_message_resolution_email(params).deliver + render json: { outcome: "Success" } + else + render json: { outcome: "Failure" } + end + end + + def create_note + note = Note.new( + noteable_id: params["noteable_id"], + noteable_type: params["noteable_type"], + author_id: params["author_id"], + content: params["content"], + reason: params["reason"], + ) + if note.save + render json: { + outcome: "Success", + content: params["content"], + author_name: note.author.name, + } + else + render json: { outcome: note.errors.full_messages } end end @@ -30,8 +54,8 @@ class Internal::FeedbackMessagesController < Internal::ApplicationController def feedback_message_params params[:feedback_message].permit( - :status, :reviewer_id, - note: %i[content reason] + :id, :status, :reviewer_id, + note: %i[content reason noteable_id noteable_type author_id] ) end end diff --git a/app/helpers/feedback_messages_helper.rb b/app/helpers/feedback_messages_helper.rb new file mode 100644 index 000000000..cf5d25afe --- /dev/null +++ b/app/helpers/feedback_messages_helper.rb @@ -0,0 +1,52 @@ +module FeedbackMessagesHelper + def offender_email_details + body = <<~HEREDOC + Hi [*USERNAME*], + + All dev.to members are expected to help foster a welcoming environment for the community and abide by our terms and conditions of use. It's been brought to our attention that you may have violated our code of conduct. If this behavior continues, we will need to ban your posting privileges on dev.to. + + If you think there's been a mistake, please reply to this email and we'll sort it out. + + Thanks, + dev.to team + HEREDOC + { + subject: "dev.to Status Update", + body: body, + }.freeze + end + + def reporter_email_details + body = <<~HEREDOC + Hi [*USERNAME*], + + We wanted to say thank you for flagging a [*comment/post*] that was in violation of the dev.to code of conduct and terms of service. Your action has helped us continue our work of fostering an open and welcoming community. + + We've also removed the offending posts and reached out to the offender(s). + + Thanks again for being a great part of the community. + + PBJ + HEREDOC + { + subject: "dev.to Status Update", + body: body, + }.freeze + end + + def victim_email_details + body = <<~HEREDOC + Hi [*USERNAME*], + + We noticed some comments (made by others) on your [*post/comment*] that violated the dev.to code of conduct. We want you to know that we have zero tolerance for such behavior, and have removed the offending posts and reached out to the offender(s). + + Thanks for being awesome and please don't hesitate to email us with any questions. We welcome all feedback and ideas as we continue our work of fostering an open and welcoming community. + + PBJ + HEREDOC + { + subject: "Courtesy Notice from dev.to", + body: body, + }.freeze + end +end diff --git a/app/mailers/notify_mailer.rb b/app/mailers/notify_mailer.rb index e0310a785..7dccb1de9 100644 --- a/app/mailers/notify_mailer.rb +++ b/app/mailers/notify_mailer.rb @@ -49,6 +49,14 @@ class NotifyMailer < ApplicationMailer mail(to: @user.email, subject: "You just got a badge") end + def feedback_message_resolution_email(params) + @user = User.find_by(email: params[:email_to]) + @email_body = params[:email_body] + track utm_campaign: params[:email_type] + track extra: { feedback_message_id: params[:feedback_message_id] } + mail(to: params[:email_to], subject: params[:email_subject]) + end + def new_report_email(report) @feedback_message = report @user = report.reporter diff --git a/app/models/email_message.rb b/app/models/email_message.rb index dd7f737b3..09c455632 100644 --- a/app/models/email_message.rb +++ b/app/models/email_message.rb @@ -2,4 +2,9 @@ class EmailMessage < Ahoy::Message # So far this is mostly used to be compatible with administrate gem, # which doesn't seem to play nicely with namespaces. But there could be other # reasons to define behavior here, similar to how we use the Tag model. + def body_html_content + doctype_index = content.index("") + 6 + content[doctype_index..closing_html_index] + end end diff --git a/app/models/feedback_message.rb b/app/models/feedback_message.rb index 32222314a..127f03594 100644 --- a/app/models/feedback_message.rb +++ b/app/models/feedback_message.rb @@ -3,7 +3,7 @@ class FeedbackMessage < ApplicationRecord 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 + has_many :notes, as: :noteable, dependent: :destroy validates_presence_of :feedback_type, :message validates_presence_of :reported_url, :category, if: :abuse_report? @@ -11,31 +11,20 @@ class FeedbackMessage < ApplicationRecord inclusion: { in: ["spam", "other", "rude or vulgar", "harassment", "bug"], } - - before_validation :generate_slug + validates :status, + inclusion: { + in: ["Open", "Invalid", "Resolved"], + } 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") + def email_messages + EmailMessage.where(feedback_message_id: id) end end diff --git a/app/models/note.rb b/app/models/note.rb index c2135b9bf..c6288e091 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -1,6 +1,5 @@ class Note < ApplicationRecord belongs_to :noteable, polymorphic: true + belongs_to :author, class_name: "User" validates :reason, :content, presence: true - validates :noteable_id, uniqueness: - { scope: :reason, message: "limited to one note per noteable per reason" } end diff --git a/app/models/notification.rb b/app/models/notification.rb index ce5422242..ecfa4abf0 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -51,7 +51,7 @@ class Notification < ApplicationRecord if notifiable.class.name == "Broadcast" || action == "Moderation" User.find(ApplicationConfig["DEVTO_USER_ID"]) else - notifiable.user + notifiable&.user end end diff --git a/app/models/user.rb b/app/models/user.rb index 0aa4237d0..6d4fa65df 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -23,6 +23,7 @@ class User < ApplicationRecord has_many :mentions, dependent: :destroy has_many :messages has_many :notes, as: :noteable + has_many :authored_notes, as: :author, class_name: "Note" has_many :notifications, dependent: :destroy has_many :reactions, dependent: :destroy has_many :tweets, dependent: :destroy diff --git a/app/services/user_role_service.rb b/app/services/user_role_service.rb index 58ca9b48e..80b9f1fa0 100644 --- a/app/services/user_role_service.rb +++ b/app/services/user_role_service.rb @@ -1,6 +1,7 @@ class UserRoleService - def initialize(user) + def initialize(user, current_user_id) @user = user + @current_user_id = current_user_id end def check_for_roles(params) @@ -34,7 +35,11 @@ class UserRoleService def new_roles?(params) params[:trusted] == "1" ? @user.add_role(:trusted) : @user.remove_role(:trusted) - params[:analytics] == "1" ? @user.add_role(:analytics_beta_tester) : @user.remove_role(:analytics_beta_tester) + if params[:analytics] == "1" + @user.add_role(:analytics_beta_tester) + else + @user.remove_role(:analytics_beta_tester) + end if params[:scholar] == "1" @user.add_role(:workshop_pass) @user.update(workshop_expiration: params[:workshop_expiration]) @@ -70,6 +75,7 @@ class UserRoleService note = Note.find_by(noteable_id: @user.id, noteable_type: "User", reason: reason) if note.nil? Note.create( + author_id: @current_user_id, noteable_id: @user.id, noteable_type: "User", reason: reason, diff --git a/app/views/feedback_messages/index.html.erb b/app/views/feedback_messages/index.html.erb index 3b3296550..80d8f8bfe 100644 --- a/app/views/feedback_messages/index.html.erb +++ b/app/views/feedback_messages/index.html.erb @@ -2,5 +2,8 @@
diff --git a/app/views/feedback_messages/show.html.erb b/app/views/feedback_messages/show.html.erb deleted file mode 100644 index ce28c3898..000000000 --- a/app/views/feedback_messages/show.html.erb +++ /dev/null @@ -1,30 +0,0 @@ - -Note that the link above is public, but secret.
-- <% if @feedback_message.message.blank? %> - - <% else %> - <%= @feedback_message.message %> - <% end %> -
-- Questions? Send an email to yo@dev.to -
-+ <% if feedback_message.message.blank? %> + + <% else %> + <%= feedback_message.message %> + <% end %> +
+Type: <%= email.utm_campaign.capitalize %>
+To: <%= email.to %>
+Subject: <%= email.subject %>
+ <%= email.body_html_content.html_safe %> +- <% if feedback_message.message.blank? %> - - <% else %> - <%= feedback_message.message %> - <% end %> -
-+ <%= note.author.name %>: <%= note.content %> +
+