forked from midou/invidious
Usually, next steps are after the error message. Here, we want the same options to be right above the stack trace, so users are less likely to report duplicates.
170 lines
6.4 KiB
Crystal
170 lines
6.4 KiB
Crystal
# InfoExceptions are for displaying information to the user.
|
|
#
|
|
# An InfoException might or might not indicate that something went wrong.
|
|
# Historically Invidious didn't differentiate between these two options, so to
|
|
# maintain previous functionality InfoExceptions do not print backtraces.
|
|
class InfoException < Exception
|
|
end
|
|
|
|
macro error_template(*args)
|
|
error_template_helper(env, locale, {{*args}})
|
|
end
|
|
|
|
def github_details(summary : String, content : String)
|
|
details = %(\n<details>)
|
|
details += %(\n<summary>#{summary}</summary>)
|
|
details += %(\n<p>)
|
|
details += %(\n \n```\n)
|
|
details += content.strip
|
|
details += %(\n```)
|
|
details += %(\n</p>)
|
|
details += %(\n</details>)
|
|
return HTML.escape(details)
|
|
end
|
|
|
|
def error_template_helper(env : HTTP::Server::Context, locale : String?, status_code : Int32, exception : Exception)
|
|
if exception.is_a?(InfoException)
|
|
return error_template_helper(env, locale, status_code, exception.message || "")
|
|
end
|
|
|
|
env.response.content_type = "text/html"
|
|
env.response.status_code = status_code
|
|
|
|
issue_title = "#{exception.message} (#{exception.class})"
|
|
|
|
issue_template = %(Title: `#{issue_title}`)
|
|
issue_template += %(\nDate: `#{Time::Format::ISO_8601_DATE_TIME.format(Time.utc)}`)
|
|
issue_template += %(\nRoute: `#{env.request.resource}`)
|
|
issue_template += %(\nVersion: `#{SOFTWARE["version"]} @ #{SOFTWARE["branch"]}`)
|
|
# issue_template += github_details("Preferences", env.get("preferences").as(Preferences).to_pretty_json)
|
|
issue_template += github_details("Backtrace", exception.inspect_with_backtrace)
|
|
|
|
# URLs for the error message below
|
|
url_faq = "https://github.com/iv-org/documentation/blob/master/FAQ.md"
|
|
url_search_issues = "https://github.com/iv-org/invidious/issues"
|
|
|
|
url_switch = "https://redirect.invidious.io" + env.request.resource
|
|
|
|
url_new_issue = "https://github.com/iv-org/invidious/issues/new"
|
|
url_new_issue += "?labels=bug&template=bug_report.md&title="
|
|
url_new_issue += URI.encode_www_form("[Bug] " + issue_title)
|
|
|
|
error_message = <<-END_HTML
|
|
<div class="error_message">
|
|
<h2>#{translate(locale, "crash_page_you_found_a_bug")}</h2>
|
|
<br/><br/>
|
|
|
|
<p><b>#{translate(locale, "crash_page_before_reporting")}</b></p>
|
|
<ul>
|
|
<li><a href="#{env.request.resource}">#{translate(locale, "crash_page_refresh")}</a></li>
|
|
<li><a href="#{url_switch}">#{translate(locale, "crash_page_switch_instance")}</a></li>
|
|
<li>#{translate(locale, "crash_page_read_the_faq", url_faq)}</li>
|
|
<li>#{translate(locale, "crash_page_search_issue", url_search_issues)}</li>
|
|
</ul>
|
|
|
|
<br/>
|
|
<p>#{translate(locale, "crash_page_report_issue", url_new_issue)}</p>
|
|
|
|
<!-- TODO: Add a "copy to clipboard" button -->
|
|
<pre style="padding: 20px; background: rgba(0, 0, 0, 0.12345);">#{issue_template}</pre>
|
|
</div>
|
|
END_HTML
|
|
|
|
# Don't show the usual "next steps" widget. The same options are
|
|
# proposed above the error message, just worded differently.
|
|
next_steps = ""
|
|
|
|
return templated "error"
|
|
end
|
|
|
|
def error_template_helper(env : HTTP::Server::Context, locale : String?, status_code : Int32, message : String)
|
|
env.response.content_type = "text/html"
|
|
env.response.status_code = status_code
|
|
error_message = translate(locale, message)
|
|
next_steps = error_redirect_helper(env, locale)
|
|
return templated "error"
|
|
end
|
|
|
|
macro error_atom(*args)
|
|
error_atom_helper(env, locale, {{*args}})
|
|
end
|
|
|
|
def error_atom_helper(env : HTTP::Server::Context, locale : String?, status_code : Int32, exception : Exception)
|
|
if exception.is_a?(InfoException)
|
|
return error_atom_helper(env, locale, status_code, exception.message || "")
|
|
end
|
|
env.response.content_type = "application/atom+xml"
|
|
env.response.status_code = status_code
|
|
return "<error>#{exception.inspect_with_backtrace}</error>"
|
|
end
|
|
|
|
def error_atom_helper(env : HTTP::Server::Context, locale : String?, status_code : Int32, message : String)
|
|
env.response.content_type = "application/atom+xml"
|
|
env.response.status_code = status_code
|
|
return "<error>#{message}</error>"
|
|
end
|
|
|
|
macro error_json(*args)
|
|
error_json_helper(env, locale, {{*args}})
|
|
end
|
|
|
|
def error_json_helper(env : HTTP::Server::Context, locale : String?, status_code : Int32, exception : Exception, additional_fields : Hash(String, Object) | Nil)
|
|
if exception.is_a?(InfoException)
|
|
return error_json_helper(env, locale, status_code, exception.message || "", additional_fields)
|
|
end
|
|
env.response.content_type = "application/json"
|
|
env.response.status_code = status_code
|
|
error_message = {"error" => exception.message, "errorBacktrace" => exception.inspect_with_backtrace}
|
|
if additional_fields
|
|
error_message = error_message.merge(additional_fields)
|
|
end
|
|
return error_message.to_json
|
|
end
|
|
|
|
def error_json_helper(env : HTTP::Server::Context, locale : String?, status_code : Int32, exception : Exception)
|
|
return error_json_helper(env, locale, status_code, exception, nil)
|
|
end
|
|
|
|
def error_json_helper(env : HTTP::Server::Context, locale : String?, status_code : Int32, message : String, additional_fields : Hash(String, Object) | Nil)
|
|
env.response.content_type = "application/json"
|
|
env.response.status_code = status_code
|
|
error_message = {"error" => message}
|
|
if additional_fields
|
|
error_message = error_message.merge(additional_fields)
|
|
end
|
|
return error_message.to_json
|
|
end
|
|
|
|
def error_json_helper(env : HTTP::Server::Context, locale : String?, status_code : Int32, message : String)
|
|
error_json_helper(env, locale, status_code, message, nil)
|
|
end
|
|
|
|
def error_redirect_helper(env : HTTP::Server::Context, locale : String?)
|
|
request_path = env.request.path
|
|
|
|
if request_path.starts_with?("/search") || request_path.starts_with?("/watch") ||
|
|
request_path.starts_with?("/channel") || request_path.starts_with?("/playlist?list=PL")
|
|
next_steps_text = translate(locale, "next_steps_error_message")
|
|
refresh = translate(locale, "next_steps_error_message_refresh")
|
|
go_to_youtube = translate(locale, "next_steps_error_message_go_to_youtube")
|
|
switch_instance = translate(locale, "Switch Invidious Instance")
|
|
|
|
return <<-END_HTML
|
|
<p style="margin-bottom: 4px;">#{next_steps_text}</p>
|
|
<ul>
|
|
<li>
|
|
<a href="#{env.request.resource}">#{refresh}</a>
|
|
</li>
|
|
<li>
|
|
<a href="/redirect?referer=#{env.get("current_page")}">#{switch_instance}</a>
|
|
</li>
|
|
<li>
|
|
<a href="https://youtube.com#{env.request.resource}">#{go_to_youtube}</a>
|
|
</li>
|
|
</ul>
|
|
END_HTML
|
|
else
|
|
return ""
|
|
end
|
|
end
|