Dry up routable lookups. Fixes #30317
Note: This changes the behavior of user lookups (see the spec change) so it acts the same way as groups and projects. Unauthenticated clients attempting to access a user page will be redirected to login whether the user exists and is publicly restricted, or does not exist at all.
This commit is contained in:
parent
e4bcc90d95
commit
9e48f02ea8
5 changed files with 58 additions and 55 deletions
|
@ -1,12 +1,36 @@
|
|||
module RoutableActions
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def find_routable!(routable_klass, requested_full_path, extra_authorization_method: nil)
|
||||
routable = routable_klass.find_by_full_path(requested_full_path, follow_redirects: request.get?)
|
||||
|
||||
if authorized?(routable_klass, routable, extra_authorization_method)
|
||||
ensure_canonical_path(routable, requested_full_path)
|
||||
routable
|
||||
else
|
||||
route_not_found
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def authorized?(routable_klass, routable, extra_authorization_method)
|
||||
action = :"read_#{routable_klass.to_s.underscore}"
|
||||
return false unless can?(current_user, action, routable)
|
||||
|
||||
if extra_authorization_method
|
||||
send(extra_authorization_method, routable)
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_canonical_path(routable, requested_path)
|
||||
return unless request.get?
|
||||
|
||||
if routable.full_path != requested_path
|
||||
canonical_path = routable.try(:full_path) || routable.namespace.full_path
|
||||
if canonical_path != requested_path
|
||||
flash[:notice] = 'This project has moved to this location. Please update your links and bookmarks.'
|
||||
redirect_to request.original_url.sub(requested_path, routable.full_path)
|
||||
redirect_to request.original_url.sub(requested_path, canonical_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,20 +9,11 @@ class Groups::ApplicationController < ApplicationController
|
|||
private
|
||||
|
||||
def group
|
||||
unless @group
|
||||
given_path = params[:group_id] || params[:id]
|
||||
@group = Group.find_by_full_path(given_path, follow_redirects: request.get?)
|
||||
@group ||= find_routable!(Group, requested_full_path)
|
||||
end
|
||||
|
||||
if @group && can?(current_user, :read_group, @group)
|
||||
ensure_canonical_path(@group, given_path)
|
||||
else
|
||||
@group = nil
|
||||
|
||||
route_not_found
|
||||
end
|
||||
end
|
||||
|
||||
@group
|
||||
def requested_full_path
|
||||
params[:group_id] || params[:id]
|
||||
end
|
||||
|
||||
def group_projects
|
||||
|
|
|
@ -2,6 +2,7 @@ class Projects::ApplicationController < ApplicationController
|
|||
include RoutableActions
|
||||
|
||||
skip_before_action :authenticate_user!
|
||||
before_action :redirect_git_extension
|
||||
before_action :project
|
||||
before_action :repository
|
||||
layout 'project'
|
||||
|
@ -10,34 +11,30 @@ class Projects::ApplicationController < ApplicationController
|
|||
|
||||
private
|
||||
|
||||
def project
|
||||
unless @project
|
||||
namespace = params[:namespace_id]
|
||||
id = params[:project_id] || params[:id]
|
||||
|
||||
# Redirect from
|
||||
# localhost/group/project.git
|
||||
# to
|
||||
# localhost/group/project
|
||||
#
|
||||
if params[:format] == 'git'
|
||||
redirect_to request.original_url.gsub(/\.git\/?\Z/, '')
|
||||
return
|
||||
end
|
||||
|
||||
project_path = "#{namespace}/#{id}"
|
||||
@project = Project.find_by_full_path(project_path, follow_redirects: request.get?)
|
||||
|
||||
if can?(current_user, :read_project, @project) && !@project.pending_delete?
|
||||
ensure_canonical_path(@project, project_path)
|
||||
else
|
||||
@project = nil
|
||||
|
||||
route_not_found
|
||||
end
|
||||
def redirect_git_extension
|
||||
# Redirect from
|
||||
# localhost/group/project.git
|
||||
# to
|
||||
# localhost/group/project
|
||||
#
|
||||
if params[:format] == 'git'
|
||||
redirect_to request.original_url.gsub(/\.git\/?\Z/, '')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
@project
|
||||
def project
|
||||
@project ||= find_routable!(Project, requested_full_path, extra_authorization_method: :project_not_being_deleted?)
|
||||
end
|
||||
|
||||
def requested_full_path
|
||||
namespace = params[:namespace_id]
|
||||
id = params[:project_id] || params[:id]
|
||||
"#{namespace}/#{id}"
|
||||
end
|
||||
|
||||
def project_not_being_deleted?(project)
|
||||
!project.pending_delete?
|
||||
end
|
||||
|
||||
def repository
|
||||
|
|
|
@ -93,16 +93,7 @@ class UsersController < ApplicationController
|
|||
private
|
||||
|
||||
def user
|
||||
return @user if @user
|
||||
|
||||
@user = User.find_by_full_path(params[:username], follow_redirects: true)
|
||||
|
||||
return render_404 unless @user
|
||||
return render_404 unless can?(current_user, :read_user, @user)
|
||||
|
||||
ensure_canonical_path(@user.namespace, params[:username])
|
||||
|
||||
@user
|
||||
@user ||= find_routable!(User, params[:username])
|
||||
end
|
||||
|
||||
def contributed_projects
|
||||
|
|
|
@ -36,9 +36,9 @@ describe UsersController do
|
|||
end
|
||||
|
||||
context 'when logged out' do
|
||||
it 'renders 404' do
|
||||
it 'redirects to login page' do
|
||||
get :show, username: user.username
|
||||
expect(response).to have_http_status(404)
|
||||
expect(response).to redirect_to new_user_session_path
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -88,9 +88,9 @@ describe UsersController do
|
|||
|
||||
context 'when a user by that username does not exist' do
|
||||
context 'when logged out' do
|
||||
it 'renders 404 (does not redirect to login)' do
|
||||
it 'redirects to login page' do
|
||||
get :show, username: 'nonexistent'
|
||||
expect(response).to have_http_status(404)
|
||||
expect(response).to redirect_to new_user_session_path
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue