Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
2c569be6
Commit
2c569be6
authored
Dec 07, 2017
by
Mike Greiling
Committed by
Phil Hughes
Dec 07, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Resolve "Display member role per project"
parent
61bd5b2c
Changes
22
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
347 additions
and
94 deletions
+347
-94
app/assets/javascripts/groups/components/group_item.vue
app/assets/javascripts/groups/components/group_item.vue
+11
-6
app/assets/javascripts/notes/components/note_actions.vue
app/assets/javascripts/notes/components/note_actions.vue
+1
-1
app/assets/stylesheets/framework/lists.scss
app/assets/stylesheets/framework/lists.scss
+3
-5
app/assets/stylesheets/framework/variables.scss
app/assets/stylesheets/framework/variables.scss
+1
-1
app/assets/stylesheets/pages/groups.scss
app/assets/stylesheets/pages/groups.scss
+12
-0
app/assets/stylesheets/pages/labels.scss
app/assets/stylesheets/pages/labels.scss
+1
-1
app/assets/stylesheets/pages/notes.scss
app/assets/stylesheets/pages/notes.scss
+6
-15
app/controllers/concerns/renders_member_access.rb
app/controllers/concerns/renders_member_access.rb
+23
-0
app/controllers/dashboard/projects_controller.rb
app/controllers/dashboard/projects_controller.rb
+7
-4
app/controllers/explore/projects_controller.rb
app/controllers/explore/projects_controller.rb
+8
-5
app/controllers/users_controller.rb
app/controllers/users_controller.rb
+7
-0
app/models/concerns/bulk_member_access_load.rb
app/models/concerns/bulk_member_access_load.rb
+46
-0
app/models/project_team.rb
app/models/project_team.rb
+8
-29
app/models/user.rb
app/models/user.rb
+29
-0
app/views/dashboard/projects/_projects.html.haml
app/views/dashboard/projects/_projects.html.haml
+1
-1
app/views/explore/projects/_projects.html.haml
app/views/explore/projects/_projects.html.haml
+1
-1
app/views/projects/notes/_actions.html.haml
app/views/projects/notes/_actions.html.haml
+1
-1
app/views/shared/groups/_group.html.haml
app/views/shared/groups/_group.html.haml
+6
-19
app/views/shared/groups/_list.html.haml
app/views/shared/groups/_list.html.haml
+3
-1
app/views/shared/projects/_list.html.haml
app/views/shared/projects/_list.html.haml
+4
-2
app/views/shared/projects/_project.html.haml
app/views/shared/projects/_project.html.haml
+9
-2
spec/models/user_spec.rb
spec/models/user_spec.rb
+159
-0
No files found.
app/assets/javascripts/groups/components/group_item.vue
View file @
2c569be6
...
@@ -123,18 +123,23 @@ export default {
...
@@ -123,18 +123,23 @@ export default {
:title=
"group.fullName"
:title=
"group.fullName"
class=
"no-expand"
class=
"no-expand"
data-placement=
"top"
data-placement=
"top"
>
>
{{
{{
group
.
name
}}
// ending bracket must be by closing tag to prevent
</a>
// link hover text-decoration from over-extending
group
.
name
}}
</a>
<span
<span
v-if=
"group.permission"
v-if=
"group.permission"
class=
"
access-typ
e"
class=
"
user-access-rol
e"
>
>
{{
s__
(
'
GroupsTreeRole|as
'
)
}}
{{
group
.
permission
}}
{{
group
.
permission
}}
</span>
</span>
</div>
</div>
<div
<div
class=
"description"
>
{{
group
.
description
}}
</div>
v-if=
"group.description"
class=
"description"
>
{{
group
.
description
}}
</div>
</div>
</div>
<group-folder
<group-folder
v-if=
"group.isOpen && hasChildren"
v-if=
"group.isOpen && hasChildren"
...
...
app/assets/javascripts/notes/components/note_actions.vue
View file @
2c569be6
...
@@ -86,7 +86,7 @@
...
@@ -86,7 +86,7 @@
<div
class=
"note-actions"
>
<div
class=
"note-actions"
>
<span
<span
v-if=
"accessLevel"
v-if=
"accessLevel"
class=
"note-role
note-role-access
"
>
{{
accessLevel
}}
</span>
class=
"note-role
user-access-role
"
>
{{
accessLevel
}}
</span>
<div
<div
v-if=
"canAddAwardEmoji"
v-if=
"canAddAwardEmoji"
class=
"note-actions-item"
>
class=
"note-actions-item"
>
...
...
app/assets/stylesheets/framework/lists.scss
View file @
2c569be6
...
@@ -457,13 +457,11 @@ ul.indent-list {
...
@@ -457,13 +457,11 @@ ul.indent-list {
ul
.group-list-tree
{
ul
.group-list-tree
{
li
.group-row
{
li
.group-row
{
&
.has-description
{
&
.has-description
.title
{
.title
{
line-height
:
inherit
;
line-height
:
inherit
;
}
}
}
.title
{
&
:not
(
.has-description
)
.title
{
line-height
:
$list-text-height
;
line-height
:
$list-text-height
;
}
}
}
}
...
...
app/assets/stylesheets/framework/variables.scss
View file @
2c569be6
...
@@ -408,7 +408,6 @@ $location-icon-color: #e7e9ed;
...
@@ -408,7 +408,6 @@ $location-icon-color: #e7e9ed;
* Notes
* Notes
*/
*/
$notes-light-color
:
$gl-text-color-secondary
;
$notes-light-color
:
$gl-text-color-secondary
;
$notes-role-color
:
$gl-text-color-secondary
;
$note-disabled-comment-color
:
#b2b2b2
;
$note-disabled-comment-color
:
#b2b2b2
;
$note-targe3-outside
:
#fffff0
;
$note-targe3-outside
:
#fffff0
;
$note-targe3-inside
:
#ffffd3
;
$note-targe3-inside
:
#ffffd3
;
...
@@ -557,6 +556,7 @@ $jq-ui-default-color: #777;
...
@@ -557,6 +556,7 @@ $jq-ui-default-color: #777;
/*
/*
* Label
* Label
*/
*/
$label-padding
:
7px
;
$label-gray-bg
:
#f8fafc
;
$label-gray-bg
:
#f8fafc
;
$label-inverse-bg
:
#333
;
$label-inverse-bg
:
#333
;
$label-remove-border
:
rgba
(
0
,
0
,
0
,
.1
);
$label-remove-border
:
rgba
(
0
,
0
,
0
,
.1
);
...
...
app/assets/stylesheets/pages/groups.scss
View file @
2c569be6
...
@@ -212,3 +212,15 @@
...
@@ -212,3 +212,15 @@
height
:
50px
;
height
:
50px
;
}
}
}
}
.user-access-role
{
display
:
inline-block
;
color
:
$gl-text-color-secondary
;
font-size
:
12px
;
line-height
:
20px
;
margin
:
-5px
3px
;
padding
:
0
$label-padding
;
border
:
1px
solid
$border-color
;
border-radius
:
$label-border-radius
;
font-weight
:
$gl-font-weight-normal
;
}
app/assets/stylesheets/pages/labels.scss
View file @
2c569be6
...
@@ -104,7 +104,7 @@
...
@@ -104,7 +104,7 @@
}
}
.color-label
{
.color-label
{
padding
:
3px
7px
;
padding
:
3px
$label-padding
;
border-radius
:
$label-border-radius
;
border-radius
:
$label-border-radius
;
}
}
...
...
app/assets/stylesheets/pages/notes.scss
View file @
2c569be6
...
@@ -619,26 +619,17 @@ ul.notes {
...
@@ -619,26 +619,17 @@ ul.notes {
}
}
.note-role
{
.note-role
{
margin
:
0
3px
;
}
.note-role-special
{
position
:
relative
;
position
:
relative
;
display
:
inline-block
;
display
:
inline-block
;
color
:
$
notes-role-color
;
color
:
$
gl-text-color-secondary
;
font-size
:
12px
;
font-size
:
12px
;
line-height
:
20px
;
text-shadow
:
0
0
15px
$gl-text-color-inverted
;
margin
:
0
3px
;
&
.note-role-access
{
padding
:
0
7px
;
border
:
1px
solid
$border-color
;
border-radius
:
$label-border-radius
;
}
&
.note-role-special
{
text-shadow
:
0
0
15px
$gl-text-color-inverted
;
}
}
}
/**
/**
* Line note button on the side of diffs
* Line note button on the side of diffs
*/
*/
...
...
app/controllers/concerns/renders_member_access.rb
0 → 100644
View file @
2c569be6
module
RendersMemberAccess
def
prepare_groups_for_rendering
(
groups
)
preload_max_member_access_for_collection
(
Group
,
groups
)
groups
end
def
prepare_projects_for_rendering
(
projects
)
preload_max_member_access_for_collection
(
Project
,
projects
)
projects
end
private
def
preload_max_member_access_for_collection
(
klass
,
collection
)
return
if
!
current_user
||
collection
.
blank?
method_name
=
"max_member_access_for_
#{
klass
.
name
.
underscore
}
_ids"
current_user
.
public_send
(
method_name
,
collection
.
ids
)
# rubocop:disable GitlabSecurity/PublicSend
end
end
app/controllers/dashboard/projects_controller.rb
View file @
2c569be6
class
Dashboard::ProjectsController
<
Dashboard
::
ApplicationController
class
Dashboard::ProjectsController
<
Dashboard
::
ApplicationController
include
ParamsBackwardCompatibility
include
ParamsBackwardCompatibility
include
RendersMemberAccess
before_action
:set_non_archived_param
before_action
:set_non_archived_param
before_action
:default_sorting
before_action
:default_sorting
...
@@ -45,10 +46,12 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
...
@@ -45,10 +46,12 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end
end
def
load_projects
(
finder_params
)
def
load_projects
(
finder_params
)
ProjectsFinder
projects
=
ProjectsFinder
.
new
(
params:
finder_params
,
current_user:
current_user
)
.
new
(
params:
finder_params
,
current_user:
current_user
)
.
execute
.
execute
.
includes
(
:route
,
:creator
,
namespace:
[
:route
,
:owner
])
.
includes
(
:route
,
:creator
,
namespace:
[
:route
,
:owner
])
prepare_projects_for_rendering
(
projects
)
end
end
def
load_events
def
load_events
...
...
app/controllers/explore/projects_controller.rb
View file @
2c569be6
class
Explore::ProjectsController
<
Explore
::
ApplicationController
class
Explore::ProjectsController
<
Explore
::
ApplicationController
include
ParamsBackwardCompatibility
include
ParamsBackwardCompatibility
include
RendersMemberAccess
before_action
:set_non_archived_param
before_action
:set_non_archived_param
...
@@ -49,10 +50,12 @@ class Explore::ProjectsController < Explore::ApplicationController
...
@@ -49,10 +50,12 @@ class Explore::ProjectsController < Explore::ApplicationController
private
private
def
load_projects
def
load_projects
ProjectsFinder
.
new
(
current_user:
current_user
,
params:
params
)
projects
=
ProjectsFinder
.
new
(
current_user:
current_user
,
params:
params
)
.
execute
.
execute
.
includes
(
:route
,
namespace: :route
)
.
includes
(
:route
,
namespace: :route
)
.
page
(
params
[
:page
])
.
page
(
params
[
:page
])
.
without_count
.
without_count
prepare_projects_for_rendering
(
projects
)
end
end
end
end
app/controllers/users_controller.rb
View file @
2c569be6
class
UsersController
<
ApplicationController
class
UsersController
<
ApplicationController
include
RoutableActions
include
RoutableActions
include
RendersMemberAccess
skip_before_action
:authenticate_user!
skip_before_action
:authenticate_user!
before_action
:user
,
except:
[
:exists
]
before_action
:user
,
except:
[
:exists
]
...
@@ -116,14 +117,20 @@ class UsersController < ApplicationController
...
@@ -116,14 +117,20 @@ class UsersController < ApplicationController
@projects
=
@projects
=
PersonalProjectsFinder
.
new
(
user
).
execute
(
current_user
)
PersonalProjectsFinder
.
new
(
user
).
execute
(
current_user
)
.
page
(
params
[
:page
])
.
page
(
params
[
:page
])
prepare_projects_for_rendering
(
@projects
)
end
end
def
load_contributed_projects
def
load_contributed_projects
@contributed_projects
=
contributed_projects
.
joined
(
user
)
@contributed_projects
=
contributed_projects
.
joined
(
user
)
prepare_projects_for_rendering
(
@contributed_projects
)
end
end
def
load_groups
def
load_groups
@groups
=
JoinedGroupsFinder
.
new
(
user
).
execute
(
current_user
)
@groups
=
JoinedGroupsFinder
.
new
(
user
).
execute
(
current_user
)
prepare_groups_for_rendering
(
@groups
)
end
end
def
load_snippets
def
load_snippets
...
...
app/models/concerns/bulk_member_access_load.rb
0 → 100644
View file @
2c569be6
# Returns and caches in thread max member access for a resource
#
module
BulkMemberAccessLoad
extend
ActiveSupport
::
Concern
included
do
# Determine the maximum access level for a group of resources in bulk.
#
# Returns a Hash mapping resource ID -> maximum access level.
def
max_member_access_for_resource_ids
(
resource_klass
,
resource_ids
,
memoization_index
=
self
.
id
,
&
block
)
raise
'Block is mandatory'
unless
block_given?
resource_ids
=
resource_ids
.
uniq
key
=
max_member_access_for_resource_key
(
resource_klass
,
memoization_index
)
access
=
{}
if
RequestStore
.
active?
RequestStore
.
store
[
key
]
||=
{}
access
=
RequestStore
.
store
[
key
]
end
# Look up only the IDs we need
resource_ids
=
resource_ids
-
access
.
keys
return
access
if
resource_ids
.
empty?
resource_access
=
yield
(
resource_ids
)
access
.
merge!
(
resource_access
)
missing_resource_ids
=
resource_ids
-
resource_access
.
keys
missing_resource_ids
.
each
do
|
resource_id
|
access
[
resource_id
]
=
Gitlab
::
Access
::
NO_ACCESS
end
access
end
private
def
max_member_access_for_resource_key
(
klass
,
memoization_index
)
"max_member_access_for_
#{
klass
.
name
.
underscore
.
pluralize
}
:
#{
memoization_index
}
"
end
end
end
app/models/project_team.rb
View file @
2c569be6
class
ProjectTeam
class
ProjectTeam
include
BulkMemberAccessLoad
attr_accessor
:project
attr_accessor
:project
def
initialize
(
project
)
def
initialize
(
project
)
...
@@ -157,39 +159,16 @@ class ProjectTeam
...
@@ -157,39 +159,16 @@ class ProjectTeam
#
#
# Returns a Hash mapping user ID -> maximum access level.
# Returns a Hash mapping user ID -> maximum access level.
def
max_member_access_for_user_ids
(
user_ids
)
def
max_member_access_for_user_ids
(
user_ids
)
user_ids
=
user_ids
.
uniq
max_member_access_for_resource_ids
(
User
,
user_ids
,
project
.
id
)
do
|
user_ids
|
key
=
"max_member_access:
#{
project
.
id
}
"
project
.
project_authorizations
.
where
(
user:
user_ids
)
access
=
{}
.
group
(
:user_id
)
.
maximum
(
:access_level
)
if
RequestStore
.
active?
RequestStore
.
store
[
key
]
||=
{}
access
=
RequestStore
.
store
[
key
]
end
end
# Look up only the IDs we need
user_ids
=
user_ids
-
access
.
keys
return
access
if
user_ids
.
empty?
users_access
=
project
.
project_authorizations
.
where
(
user:
user_ids
)
.
group
(
:user_id
)
.
maximum
(
:access_level
)
access
.
merge!
(
users_access
)
missing_user_ids
=
user_ids
-
users_access
.
keys
missing_user_ids
.
each
do
|
user_id
|
access
[
user_id
]
=
Gitlab
::
Access
::
NO_ACCESS
end
access
end
end
def
max_member_access
(
user_id
)
def
max_member_access
(
user_id
)
max_member_access_for_user_ids
([
user_id
])[
user_id
]
||
Gitlab
::
Access
::
NO_ACCESS
max_member_access_for_user_ids
([
user_id
])[
user_id
]
end
end
private
private
...
...
app/models/user.rb
View file @
2c569be6
...
@@ -17,6 +17,7 @@ class User < ActiveRecord::Base
...
@@ -17,6 +17,7 @@ class User < ActiveRecord::Base
include
FeatureGate
include
FeatureGate
include
CreatedAtFilterable
include
CreatedAtFilterable
include
IgnorableColumn
include
IgnorableColumn
include
BulkMemberAccessLoad
DEFAULT_NOTIFICATION_LEVEL
=
:participating
DEFAULT_NOTIFICATION_LEVEL
=
:participating
...
@@ -1144,6 +1145,34 @@ class User < ActiveRecord::Base
...
@@ -1144,6 +1145,34 @@ class User < ActiveRecord::Base
super
super
end
end
# Determine the maximum access level for a group of projects in bulk.
#
# Returns a Hash mapping project ID -> maximum access level.
def
max_member_access_for_project_ids
(
project_ids
)
max_member_access_for_resource_ids
(
Project
,
project_ids
)
do
|
project_ids
|
project_authorizations
.
where
(
project:
project_ids
)
.
group
(
:project_id
)
.
maximum
(
:access_level
)
end
end
def
max_member_access_for_project
(
project_id
)
max_member_access_for_project_ids
([
project_id
])[
project_id
]
end
# Determine the maximum access level for a group of groups in bulk.
#
# Returns a Hash mapping project ID -> maximum access level.
def
max_member_access_for_group_ids
(
group_ids
)
max_member_access_for_resource_ids
(
Group
,
group_ids
)
do
|
group_ids
|
group_members
.
where
(
source:
group_ids
).
group
(
:source_id
).
maximum
(
:access_level
)
end
end
def
max_member_access_for_group
(
group_id
)
max_member_access_for_group_ids
([
group_id
])[
group_id
]
end
protected
protected
# override, from Devise::Validatable
# override, from Devise::Validatable
...
...
app/views/dashboard/projects/_projects.html.haml
View file @
2c569be6
=
render
'shared/projects/list'
,
projects:
@projects
,
ci:
true
=
render
'shared/projects/list'
,
projects:
@projects
,
ci:
true
,
user:
current_user
app/views/explore/projects/_projects.html.haml
View file @
2c569be6
=
render
'shared/projects/list'
,
projects:
projects
=
render
'shared/projects/list'
,
projects:
projects
,
user:
current_user
app/views/projects/notes/_actions.html.haml
View file @
2c569be6
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
%span
.note-role.note-role-special.has-tooltip
{
title:
_
(
"This is the author's first Merge Request to this project."
)
}
%span
.note-role.note-role-special.has-tooltip
{
title:
_
(
"This is the author's first Merge Request to this project."
)
}
=
issuable_first_contribution_icon
=
issuable_first_contribution_icon
-
if
access
.
nonzero?
-
if
access
.
nonzero?
%span
.note-role.
note-role-access
=
Gitlab
::
Access
.
human_access
(
access
)
%span
.note-role.
user-access-role
=
Gitlab
::
Access
.
human_access
(
access
)
-
if
note
.
resolvable?
-
if
note
.
resolvable?
-
can_resolve
=
can?
(
current_user
,
:resolve_note
,
note
)
-
can_resolve
=
can?
(
current_user
,
:resolve_note
,
note
)
...
...
app/views/shared/groups/_group.html.haml
View file @
2c569be6
-
group_member
=
local_assigns
[
:group_member
]
-
user
=
local_assigns
.
fetch
(
:user
,
current_user
)
-
full_name
=
true
unless
local_assigns
[
:full_name
]
==
false
-
access
=
user
&
.
max_member_access_for_group
(
group
.
id
)
-
group_name
=
full_name
?
group
.
full_name
:
group
.
name
-
css_class
=
''
unless
local_assigns
[
:css_class
]
-
css_class
+=
" no-description"
if
group
.
description
.
blank?
%li
.group-row
{
class:
css_class
}
-
if
group_member
.controls.hidden-xs
-
if
can?
(
current_user
,
:admin_group
,
group
)
=
link_to
edit_group_path
(
group
),
class:
"btn"
do
=
sprite_icon
(
'settings'
)
=
link_to
leave_group_group_members_path
(
group
),
data:
{
confirm:
leave_confirmation_message
(
group
)
},
method: :delete
,
class:
"btn"
,
title:
s_
(
"GroupsTree|Leave this group"
)
do
=
icon
(
'sign-out'
)
%li
.group-row
{
class:
(
'no-description'
if
group
.
description
.
blank?
)
}
.stats
.stats
%span
%span
=
icon
(
'bookmark'
)
=
icon
(
'bookmark'
)
...
@@ -30,11 +18,10 @@
...
@@ -30,11 +18,10 @@
=
link_to
group
do
=
link_to
group
do
=
group_icon
(
group
,
class:
"avatar s40 hidden-xs"
)
=
group_icon
(
group
,
class:
"avatar s40 hidden-xs"
)
.title
.title
=
link_to
group_name
,
group
,
class:
'group-name'
=
link_to
group
.
full
_name
,
group
,
class:
'group-name'
-
if
group_member
-
if
access
&
.
nonzero?
as
%span
.user-access-role
=
Gitlab
::
Access
.
human_access
(
access
)
%span
=
group_member
.
human_access
-
if
group
.
description
.
present?
-
if
group
.
description
.
present?
.description
.description
...
...
app/views/shared/groups/_list.html.haml
View file @
2c569be6
-
if
groups
.
any?
-
if
groups
.
any?
-
user
=
local_assigns
[
:user
]
%ul
.content-list
%ul
.content-list
-
groups
.
each_with_index
do
|
group
,
i
|
-
groups
.
each_with_index
do
|
group
,
i
|
=
render
"shared/groups/group"
,
group:
group
=
render
"shared/groups/group"
,
group:
group
,
user:
user
-
else
-
else
.nothing-here-block
=
s_
(
"GroupsEmptyState|No groups found"
)
.nothing-here-block
=
s_
(
"GroupsEmptyState|No groups found"
)
app/views/shared/projects/_list.html.haml
View file @
2c569be6
...
@@ -5,18 +5,20 @@
...
@@ -5,18 +5,20 @@
-
forks
=
false
unless
local_assigns
[
:forks
]
==
true
-
forks
=
false
unless
local_assigns
[
:forks
]
==
true
-
ci
=
false
unless
local_assigns
[
:ci
]
==
true
-
ci
=
false
unless
local_assigns
[
:ci
]
==
true
-
skip_namespace
=
false
unless
local_assigns
[
:skip_namespace
]
==
true
-
skip_namespace
=
false
unless
local_assigns
[
:skip_namespace
]
==
true
-
user
=
local_assigns
[
:user
]
-
show_last_commit_as_description
=
false
unless
local_assigns
[
:show_last_commit_as_description
]
==
true
-
show_last_commit_as_description
=
false
unless
local_assigns
[
:show_last_commit_as_description
]
==
true
-
remote
=
false
unless
local_assigns
[
:remote
]
==
true
-
remote
=
false
unless
local_assigns
[
:remote
]
==
true
-
load_pipeline_status
(
projects
)
.js-projects-list-holder
.js-projects-list-holder
-
if
any_projects?
(
projects
)
-
if
any_projects?
(
projects
)
-
load_pipeline_status
(
projects
)
%ul
.projects-list
%ul
.projects-list
-
projects
.
each_with_index
do
|
project
,
i
|
-
projects
.
each_with_index
do
|
project
,
i
|
-
css_class
=
(
i
>=
projects_limit
)
||
project
.
pending_delete?
?
'hide'
:
nil
-
css_class
=
(
i
>=
projects_limit
)
||
project
.
pending_delete?
?
'hide'
:
nil
=
render
"shared/projects/project"
,
project:
project
,
skip_namespace:
skip_namespace
,
=
render
"shared/projects/project"
,
project:
project
,
skip_namespace:
skip_namespace
,
avatar:
avatar
,
stars:
stars
,
css_class:
css_class
,
ci:
ci
,
use_creator_avatar:
use_creator_avatar
,
avatar:
avatar
,
stars:
stars
,
css_class:
css_class
,
ci:
ci
,
use_creator_avatar:
use_creator_avatar
,
forks:
forks
,
show_last_commit_as_description:
show_last_commit_as_description
forks:
forks
,
show_last_commit_as_description:
show_last_commit_as_description
,
user:
user
-
if
@private_forks_count
&&
@private_forks_count
>
0
-
if
@private_forks_count
&&
@private_forks_count
>
0
%li
.project-row.private-forks-notice
%li
.project-row.private-forks-notice
...
...
app/views/shared/projects/_project.html.haml
View file @
2c569be6
...
@@ -3,6 +3,8 @@
...
@@ -3,6 +3,8 @@
-
forks
=
false
unless
local_assigns
[
:forks
]
==
true
-
forks
=
false
unless
local_assigns
[
:forks
]
==
true
-
ci
=
false
unless
local_assigns
[
:ci
]
==
true
-
ci
=
false
unless
local_assigns
[
:ci
]
==
true
-
skip_namespace
=
false
unless
local_assigns
[
:skip_namespace
]
==
true
-
skip_namespace
=
false
unless
local_assigns
[
:skip_namespace
]
==
true
-
user
=
local_assigns
[
:user
]
-
access
=
user
&
.
max_member_access_for_project
(
project
.
id
)
unless
user
.
nil?
-
css_class
=
''
unless
local_assigns
[
:css_class
]
-
css_class
=
''
unless
local_assigns
[
:css_class
]
-
show_last_commit_as_description
=
false
unless
local_assigns
[
:show_last_commit_as_description
]
==
true
&&
project
.
commit
-
show_last_commit_as_description
=
false
unless
local_assigns
[
:show_last_commit_as_description
]
==
true
&&
project
.
commit
-
css_class
+=
" no-description"
if
project
.
description
.
blank?
&&
!
show_last_commit_as_description
-
css_class
+=
" no-description"
if
project
.
description
.
blank?
&&
!
show_last_commit_as_description
...
@@ -21,14 +23,19 @@
...
@@ -21,14 +23,19 @@
.project-details
.project-details
%h3
.prepend-top-0.append-bottom-0
%h3
.prepend-top-0.append-bottom-0
=
link_to
project_path
(
project
),
class:
'text-plain'
do
=
link_to
project_path
(
project
),
class:
'text-plain'
do
%span
.project-full-name
%span
.project-full-name
>
<
%span
.namespace-name
%span
.namespace-name
-
if
project
.
namespace
&&
!
skip_namespace
-
if
project
.
namespace
&&
!
skip_namespace
=
project
.
namespace
.
human_name
=
project
.
namespace
.
human_name
\/
\/
%span
.project-name
%span
.project-name
<
=
project
.
name
=
project
.
name
-
if
access
&
.
nonzero?
-# haml-lint:disable UnnecessaryStringOutput
=
' '
# prevent haml from eating the space between elements
%span
.user-access-role
=
Gitlab
::
Access
.
human_access
(
access
)
-
if
show_last_commit_as_description
-
if
show_last_commit_as_description
.description.prepend-top-5
.description.prepend-top-5
=
link_to_markdown
(
project
.
commit
.
title
,
project_commit_path
(
project
,
project
.
commit
),
class:
"commit-row-message"
)
=
link_to_markdown
(
project
.
commit
.
title
,
project_commit_path
(
project
,
project
.
commit
),
class:
"commit-row-message"
)
...
...
spec/models/user_spec.rb
View file @
2c569be6
...
@@ -2433,4 +2433,163 @@ describe User do
...
@@ -2433,4 +2433,163 @@ describe User do
expect
(
user
).
not_to
be_blocked
expect
(
user
).
not_to
be_blocked
end
end
end
end
describe
'#max_member_access_for_project_ids'
do
shared_examples
'max member access for projects'
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:group
)
{
create
(
:group
)
}
let
(
:owner_project
)
{
create
(
:project
,
group:
group
)
}
let
(
:master_project
)
{
create
(
:project
)
}
let
(
:reporter_project
)
{
create
(
:project
)
}
let
(
:developer_project
)
{
create
(
:project
)
}
let
(
:guest_project
)
{
create
(
:project
)
}
let
(
:no_access_project
)
{
create
(
:project
)
}
let
(
:projects
)
do
[
owner_project
,
master_project
,
reporter_project
,
developer_project
,
guest_project
,
no_access_project
].
map
(
&
:id
)
end
let
(
:expected
)
do
{
owner_project
.
id
=>
Gitlab
::
Access
::
OWNER
,
master_project
.
id
=>
Gitlab
::
Access
::
MASTER
,
reporter_project
.
id
=>
Gitlab
::
Access
::
REPORTER
,
developer_project
.
id
=>
Gitlab
::
Access
::
DEVELOPER
,
guest_project
.
id
=>
Gitlab
::
Access
::
GUEST
,
no_access_project
.
id
=>
Gitlab
::
Access
::
NO_ACCESS
}
end
before
do
create
(
:group_member
,
user:
user
,
group:
group
)
master_project
.
add_master
(
user
)
reporter_project
.
add_reporter
(
user
)
developer_project
.
add_developer
(
user
)
guest_project
.
add_guest
(
user
)
end
it
'returns correct roles for different projects'
do
expect
(
user
.
max_member_access_for_project_ids
(
projects
)).
to
eq
(
expected
)
end
end
context
'with RequestStore enabled'
,
:request_store
do
include_examples
'max member access for projects'
def
access_levels
(
projects
)
user
.
max_member_access_for_project_ids
(
projects
)
end
it
'does not perform extra queries when asked for projects who have already been found'
do
access_levels
(
projects
)
expect
{
access_levels
(
projects
)
}.
not_to
exceed_query_limit
(
0
)
expect
(
access_levels
(
projects
)).
to
eq
(
expected
)
end
it
'only requests the extra projects when uncached projects are passed'
do
second_master_project
=
create
(
:project
)
second_developer_project
=
create
(
:project
)
second_master_project
.
add_master
(
user
)
second_developer_project
.
add_developer
(
user
)
all_projects
=
projects
+
[
second_master_project
.
id
,
second_developer_project
.
id
]
expected_all
=
expected
.
merge
(
second_master_project
.
id
=>
Gitlab
::
Access
::
MASTER
,
second_developer_project
.
id
=>
Gitlab
::
Access
::
DEVELOPER
)
access_levels
(
projects
)
queries
=
ActiveRecord
::
QueryRecorder
.
new
{
access_levels
(
all_projects
)
}
expect
(
queries
.
count
).
to
eq
(
1
)
expect
(
queries
.
log_message
).
to
match
(
/\W(
#{
second_master_project
.
id
}
,
#{
second_developer_project
.
id
}
)\W/
)
expect
(
access_levels
(
all_projects
)).
to
eq
(
expected_all
)
end
end
context
'with RequestStore disabled'
do
include_examples
'max member access for projects'
end
end
describe
'#max_member_access_for_group_ids'
do
shared_examples
'max member access for groups'
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:owner_group
)
{
create
(
:group
)
}
let
(
:master_group
)
{
create
(
:group
)
}
let
(
:reporter_group
)
{
create
(
:group
)
}
let
(
:developer_group
)
{
create
(
:group
)
}
let
(
:guest_group
)
{
create
(
:group
)
}
let
(
:no_access_group
)
{
create
(
:group
)
}
let
(
:groups
)
do
[
owner_group
,
master_group
,
reporter_group
,
developer_group
,
guest_group
,
no_access_group
].
map
(
&
:id
)
end
let
(
:expected
)
do
{
owner_group
.
id
=>
Gitlab
::
Access
::
OWNER
,
master_group
.
id
=>
Gitlab
::
Access
::
MASTER
,
reporter_group
.
id
=>
Gitlab
::
Access
::
REPORTER
,
developer_group
.
id
=>
Gitlab
::
Access
::
DEVELOPER
,
guest_group
.
id
=>
Gitlab
::
Access
::
GUEST
,
no_access_group
.
id
=>
Gitlab
::
Access
::
NO_ACCESS
}
end
before
do
owner_group
.
add_owner
(
user
)
master_group
.
add_master
(
user
)
reporter_group
.
add_reporter
(
user
)
developer_group
.
add_developer
(
user
)
guest_group
.
add_guest
(
user
)
end
it
'returns correct roles for different groups'
do
expect
(
user
.
max_member_access_for_group_ids
(
groups
)).
to
eq
(
expected
)
end
end
context
'with RequestStore enabled'
,
:request_store
do
include_examples
'max member access for groups'
def
access_levels
(
groups
)
user
.
max_member_access_for_group_ids
(
groups
)
end
it
'does not perform extra queries when asked for groups who have already been found'
do
access_levels
(
groups
)
expect
{
access_levels
(
groups
)
}.
not_to
exceed_query_limit
(
0
)
expect
(
access_levels
(
groups
)).
to
eq
(
expected
)
end
it
'only requests the extra groups when uncached groups are passed'
do
second_master_group
=
create
(
:group
)
second_developer_group
=
create
(
:group
)
second_master_group
.
add_master
(
user
)
second_developer_group
.
add_developer
(
user
)
all_groups
=
groups
+
[
second_master_group
.
id
,
second_developer_group
.
id
]
expected_all
=
expected
.
merge
(
second_master_group
.
id
=>
Gitlab
::
Access
::
MASTER
,
second_developer_group
.
id
=>
Gitlab
::
Access
::
DEVELOPER
)
access_levels
(
groups
)
queries
=
ActiveRecord
::
QueryRecorder
.
new
{
access_levels
(
all_groups
)
}
expect
(
queries
.
count
).
to
eq
(
1
)
expect
(
queries
.
log_message
).
to
match
(
/\W(
#{
second_master_group
.
id
}
,
#{
second_developer_group
.
id
}
)\W/
)
expect
(
access_levels
(
all_groups
)).
to
eq
(
expected_all
)
end
end
context
'with RequestStore disabled'
do
include_examples
'max member access for groups'
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment