Commit 2f69213e3f32e2e4222f6335e790e2c778069014

Authored by Jason Hollingsworth
1 parent 138e2a50

Allow access to groups with public projects.

Fixed Group avatars to only display when user has read
permissions to at least one project in the group.
app/controllers/dashboard_controller.rb
... ... @@ -77,5 +77,6 @@ class DashboardController < ApplicationController
77 77 def default_filter
78 78 params[:scope] = 'assigned-to-me' if params[:scope].blank?
79 79 params[:state] = 'opened' if params[:state].blank?
  80 + params[:authorized_only] = true
80 81 end
81 82 end
... ...
app/controllers/groups_controller.rb
1 1 class GroupsController < ApplicationController
  2 + skip_before_filter :authenticate_user!, only: [:show, :issues, :members, :merge_requests]
2 3 respond_to :html
3 4 before_filter :group, except: [:new, :create]
4 5  
... ... @@ -36,7 +37,7 @@ class GroupsController &lt; ApplicationController
36 37 @events = Event.in_projects(project_ids)
37 38 @events = event_filter.apply_filter(@events)
38 39 @events = @events.limit(20).offset(params[:offset] || 0)
39   - @last_push = current_user.recent_push
  40 + @last_push = current_user.recent_push if current_user
40 41  
41 42 respond_to do |format|
42 43 format.html
... ... @@ -98,17 +99,21 @@ class GroupsController &lt; ApplicationController
98 99 end
99 100  
100 101 def projects
101   - @projects ||= current_user.authorized_projects.where(namespace_id: group.id).sorted_by_activity
  102 + @projects ||= group.projects_accessible_to(current_user).sorted_by_activity
102 103 end
103 104  
104 105 def project_ids
105   - projects.map(&:id)
  106 + projects.pluck(:id)
106 107 end
107 108  
108 109 # Dont allow unauthorized access to group
109 110 def authorize_read_group!
110 111 unless @group and (projects.present? or can?(current_user, :read_group, @group))
111   - return render_404
  112 + if current_user.nil?
  113 + return authenticate_user!
  114 + else
  115 + return render_404
  116 + end
112 117 end
113 118 end
114 119  
... ... @@ -131,13 +136,21 @@ class GroupsController &lt; ApplicationController
131 136 def determine_layout
132 137 if [:new, :create].include?(action_name.to_sym)
133 138 'navless'
134   - else
  139 + elsif current_user
135 140 'group'
  141 + else
  142 + 'public_group'
136 143 end
137 144 end
138 145  
139 146 def default_filter
140   - params[:scope] = 'assigned-to-me' if params[:scope].blank?
  147 + if params[:scope].blank?
  148 + if current_user
  149 + params[:scope] = 'assigned-to-me'
  150 + else
  151 + params[:scope] = 'all'
  152 + end
  153 + end
141 154 params[:state] = 'opened' if params[:state].blank?
142 155 params[:group_id] = @group.id
143 156 end
... ...
app/controllers/public/projects_controller.rb
... ... @@ -6,7 +6,7 @@ class Public::ProjectsController &lt; ApplicationController
6 6 layout 'public'
7 7  
8 8 def index
9   - @projects = Project.public_or_internal_only(current_user)
  9 + @projects = Project.publicish(current_user)
10 10 @projects = @projects.search(params[:search]) if params[:search].present?
11 11 @projects = @projects.sort(@sort = params[:sort])
12 12 @projects = @projects.includes(:namespace).page(params[:page]).per(20)
... ...
app/controllers/users_controller.rb
1 1 class UsersController < ApplicationController
2   -
3 2 skip_before_filter :authenticate_user!, only: [:show]
4 3 layout :determine_layout
5 4  
6 5 def show
7 6 @user = User.find_by_username!(params[:username])
8   - @projects = @user.authorized_projects.includes(:namespace).select {|project| can?(current_user, :read_project, project)}
  7 + @projects = @user.authorized_projects.accessible_to(current_user)
9 8 if !current_user && @projects.empty?
10 9 return authenticate_user!
11 10 end
12   - @events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20)
  11 + @groups = @user.groups.accessible_to(current_user)
  12 + @events = @user.recent_events.where(project_id: @projects.pluck(:id)).limit(20)
13 13 @title = @user.name
14 14 end
15 15  
... ...
app/helpers/groups_helper.rb
... ... @@ -6,6 +6,14 @@ module GroupsHelper
6 6 def leave_group_message(group)
7 7 "Are you sure you want to leave \"#{group}\" group?"
8 8 end
  9 +
  10 + def should_user_see_group_roles?(user, group)
  11 + if user
  12 + user.is_admin? || group.members.exists?(user_id: user.id)
  13 + else
  14 + false
  15 + end
  16 + end
9 17  
10 18 def group_head_title
11 19 title = @group.name
... ...
app/helpers/search_helper.rb
... ... @@ -4,8 +4,7 @@ module SearchHelper
4 4  
5 5 resources_results = [
6 6 groups_autocomplete(term),
7   - projects_autocomplete(term),
8   - public_projects_autocomplete(term),
  7 + projects_autocomplete(term)
9 8 ].flatten
10 9  
11 10 generic_results = project_autocomplete + default_autocomplete + help_autocomplete
... ... @@ -82,17 +81,7 @@ module SearchHelper
82 81  
83 82 # Autocomplete results for the current user's projects
84 83 def projects_autocomplete(term, limit = 5)
85   - current_user.authorized_projects.search_by_title(term).non_archived.limit(limit).map do |p|
86   - {
87   - label: "project: #{search_result_sanitize(p.name_with_namespace)}",
88   - url: project_path(p)
89   - }
90   - end
91   - end
92   -
93   - # Autocomplete results for the current user's projects
94   - def public_projects_autocomplete(term, limit = 5)
95   - Project.public_or_internal_only(current_user).search_by_title(term).non_archived.limit(limit).map do |p|
  84 + Project.accessible_to(current_user).search_by_title(term).non_archived.limit(limit).map do |p|
96 85 {
97 86 label: "project: #{search_result_sanitize(p.name_with_namespace)}",
98 87 url: project_path(p)
... ...
app/models/ability.rb
... ... @@ -43,7 +43,19 @@ class Ability
43 43 :download_code
44 44 ]
45 45 else
46   - []
  46 + group = if subject.kind_of?(Group)
  47 + subject
  48 + elsif subject.respond_to?(:group)
  49 + subject.group
  50 + else
  51 + nil
  52 + end
  53 +
  54 + if group && group.has_projects_accessible_to?(nil)
  55 + [:read_group]
  56 + else
  57 + []
  58 + end
47 59 end
48 60 end
49 61  
... ... @@ -172,7 +184,7 @@ class Ability
172 184 def group_abilities user, group
173 185 rules = []
174 186  
175   - if group.users.include?(user) || user.admin?
  187 + if user.admin? || group.users.include?(user) || group.has_projects_accessible_to?(user)
176 188 rules << :read_group
177 189 end
178 190  
... ...
app/models/group.rb
... ... @@ -25,6 +25,12 @@ class Group &lt; Namespace
25 25 validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
26 26  
27 27 mount_uploader :avatar, AttachmentUploader
  28 +
  29 + def self.accessible_to(user)
  30 + accessible_ids = Project.accessible_to(user).pluck(:namespace_id)
  31 + accessible_ids += user.groups.pluck(:id) if user
  32 + where(id: accessible_ids)
  33 + end
28 34  
29 35 def human_name
30 36 name
... ...
app/models/namespace.rb
... ... @@ -47,6 +47,14 @@ class Namespace &lt; ActiveRecord::Base
47 47 def self.global_id
48 48 'GLN'
49 49 end
  50 +
  51 + def projects_accessible_to(user)
  52 + projects.accessible_to(user)
  53 + end
  54 +
  55 + def has_projects_accessible_to?(user)
  56 + projects_accessible_to(user).present?
  57 + end
50 58  
51 59 def to_param
52 60 path
... ...
app/models/project.rb
... ... @@ -114,8 +114,6 @@ class Project &lt; ActiveRecord::Base
114 114 scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") }
115 115 scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
116 116 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
117   - scope :public_only, -> { where(visibility_level: PUBLIC) }
118   - scope :public_or_internal_only, ->(user) { where("visibility_level IN (:levels)", levels: user ? [ INTERNAL, PUBLIC ] : [ PUBLIC ]) }
119 117  
120 118 scope :non_archived, -> { where(archived: false) }
121 119  
... ... @@ -125,6 +123,18 @@ class Project &lt; ActiveRecord::Base
125 123 def abandoned
126 124 where('projects.last_activity_at < ?', 6.months.ago)
127 125 end
  126 +
  127 + def publicish(user)
  128 + visibility_levels = [Project::PUBLIC]
  129 + visibility_levels += [Project::INTERNAL] if user
  130 + where(visibility_level: visibility_levels)
  131 + end
  132 +
  133 + def accessible_to(user)
  134 + accessible_ids = publicish(user).pluck(:id)
  135 + accessible_ids += user.authorized_projects.pluck(:id) if user
  136 + where(id: accessible_ids)
  137 + end
128 138  
129 139 def with_push
130 140 includes(:events).where('events.action = ?', Event::PUSHED)
... ...
app/services/filtering_service.rb
... ... @@ -41,16 +41,16 @@ class FilteringService
41 41 def init_collection
42 42 table_name = klass.table_name
43 43  
44   - return klass.of_projects(Project.public_only) unless current_user
45   -
46 44 if project
47   - if current_user.can?(:read_project, project)
  45 + if project.public? || (current_user && current_user.can?(:read_project, project))
48 46 project.send(table_name)
49 47 else
50 48 []
51 49 end
52   - else
  50 + elsif current_user && params[:authorized_only].presence
53 51 klass.of_projects(current_user.authorized_projects)
  52 + else
  53 + klass.of_projects(Project.accessible_to(current_user))
54 54 end
55 55 end
56 56  
... ...
app/services/search/global_service.rb
... ... @@ -11,12 +11,8 @@ module Search
11 11 query = Shellwords.shellescape(query) if query.present?
12 12 return result unless query.present?
13 13  
14   - authorized_projects_ids = []
15   - authorized_projects_ids += current_user.authorized_projects.pluck(:id) if current_user
16   - authorized_projects_ids += Project.public_or_internal_only(current_user).pluck(:id)
17   -
18 14 group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
19   - projects = Project.where(id: authorized_projects_ids)
  15 + projects = Project.accessible_to(current_user)
20 16 projects = projects.where(namespace_id: group.id) if group
21 17 projects = projects.search(query)
22 18 project_ids = projects.pluck(:id)
... ...
app/views/groups/issues.html.haml
... ... @@ -5,7 +5,9 @@
5 5 %p.light
6 6 Only issues from
7 7 %strong #{@group.name}
8   - group are listed here. To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
  8 + group are listed here.
  9 + - if current_user
  10 + To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
9 11 %hr
10 12  
11 13 .row
... ...
app/views/groups/members.html.haml
  1 +- show_roles = should_user_see_group_roles?(current_user, @group)
1 2 %h3.page-title
2 3 Group members
3   -%p.light
4   - Members of group have access to all group projects.
5   - Read more about permissions
6   - %strong= link_to "here", help_permissions_path, class: "vlink"
  4 +- if show_roles
  5 + %p.light
  6 + Members of group have access to all group projects.
  7 + Read more about permissions
  8 + %strong= link_to "here", help_permissions_path, class: "vlink"
7 9  
8 10 %hr
9 11  
... ... @@ -13,7 +15,7 @@
13 15 = search_field_tag :search, params[:search], { placeholder: 'Find member by name', class: 'form-control search-text-input input-mn-300' }
14 16 = submit_tag 'Search', class: 'btn'
15 17  
16   - - if current_user.can? :manage_group, @group
  18 + - if current_user && current_user.can?(:manage_group, @group)
17 19 .pull-right
18 20 = link_to '#', class: 'btn btn-new js-toggle-visibility-link' do
19 21 Add members
... ... @@ -30,7 +32,7 @@
30 32 (#{@members.total_count})
31 33 %ul.well-list
32 34 - @members.each do |member|
33   - = render 'users_groups/users_group', member: member, show_controls: true
  35 + = render 'users_groups/users_group', member: member, show_roles: show_roles, show_controls: true
34 36 = paginate @members, theme: 'gitlab'
35 37  
36 38 :coffeescript
... ...
app/views/groups/merge_requests.html.haml
... ... @@ -5,7 +5,9 @@
5 5 %p.light
6 6 Only merge requests from
7 7 %strong #{@group.name}
8   - group are listed here. To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
  8 + group are listed here.
  9 + - if current_user
  10 + To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
9 11 %hr
10 12 .row
11 13 .col-md-3
... ...
app/views/groups/show.html.haml
1 1 .dashboard
2 2 .activities.col-md-8.hidden-sm
3   - = render "events/event_last_push", event: @last_push
4   - = link_to dashboard_path, class: 'btn btn-tiny' do
5   - &larr; To dashboard
6   - &nbsp;
  3 + - if current_user
  4 + = render "events/event_last_push", event: @last_push
  5 + = link_to dashboard_path, class: 'btn btn-tiny' do
  6 + &larr; To dashboard
  7 + &nbsp;
7 8 %span.cgray You will only see events from projects in this group
8 9 %hr
9 10 = render 'shared/event_filter'
... ... @@ -21,11 +22,12 @@
21 22 - if @group.description.present?
22 23 %p= @group.description
23 24 = render "projects", projects: @projects
24   - .prepend-top-20
25   - = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed" do
26   - %strong
27   - %i.icon-rss
28   - News Feed
  25 + - if current_user
  26 + .prepend-top-20
  27 + = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed" do
  28 + %strong
  29 + %i.icon-rss
  30 + News Feed
29 31  
30 32 %hr
31 33 = render 'shared/promo'
... ...
app/views/layouts/nav/_group.html.haml
... ... @@ -5,11 +5,13 @@
5 5 = nav_link(path: 'groups#issues') do
6 6 = link_to issues_group_path(@group) do
7 7 Issues
8   - %span.count= current_user.assigned_issues.opened.of_group(@group).count
  8 + - if current_user
  9 + %span.count= current_user.assigned_issues.opened.of_group(@group).count
9 10 = nav_link(path: 'groups#merge_requests') do
10 11 = link_to merge_requests_group_path(@group) do
11 12 Merge Requests
12   - %span.count= current_user.cared_merge_requests.opened.of_group(@group).count
  13 + - if current_user
  14 + %span.count= current_user.cared_merge_requests.opened.of_group(@group).count
13 15 = nav_link(path: 'groups#members') do
14 16 = link_to "Members", members_group_path(@group)
15 17  
... ...
app/views/layouts/public_group.html.haml 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +!!! 5
  2 +%html{ lang: "en"}
  3 + = render "layouts/head", title: group_head_title
  4 + %body{class: "#{app_theme} application", :'data-page' => body_data_page}
  5 + = render "layouts/broadcast"
  6 + = render "layouts/public_head_panel", title: "group: #{@group.name}"
  7 + %nav.main-nav.navbar-collapse.collapse
  8 + .container= render 'layouts/nav/group'
  9 + .container
  10 + .content= yield
... ...
app/views/layouts/public_projects.html.haml
... ... @@ -3,7 +3,7 @@
3 3 = render "layouts/head", title: @project.name_with_namespace
4 4 %body{class: "#{app_theme} application", :'data-page' => body_data_page}
5 5 = render "layouts/broadcast"
6   - = render "layouts/public_head_panel", title: @project.name_with_namespace
  6 + = render "layouts/public_head_panel", title: project_title(@project)
7 7 %nav.main-nav
8 8 .container= render 'layouts/nav/project'
9 9 .container
... ...
app/views/shared/_filter.html.haml
1 1 .side-filters.hidden-xs.hidden-sm
2 2 = form_tag filter_path(entity), method: 'get' do
3   - %fieldset.scope-filter
4   - %ul.nav.nav-pills.nav-stacked
5   - %li{class: ("active" if params[:scope] == 'assigned-to-me')}
6   - = link_to filter_path(entity, scope: 'assigned-to-me') do
7   - Assigned to me
8   - %li{class: ("active" if params[:scope] == 'authored')}
9   - = link_to filter_path(entity, scope: 'authored') do
10   - Created by me
11   - %li{class: ("active" if params[:scope] == 'all')}
12   - = link_to filter_path(entity, scope: 'all') do
13   - Everyone's
  3 + - if current_user
  4 + %fieldset.scope-filter
  5 + %ul.nav.nav-pills.nav-stacked
  6 + %li{class: ("active" if params[:scope] == 'assigned-to-me')}
  7 + = link_to filter_path(entity, scope: 'assigned-to-me') do
  8 + Assigned to me
  9 + %li{class: ("active" if params[:scope] == 'authored')}
  10 + = link_to filter_path(entity, scope: 'authored') do
  11 + Created by me
  12 + %li{class: ("active" if params[:scope] == 'all')}
  13 + = link_to filter_path(entity, scope: 'all') do
  14 + Everyone's
14 15  
15 16 %fieldset.status-filter
16 17 %legend State
... ...
app/views/users/show.html.haml
... ... @@ -14,10 +14,10 @@
14 14 %small member since #{@user.created_at.stamp("Nov 12, 2031")}
15 15 .clearfix
16 16 %h4 Groups:
17   - = render 'groups', groups: @user.groups
  17 + = render 'groups', groups: @groups
18 18 %hr
19 19 %h4 User Activity:
20 20 = render @events
21 21 .col-md-4
22 22 = render 'profile', user: @user
23   - = render 'projects', user: @user
  23 + = render 'projects'
... ...
app/views/users_groups/_users_group.html.haml
1 1 - user = member.user
2 2 - return unless user
  3 +- show_roles = true if show_roles.nil?
3 4 %li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)}
4 5 = image_tag avatar_icon(user.email, 16), class: "avatar s16"
5 6 %strong= user.name
... ... @@ -7,22 +8,23 @@
7 8 - if user == current_user
8 9 %span.label.label-success It's you
9 10  
10   - %span.pull-right
11   - %strong= member.human_access
12   - - if show_controls
13   - - if can?(current_user, :modify, member)
14   - = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
15   - %i.icon-edit
16   - - if can?(current_user, :destroy, member)
17   - - if current_user == member.user
18   - = link_to leave_profile_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
19   - %i.icon-minus.icon-white
20   - - else
21   - = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
22   - %i.icon-minus.icon-white
23   -
24   - .edit-member.hide.js-toggle-content
25   - = form_for [@group, member], remote: true do |f|
26   - .alert.prepend-top-20
27   - = f.select :group_access, options_for_select(UsersGroup.group_access_roles, member.group_access)
28   - = f.submit 'Save', class: 'btn btn-save btn-small'
  11 + - if show_roles
  12 + %span.pull-right
  13 + %strong= member.human_access
  14 + - if show_controls
  15 + - if can?(current_user, :modify, member)
  16 + = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
  17 + %i.icon-edit
  18 + - if can?(current_user, :destroy, member)
  19 + - if current_user == member.user
  20 + = link_to leave_profile_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
  21 + %i.icon-minus.icon-white
  22 + - else
  23 + = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
  24 + %i.icon-minus.icon-white
  25 +
  26 + .edit-member.hide.js-toggle-content
  27 + = form_for [@group, member], remote: true do |f|
  28 + .alert.prepend-top-20
  29 + = f.select :group_access, options_for_select(UsersGroup.group_access_roles, member.group_access)
  30 + = f.submit 'Save', class: 'btn btn-save btn-small'
... ...
features/public/public_groups.feature 0 → 100644
... ... @@ -0,0 +1,118 @@
  1 +Feature: Public Projects Feature
  2 + Background:
  3 + Given group "TestGroup" has private project "Enterprise"
  4 +
  5 + Scenario: I should not see group with private projects as visitor
  6 + When I visit group "TestGroup" page
  7 + Then I should be redirected to sign in page
  8 +
  9 + Scenario: I should not see group with private projects group as user
  10 + When I sign in as a user
  11 + And I visit group "TestGroup" page
  12 + Then page status code should be 404
  13 +
  14 + Scenario: I should not see group with private and internal projects as visitor
  15 + Given group "TestGroup" has internal project "Internal"
  16 + When I visit group "TestGroup" page
  17 + Then I should be redirected to sign in page
  18 +
  19 + Scenario: I should see group with private and internal projects as user
  20 + Given group "TestGroup" has internal project "Internal"
  21 + When I sign in as a user
  22 + And I visit group "TestGroup" page
  23 + Then I should see project "Internal" items
  24 + And I should not see project "Enterprise" items
  25 +
  26 + Scenario: I should see group issues for internal project as user
  27 + Given group "TestGroup" has internal project "Internal"
  28 + When I sign in as a user
  29 + And I visit group "TestGroup" issues page
  30 + And I change filter to Everyone's
  31 + Then I should see project "Internal" items
  32 + And I should not see project "Enterprise" items
  33 +
  34 + Scenario: I should see group merge requests for internal project as user
  35 + Given group "TestGroup" has internal project "Internal"
  36 + When I sign in as a user
  37 + And I visit group "TestGroup" merge requests page
  38 + And I change filter to Everyone's
  39 + Then I should see project "Internal" items
  40 + And I should not see project "Enterprise" items
  41 +
  42 + Scenario: I should see group's members as user
  43 + Given group "TestGroup" has internal project "Internal"
  44 + And "John Doe" is owner of group "TestGroup"
  45 + When I sign in as a user
  46 + And I visit group "TestGroup" members page
  47 + Then I should see group member "John Doe"
  48 + And I should not see member roles
  49 +
  50 + Scenario: I should see group with private, internal and public projects as visitor
  51 + Given group "TestGroup" has internal project "Internal"
  52 + Given group "TestGroup" has public project "Community"
  53 + When I visit group "TestGroup" page
  54 + Then I should see project "Community" items
  55 + And I should not see project "Internal" items
  56 + And I should not see project "Enterprise" items
  57 +
  58 + Scenario: I should see group issues for public project as visitor
  59 + Given group "TestGroup" has internal project "Internal"
  60 + Given group "TestGroup" has public project "Community"
  61 + When I visit group "TestGroup" issues page
  62 + Then I should see project "Community" items
  63 + And I should not see project "Internal" items
  64 + And I should not see project "Enterprise" items
  65 +
  66 + Scenario: I should see group merge requests for public project as visitor
  67 + Given group "TestGroup" has internal project "Internal"
  68 + Given group "TestGroup" has public project "Community"
  69 + When I visit group "TestGroup" merge requests page
  70 + Then I should see project "Community" items
  71 + And I should not see project "Internal" items
  72 + And I should not see project "Enterprise" items
  73 +
  74 + Scenario: I should see group's members as visitor
  75 + Given group "TestGroup" has internal project "Internal"
  76 + Given group "TestGroup" has public project "Community"
  77 + And "John Doe" is owner of group "TestGroup"
  78 + When I visit group "TestGroup" members page
  79 + Then I should see group member "John Doe"
  80 + And I should not see member roles
  81 +
  82 + Scenario: I should see group with private, internal and public projects as user
  83 + Given group "TestGroup" has internal project "Internal"
  84 + Given group "TestGroup" has public project "Community"
  85 + When I sign in as a user
  86 + And I visit group "TestGroup" page
  87 + Then I should see project "Community" items
  88 + And I should see project "Internal" items
  89 + And I should not see project "Enterprise" items
  90 +
  91 + Scenario: I should see group issues for internal and public projects as user
  92 + Given group "TestGroup" has internal project "Internal"
  93 + Given group "TestGroup" has public project "Community"
  94 + When I sign in as a user
  95 + And I visit group "TestGroup" issues page
  96 + And I change filter to Everyone's
  97 + Then I should see project "Community" items
  98 + And I should see project "Internal" items
  99 + And I should not see project "Enterprise" items
  100 +
  101 + Scenario: I should see group merge requests for internal and public projects as user
  102 + Given group "TestGroup" has internal project "Internal"
  103 + Given group "TestGroup" has public project "Community"
  104 + When I sign in as a user
  105 + And I visit group "TestGroup" merge requests page
  106 + And I change filter to Everyone's
  107 + Then I should see project "Community" items
  108 + And I should see project "Internal" items
  109 + And I should not see project "Enterprise" items
  110 +
  111 + Scenario: I should see group's members as user
  112 + Given group "TestGroup" has internal project "Internal"
  113 + Given group "TestGroup" has public project "Community"
  114 + And "John Doe" is owner of group "TestGroup"
  115 + When I sign in as a user
  116 + And I visit group "TestGroup" members page
  117 + Then I should see group member "John Doe"
  118 + And I should not see member roles
... ...
features/steps/public/groups_feature.rb 0 → 100644
... ... @@ -0,0 +1,93 @@
  1 +class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps
  2 + include SharedAuthentication
  3 + include SharedPaths
  4 + include SharedGroup
  5 + include SharedProject
  6 +
  7 + step 'group "TestGroup" has private project "Enterprise"' do
  8 + group_has_project("TestGroup", "Enterprise", Gitlab::VisibilityLevel::PRIVATE)
  9 + end
  10 +
  11 + step 'group "TestGroup" has internal project "Internal"' do
  12 + group_has_project("TestGroup", "Internal", Gitlab::VisibilityLevel::INTERNAL)
  13 + end
  14 +
  15 + step 'group "TestGroup" has public project "Community"' do
  16 + group_has_project("TestGroup", "Community", Gitlab::VisibilityLevel::PUBLIC)
  17 + end
  18 +
  19 + step '"John Doe" is owner of group "TestGroup"' do
  20 + group = Group.find_by(name: "TestGroup") || create(:group, name: "TestGroup")
  21 + user = create(:user, name: "John Doe")
  22 + group.add_user(user, Gitlab::Access::OWNER)
  23 + end
  24 +
  25 + step 'I visit group "TestGroup" page' do
  26 + visit group_path(Group.find_by(name: "TestGroup"))
  27 + end
  28 +
  29 + step 'I visit group "TestGroup" issues page' do
  30 + visit issues_group_path(Group.find_by(name: "TestGroup"))
  31 + end
  32 +
  33 + step 'I visit group "TestGroup" merge requests page' do
  34 + visit merge_requests_group_path(Group.find_by(name: "TestGroup"))
  35 + end
  36 +
  37 + step 'I visit group "TestGroup" members page' do
  38 + visit members_group_path(Group.find_by(name: "TestGroup"))
  39 + end
  40 +
  41 + step 'I should not see project "Enterprise" items' do
  42 + page.should_not have_content "Enterprise"
  43 + end
  44 +
  45 + step 'I should see project "Internal" items' do
  46 + page.should have_content "Internal"
  47 + end
  48 +
  49 + step 'I should not see project "Internal" items' do
  50 + page.should_not have_content "Internal"
  51 + end
  52 +
  53 + step 'I should see project "Community" items' do
  54 + page.should have_content "Community"
  55 + end
  56 +
  57 + step 'I change filter to Everyone\'s' do
  58 + click_link "Everyone's"
  59 + end
  60 +
  61 + step 'I should see group member "John Doe"' do
  62 + page.should have_content "John Doe"
  63 + end
  64 +
  65 + step 'I should not see member roles' do
  66 + page.body.should_not match(%r{owner|developer|reporter|guest}i)
  67 + end
  68 +
  69 + protected
  70 +
  71 + def group_has_project(groupname, projectname, visibility_level)
  72 + group = Group.find_by(name: groupname) || create(:group, name: groupname)
  73 + project = create(:project,
  74 + namespace: group,
  75 + name: projectname,
  76 + path: "#{groupname}-#{projectname}",
  77 + visibility_level: visibility_level
  78 + )
  79 + create(:issue,
  80 + title: "#{projectname} feature",
  81 + project: project
  82 + )
  83 + create(:merge_request,
  84 + title: "#{projectname} feature implemented",
  85 + source_project: project,
  86 + target_project: project
  87 + )
  88 + create(:closed_issue_event,
  89 + project: project
  90 + )
  91 + end
  92 +end
  93 +
... ...
spec/features/security/group/group_access_spec.rb 0 → 100644
... ... @@ -0,0 +1,91 @@
  1 +require 'spec_helper'
  2 +
  3 +describe "Group access" do
  4 + describe "GET /projects/new" do
  5 + it { new_group_path.should be_allowed_for :admin }
  6 + it { new_group_path.should be_allowed_for :user }
  7 + it { new_group_path.should be_denied_for :visitor }
  8 + end
  9 +
  10 + describe "Group" do
  11 + let(:group) { create(:group) }
  12 +
  13 + let(:owner) { create(:owner) }
  14 + let(:master) { create(:user) }
  15 + let(:reporter) { create(:user) }
  16 + let(:guest) { create(:user) }
  17 + let(:nonmember) { create(:user) }
  18 +
  19 + before do
  20 + group.add_user(owner, Gitlab::Access::OWNER)
  21 + group.add_user(master, Gitlab::Access::MASTER)
  22 + group.add_user(reporter, Gitlab::Access::REPORTER)
  23 + group.add_user(guest, Gitlab::Access::GUEST)
  24 + end
  25 +
  26 + describe "Group should not have accessible projects" do
  27 + it { group.has_projects_accessible_to?(nil).should be_false }
  28 + it { group.has_projects_accessible_to?(nonmember).should be_false }
  29 + end
  30 +
  31 + describe "GET /groups/:path" do
  32 + subject { group_path(group) }
  33 +
  34 + it { should be_allowed_for owner }
  35 + it { should be_allowed_for master }
  36 + it { should be_allowed_for reporter }
  37 + it { should be_allowed_for :admin }
  38 + it { should be_allowed_for guest }
  39 + it { should be_denied_for :user }
  40 + it { should be_denied_for :visitor }
  41 + end
  42 +
  43 + describe "GET /groups/:path/issues" do
  44 + subject { issues_group_path(group) }
  45 +
  46 + it { should be_allowed_for owner }
  47 + it { should be_allowed_for master }
  48 + it { should be_allowed_for reporter }
  49 + it { should be_allowed_for :admin }
  50 + it { should be_allowed_for guest }
  51 + it { should be_denied_for :user }
  52 + it { should be_denied_for :visitor }
  53 + end
  54 +
  55 + describe "GET /groups/:path/merge_requests" do
  56 + subject { merge_requests_group_path(group) }
  57 +
  58 + it { should be_allowed_for owner }
  59 + it { should be_allowed_for master }
  60 + it { should be_allowed_for reporter }
  61 + it { should be_allowed_for :admin }
  62 + it { should be_allowed_for guest }
  63 + it { should be_denied_for :user }
  64 + it { should be_denied_for :visitor }
  65 + end
  66 +
  67 + describe "GET /groups/:path/members" do
  68 + subject { members_group_path(group) }
  69 +
  70 + it { should be_allowed_for owner }
  71 + it { should be_allowed_for master }
  72 + it { should be_allowed_for reporter }
  73 + it { should be_allowed_for :admin }
  74 + it { should be_allowed_for guest }
  75 + it { should be_denied_for :user }
  76 + it { should be_denied_for :visitor }
  77 + end
  78 +
  79 + describe "GET /groups/:path/edit" do
  80 + subject { edit_group_path(group) }
  81 +
  82 + it { should be_allowed_for owner }
  83 + it { should be_denied_for master }
  84 + it { should be_denied_for reporter }
  85 + it { should be_allowed_for :admin }
  86 + it { should be_denied_for guest }
  87 + it { should be_denied_for :user }
  88 + it { should be_denied_for :visitor }
  89 + end
  90 + end
  91 +end
... ...
spec/features/security/group/internal_group_access_spec.rb 0 → 100644
... ... @@ -0,0 +1,87 @@
  1 +require 'spec_helper'
  2 +
  3 +describe "Group with internal project access" do
  4 + describe "Group" do
  5 + let(:group) { create(:group) }
  6 +
  7 + let(:owner) { create(:owner) }
  8 + let(:master) { create(:user) }
  9 + let(:reporter) { create(:user) }
  10 + let(:guest) { create(:user) }
  11 + let(:nonmember) { create(:user) }
  12 +
  13 + before do
  14 + group.add_user(owner, Gitlab::Access::OWNER)
  15 + group.add_user(master, Gitlab::Access::MASTER)
  16 + group.add_user(reporter, Gitlab::Access::REPORTER)
  17 + group.add_user(guest, Gitlab::Access::GUEST)
  18 +
  19 + create(:project, group: group, visibility_level: Gitlab::VisibilityLevel::INTERNAL)
  20 + end
  21 +
  22 + describe "Group should have accessible projects for users" do
  23 + it { group.has_projects_accessible_to?(nil).should be_false }
  24 + it { group.has_projects_accessible_to?(nonmember).should be_true }
  25 + end
  26 +
  27 + describe "GET /groups/:path" do
  28 + subject { group_path(group) }
  29 +
  30 + it { should be_allowed_for owner }
  31 + it { should be_allowed_for master }
  32 + it { should be_allowed_for reporter }
  33 + it { should be_allowed_for :admin }
  34 + it { should be_allowed_for guest }
  35 + it { should be_allowed_for :user }
  36 + it { should be_denied_for :visitor }
  37 + end
  38 +
  39 + describe "GET /groups/:path/issues" do
  40 + subject { issues_group_path(group) }
  41 +
  42 + it { should be_allowed_for owner }
  43 + it { should be_allowed_for master }
  44 + it { should be_allowed_for reporter }
  45 + it { should be_allowed_for :admin }
  46 + it { should be_allowed_for guest }
  47 + it { should be_allowed_for :user }
  48 + it { should be_denied_for :visitor }
  49 + end
  50 +
  51 + describe "GET /groups/:path/merge_requests" do
  52 + subject { merge_requests_group_path(group) }
  53 +
  54 + it { should be_allowed_for owner }
  55 + it { should be_allowed_for master }
  56 + it { should be_allowed_for reporter }
  57 + it { should be_allowed_for :admin }
  58 + it { should be_allowed_for guest }
  59 + it { should be_allowed_for :user }
  60 + it { should be_denied_for :visitor }
  61 + end
  62 +
  63 + describe "GET /groups/:path/members" do
  64 + subject { members_group_path(group) }
  65 +
  66 + it { should be_allowed_for owner }
  67 + it { should be_allowed_for master }
  68 + it { should be_allowed_for reporter }
  69 + it { should be_allowed_for :admin }
  70 + it { should be_allowed_for guest }
  71 + it { should be_allowed_for :user }
  72 + it { should be_denied_for :visitor }
  73 + end
  74 +
  75 + describe "GET /groups/:path/edit" do
  76 + subject { edit_group_path(group) }
  77 +
  78 + it { should be_allowed_for owner }
  79 + it { should be_denied_for master }
  80 + it { should be_denied_for reporter }
  81 + it { should be_allowed_for :admin }
  82 + it { should be_denied_for guest }
  83 + it { should be_denied_for :user }
  84 + it { should be_denied_for :visitor }
  85 + end
  86 + end
  87 +end
... ...
spec/features/security/group/mixed_group_access_spec.rb 0 → 100644
... ... @@ -0,0 +1,88 @@
  1 +require 'spec_helper'
  2 +
  3 +describe "Group access" do
  4 + describe "Group" do
  5 + let(:group) { create(:group) }
  6 +
  7 + let(:owner) { create(:owner) }
  8 + let(:master) { create(:user) }
  9 + let(:reporter) { create(:user) }
  10 + let(:guest) { create(:user) }
  11 + let(:nonmember) { create(:user) }
  12 +
  13 + before do
  14 + group.add_user(owner, Gitlab::Access::OWNER)
  15 + group.add_user(master, Gitlab::Access::MASTER)
  16 + group.add_user(reporter, Gitlab::Access::REPORTER)
  17 + group.add_user(guest, Gitlab::Access::GUEST)
  18 +
  19 + create(:project, path: "internal_project", group: group, visibility_level: Gitlab::VisibilityLevel::INTERNAL)
  20 + create(:project, path: "public_project", group: group, visibility_level: Gitlab::VisibilityLevel::PUBLIC)
  21 + end
  22 +
  23 + describe "Group should have accessible projects" do
  24 + it { group.has_projects_accessible_to?(nil).should be_true }
  25 + it { group.has_projects_accessible_to?(nonmember).should be_true }
  26 + end
  27 +
  28 + describe "GET /groups/:path" do
  29 + subject { group_path(group) }
  30 +
  31 + it { should be_allowed_for owner }
  32 + it { should be_allowed_for master }
  33 + it { should be_allowed_for reporter }
  34 + it { should be_allowed_for :admin }
  35 + it { should be_allowed_for guest }
  36 + it { should be_allowed_for :user }
  37 + it { should be_allowed_for :visitor }
  38 + end
  39 +
  40 + describe "GET /groups/:path/issues" do
  41 + subject { issues_group_path(group) }
  42 +
  43 + it { should be_allowed_for owner }
  44 + it { should be_allowed_for master }
  45 + it { should be_allowed_for reporter }
  46 + it { should be_allowed_for :admin }
  47 + it { should be_allowed_for guest }
  48 + it { should be_allowed_for :user }
  49 + it { should be_allowed_for :visitor }
  50 + end
  51 +
  52 + describe "GET /groups/:path/merge_requests" do
  53 + subject { merge_requests_group_path(group) }
  54 +
  55 + it { should be_allowed_for owner }
  56 + it { should be_allowed_for master }
  57 + it { should be_allowed_for reporter }
  58 + it { should be_allowed_for :admin }
  59 + it { should be_allowed_for guest }
  60 + it { should be_allowed_for :user }
  61 + it { should be_allowed_for :visitor }
  62 + end
  63 +
  64 + describe "GET /groups/:path/members" do
  65 + subject { members_group_path(group) }
  66 +
  67 + it { should be_allowed_for owner }
  68 + it { should be_allowed_for master }
  69 + it { should be_allowed_for reporter }
  70 + it { should be_allowed_for :admin }
  71 + it { should be_allowed_for guest }
  72 + it { should be_allowed_for :user }
  73 + it { should be_allowed_for :visitor }
  74 + end
  75 +
  76 + describe "GET /groups/:path/edit" do
  77 + subject { edit_group_path(group) }
  78 +
  79 + it { should be_allowed_for owner }
  80 + it { should be_denied_for master }
  81 + it { should be_denied_for reporter }
  82 + it { should be_allowed_for :admin }
  83 + it { should be_denied_for guest }
  84 + it { should be_denied_for :user }
  85 + it { should be_denied_for :visitor }
  86 + end
  87 + end
  88 +end
... ...
spec/features/security/group/public_group_access_spec.rb 0 → 100644
... ... @@ -0,0 +1,87 @@
  1 +require 'spec_helper'
  2 +
  3 +describe "Group with public project access" do
  4 + describe "Group" do
  5 + let(:group) { create(:group) }
  6 +
  7 + let(:owner) { create(:owner) }
  8 + let(:master) { create(:user) }
  9 + let(:reporter) { create(:user) }
  10 + let(:guest) { create(:user) }
  11 + let(:nonmember) { create(:user) }
  12 +
  13 + before do
  14 + group.add_user(owner, Gitlab::Access::OWNER)
  15 + group.add_user(master, Gitlab::Access::MASTER)
  16 + group.add_user(reporter, Gitlab::Access::REPORTER)
  17 + group.add_user(guest, Gitlab::Access::GUEST)
  18 +
  19 + create(:project, group: group, visibility_level: Gitlab::VisibilityLevel::PUBLIC)
  20 + end
  21 +
  22 + describe "Group should have accessible projects" do
  23 + it { group.has_projects_accessible_to?(nil).should be_true }
  24 + it { group.has_projects_accessible_to?(nonmember).should be_true }
  25 + end
  26 +
  27 + describe "GET /groups/:path" do
  28 + subject { group_path(group) }
  29 +
  30 + it { should be_allowed_for owner }
  31 + it { should be_allowed_for master }
  32 + it { should be_allowed_for reporter }
  33 + it { should be_allowed_for :admin }
  34 + it { should be_allowed_for guest }
  35 + it { should be_allowed_for :user }
  36 + it { should be_allowed_for :visitor }
  37 + end
  38 +
  39 + describe "GET /groups/:path/issues" do
  40 + subject { issues_group_path(group) }
  41 +
  42 + it { should be_allowed_for owner }
  43 + it { should be_allowed_for master }
  44 + it { should be_allowed_for reporter }
  45 + it { should be_allowed_for :admin }
  46 + it { should be_allowed_for guest }
  47 + it { should be_allowed_for :user }
  48 + it { should be_allowed_for :visitor }
  49 + end
  50 +
  51 + describe "GET /groups/:path/merge_requests" do
  52 + subject { merge_requests_group_path(group) }
  53 +
  54 + it { should be_allowed_for owner }
  55 + it { should be_allowed_for master }
  56 + it { should be_allowed_for reporter }
  57 + it { should be_allowed_for :admin }
  58 + it { should be_allowed_for guest }
  59 + it { should be_allowed_for :user }
  60 + it { should be_allowed_for :visitor }
  61 + end
  62 +
  63 + describe "GET /groups/:path/members" do
  64 + subject { members_group_path(group) }
  65 +
  66 + it { should be_allowed_for owner }
  67 + it { should be_allowed_for master }
  68 + it { should be_allowed_for reporter }
  69 + it { should be_allowed_for :admin }
  70 + it { should be_allowed_for guest }
  71 + it { should be_allowed_for :user }
  72 + it { should be_allowed_for :visitor }
  73 + end
  74 +
  75 + describe "GET /groups/:path/edit" do
  76 + subject { edit_group_path(group) }
  77 +
  78 + it { should be_allowed_for owner }
  79 + it { should be_denied_for master }
  80 + it { should be_denied_for reporter }
  81 + it { should be_allowed_for :admin }
  82 + it { should be_denied_for guest }
  83 + it { should be_denied_for :user }
  84 + it { should be_denied_for :visitor }
  85 + end
  86 + end
  87 +end
... ...
spec/features/security/group_access_spec.rb
... ... @@ -1,85 +0,0 @@
1   -require 'spec_helper'
2   -
3   -describe "Group access" do
4   - describe "GET /projects/new" do
5   - it { new_group_path.should be_allowed_for :admin }
6   - it { new_group_path.should be_allowed_for :user }
7   - it { new_group_path.should be_denied_for :visitor }
8   - end
9   -
10   - describe "Group" do
11   - let(:group) { create(:group) }
12   -
13   - let(:owner) { create(:owner) }
14   - let(:master) { create(:user) }
15   - let(:reporter) { create(:user) }
16   - let(:guest) { create(:user) }
17   -
18   - before do
19   - group.add_user(owner, Gitlab::Access::OWNER)
20   - group.add_user(master, Gitlab::Access::MASTER)
21   - group.add_user(reporter, Gitlab::Access::REPORTER)
22   - group.add_user(guest, Gitlab::Access::GUEST)
23   - end
24   -
25   - describe "GET /groups/:path" do
26   - subject { group_path(group) }
27   -
28   - it { should be_allowed_for owner }
29   - it { should be_allowed_for master }
30   - it { should be_allowed_for reporter }
31   - it { should be_allowed_for :admin }
32   - it { should be_allowed_for guest }
33   - it { should be_denied_for :user }
34   - it { should be_denied_for :visitor }
35   - end
36   -
37   - describe "GET /groups/:path/issues" do
38   - subject { issues_group_path(group) }
39   -
40   - it { should be_allowed_for owner }
41   - it { should be_allowed_for master }
42   - it { should be_allowed_for reporter }
43   - it { should be_allowed_for :admin }
44   - it { should be_allowed_for guest }
45   - it { should be_denied_for :user }
46   - it { should be_denied_for :visitor }
47   - end
48   -
49   - describe "GET /groups/:path/merge_requests" do
50   - subject { merge_requests_group_path(group) }
51   -
52   - it { should be_allowed_for owner }
53   - it { should be_allowed_for master }
54   - it { should be_allowed_for reporter }
55   - it { should be_allowed_for :admin }
56   - it { should be_allowed_for guest }
57   - it { should be_denied_for :user }
58   - it { should be_denied_for :visitor }
59   - end
60   -
61   - describe "GET /groups/:path/members" do
62   - subject { members_group_path(group) }
63   -
64   - it { should be_allowed_for owner }
65   - it { should be_allowed_for master }
66   - it { should be_allowed_for reporter }
67   - it { should be_allowed_for :admin }
68   - it { should be_allowed_for guest }
69   - it { should be_denied_for :user }
70   - it { should be_denied_for :visitor }
71   - end
72   -
73   - describe "GET /groups/:path/edit" do
74   - subject { edit_group_path(group) }
75   -
76   - it { should be_allowed_for owner }
77   - it { should be_denied_for master }
78   - it { should be_denied_for reporter }
79   - it { should be_allowed_for :admin }
80   - it { should be_denied_for guest }
81   - it { should be_denied_for :user }
82   - it { should be_denied_for :visitor }
83   - end
84   - end
85   -end