Commit 5d5e6954 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'fix-issue-32506' into 'master'

Fix redirects modifying the host

Closes #32506

See merge request !11498
parents bdf62a19 49697bc8
...@@ -24,15 +24,15 @@ module RoutableActions ...@@ -24,15 +24,15 @@ module RoutableActions
end end
end end
def ensure_canonical_path(routable, requested_path) def ensure_canonical_path(routable, requested_full_path)
return unless request.get? return unless request.get?
canonical_path = routable.full_path canonical_path = routable.full_path
if canonical_path != requested_path if canonical_path != requested_full_path
if canonical_path.casecmp(requested_path) != 0 if canonical_path.casecmp(requested_full_path) != 0
flash[:notice] = "#{routable.class.to_s.titleize} '#{requested_path}' was moved to '#{canonical_path}'. Please update any links and bookmarks that may still have the old path." flash[:notice] = "#{routable.class.to_s.titleize} '#{requested_full_path}' was moved to '#{canonical_path}'. Please update any links and bookmarks that may still have the old path."
end end
redirect_to request.original_url.sub(requested_path, canonical_path) redirect_to build_canonical_path(routable)
end end
end end
end end
...@@ -31,4 +31,10 @@ class Groups::ApplicationController < ApplicationController ...@@ -31,4 +31,10 @@ class Groups::ApplicationController < ApplicationController
return render_403 return render_403
end end
end end
def build_canonical_path(group)
params[:group_id] = group.to_param
url_for(params)
end
end end
...@@ -169,4 +169,12 @@ class GroupsController < Groups::ApplicationController ...@@ -169,4 +169,12 @@ class GroupsController < Groups::ApplicationController
@notification_setting = current_user.notification_settings_for(group) @notification_setting = current_user.notification_settings_for(group)
end end
end end
def build_canonical_path(group)
return group_path(group) if action_name == 'show' # root group path
params[:id] = group.to_param
url_for(params)
end
end end
...@@ -29,6 +29,13 @@ class Projects::ApplicationController < ApplicationController ...@@ -29,6 +29,13 @@ class Projects::ApplicationController < ApplicationController
@project = find_routable!(Project, path, extra_authorization_proc: auth_proc) @project = find_routable!(Project, path, extra_authorization_proc: auth_proc)
end end
def build_canonical_path(project)
params[:namespace_id] = project.namespace.to_param
params[:project_id] = project.to_param
url_for(params)
end
def repository def repository
@repository ||= project.repository @repository ||= project.repository
end end
......
...@@ -365,4 +365,11 @@ class ProjectsController < Projects::ApplicationController ...@@ -365,4 +365,11 @@ class ProjectsController < Projects::ApplicationController
def project_view_files_allowed? def project_view_files_allowed?
!project.empty_repo? && can?(current_user, :download_code, project) !project.empty_repo? && can?(current_user, :download_code, project)
end end
def build_canonical_path(project)
params[:namespace_id] = project.namespace.to_param
params[:id] = project.to_param
url_for(params)
end
end end
...@@ -138,4 +138,8 @@ class UsersController < ApplicationController ...@@ -138,4 +138,8 @@ class UsersController < ApplicationController
def projects_for_current_user def projects_for_current_user
ProjectsFinder.new(current_user: current_user).execute ProjectsFinder.new(current_user: current_user).execute
end end
def build_canonical_path(user)
url_for(params.merge(username: user.to_param))
end
end end
...@@ -21,7 +21,6 @@ describe Groups::MilestonesController do ...@@ -21,7 +21,6 @@ describe Groups::MilestonesController do
sign_in(user) sign_in(user)
group.add_owner(user) group.add_owner(user)
project.team << [user, :master] project.team << [user, :master]
controller.instance_variable_set(:@group, group)
end end
it_behaves_like 'milestone tabs' it_behaves_like 'milestone tabs'
...@@ -29,7 +28,7 @@ describe Groups::MilestonesController do ...@@ -29,7 +28,7 @@ describe Groups::MilestonesController do
describe "#create" do describe "#create" do
it "creates group milestone with Chinese title" do it "creates group milestone with Chinese title" do
post :create, post :create,
group_id: group.id, group_id: group.to_param,
milestone: { project_ids: [project.id, project2.id], title: title } milestone: { project_ids: [project.id, project2.id], title: title }
expect(response).to redirect_to(group_milestone_path(group, title.to_slug.to_s, title: title)) expect(response).to redirect_to(group_milestone_path(group, title.to_slug.to_s, title: title))
...@@ -37,9 +36,139 @@ describe Groups::MilestonesController do ...@@ -37,9 +36,139 @@ describe Groups::MilestonesController do
end end
it "redirects to new when there are no project ids" do it "redirects to new when there are no project ids" do
post :create, group_id: group.id, milestone: { title: title, project_ids: [""] } post :create, group_id: group.to_param, milestone: { title: title, project_ids: [""] }
expect(response).to render_template :new expect(response).to render_template :new
expect(assigns(:milestone).errors).not_to be_nil expect(assigns(:milestone).errors).not_to be_nil
end end
end end
describe '#ensure_canonical_path' do
before do
sign_in(user)
end
context 'for a GET request' do
context 'when requesting the canonical path' do
context 'non-show path' do
context 'with exactly matching casing' do
it 'does not redirect' do
get :index, group_id: group.to_param
expect(response).not_to have_http_status(301)
end
end
context 'with different casing' do
it 'redirects to the correct casing' do
get :index, group_id: group.to_param.upcase
expect(response).to redirect_to(group_milestones_path(group.to_param))
expect(controller).not_to set_flash[:notice]
end
end
end
context 'show path' do
context 'with exactly matching casing' do
it 'does not redirect' do
get :show, group_id: group.to_param, id: title
expect(response).not_to have_http_status(301)
end
end
context 'with different casing' do
it 'redirects to the correct casing' do
get :show, group_id: group.to_param.upcase, id: title
expect(response).to redirect_to(group_milestone_path(group.to_param, title))
expect(controller).not_to set_flash[:notice]
end
end
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'redirects to the canonical path' do
get :merge_requests, group_id: redirect_route.path, id: title
expect(response).to redirect_to(merge_requests_group_milestone_path(group.to_param, title))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
context 'when the old group path is a substring of the scheme or host' do
let(:redirect_route) { group.redirect_routes.create(path: 'http') }
it 'does not modify the requested host' do
get :merge_requests, group_id: redirect_route.path, id: title
expect(response).to redirect_to(merge_requests_group_milestone_path(group.to_param, title))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
context 'when the old group path is substring of groups' do
# I.e. /groups/oups should not become /grfoo/oups
let(:redirect_route) { group.redirect_routes.create(path: 'oups') }
it 'does not modify the /groups part of the path' do
get :merge_requests, group_id: redirect_route.path, id: title
expect(response).to redirect_to(merge_requests_group_milestone_path(group.to_param, title))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
context 'when the old group path is substring of groups plus the new path' do
# I.e. /groups/oups/oup should not become /grfoos
let(:redirect_route) { group.redirect_routes.create(path: 'oups/oup') }
it 'does not modify the /groups part of the path' do
get :merge_requests, group_id: redirect_route.path, id: title
expect(response).to redirect_to(merge_requests_group_milestone_path(group.to_param, title))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
end
end
end
context 'for a non-GET request' do
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
post :create,
group_id: group.to_param,
milestone: { project_ids: [project.id, project2.id], title: title }
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
post :create,
group_id: group.to_param,
milestone: { project_ids: [project.id, project2.id], title: title }
expect(response).not_to have_http_status(301)
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'returns not found' do
post :create,
group_id: redirect_route.path,
milestone: { project_ids: [project.id, project2.id], title: title }
expect(response).to have_http_status(404)
end
end
end
def group_moved_message(redirect_route, group)
"Group '#{redirect_route.path}' was moved to '#{group.full_path}'. Please update any links and bookmarks that may still have the old path."
end
end end
...@@ -84,26 +84,6 @@ describe GroupsController do ...@@ -84,26 +84,6 @@ describe GroupsController do
expect(assigns(:issues)).to eq [issue_2, issue_1] expect(assigns(:issues)).to eq [issue_2, issue_1]
end end
end end
context 'when requesting the canonical path with different casing' do
it 'redirects to the correct casing' do
get :issues, id: group.to_param.upcase
expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).not_to set_flash[:notice]
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'redirects to the canonical path' do
get :issues, id: redirect_route.path
expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
end end
describe 'GET #merge_requests' do describe 'GET #merge_requests' do
...@@ -129,26 +109,6 @@ describe GroupsController do ...@@ -129,26 +109,6 @@ describe GroupsController do
expect(assigns(:merge_requests)).to eq [merge_request_2, merge_request_1] expect(assigns(:merge_requests)).to eq [merge_request_2, merge_request_1]
end end
end end
context 'when requesting the canonical path with different casing' do
it 'redirects to the correct casing' do
get :merge_requests, id: group.to_param.upcase
expect(response).to redirect_to(merge_requests_group_path(group.to_param))
expect(controller).not_to set_flash[:notice]
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'redirects to the canonical path' do
get :merge_requests, id: redirect_route.path
expect(response).to redirect_to(merge_requests_group_path(group.to_param))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
end end
describe 'DELETE #destroy' do describe 'DELETE #destroy' do
...@@ -178,53 +138,171 @@ describe GroupsController do ...@@ -178,53 +138,171 @@ describe GroupsController do
expect(response).to redirect_to(root_path) expect(response).to redirect_to(root_path)
end end
end
end
context 'when requesting the canonical path with different casing' do describe 'PUT update' do
it 'does not 404' do before do
delete :destroy, id: group.to_param.upcase sign_in(user)
end
expect(response).not_to have_http_status(404) it 'updates the path successfully' do
post :update, id: group.to_param, group: { path: 'new_path' }
expect(response).to have_http_status(302)
expect(controller).to set_flash[:notice]
end end
it 'does not redirect to the correct casing' do it 'does not update the path on error' do
delete :destroy, id: group.to_param.upcase allow_any_instance_of(Group).to receive(:move_dir).and_raise(Gitlab::UpdatePathError)
post :update, id: group.to_param, group: { path: 'new_path' }
expect(assigns(:group).errors).not_to be_empty
expect(assigns(:group).path).not_to eq('new_path')
end
end
describe '#ensure_canonical_path' do
before do
sign_in(user)
end
context 'for a GET request' do
context 'when requesting groups at the root path' do
before do
allow(request).to receive(:original_fullpath).and_return("/#{group_full_path}")
get :show, id: group_full_path
end
context 'when requesting the canonical path with different casing' do
let(:group_full_path) { group.to_param.upcase }
expect(response).not_to redirect_to(group_path(group.to_param)) it 'redirects to the correct casing' do
expect(response).to redirect_to(group)
expect(controller).not_to set_flash[:notice]
end end
end end
context 'when requesting a redirected path' do context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') } let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
let(:group_full_path) { redirect_route.path }
it 'returns not found' do it 'redirects to the canonical path' do
delete :destroy, id: redirect_route.path expect(response).to redirect_to(group)
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
expect(response).to have_http_status(404) context 'when the old group path is a substring of the scheme or host' do
let(:redirect_route) { group.redirect_routes.create(path: 'http') }
it 'does not modify the requested host' do
expect(response).to redirect_to(group)
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
context 'when the old group path is substring of groups' do
# I.e. /groups/oups should not become /grfoo/oups
let(:redirect_route) { group.redirect_routes.create(path: 'oups') }
it 'does not modify the /groups part of the path' do
expect(response).to redirect_to(group)
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end end
end end
end end
end end
describe 'PUT update' do context 'when requesting groups under the /groups path' do
before do context 'when requesting the canonical path' do
sign_in(user) context 'non-show path' do
context 'with exactly matching casing' do
it 'does not redirect' do
get :issues, id: group.to_param
expect(response).not_to have_http_status(301)
end
end end
it 'updates the path successfully' do context 'with different casing' do
post :update, id: group.to_param, group: { path: 'new_path' } it 'redirects to the correct casing' do
get :issues, id: group.to_param.upcase
expect(response).to have_http_status(302) expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).to set_flash[:notice] expect(controller).not_to set_flash[:notice]
end
end
end end
it 'does not update the path on error' do context 'show path' do
allow_any_instance_of(Group).to receive(:move_dir).and_raise(Gitlab::UpdatePathError) context 'with exactly matching casing' do
post :update, id: group.to_param, group: { path: 'new_path' } it 'does not redirect' do
get :show, id: group.to_param
expect(assigns(:group).errors).not_to be_empty expect(response).not_to have_http_status(301)
expect(assigns(:group).path).not_to eq('new_path') end
end
context 'with different casing' do
it 'redirects to the correct casing at the root path' do
get :show, id: group.to_param.upcase
expect(response).to redirect_to(group)
expect(controller).not_to set_flash[:notice]
end end
end
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'redirects to the canonical path' do
get :issues, id: redirect_route.path
expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
context 'when the old group path is a substring of the scheme or host' do
let(:redirect_route) { group.redirect_routes.create(path: 'http') }
it 'does not modify the requested host' do
get :issues, id: redirect_route.path
expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
context 'when the old group path is substring of groups' do
# I.e. /groups/oups should not become /grfoo/oups
let(:redirect_route) { group.redirect_routes.create(path: 'oups') }
it 'does not modify the /groups part of the path' do
get :issues, id: redirect_route.path
expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
context 'when the old group path is substring of groups plus the new path' do
# I.e. /groups/oups/oup should not become /grfoos
let(:redirect_route) { group.redirect_routes.create(path: 'oups/oup') }
it 'does not modify the /groups part of the path' do
get :issues, id: redirect_route.path
expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
end
end
end
context 'for a POST request' do
context 'when requesting the canonical path with different casing' do context 'when requesting the canonical path with different casing' do
it 'does not 404' do it 'does not 404' do
post :update, id: group.to_param.upcase, group: { path: 'new_path' } post :update, id: group.to_param.upcase, group: { path: 'new_path' }
...@@ -235,7 +313,7 @@ describe GroupsController do ...@@ -235,7 +313,7 @@ describe GroupsController do
it 'does not redirect to the correct casing' do it 'does not redirect to the correct casing' do
post :update, id: group.to_param.upcase, group: { path: 'new_path' } post :update, id: group.to_param.upcase, group: { path: 'new_path' }
expect(response).not_to redirect_to(group_path(group.to_param)) expect(response).not_to have_http_status(301)
end end
end end
...@@ -250,6 +328,33 @@ describe GroupsController do ...@@ -250,6 +328,33 @@ describe GroupsController do
end end
end end
context 'for a DELETE request' do
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
delete :destroy, id: group.to_param.upcase
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
delete :destroy, id: group.to_param.upcase
expect(response).not_to have_http_status(301)
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'returns not found' do
delete :destroy, id: redirect_route.path
expect(response).to have_http_status(404)
end
end
end
end
def group_moved_message(redirect_route, group) def group_moved_message(redirect_route, group)
"Group '#{redirect_route.path}' was moved to '#{group.full_path}'. Please update any links and bookmarks that may still have the old path." "Group '#{redirect_route.path}' was moved to '#{group.full_path}'. Please update any links and bookmarks that may still have the old path."
end end
......
...@@ -157,4 +157,74 @@ describe Projects::LabelsController do ...@@ -157,4 +157,74 @@ describe Projects::LabelsController do
end end
end end
end end
describe '#ensure_canonical_path' do
before do
sign_in(user)
end
context 'for a GET request' do
context 'when requesting the canonical path' do
context 'non-show path' do
context 'with exactly matching casing' do
it 'does not redirect' do
get :index, namespace_id: project.namespace, project_id: project.to_param
expect(response).not_to have_http_status(301)
end
end
context 'with different casing' do
it 'redirects to the correct casing' do
get :index, namespace_id: project.namespace, project_id: project.to_param.upcase
expect(response).to redirect_to(namespace_project_labels_path(project.namespace, project))
expect(controller).not_to set_flash[:notice]
end
end
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { project.redirect_routes.create(path: project.full_path + 'old') }
it 'redirects to the canonical path' do
get :index, namespace_id: project.namespace, project_id: project.to_param + 'old'
expect(response).to redirect_to(namespace_project_labels_path(project.namespace, project))
expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, project))
end
end
end
end
context 'for a non-GET request' do
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
post :generate, namespace_id: project.namespace, project_id: project
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
post :generate, namespace_id: project.namespace, project_id: project
expect(response).not_to have_http_status(301)
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { project.redirect_routes.create(path: project.full_path + 'old') }
it 'returns not found' do
post :generate, namespace_id: project.namespace, project_id: project.to_param + 'old'
expect(response).to have_http_status(404)
end
end
end
def project_moved_message(redirect_route, project)
"Project '#{redirect_route.path}' was moved to '#{project.full_path}'. Please update any links and bookmarks that may still have the old path."
end
end end
...@@ -169,27 +169,6 @@ describe ProjectsController do ...@@ -169,27 +169,6 @@ describe ProjectsController do
end end
end end
context "when requested with case sensitive namespace and project path" do
context "when there is a match with the same casing" do
it "loads the project" do
get :show, namespace_id: public_project.namespace, id: public_project
expect(assigns(:project)).to eq(public_project)
expect(response).to have_http_status(200)
end
end
context "when there is a match with different casing" do
it "redirects to the normalized path" do
get :show, namespace_id: public_project.namespace, id: public_project.path.upcase
expect(assigns(:project)).to eq(public_project)
expect(response).to redirect_to("/#{public_project.full_path}")
expect(controller).not_to set_flash[:notice]
end
end
end
context "when the url contains .atom" do context "when the url contains .atom" do
let(:public_project_with_dot_atom) { build(:empty_project, :public, name: 'my.atom', path: 'my.atom') } let(:public_project_with_dot_atom) { build(:empty_project, :public, name: 'my.atom', path: 'my.atom') }
...@@ -219,17 +198,6 @@ describe ProjectsController do ...@@ -219,17 +198,6 @@ describe ProjectsController do
expect(response).to redirect_to(namespace_project_path) expect(response).to redirect_to(namespace_project_path)
end end
end end
context 'when requesting a redirected path' do
let!(:redirect_route) { public_project.redirect_routes.create!(path: "foo/bar") }
it 'redirects to the canonical path' do
get :show, namespace_id: 'foo', id: 'bar'
expect(response).to redirect_to(public_project)
expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, public_project))
end
end
end end
describe "#update" do describe "#update" do
...@@ -256,34 +224,6 @@ describe ProjectsController do ...@@ -256,34 +224,6 @@ describe ProjectsController do
expect(assigns(:repository).path).to eq(project.repository.path) expect(assigns(:repository).path).to eq(project.repository.path)
expect(response).to have_http_status(302) expect(response).to have_http_status(302)
end end
context 'when requesting the canonical path' do
it "is case-insensitive" do
controller.instance_variable_set(:@project, project)
put :update,
namespace_id: 'FOo',
id: 'baR',
project: project_params
expect(project.repository.path).to include(new_path)
expect(assigns(:repository).path).to eq(project.repository.path)
expect(response).to have_http_status(302)
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { project.redirect_routes.create!(path: "foo/bar") }
it 'returns not found' do
put :update,
namespace_id: 'foo',
id: 'bar',
project: project_params
expect(response).to have_http_status(404)
end
end
end end
describe "#destroy" do describe "#destroy" do
...@@ -319,31 +259,6 @@ describe ProjectsController do ...@@ -319,31 +259,6 @@ describe ProjectsController do
expect(merge_request.reload.state).to eq('closed') expect(merge_request.reload.state).to eq('closed')
end end
end end
context 'when requesting the canonical path' do
it "is case-insensitive" do
controller.instance_variable_set(:@project, project)
sign_in(admin)
orig_id = project.id
delete :destroy, namespace_id: project.namespace, id: project.path.upcase
expect { Project.find(orig_id) }.to raise_error(ActiveRecord::RecordNotFound)
expect(response).to have_http_status(302)
expect(response).to redirect_to(dashboard_projects_path)
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { project.redirect_routes.create!(path: "foo/bar") }
it 'returns not found' do
sign_in(admin)
delete :destroy, namespace_id: 'foo', id: 'bar'
expect(response).to have_http_status(404)
end
end
end end
describe 'PUT #new_issue_address' do describe 'PUT #new_issue_address' do
...@@ -465,11 +380,56 @@ describe ProjectsController do ...@@ -465,11 +380,56 @@ describe ProjectsController do
expect(parsed_body["Tags"]).to include("v1.0.0") expect(parsed_body["Tags"]).to include("v1.0.0")
expect(parsed_body["Commits"]).to include("123456") expect(parsed_body["Commits"]).to include("123456")
end end
end
describe 'POST #preview_markdown' do
it 'renders json in a correct format' do
sign_in(user)
post :preview_markdown, namespace_id: public_project.namespace, id: public_project, text: '*Markdown* text'
expect(JSON.parse(response.body).keys).to match_array(%w(body references))
end
end
describe '#ensure_canonical_path' do
before do
sign_in(user)
end
context 'for a GET request' do
context 'when requesting the canonical path' do
context "with exactly matching casing" do
it "loads the project" do
get :show, namespace_id: public_project.namespace, id: public_project
expect(assigns(:project)).to eq(public_project)
expect(response).to have_http_status(200)
end
end
context "with different casing" do
it "redirects to the normalized path" do
get :show, namespace_id: public_project.namespace, id: public_project.path.upcase
expect(assigns(:project)).to eq(public_project)
expect(response).to redirect_to("/#{public_project.full_path}")
expect(controller).not_to set_flash[:notice]
end
end
end
context 'when requesting a redirected path' do context 'when requesting a redirected path' do
let!(:redirect_route) { public_project.redirect_routes.create!(path: "foo/bar") } let!(:redirect_route) { public_project.redirect_routes.create!(path: "foo/bar") }
it 'redirects to the canonical path' do it 'redirects to the canonical path' do
get :show, namespace_id: 'foo', id: 'bar'
expect(response).to redirect_to(public_project)
expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, public_project))
end
it 'redirects to the canonical path (testing non-show action)' do
get :refs, namespace_id: 'foo', id: 'bar' get :refs, namespace_id: 'foo', id: 'bar'
expect(response).to redirect_to(refs_namespace_project_path(namespace_id: public_project.namespace, id: public_project)) expect(response).to redirect_to(refs_namespace_project_path(namespace_id: public_project.namespace, id: public_project))
...@@ -478,13 +438,60 @@ describe ProjectsController do ...@@ -478,13 +438,60 @@ describe ProjectsController do
end end
end end
describe 'POST #preview_markdown' do context 'for a POST request' do
it 'renders json in a correct format' do context 'when requesting the canonical path with different casing' do
sign_in(user) it 'does not 404' do
post :toggle_star, namespace_id: public_project.namespace, id: public_project.path.upcase
post :preview_markdown, namespace_id: public_project.namespace, id: public_project, text: '*Markdown* text' expect(response).not_to have_http_status(404)
end
expect(JSON.parse(response.body).keys).to match_array(%w(body references)) it 'does not redirect to the correct casing' do
post :toggle_star, namespace_id: public_project.namespace, id: public_project.path.upcase
expect(response).not_to have_http_status(301)
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { public_project.redirect_routes.create!(path: "foo/bar") }
it 'returns not found' do
post :toggle_star, namespace_id: 'foo', id: 'bar'
expect(response).to have_http_status(404)
end
end
end
context 'for a DELETE request' do
before do
sign_in(create(:admin))
end
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
delete :destroy, namespace_id: project.namespace, id: project.path.upcase
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
delete :destroy, namespace_id: project.namespace, id: project.path.upcase
expect(response).not_to have_http_status(301)
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { project.redirect_routes.create!(path: "foo/bar") }
it 'returns not found' do
delete :destroy, namespace_id: 'foo', id: 'bar'
expect(response).to have_http_status(404)
end
end
end end
end end
......
...@@ -53,40 +53,6 @@ describe UsersController do ...@@ -53,40 +53,6 @@ describe UsersController do
end end
end end
context 'when requesting the canonical path' do
let(:user) { create(:user, username: 'CamelCaseUser') }
before { sign_in(user) }
context 'with exactly matching casing' do
it 'responds with success' do
get :show, username: user.username
expect(response).to be_success
end
end
context 'with different casing' do
it 'redirects to the correct casing' do
get :show, username: user.username.downcase
expect(response).to redirect_to(user)
expect(controller).not_to set_flash[:notice]
end
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-username') }
it 'redirects to the canonical path' do
get :show, username: redirect_route.path
expect(response).to redirect_to(user)
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
end
context 'when a user by that username does not exist' do context 'when a user by that username does not exist' do
context 'when logged out' do context 'when logged out' do
it 'redirects to login page' do it 'redirects to login page' do
...@@ -131,69 +97,111 @@ describe UsersController do ...@@ -131,69 +97,111 @@ describe UsersController do
expect(assigns(:contributions_calendar).projects.count).to eq(2) expect(assigns(:contributions_calendar).projects.count).to eq(2)
end end
end end
end
context 'when requesting the canonical path' do describe 'GET #calendar_activities' do
let(:user) { create(:user, username: 'CamelCaseUser') } let!(:project) { create(:empty_project) }
let(:user) { create(:user) }
before { sign_in(user) } before do
allow_any_instance_of(User).to receive(:contributed_projects_ids).and_return([project.id])
context 'with exactly matching casing' do sign_in(user)
it 'responds with success' do project.team << [user, :developer]
get :calendar, username: user.username end
expect(response).to be_success it 'assigns @calendar_date' do
get :calendar_activities, username: user.username, date: '2014-07-31'
expect(assigns(:calendar_date)).to eq(Date.parse('2014-07-31'))
end
it 'renders calendar_activities' do
get :calendar_activities, username: user.username
expect(response).to render_template('calendar_activities')
end end
end end
context 'with different casing' do describe 'GET #snippets' do
it 'redirects to the correct casing' do before do
get :calendar, username: user.username.downcase sign_in(user)
end
expect(response).to redirect_to(user_calendar_path(user)) context 'format html' do
expect(controller).not_to set_flash[:notice] it 'renders snippets page' do
get :snippets, username: user.username
expect(response).to have_http_status(200)
expect(response).to render_template('show')
end
end
context 'format json' do
it 'response with snippets json data' do
get :snippets, username: user.username, format: :json
expect(response).to have_http_status(200)
expect(JSON.parse(response.body)).to have_key('html')
end end
end end
end end
context 'when requesting a redirected path' do describe 'GET #exists' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-username') } before do
sign_in(user)
end
it 'redirects to the canonical path' do context 'when user exists' do
get :calendar, username: redirect_route.path it 'returns JSON indicating the user exists' do
get :exists, username: user.username
expect(response).to redirect_to(user_calendar_path(user)) expected_json = { exists: true }.to_json
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user)) expect(response.body).to eq(expected_json)
end
context 'when the casing is different' do
let(:user) { create(:user, username: 'CamelCaseUser') }
it 'returns JSON indicating the user exists' do
get :exists, username: user.username.downcase
expected_json = { exists: true }.to_json
expect(response.body).to eq(expected_json)
end end
end end
end end
describe 'GET #calendar_activities' do context 'when the user does not exist' do
let!(:project) { create(:empty_project) } it 'returns JSON indicating the user does not exist' do
let(:user) { create(:user) } get :exists, username: 'foo'
before do
allow_any_instance_of(User).to receive(:contributed_projects_ids).and_return([project.id])
sign_in(user) expected_json = { exists: false }.to_json
project.team << [user, :developer] expect(response.body).to eq(expected_json)
end end
it 'assigns @calendar_date' do context 'when a user changed their username' do
get :calendar_activities, username: user.username, date: '2014-07-31' let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-username') }
expect(assigns(:calendar_date)).to eq(Date.parse('2014-07-31'))
it 'returns JSON indicating a user by that username does not exist' do
get :exists, username: 'old-username'
expected_json = { exists: false }.to_json
expect(response.body).to eq(expected_json)
end
end
end
end end
it 'renders calendar_activities' do describe '#ensure_canonical_path' do
get :calendar_activities, username: user.username before do
expect(response).to render_template('calendar_activities') sign_in(user)
end end
context 'for a GET request' do
context 'when requesting users at the root path' do
context 'when requesting the canonical path' do context 'when requesting the canonical path' do
let(:user) { create(:user, username: 'CamelCaseUser') } let(:user) { create(:user, username: 'CamelCaseUser') }
context 'with exactly matching casing' do context 'with exactly matching casing' do
it 'responds with success' do it 'responds with success' do
get :calendar_activities, username: user.username get :show, username: user.username
expect(response).to be_success expect(response).to be_success
end end
...@@ -201,53 +209,55 @@ describe UsersController do ...@@ -201,53 +209,55 @@ describe UsersController do
context 'with different casing' do context 'with different casing' do
it 'redirects to the correct casing' do it 'redirects to the correct casing' do
get :calendar_activities, username: user.username.downcase get :show, username: user.username.downcase
expect(response).to redirect_to(user_calendar_activities_path(user)) expect(response).to redirect_to(user)
expect(controller).not_to set_flash[:notice] expect(controller).not_to set_flash[:notice]
end end
end end
end end
context 'when requesting a redirected path' do context 'when requesting a redirected path' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-username') } let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-path') }
it 'redirects to the canonical path' do it 'redirects to the canonical path' do
get :calendar_activities, username: redirect_route.path get :show, username: redirect_route.path
expect(response).to redirect_to(user_calendar_activities_path(user)) expect(response).to redirect_to(user)
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user)) expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end end
context 'when the old path is a substring of the scheme or host' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'http') }
it 'does not modify the requested host' do
get :show, username: redirect_route.path
expect(response).to redirect_to(user)
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end end
end end
describe 'GET #snippets' do context 'when the old path is substring of users' do
before do let(:redirect_route) { user.namespace.redirect_routes.create(path: 'ser') }
sign_in(user)
end
context 'format html' do it 'redirects to the canonical path' do
it 'renders snippets page' do get :show, username: redirect_route.path
get :snippets, username: user.username
expect(response).to have_http_status(200) expect(response).to redirect_to(user)
expect(response).to render_template('show') expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end end
end end
context 'format json' do
it 'response with snippets json data' do
get :snippets, username: user.username, format: :json
expect(response).to have_http_status(200)
expect(JSON.parse(response.body)).to have_key('html')
end end
end end
context 'when requesting users under the /users path' do
context 'when requesting the canonical path' do context 'when requesting the canonical path' do
let(:user) { create(:user, username: 'CamelCaseUser') } let(:user) { create(:user, username: 'CamelCaseUser') }
context 'with exactly matching casing' do context 'with exactly matching casing' do
it 'responds with success' do it 'responds with success' do
get :snippets, username: user.username get :projects, username: user.username
expect(response).to be_success expect(response).to be_success
end end
...@@ -255,67 +265,46 @@ describe UsersController do ...@@ -255,67 +265,46 @@ describe UsersController do
context 'with different casing' do context 'with different casing' do
it 'redirects to the correct casing' do it 'redirects to the correct casing' do
get :snippets, username: user.username.downcase get :projects, username: user.username.downcase
expect(response).to redirect_to(user_snippets_path(user)) expect(response).to redirect_to(user_projects_path(user))
expect(controller).not_to set_flash[:notice] expect(controller).not_to set_flash[:notice]
end end
end end
end end
context 'when requesting a redirected path' do context 'when requesting a redirected path' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-username') } let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-path') }
it 'redirects to the canonical path' do it 'redirects to the canonical path' do
get :snippets, username: redirect_route.path get :projects, username: redirect_route.path
expect(response).to redirect_to(user_snippets_path(user)) expect(response).to redirect_to(user_projects_path(user))
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user)) expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end end
end
end
describe 'GET #exists' do context 'when the old path is a substring of the scheme or host' do
before do let(:redirect_route) { user.namespace.redirect_routes.create(path: 'http') }
sign_in(user)
end
context 'when user exists' do it 'does not modify the requested host' do
it 'returns JSON indicating the user exists' do get :projects, username: redirect_route.path
get :exists, username: user.username
expected_json = { exists: true }.to_json expect(response).to redirect_to(user_projects_path(user))
expect(response.body).to eq(expected_json) expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
end end
context 'when the casing is different' do context 'when the old path is substring of users' do
let(:user) { create(:user, username: 'CamelCaseUser') } let(:redirect_route) { user.namespace.redirect_routes.create(path: 'ser') }
it 'returns JSON indicating the user exists' do # I.e. /users/ser should not become /ufoos/ser
get :exists, username: user.username.downcase it 'does not modify the /users part of the path' do
get :projects, username: redirect_route.path
expected_json = { exists: true }.to_json expect(response).to redirect_to(user_projects_path(user))
expect(response.body).to eq(expected_json) expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
end end
end end
context 'when the user does not exist' do
it 'returns JSON indicating the user does not exist' do
get :exists, username: 'foo'
expected_json = { exists: false }.to_json
expect(response.body).to eq(expected_json)
end
context 'when a user changed their username' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-username') }
it 'returns JSON indicating a user by that username does not exist' do
get :exists, username: 'old-username'
expected_json = { exists: false }.to_json
expect(response.body).to eq(expected_json)
end end
end end
end end
......
shared_examples 'milestone tabs' do shared_examples 'milestone tabs' do
def go(path, extra_params = {}) def go(path, extra_params = {})
params = if milestone.is_a?(GlobalMilestone) params = if milestone.is_a?(GlobalMilestone)
{ group_id: group.id, id: milestone.safe_title, title: milestone.title } { group_id: group.to_param, id: milestone.safe_title, title: milestone.title }
else else
{ namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid } { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid }
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment