Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
heptapod
heptapod
Commits
4af83dc71720
Commit
4af83dc7
authored
Nov 14, 2016
by
Dmitriy Zaporozhets
Browse files
Add nested groups support to the routing
Signed-off-by:
Dmitriy Zaporozhets
<
dmitriy.zaporozhets@gmail.com
>
parent
423d7d48f248
Changes
30
Hide whitespace changes
Inline
Side-by-side
app/controllers/application_controller.rb
View file @
4af83dc7
...
...
@@ -49,6 +49,14 @@
render_404
end
def
route_not_found
if
current_user
not_found
else
redirect_to
new_user_session_path
end
end
protected
# This filter handles both private tokens and personal access tokens
...
...
app/models/project.rb
View file @
4af83dc7
...
...
@@ -174,6 +174,7 @@
message:
Gitlab
::
Regex
.
project_name_regex_message
}
validates
:path
,
presence:
true
,
project_path:
true
,
length:
{
within:
0
..
255
},
format:
{
with:
Gitlab
::
Regex
.
project_path_regex
,
message:
Gitlab
::
Regex
.
project_path_regex_message
}
...
...
app/models/user.rb
View file @
4af83dc7
...
...
@@ -291,4 +291,8 @@
end
end
def
find_by_username
(
username
)
iwhere
(
username:
username
).
take
end
def
find_by_username!
(
username
)
...
...
@@ -294,5 +298,5 @@
def
find_by_username!
(
username
)
find_by!
(
'low
er(username
) = ?'
,
username
.
downcase
)
iwh
er
e
(
username
:
username
).
take!
end
def
find_by_personal_access_token
(
token_string
)
...
...
app/validators/namespace_validator.rb
View file @
4af83dc7
...
...
@@ -35,4 +35,18 @@
users
]
.
freeze
def
self
.
valid?
(
value
)
!
reserved?
(
value
)
&&
follow_format?
(
value
)
end
def
self
.
reserved?
(
value
)
RESERVED
.
include?
(
value
)
end
def
self
.
follow_format?
(
value
)
value
=~
Gitlab
::
Regex
.
namespace_regex
end
delegate
:reserved?
,
:follow_format?
,
to: :class
def
validate_each
(
record
,
attribute
,
value
)
...
...
@@ -38,5 +52,5 @@
def
validate_each
(
record
,
attribute
,
value
)
unless
value
=~
Gitlab
::
Regex
.
namespace_regex
unless
follow_format?
(
value
)
record
.
errors
.
add
(
attribute
,
Gitlab
::
Regex
.
namespace_regex_message
)
end
...
...
@@ -44,10 +58,4 @@
record
.
errors
.
add
(
attribute
,
"
#{
value
}
is a reserved name"
)
end
end
private
def
reserved?
(
value
)
RESERVED
.
include?
(
value
)
end
end
app/validators/project_path_validator.rb
0 → 100644
View file @
4af83dc7
# ProjectPathValidator
#
# Custom validator for GitLab project path values.
#
# Values are checked for formatting and exclusion from a list of reserved path
# names.
class
ProjectPathValidator
<
ActiveModel
::
EachValidator
# All project routes with wildcard argument must be listed here.
# Otherwise it can lead to routing issues when route considered as project name.
#
# Example:
# /group/project/tree/deploy_keys
#
# without tree as reserved name routing can match 'group/project' as group name,
# 'tree' as project name and 'deploy_keys' as route.
#
RESERVED
=
(
NamespaceValidator
::
RESERVED
+
%w[tree commits wikis new edit create update logs_tree
preview blob blame raw files create_dir find_file]
).
freeze
def
self
.
valid?
(
value
)
!
reserved?
(
value
)
end
def
self
.
reserved?
(
value
)
RESERVED
.
include?
(
value
)
end
delegate
:reserved?
,
to: :class
def
validate_each
(
record
,
attribute
,
value
)
if
reserved?
(
value
)
record
.
errors
.
add
(
attribute
,
"
#{
value
}
is a reserved name"
)
end
end
end
app/views/projects/wikis/_nav.html.haml
View file @
4af83dc7
...
...
@@ -7,7 +7,7 @@
=
link_to
'Home'
,
namespace_project_wiki_path
(
@project
.
namespace
,
@project
,
:home
)
=
nav_link
(
path:
'wikis#pages'
)
do
=
link_to
'Pages'
,
namespace_project_wiki_pages_path
(
@project
.
namespace
,
@project
)
=
link_to
'Pages'
,
namespace_project_wiki
s
_pages_path
(
@project
.
namespace
,
@project
)
=
nav_link
(
path:
'wikis#git_access'
)
do
=
link_to
namespace_project_wikis_git_access_path
(
@project
.
namespace
,
@project
)
do
...
...
changelogs/unreleased/dz-allow-nested-group-routing.yml
0 → 100644
View file @
4af83dc7
---
title
:
Add nested groups support to the routing
merge_request
:
7459
author
:
config/routes.rb
View file @
4af83dc7
require
'sidekiq/web'
require
'sidekiq/cron/web'
require
'api/api'
require
'constraints/group_url_constrainer'
Rails
.
application
.
routes
.
draw
do
concern
:access_requestable
do
...
...
@@ -78,8 +79,5 @@
draw
:user
draw
:project
# Get all keys of user
get
':username.keys'
=>
'profiles/keys#get_keys'
,
constraints:
{
username:
/.*/
}
root
to:
"root#index"
...
...
@@ -84,4 +82,18 @@
root
to:
"root#index"
get
'*unmatched_route'
,
to:
'application#not_found'
# Since group show page is wildcard routing
# we want all other routing to be checked before matching this one
constraints
(
GroupUrlConstrainer
.
new
)
do
scope
(
path:
'*id'
,
as: :group
,
constraints:
{
id:
Gitlab
::
Regex
.
namespace_route_regex
,
format:
/(html|json|atom)/
},
controller: :groups
)
do
get
'/'
,
action: :show
patch
'/'
,
action: :update
put
'/'
,
action: :update
delete
'/'
,
action: :destroy
end
end
get
'*unmatched_route'
,
to:
'application#route_not_found'
end
config/routes/git_http.rb
View file @
4af83dc7
scope
constraints:
{
id:
/.+\.git/
,
format:
nil
}
do
# Git HTTP clients ('git clone' etc.)
get
'/info/refs'
,
to:
'git_http#info_refs'
post
'/git-upload-pack'
,
to:
'git_http#git_upload_pack'
post
'/git-receive-pack'
,
to:
'git_http#git_receive_pack'
scope
(
path:
'*namespace_id/:project_id'
,
constraints:
{
format:
nil
})
do
scope
(
constraints:
{
project_id:
Gitlab
::
Regex
.
project_git_route_regex
},
module: :projects
)
do
# Git HTTP clients ('git clone' etc.)
scope
(
controller: :git_http
)
do
get
'/info/refs'
,
action: :info_refs
post
'/git-upload-pack'
,
action: :git_upload_pack
post
'/git-receive-pack'
,
action: :git_receive_pack
end
...
...
@@ -6,6 +9,8 @@
# Git LFS API (metadata)
post
'/info/lfs/objects/batch'
,
to:
'lfs_api#batch'
post
'/info/lfs/objects'
,
to:
'lfs_api#deprecated'
get
'/info/lfs/objects/*oid'
,
to:
'lfs_api#deprecated'
# Git LFS API (metadata)
scope
(
path:
'info/lfs/objects'
,
controller: :lfs_api
)
do
post
:batch
post
'/'
,
action: :deprecated
get
'/*oid'
,
action: :deprecated
end
...
...
@@ -11,5 +16,5 @@
# GitLab LFS object storage
scope
constraints:
{
oid:
/[a-f0-9]{64}/
}
do
get
'/
gitlab-lfs/objects/*oid'
,
to:
'lfs_storage#
download
'
# GitLab LFS object storage
scope
(
path:
'gitlab-lfs/objects/*oid'
,
controller: :lfs_storage
,
constraints:
{
oid:
/[a-f0-9]{64}/
}
)
do
get
'/
'
,
action: :
download
...
...
@@ -15,6 +20,7 @@
scope
constraints:
{
size:
/[0-9]+/
}
do
put
'/gitlab-lfs/objects/*oid/*size/authorize'
,
to:
'lfs_storage#upload_authorize'
put
'/gitlab-lfs/objects/*oid/*size'
,
to:
'lfs_storage#upload_finalize'
scope
constraints:
{
size:
/[0-9]+/
}
do
put
'/*size/authorize'
,
action: :upload_authorize
put
'/*size'
,
action: :upload_finalize
end
end
end
...
...
@@ -19,4 +25,3 @@
end
end
end
...
...
@@ -22,8 +27,21 @@
# Allow /info/refs, /info/refs?service=git-upload-pack, and
# /info/refs?service=git-receive-pack, but nothing else.
#
git_http_handshake
=
lambda
do
|
request
|
request
.
query_string
.
blank?
||
request
.
query_string
.
match
(
/\Aservice=git-(upload|receive)-pack\z/
)
# Redirect /group/project/info/refs to /group/project.git/info/refs
scope
(
constraints:
{
project_id:
Gitlab
::
Regex
.
project_route_regex
})
do
# Allow /info/refs, /info/refs?service=git-upload-pack, and
# /info/refs?service=git-receive-pack, but nothing else.
#
git_http_handshake
=
lambda
do
|
request
|
ProjectUrlConstrainer
.
new
.
matches?
(
request
)
&&
(
request
.
query_string
.
blank?
||
request
.
query_string
.
match
(
/\Aservice=git-(upload|receive)-pack\z/
))
end
ref_redirect
=
redirect
do
|
params
,
request
|
path
=
"
#{
params
[
:namespace_id
]
}
/
#{
params
[
:project_id
]
}
.git/info/refs"
path
<<
"?
#{
request
.
query_string
}
"
unless
request
.
query_string
.
blank?
path
end
get
'/info/refs'
,
constraints:
git_http_handshake
,
to:
ref_redirect
end
end
...
...
@@ -29,9 +47,1 @@
end
ref_redirect
=
redirect
do
|
params
,
request
|
path
=
"
#{
params
[
:namespace_id
]
}
/
#{
params
[
:project_id
]
}
.git/info/refs"
path
<<
"?
#{
request
.
query_string
}
"
unless
request
.
query_string
.
blank?
path
end
get
'/info/refs'
,
constraints:
git_http_handshake
,
to:
ref_redirect
config/routes/group.rb
View file @
4af83dc7
require
'constraints/group_url_constrainer'
constraints
(
GroupUrlConstrainer
.
new
)
do
scope
(
path:
':id'
,
as: :group
,
constraints:
{
id:
Gitlab
::
Regex
.
namespace_route_regex
},
controller: :groups
)
do
get
'/'
,
action: :show
patch
'/'
,
action: :update
put
'/'
,
action: :update
delete
'/'
,
action: :destroy
end
end
resources
:groups
,
only:
[
:index
,
:new
,
:create
]
...
...
@@ -15,6 +1,6 @@
resources
:groups
,
only:
[
:index
,
:new
,
:create
]
scope
(
path:
'groups/
:
id'
,
scope
(
path:
'groups/
*
id'
,
controller: :groups
,
constraints:
{
id:
Gitlab
::
Regex
.
namespace_route_regex
})
do
get
:edit
,
as: :edit_group
...
...
@@ -24,7 +10,7 @@
get
:activity
,
as: :activity_group
end
scope
(
path:
'groups/
:
group_id'
,
scope
(
path:
'groups/
*
group_id'
,
module: :groups
,
as: :group
,
constraints:
{
group_id:
Gitlab
::
Regex
.
namespace_route_regex
})
do
...
...
@@ -42,4 +28,4 @@
end
# Must be last route in this file
get
'groups/
:
id'
=>
'groups#show'
,
as: :group_canonical
,
constraints:
{
id:
Gitlab
::
Regex
.
namespace_route_regex
}
get
'groups/
*
id'
=>
'groups#show'
,
as: :group_canonical
,
constraints:
{
id:
Gitlab
::
Regex
.
namespace_route_regex
}
config/routes/project.rb
View file @
4af83dc7
resources
:projects
,
constraints:
{
id:
/[^\/]+/
},
only:
[
:index
,
:new
,
:create
]
require
'constraints/project_url_constrainer'
resources
:projects
,
only:
[
:index
,
:new
,
:create
]
draw
:git_http
...
...
@@ -2,27 +6,10 @@
resources
:namespaces
,
path:
'/'
,
constraints:
{
id:
/[a-zA-Z.0-9_\-]+/
},
only:
[]
do
resources
(
:projects
,
constraints:
{
id:
/[a-zA-Z.0-9_\-]+(?<!\.atom)/
},
except:
[
:new
,
:create
,
:index
],
path:
"/"
)
do
member
do
put
:transfer
delete
:remove_fork
post
:archive
post
:unarchive
post
:housekeeping
post
:toggle_star
post
:preview_markdown
post
:export
post
:remove_export
post
:generate_new_export
get
:download_export
get
:autocomplete_sources
get
:activity
get
:refs
put
:new_issue_address
end
scope
module: :projects
do
draw
:git_http
constraints
(
ProjectUrlConstrainer
.
new
)
do
scope
(
path:
'*namespace_id'
,
as: :namespace
)
do
scope
(
path:
':project_id'
,
constraints:
{
project_id:
Gitlab
::
Regex
.
project_route_regex
},
module: :projects
,
as: :project
)
do
#
# Templates
...
...
@@ -311,5 +298,28 @@
draw
:wiki
draw
:repository
end
resources
(
:projects
,
path:
'/'
,
constraints:
{
id:
Gitlab
::
Regex
.
project_route_regex
},
only:
[
:edit
,
:show
,
:update
,
:destroy
])
do
member
do
put
:transfer
delete
:remove_fork
post
:archive
post
:unarchive
post
:housekeeping
post
:toggle_star
post
:preview_markdown
post
:export
post
:remove_export
post
:generate_new_export
get
:download_export
get
:autocomplete_sources
get
:activity
get
:refs
put
:new_issue_address
end
end
end
end
config/routes/repository.rb
View file @
4af83dc7
...
...
@@ -29,32 +29,11 @@
put
'/update/*id'
,
to:
'blob#update'
,
constraints:
{
id:
/.+/
},
as:
'update_blob'
post
'/preview/*id'
,
to:
'blob#preview'
,
constraints:
{
id:
/.+/
},
as:
'preview_blob'
scope
do
get
(
'/blob/*id/diff'
,
to:
'blob#diff'
,
constraints:
{
id:
/.+/
,
format:
false
},
as: :blob_diff
)
get
(
'/blob/*id'
,
to:
'blob#show'
,
constraints:
{
id:
/.+/
,
format:
false
},
as: :blob
)
delete
(
'/blob/*id'
,
to:
'blob#destroy'
,
constraints:
{
id:
/.+/
,
format:
false
}
)
put
(
'/blob/*id'
,
to:
'blob#update'
,
constraints:
{
id:
/.+/
,
format:
false
}
)
post
(
'/blob/*id'
,
to:
'blob#create'
,
constraints:
{
id:
/.+/
,
format:
false
}
)
scope
(
'/blob/*id'
,
as: :blob
,
controller: :blob
,
constraints:
{
id:
/.+/
,
format:
false
})
do
get
:diff
get
'/'
,
action: :show
delete
'/'
,
action: :destroy
post
'/'
,
action: :create
put
'/'
,
action: :update
end
...
...
@@ -60,8 +39,22 @@
get
(
'/raw/*id'
,
to:
'raw#show'
,
constraints:
{
id:
/.+/
,
format:
/(html|js)/
},
as: :raw
)
get
(
'/raw/*id'
,
to:
'raw#show'
,
constraints:
{
id:
/.+/
,
format:
/(html|js)/
},
as: :raw
)
get
(
'/tree/*id'
,
to:
'tree#show'
,
constraints:
{
id:
/.+/
,
format:
/(html|js)/
},
as: :tree
)
get
(
'/find_file/*id'
,
to:
'find_file#show'
,
constraints:
{
id:
/.+/
,
format:
/html/
},
as: :find_file
)
...
...
@@ -67,8 +60,8 @@
get
(
'/
tree
/*id'
,
to:
'
tree#show
'
,
constraints:
{
id:
/
.
+/
,
format:
/
(html|js)
/
},
as: :
tree
)
get
(
'/
files
/*id'
,
to:
'
find_file#list
'
,
constraints:
{
id:
/
(?:[^.]|\.(?!json$))
+/
,
format:
/
json
/
},
as: :
files
)
...
...
@@ -74,15 +67,8 @@
get
(
'/find_file/*id'
,
to:
'find_file#show'
,
constraints:
{
id:
/.+/
,
format:
/html/
},
as: :find_file
)
get
(
'/files/*id'
,
to:
'find_file#list'
,
constraints:
{
id:
/(?:[^.]|\.(?!json$))+/
,
format:
/json/
},
as: :files
)
post
(
'/create_dir/*id'
,
to:
'tree#create_dir'
,
constraints:
{
id:
/.+/
},
as:
'create_dir'
)
...
...
@@ -88,8 +74,8 @@
pos
t
(
'/
create_dir
/*id'
,
to:
'
tree#create_dir
'
,
constraints:
{
id:
/.+/
},
as:
'create_dir'
)
ge
t
(
'/
blame
/*id'
,
to:
'
blame#show
'
,
constraints:
{
id:
/.+/
,
format:
/(html|js)/
},
as:
:blame
)
...
...
@@ -95,16 +81,8 @@
get
(
'/blame/*id'
,
to:
'blame#show'
,
constraints:
{
id:
/.+/
,
format:
/(html|js)/
},
as: :blame
)
# File/dir history
get
(
'/commits/*id'
,
to:
'commits#show'
,
constraints:
{
id:
/.+/
,
format:
false
},
as: :commits
)
end
# File/dir history
get
(
'/commits/*id'
,
to:
'commits#show'
,
constraints:
{
id:
/.+/
,
format:
false
},
as: :commits
)
config/routes/user.rb
View file @
4af83dc7
...
...
@@ -12,6 +12,9 @@
end
constraints
(
UserUrlConstrainer
.
new
)
do
# Get all keys of user
get
':username.keys'
=>
'profiles/keys#get_keys'
,
constraints:
{
username:
Gitlab
::
Regex
.
namespace_route_regex
}
scope
(
path:
':username'
,
as: :user
,
constraints:
{
username:
Gitlab
::
Regex
.
namespace_route_regex
},
...
...
config/routes/wiki.rb
View file @
4af83dc7
WIKI_SLUG_ID
=
{
id:
/\S+/
}
unless
defined?
WIKI_SLUG_ID
scope
do
# Order matters to give priority to these matches
get
'/wikis/git_access'
,
to:
'wikis#git_access'
get
'/wikis/pages'
,
to:
'wikis#pages'
,
as:
'wiki_pages'
post
'/wikis'
,
to:
'wikis#create'
scope
(
controller: :wikis
)
do
scope
(
path:
'wikis'
,
as: :wikis
)
do
get
:git_access
get
:pages
get
'/'
,
to:
redirect
(
'/%{namespace_id}/%{project_id}/wikis/home'
)
post
'/'
,
to:
'wikis#create'
end
...
...
@@ -8,9 +10,10 @@
get
'/wikis/*id/history'
,
to:
'wikis#history'
,
as:
'wiki_history'
,
constraints:
WIKI_SLUG_ID
get
'/wikis/*id/edit'
,
to:
'wikis#edit'
,
as:
'wiki_edit'
,
constraints:
WIKI_SLUG_ID
get
'/wikis/*id'
,
to:
'wikis#show'
,
as:
'wiki'
,
constraints:
WIKI_SLUG_ID
delete
'/wikis/*id'
,
to:
'wikis#destroy'
,
constraints:
WIKI_SLUG_ID
put
'/wikis/*id'
,
to:
'wikis#update'
,
constraints:
WIKI_SLUG_ID
post
'/wikis/*id/preview_markdown'
,
to:
'wikis#preview_markdown'
,
constraints:
WIKI_SLUG_ID
,
as:
'wiki_preview_markdown'
scope
(
path:
'wikis/*id'
,
as: :wiki
,
constraints:
WIKI_SLUG_ID
,
format:
false
)
do
get
:edit
get
:history
post
:preview_markdown
get
'/'
,
action: :show
put
'/'
,
action: :update
delete
'/'
,
action: :destroy
end
end
features/steps/project/labels.rb
View file @
4af83dc7
...
...
@@ -2,5 +2,4 @@
include
SharedAuthentication
include
SharedIssuable
include
SharedProject
include
SharedNote
include
SharedPaths
...
...
@@ -6,5 +5,4 @@
include
SharedPaths
include
SharedMarkdown
step
'And I visit project "Shop" labels page'
do
visit
namespace_project_labels_path
(
project
.
namespace
,
project
)
...
...
features/steps/shared/diff_note.rb
View file @
4af83dc7
module
SharedDiffNote
include
Spinach
::
DSL
include
RepoHelpers
include
WaitForAjax
after
do
wait_for_ajax
if
javascript_test?
end
step
'I cancel the diff comment'
do
page
.
within
(
diff_file_selector
)
do
...
...
features/steps/shared/note.rb
View file @
4af83dc7
...
...
@@ -2,6 +2,10 @@
include
Spinach
::
DSL
include
WaitForAjax
after
do
wait_for_ajax
if
javascript_test?
end
step
'I delete a comment'
do
page
.
within
(
'.main-notes-list'
)
do
find
(
'.note'
).
hover
...
...
lib/constraints/constrainer_helper.rb
deleted
100644 → 0
View file @
423d7d48
module
ConstrainerHelper
def
extract_resource_path
(
path
)
id
=
path
.
dup
id
.
sub!
(
/\A
#{
relative_url_root
}
/
,
''
)
if
relative_url_root
id
.
sub
(
/\A\/+/
,
''
).
sub
(
/\/+\z/
,
''
).
sub
(
/.atom\z/
,
''
)
end
private
def
relative_url_root
if
defined?
(
Gitlab
::
Application
.
config
.
relative_url_root
)
Gitlab
::
Application
.
config
.
relative_url_root
end
end
end
lib/constraints/group_url_constrainer.rb
View file @
4af83dc7
require_relative
'constrainer_helper'
class
GroupUrlConstrainer
...
...
@@ -3,4 +1,2 @@
class
GroupUrlConstrainer
include
ConstrainerHelper
def
matches?
(
request
)
...
...
@@ -6,3 +2,5 @@
def
matches?
(
request
)
id
=
extract_resource_path
(
request
.
path
)
id
=
request
.
params
[
:id
]
return
false
unless
valid?
(
id
)
...
...
@@ -8,8 +6,12 @@
if
id
=~
Gitlab
::
Regex
.
namespace_regex