Commit 2f69213e authored by Jason Hollingsworth's avatar Jason Hollingsworth
Browse files

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.
parent 569a7cec5d43
......@@ -77,5 +77,6 @@ def load_projects
def default_filter
params[:scope] = 'assigned-to-me' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank?
params[:authorized_only] = true
end
end
class GroupsController < ApplicationController
skip_before_filter :authenticate_user!, only: [:show, :issues, :members, :merge_requests]
respond_to :html
before_filter :group, except: [:new, :create]
......@@ -36,7 +37,7 @@ def show
@events = Event.in_projects(project_ids)
@events = event_filter.apply_filter(@events)
@events = @events.limit(20).offset(params[:offset] || 0)
@last_push = current_user.recent_push
@last_push = current_user.recent_push if current_user
respond_to do |format|
format.html
......@@ -98,17 +99,21 @@ def group
end
def projects
@projects ||= current_user.authorized_projects.where(namespace_id: group.id).sorted_by_activity
@projects ||= group.projects_accessible_to(current_user).sorted_by_activity
end
def project_ids
projects.map(&:id)
projects.pluck(:id)
end
# Dont allow unauthorized access to group
def authorize_read_group!
unless @group and (projects.present? or can?(current_user, :read_group, @group))
return render_404
if current_user.nil?
return authenticate_user!
else
return render_404
end
end
end
......@@ -131,13 +136,21 @@ def set_title
def determine_layout
if [:new, :create].include?(action_name.to_sym)
'navless'
else
elsif current_user
'group'
else
'public_group'
end
end
def default_filter
params[:scope] = 'assigned-to-me' if params[:scope].blank?
if params[:scope].blank?
if current_user
params[:scope] = 'assigned-to-me'
else
params[:scope] = 'all'
end
end
params[:state] = 'opened' if params[:state].blank?
params[:group_id] = @group.id
end
......
......@@ -6,7 +6,7 @@ class Public::ProjectsController < ApplicationController
layout 'public'
def index
@projects = Project.public_or_internal_only(current_user)
@projects = Project.publicish(current_user)
@projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.includes(:namespace).page(params[:page]).per(20)
......
class UsersController < ApplicationController
skip_before_filter :authenticate_user!, only: [:show]
layout :determine_layout
def show
@user = User.find_by_username!(params[:username])
@projects = @user.authorized_projects.includes(:namespace).select {|project| can?(current_user, :read_project, project)}
@projects = @user.authorized_projects.accessible_to(current_user)
if !current_user && @projects.empty?
return authenticate_user!
end
@events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20)
@groups = @user.groups.accessible_to(current_user)
@events = @user.recent_events.where(project_id: @projects.pluck(:id)).limit(20)
@title = @user.name
end
......
......@@ -6,6 +6,14 @@ def remove_user_from_group_message(group, user)
def leave_group_message(group)
"Are you sure you want to leave \"#{group}\" group?"
end
def should_user_see_group_roles?(user, group)
if user
user.is_admin? || group.members.exists?(user_id: user.id)
else
false
end
end
def group_head_title
title = @group.name
......
......@@ -4,8 +4,7 @@ def search_autocomplete_opts(term)
resources_results = [
groups_autocomplete(term),
projects_autocomplete(term),
public_projects_autocomplete(term),
projects_autocomplete(term)
].flatten
generic_results = project_autocomplete + default_autocomplete + help_autocomplete
......@@ -82,17 +81,7 @@ def groups_autocomplete(term, limit = 5)
# Autocomplete results for the current user's projects
def projects_autocomplete(term, limit = 5)
current_user.authorized_projects.search_by_title(term).non_archived.limit(limit).map do |p|
{
label: "project: #{search_result_sanitize(p.name_with_namespace)}",
url: project_path(p)
}
end
end
# Autocomplete results for the current user's projects
def public_projects_autocomplete(term, limit = 5)
Project.public_or_internal_only(current_user).search_by_title(term).non_archived.limit(limit).map do |p|
Project.accessible_to(current_user).search_by_title(term).non_archived.limit(limit).map do |p|
{
label: "project: #{search_result_sanitize(p.name_with_namespace)}",
url: project_path(p)
......
......@@ -43,7 +43,19 @@ def not_auth_abilities(user, subject)
:download_code
]
else
[]
group = if subject.kind_of?(Group)
subject
elsif subject.respond_to?(:group)
subject.group
else
nil
end
if group && group.has_projects_accessible_to?(nil)
[:read_group]
else
[]
end
end
end
......@@ -172,7 +184,7 @@ def project_admin_rules
def group_abilities user, group
rules = []
if group.users.include?(user) || user.admin?
if user.admin? || group.users.include?(user) || group.has_projects_accessible_to?(user)
rules << :read_group
end
......
......@@ -25,6 +25,12 @@ class Group < Namespace
validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
mount_uploader :avatar, AttachmentUploader
def self.accessible_to(user)
accessible_ids = Project.accessible_to(user).pluck(:namespace_id)
accessible_ids += user.groups.pluck(:id) if user
where(id: accessible_ids)
end
def human_name
name
......
......@@ -47,6 +47,14 @@ def self.search query
def self.global_id
'GLN'
end
def projects_accessible_to(user)
projects.accessible_to(user)
end
def has_projects_accessible_to?(user)
projects_accessible_to(user).present?
end
def to_param
path
......
......@@ -114,8 +114,6 @@ class Project < ActiveRecord::Base
scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
scope :public_only, -> { where(visibility_level: PUBLIC) }
scope :public_or_internal_only, ->(user) { where("visibility_level IN (:levels)", levels: user ? [ INTERNAL, PUBLIC ] : [ PUBLIC ]) }
scope :non_archived, -> { where(archived: false) }
......@@ -125,6 +123,18 @@ class << self
def abandoned
where('projects.last_activity_at < ?', 6.months.ago)
end
def publicish(user)
visibility_levels = [Project::PUBLIC]
visibility_levels += [Project::INTERNAL] if user
where(visibility_level: visibility_levels)
end
def accessible_to(user)
accessible_ids = publicish(user).pluck(:id)
accessible_ids += user.authorized_projects.pluck(:id) if user
where(id: accessible_ids)
end
def with_push
includes(:events).where('events.action = ?', Event::PUSHED)
......
......@@ -41,16 +41,16 @@ def execute(klass, current_user, params)
def init_collection
table_name = klass.table_name
return klass.of_projects(Project.public_only) unless current_user
if project
if current_user.can?(:read_project, project)
if project.public? || (current_user && current_user.can?(:read_project, project))
project.send(table_name)
else
[]
end
else
elsif current_user && params[:authorized_only].presence
klass.of_projects(current_user.authorized_projects)
else
klass.of_projects(Project.accessible_to(current_user))
end
end
......
......@@ -11,12 +11,8 @@ def execute
query = Shellwords.shellescape(query) if query.present?
return result unless query.present?
authorized_projects_ids = []
authorized_projects_ids += current_user.authorized_projects.pluck(:id) if current_user
authorized_projects_ids += Project.public_or_internal_only(current_user).pluck(:id)
group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
projects = Project.where(id: authorized_projects_ids)
projects = Project.accessible_to(current_user)
projects = projects.where(namespace_id: group.id) if group
projects = projects.search(query)
project_ids = projects.pluck(:id)
......
......@@ -5,7 +5,9 @@
%p.light
Only issues from
%strong #{@group.name}
group are listed here. To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
group are listed here.
- if current_user
To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
%hr
.row
......
- show_roles = should_user_see_group_roles?(current_user, @group)
%h3.page-title
Group members
%p.light
Members of group have access to all group projects.
Read more about permissions
%strong= link_to "here", help_permissions_path, class: "vlink"
- if show_roles
%p.light
Members of group have access to all group projects.
Read more about permissions
%strong= link_to "here", help_permissions_path, class: "vlink"
%hr
......@@ -13,7 +15,7 @@
= search_field_tag :search, params[:search], { placeholder: 'Find member by name', class: 'form-control search-text-input input-mn-300' }
= submit_tag 'Search', class: 'btn'
- if current_user.can? :manage_group, @group
- if current_user && current_user.can?(:manage_group, @group)
.pull-right
= link_to '#', class: 'btn btn-new js-toggle-visibility-link' do
Add members
......@@ -30,7 +32,7 @@
(#{@members.total_count})
%ul.well-list
- @members.each do |member|
= render 'users_groups/users_group', member: member, show_controls: true
= render 'users_groups/users_group', member: member, show_roles: show_roles, show_controls: true
= paginate @members, theme: 'gitlab'
:coffeescript
......
......@@ -5,7 +5,9 @@
%p.light
Only merge requests from
%strong #{@group.name}
group are listed here. To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
group are listed here.
- if current_user
To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
%hr
.row
.col-md-3
......
.dashboard
.activities.col-md-8.hidden-sm
= render "events/event_last_push", event: @last_push
= link_to dashboard_path, class: 'btn btn-tiny' do
&larr; To dashboard
&nbsp;
- if current_user
= render "events/event_last_push", event: @last_push
= link_to dashboard_path, class: 'btn btn-tiny' do
&larr; To dashboard
&nbsp;
%span.cgray You will only see events from projects in this group
%hr
= render 'shared/event_filter'
......@@ -21,11 +22,12 @@
- if @group.description.present?
%p= @group.description
= render "projects", projects: @projects
.prepend-top-20
= link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed" do
%strong
%i.icon-rss
News Feed
- if current_user
.prepend-top-20
= link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed" do
%strong
%i.icon-rss
News Feed
%hr
= render 'shared/promo'
......@@ -5,11 +5,13 @@
= nav_link(path: 'groups#issues') do
= link_to issues_group_path(@group) do
Issues
%span.count= current_user.assigned_issues.opened.of_group(@group).count
- if current_user
%span.count= current_user.assigned_issues.opened.of_group(@group).count
= nav_link(path: 'groups#merge_requests') do
= link_to merge_requests_group_path(@group) do
Merge Requests
%span.count= current_user.cared_merge_requests.opened.of_group(@group).count
- if current_user
%span.count= current_user.cared_merge_requests.opened.of_group(@group).count
= nav_link(path: 'groups#members') do
= link_to "Members", members_group_path(@group)
......
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: group_head_title
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
= render "layouts/broadcast"
= render "layouts/public_head_panel", title: "group: #{@group.name}"
%nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/group'
.container
.content= yield
......@@ -3,7 +3,7 @@
= render "layouts/head", title: @project.name_with_namespace
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
= render "layouts/broadcast"
= render "layouts/public_head_panel", title: @project.name_with_namespace
= render "layouts/public_head_panel", title: project_title(@project)
%nav.main-nav
.container= render 'layouts/nav/project'
.container
......
.side-filters.hidden-xs.hidden-sm
= form_tag filter_path(entity), method: 'get' do
%fieldset.scope-filter
%ul.nav.nav-pills.nav-stacked
%li{class: ("active" if params[:scope] == 'assigned-to-me')}
= link_to filter_path(entity, scope: 'assigned-to-me') do
Assigned to me
%li{class: ("active" if params[:scope] == 'authored')}
= link_to filter_path(entity, scope: 'authored') do
Created by me
%li{class: ("active" if params[:scope] == 'all')}
= link_to filter_path(entity, scope: 'all') do
Everyone's
- if current_user
%fieldset.scope-filter
%ul.nav.nav-pills.nav-stacked
%li{class: ("active" if params[:scope] == 'assigned-to-me')}
= link_to filter_path(entity, scope: 'assigned-to-me') do
Assigned to me
%li{class: ("active" if params[:scope] == 'authored')}
= link_to filter_path(entity, scope: 'authored') do
Created by me
%li{class: ("active" if params[:scope] == 'all')}
= link_to filter_path(entity, scope: 'all') do
Everyone's
%fieldset.status-filter
%legend State
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment