Render error pages using our own templates (#9455)

pull/9479/head
Oliver Günther 3 years ago committed by GitHub
parent b7696a6c5c
commit b75fbcfc4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      app/controllers/errors_controller.rb
  2. 13
      app/helpers/meta_tags_helper.rb
  3. 53
      app/views/layouts/_common_head.html.erb
  4. 61
      app/views/layouts/base.html.erb
  5. 8
      app/views/layouts/only_logo.html.erb
  6. 3
      config/application.rb
  7. 5
      config/routes.rb
  8. 52
      public/404.html
  9. 55
      public/500.html
  10. 28
      spec/features/errors/errors_handler_spec.rb
  11. 35
      spec/routing/errors_routing_spec.rb

@ -0,0 +1,25 @@
class ErrorsController < ::ActionController::Base
include ErrorsHelper
include OpenProjectErrorHelper
include Accounts::CurrentUser
def not_found
render_404
end
def unacceptable
render file: "#{Rails.root}/public/422.html",
status: :unacceptable,
layout: false
end
def internal_error
render_500
end
private
def use_layout
'only_logo'
end
end

@ -38,6 +38,19 @@ module MetaTagsHelper
reverse: true
end
def initializer_meta_tag
tag :meta,
name: :openproject_initializer,
data: {
locale: I18n.locale,
defaultLocale: I18n.default_locale,
firstWeekOfYear: locale_first_week_of_year,
firstDayOfWeek: locale_first_day_of_week,
environment: Rails.env,
edition: OpenProject::Configuration.edition
}
end
##
# Writer of html_title as string
def html_title(*args)

@ -0,0 +1,53 @@
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width">
<%= output_title_and_meta_tags %>
<%= sentry_frontend_tags %>
<% relative_url_root = OpenProject::Configuration['rails_relative_url_root'] || '' %>
<meta name="app_base_path" content="<%= relative_url_root %>"/>
<base href="<%= relative_url_root %>/" />
<% if @project %>
<meta name="current_project"
data-project-name="<%= h @project.name %>"
data-project-id="<%= @project.id %>"
data-project-identifier="<%= @project.identifier %>"/>
<% end %>
<% unless User.current.anonymous? %>
<meta name="current_user"
data-name="<%= User.current.name %>"
data-mail="<%= User.current.mail %>"
data-id="<%= User.current.id %>" />
<% end %>
<% if Setting.demo_projects_available %><meta name="demo_projects_available" content="true"/><% end %>
<% if Setting.boards_demo_data_available %><meta name="boards_demo_data_available" content="true"/><% end %>
<%= csrf_meta_tags %>
<%= initializer_meta_tag %>
<!-- global meta hooks before any scripts are loaded-->
<%= call_hook :view_layouts_base_html_meta %>
<%= render 'common/favicons' %>
<%# Include CLI assets (development) or prod build assets %>
<%= include_frontend_assets %>
<%# Render CSS highlighting %>
<%= stylesheet_link_tag "/highlighting/styles/#{highlight_css_version_tag}",
media: :all,
skip_pipeline: true %>
<%# Custom styles %>
<%= render partial: "custom_styles/inline_css_logo" %>
<% if apply_custom_styles? %>
<% cache(CustomStyle.current) do %>
<%= render partial: "custom_styles/inline_css" %>
<% if CustomStyle.current.favicon.present? %>
<link rel="icon" type="image/png" href="<%= custom_style_favicon_path(digest: CustomStyle.current.digest, filename: CustomStyle.current.favicon_identifier) %>" sizes="32x32">
<% end %>
<% if CustomStyle.current.touch_icon.present? %>
<link rel="apple-touch-icon" sizes="180x180" href="<%= custom_style_touch_icon_path(digest: CustomStyle.current.digest, filename: CustomStyle.current.touch_icon_identifier) %>">
<% end %>
<% end %>
<% end %>
<%= crowdin_in_context_translation %>

@ -32,69 +32,12 @@ See docs/COPYRIGHT.rdoc for more details.
xml:lang="<%= I18n.locale.to_s %>"
class="<%= 'in_modal' unless show_decoration %>">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width">
<%= output_title_and_meta_tags %>
<%= sentry_frontend_tags %>
<% relative_url_root = OpenProject::Configuration['rails_relative_url_root'] || '' %>
<meta name="app_base_path" content="<%= relative_url_root %>"/>
<base href="<%= relative_url_root %>/" />
<% if @project %>
<meta name="current_project"
data-project-name="<%= h @project.name %>"
data-project-id="<%= @project.id %>"
data-project-identifier="<%= @project.identifier %>"/>
<% end %>
<% unless User.current.anonymous? %>
<meta name="current_user"
data-name="<%= User.current.name %>"
data-mail="<%= User.current.mail %>"
data-id="<%= User.current.id %>" />
<% end %>
<meta name="openproject_initializer"
data-locale="<%= I18n.locale %>"
data-first-week-of-year="<%= locale_first_week_of_year %>"
data-first-day-of-week="<%= locale_first_day_of_week %>"
data-default-locale="<%= I18n.default_locale %>"
data-environment="<%= Rails.env %>"
data-edition="<%= OpenProject::Configuration.edition %>"/>
<meta name="current_menu_item" content="<%= current_menu_item %>"/>
<% if Setting.demo_projects_available %><meta name="demo_projects_available" content="true"/><% end %>
<% if Setting.boards_demo_data_available %><meta name="boards_demo_data_available" content="true"/><% end %>
<%= csrf_meta_tags %>
<!-- global meta hooks before any scripts are loaded-->
<%= call_hook :view_layouts_base_html_meta %>
<%= render 'common/favicons' %>
<%# Include CLI assets (development) or prod build assets %>
<%= include_frontend_assets %>
<%# Render CSS highlighting %>
<%= stylesheet_link_tag "/highlighting/styles/#{highlight_css_version_tag}",
media: :all,
skip_pipeline: true %>
<%= render partial: 'layouts/common_head' %>
<!-- project specific tags -->
<%= call_hook :view_layouts_base_html_head %>
<!-- page specific tags -->
<%= content_for(:header_tags) if content_for?(:header_tags) %>
<%= render partial: "custom_styles/inline_css_logo" %>
<% if apply_custom_styles? %>
<% cache(CustomStyle.current) do %>
<%= render partial: "custom_styles/inline_css" %>
<% if CustomStyle.current.favicon.present? %>
<link rel="icon" type="image/png" href="<%= custom_style_favicon_path(digest: CustomStyle.current.digest, filename: CustomStyle.current.favicon_identifier) %>" sizes="32x32">
<% end %>
<% if CustomStyle.current.touch_icon.present? %>
<link rel="apple-touch-icon" sizes="180x180" href="<%= custom_style_touch_icon_path(digest: CustomStyle.current.digest, filename: CustomStyle.current.touch_icon_identifier) %>">
<% end %>
<% end %>
<% end %>
<%= crowdin_in_context_translation %>
<meta name="current_menu_item" content="<%= current_menu_item %>"/>
</head>
<body class="<%= body_css_classes %> __overflowing_element_container __overflowing_body" data-relative_url_root="<%= root_path %>" data-overflowing-identifier=".__overflowing_body">
<%= render partial: 'warning_bar/warning_bar' %>

@ -32,13 +32,7 @@ See docs/COPYRIGHT.rdoc for more details.
xml:lang="<%= I18n.locale.to_s %>"
class="<%= 'in_modal' unless show_decoration %>">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width">
<%= output_title_and_meta_tags %>
<%= csrf_meta_tags %>
<%= render 'common/favicons' %>
<%# Include CLI assets (development) or prod build assets %>
<%= include_frontend_assets %>
<%= render partial: 'layouts/common_head' %>
</head>
<body>
<div id="wrapper">

@ -105,6 +105,9 @@ module OpenProject
config.paths.add Rails.root.join('lib').to_s, eager_load: true
config.paths.add Rails.root.join('lib/constraints').to_s, eager_load: true
# Use our own error rendering for prettier error pages
config.exceptions_app = routes
# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]

@ -32,6 +32,11 @@ OpenProject::Application.routes.draw do
root to: 'homescreen#index', as: 'home'
rails_relative_url_root = OpenProject::Configuration['rails_relative_url_root'] || ''
# Route for error pages
get '/404', to: "errors#not_found"
get '/422', to: "errors#unacceptable"
get '/500', to: "errors#internal_error"
# Route for health_checks
get '/health_check' => 'ok_computer/ok_computer#show', check: 'web'
# Override the default `all` checks route to return the full check

@ -1,52 +0,0 @@
<!---- copyright
OpenProject is a project management system.
Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
Copyright (C) 2006-2017 Jean-Philippe Lang
Copyright (C) 2010-2013 the ChiliProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
See doc/COPYRIGHT.rdoc for more details.
++-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<title>OpenProject 404 error</title>
<style>
body{
font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
color:#303030;
margin:10px;
}
h1{
font-size:1.5em;
}
p{
font-size:0.8em;
}
</style>
<body>
<h1>Page not found</h1>
<p>The page you were trying to access doesn't exist or has been removed.</p>
<p><a href="javascript:history.back()">Back</a></p>
</body>
</html>

@ -1,55 +0,0 @@
<!---- copyright
OpenProject is a project management system.
Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
Copyright (C) 2006-2017 Jean-Philippe Lang
Copyright (C) 2010-2013 the ChiliProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
See doc/COPYRIGHT.rdoc for more details.
++-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<title>OpenProject 500 error</title>
<style>
body{
font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
color:#303030;
margin:10px;
}
h1{
font-size:1.5em;
}
p{
font-size:0.8em;
}
</style>
<body>
<h1>Internal error</h1>
<p>An error occurred on the page you were trying to access.<br />
If you continue to experience problems please contact your OpenProject administrator for assistance.</p>
<p>If you are the OpenProject administrator, check your log files for details about the error.</p>
<p><a href="javascript:history.back()">Back</a></p>
</body>
</html>

@ -0,0 +1,28 @@
require 'spec_helper'
describe 'Errors handling', type: :feature do
it 'renders the internal error page in case of exceptions' do
# We unfortunately cannot test raising exceptions as the test environment
# marks all requests as local and thus shows exception details instead (like in dev mode)
visit '/500'
expect(page).to have_current_path '/500'
expect(page).to have_text "An error occurred on the page you were trying to access."
expect(page).to have_no_text "Oh no, this is an internal error!"
end
it 'renders the not found page' do
# We unfortunately cannot test raising exceptions as the test environment
# marks all requests as local and thus shows exception details instead (like in dev mode)
visit '/404'
expect(page).to have_current_path '/404'
expect(page).to have_text "[Error 404] The page you were trying to access doesn't exist or has been removed."
end
it 'renders the unacceptable response' do
# This file exists in public and is recommended to be rendered, but I'm not aware
# of any path that would trigger this
visit '/422'
expect(page).to have_current_path '/422'
expect(page).to have_text 'The change you wanted was rejected.'
end
end

@ -0,0 +1,35 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2021 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See docs/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe 'errors routing', type: :routing do
it { is_expected.to route(:get, '/404').to(controller: 'errors', action: 'not_found') }
it { is_expected.to route(:get, '/422').to(controller: 'errors', action: 'unacceptable') }
it { is_expected.to route(:get, '/500').to(controller: 'errors', action: 'internal_error') }
end
Loading…
Cancel
Save