canvas-lms/app/controllers/errors_controller.rb

180 lines
6.6 KiB
Ruby

#
# Copyright (C) 2011 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# @API Error Reports
#
# @model ErrorReport
# {
# "id": "ErrorReport",
# "description": "A collection of information around a specific notification of a problem",
# "properties": {
# "subject": {
# "description": "The users problem summary, like an email subject line",
# "type": "string",
# "example": "File upload breaking"
# },
# "comments": {
# "description": "long form documentation of what was witnessed",
# "type": "string",
# "example": "When I went to upload a .mov file to my files page, I got an error. Retrying didn't help, other file types seem ok"
# },
# "user_perceived_severity": {
# "description": "categorization of how bad the user thinks the problem is. Should be one of [just_a_comment, not_urgent, workaround_possible, blocks_what_i_need_to_do, extreme_critical_emergency].",
# "type": "string",
# "example": "just_a_comment"
# },
# "email": {
# "description": "the email address of the reporting user",
# "type": "string",
# "example": "name@example.com"
# },
# "url": {
# "description": "URL of the page on which the error was reported",
# "type": "string",
# "example": "https://canvas.instructure.com/courses/1"
# },
# "context_asset_string": {
# "description": "string describing the asset being interacted with at the time of error. Formatted '[type]_[id]'",
# "type": "string",
# "example": "user_1"
# },
# "user_roles": {
# "description": "comma seperated list of roles the reporting user holds. Can be one [student], or many [teacher,admin]",
# "type": "string",
# "example": "user,teacher,admin"
# }
# }
# }
#
class ErrorsController < ApplicationController
PER_PAGE = 20
before_filter :require_view_error_reports, except: [:create]
skip_before_filter :verify_authenticity_token, only: [:create]
def require_view_error_reports
require_site_admin_with_permission(:view_error_reports)
end
def index
params[:page] = params[:page].to_i > 0 ? params[:page].to_i : 1
@reports = ErrorReport.preload(:user)
@message = params[:message]
if error_search_enabled? && @message.present?
@reports = @reports.where("message LIKE ?", '%' + @message + '%')
elsif params[:category].blank?
@reports = @reports.where("category<>'404'")
end
if params[:category].present?
@reports = @reports.where(:category => params[:category])
end
@reports = @reports.order('created_at DESC').paginate(:per_page => PER_PAGE, :page => params[:page], :total_entries => nil)
end
def show
@reports = [ErrorReport.find(params[:id])]
render :index
end
# @API Create Error Report
#
# Create a new error report documenting an experienced problem
#
# Performs the same action as when a user uses the "help -> report a problem"
# dialog.
#
# @argument error[subject] [Required, String]
# The summary of the problem
#
# @argument error[url] [Optional, String]
# URL from which the report was issued
#
# @argument error[email] [Optional, String]
# Email address for the reporting user
#
# @argument error[comments] [Optional, String]
# The long version of the story from the user one what they experienced
#
# @argument error[http_env] [Optional, SerializedHash]
# A collection of metadata about the users' environment. If not provided,
# canvas will collect it based on information found in the request.
# (Doesn't have to be HTTPENV info, could be anything JSON object that can be
# serialized as a hash, a mobile app might include relevant metadata for
# itself)
#
# @example_request
# # Create error report
# curl 'https://<canvas>/api/v1/error_reports' \
# -X POST \
# -F 'error[subject]="things are broken"' \
# -F 'error[url]=http://<canvas>/courses/1' \
# -F 'error[description]="All my thoughts on what I saw"' \
# -H 'Authorization: Bearer <token>'
def create
# this action can be called by an unauthenticated user. To prevent
# abuse, we're representing this as an expensive operation so it would
# get quickly rate limited if hit repeatedly.
increment_request_cost(200)
reporter = @current_user.try(:fake_student?) ? @real_current_user : @current_user
error = params[:error] || {}
error[:user_agent] = request.headers['User-Agent']
begin
report_id = error.delete(:id)
report = ErrorReport.where(id: report_id.to_i).first if report_id.present? && report_id.to_i != 0
report ||= ErrorReport.where(id: session.delete(:last_error_id)).first if session[:last_error_id].present?
report ||= ErrorReport.new
error.delete(:category) if report.category.present?
report.user = reporter
report.account ||= @domain_root_account
backtrace = error.fetch(:backtrace, "")
if report.backtrace
backtrace += "\n\n-----------------------------------------\n\n"
backtrace += report.backtrace
end
report.backtrace = backtrace
report.http_env ||= Canvas::Errors::Info.useful_http_env_stuff_from_request(request)
report.request_context_id = RequestContextGenerator.request_id
report.assign_data(error)
report.save
report.send_later(:send_to_external)
rescue => e
@exception = e
Canvas::Errors.capture(
e,
message: "Error Report Creation failed",
user_email: error[:email],
user_id: reporter.try(:id)
)
end
respond_to do |format|
flash[:notice] = t('notices.error_reported', "Thanks for your help! We'll get right on this")
format.html { redirect_to root_url }
format.json { render json: {logged: true, id: report.try(:id) } }
end
end
def error_search_enabled?
Setting.get("error_search_enabled", "true") == "true"
end
helper_method :error_search_enabled?
end