From 2f7fc7e9f7e7a43914abe81a510bd0dffa113979 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 20 Oct 2015 16:16:08 +0200 Subject: [PATCH] Prefer project with exact path to differently cased one when both exist. --- app/controllers/application_controller.rb | 4 +-- app/models/project.rb | 17 +++++++---- spec/controllers/projects_controller_spec.rb | 30 ++++++++++++++++---- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f0124c6bd60..38e6b44eb6f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -118,8 +118,8 @@ class ApplicationController < ActionController::Base end project_path = "#{namespace}/#{id}" - @project = Project.find_with_namespace(project_path) - + @project = Project.find_with_namespace(project_path) || + Project.find_with_namespace(project_path, case_sensitive: false) if @project and can?(current_user, :read_project, @project) if @project.path_with_namespace != project_path diff --git a/app/models/project.rb b/app/models/project.rb index 88cd88dcb5a..b2a8dde9ba2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -235,7 +235,7 @@ class Project < ActiveRecord::Base where('projects.archived = ?', false).where('LOWER(projects.name) LIKE :query', query: "%#{query.downcase}%") end - def find_with_namespace(id) + def find_with_namespace(id, case_sensitive: true) namespace_path, project_path = id.split('/') return nil if !namespace_path || !project_path @@ -243,11 +243,18 @@ class Project < ActiveRecord::Base # Use of unscoped ensures we're not secretly adding any ORDER BYs, which # have a negative impact on performance (and aren't needed for this # query). - unscoped. + projects = unscoped. joins(:namespace). - iwhere('namespaces.path' => namespace_path). - iwhere('projects.path' => project_path). - take + iwhere('namespaces.path' => namespace_path) + + projects = + if case_sensitive + projects.where('projects.path' => project_path) + else + projects.iwhere('projects.path' => project_path) + end + + projects.take end def visibility_levels diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 4460bf12f96..5090f87c73d 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -51,16 +51,34 @@ describe ProjectsController do end context "when requested with case sensitive namespace and project path" do - it "redirects to the normalized path for case mismatch" do - get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase + context "when there is a match with the same casing" do + it "loads the project" do + get :show, namespace_id: public_project.namespace.path, id: public_project.path - expect(response).to redirect_to("/#{public_project.path_with_namespace}") + expect(assigns(:project)).to eq(public_project) + expect(response.status).to eq(200) + end end - it "loads the page if normalized path matches request path" do - get :show, namespace_id: public_project.namespace.path, id: public_project.path + context "when there is a match with different casing" do + it "redirects to the normalized path" do + get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase - expect(response.status).to eq(200) + expect(assigns(:project)).to eq(public_project) + expect(response).to redirect_to("/#{public_project.path_with_namespace}") + end + + context "when there is also a match with the same casing" do + + let!(:other_project) { create(:project, :public, namespace: public_project.namespace, path: public_project.path.upcase) } + + it "loads the exactly matched project" do + get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase + + expect(assigns(:project)).to eq(other_project) + expect(response.status).to eq(200) + end + end end end end