Commit 8db12921 authored by Douwe Maan's avatar Douwe Maan

Tweaks, refactoring, and specs

parent 2eb19ea3
......@@ -48,7 +48,7 @@
display: block;
}
#project-home-desc {
.project-home-desc {
font-size: 21px;
}
......
......@@ -25,7 +25,6 @@ class ApplicationController < ActionController::Base
helper_method :abilities, :can?, :current_application_settings
helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?
helper_method :repository, :can_collaborate_with_project?
rescue_from Encoding::CompatibilityError do |exception|
log_exception(exception)
......@@ -118,47 +117,6 @@ class ApplicationController < ActionController::Base
abilities.allowed?(object, action, subject)
end
def project
unless @project
namespace = params[:namespace_id]
id = params[:project_id] || params[:id]
# Redirect from
# localhost/group/project.git
# to
# localhost/group/project
#
if id =~ /\.git\Z/
redirect_to request.original_url.gsub(/\.git\/?\Z/, '') and return
end
project_path = "#{namespace}/#{id}"
@project = Project.find_with_namespace(project_path)
if @project and can?(current_user, :read_project, @project)
if @project.path_with_namespace != project_path
redirect_to request.original_url.gsub(project_path, @project.path_with_namespace) and return
end
@project
elsif current_user.nil?
@project = nil
authenticate_user!
else
@project = nil
render_404 and return
end
end
@project
end
def repository
@repository ||= project.repository
end
def authorize_project!(action)
return access_denied! unless can?(current_user, action, project)
end
def access_denied!
render "errors/access_denied", layout: "errors", status: 404
end
......@@ -167,14 +125,6 @@ class ApplicationController < ActionController::Base
render "errors/git_not_found.html", layout: "errors", status: 404
end
def method_missing(method_sym, *arguments, &block)
if method_sym.to_s =~ /\Aauthorize_(.*)!\z/
authorize_project!($1.to_sym)
else
super
end
end
def render_403
head :forbidden
end
......@@ -183,10 +133,6 @@ class ApplicationController < ActionController::Base
render file: Rails.root.join("public", "404"), layout: false, status: "404"
end
def require_non_empty_project
redirect_to @project if @project.empty_repo?
end
def no_cache_headers
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Pragma"] = "no-cache"
......@@ -412,13 +358,6 @@ class ApplicationController < ActionController::Base
current_user.nil? && root_path == request.path
end
def can_collaborate_with_project?(project = nil)
project ||= @project
can?(current_user, :push_code, project) ||
(current_user && current_user.already_forked?(project))
end
private
def set_default_sort
......
class Groups::ApplicationController < ApplicationController
layout 'group'
skip_before_action :authenticate_user!
before_action :group
private
def group
@group ||= Group.find_by(path: params[:group_id])
end
unless @group
id = params[:group_id] || params[:id]
@group = Group.find_by(path: id)
unless @group && can?(current_user, :read_group, @group)
@group = nil
def authorize_read_group!
unless @group && can?(current_user, :read_group, @group)
if current_user.nil?
return authenticate_user!
else
return render_404
if current_user.nil?
authenticate_user!
else
render_404
end
end
end
@group
end
def group_projects
@projects ||= GroupProjectsFinder.new(group).execute(current_user)
end
def authorize_admin_group!
......
class Groups::AvatarsController < Groups::ApplicationController
before_action :authorize_admin_group!
def destroy
@group.remove_avatar!
@group.save
......
class Groups::GroupMembersController < Groups::ApplicationController
skip_before_action :authenticate_user!, only: [:index]
# Authorize
before_action :authorize_read_group!
before_action :authorize_admin_group_member!, except: [:index, :leave]
def index
......
class Groups::MilestonesController < Groups::ApplicationController
include GlobalMilestones
before_action :projects
before_action :group_projects
before_action :milestones, only: [:index]
before_action :milestone, only: [:show, :update]
before_action :authorize_group_milestone!, only: [:create, :update]
before_action :authorize_admin_milestones!, only: [:new, :create, :update]
def index
end
......@@ -17,7 +17,7 @@ class Groups::MilestonesController < Groups::ApplicationController
project_ids = params[:milestone][:project_ids]
title = milestone_params[:title]
@group.projects.where(id: project_ids).each do |project|
@projects.where(id: project_ids).each do |project|
Milestones::CreateService.new(project, current_user, milestone_params).execute
end
......@@ -37,7 +37,7 @@ class Groups::MilestonesController < Groups::ApplicationController
private
def authorize_group_milestone!
def authorize_admin_milestones!
return render_404 unless can?(current_user, :admin_milestones, group)
end
......@@ -48,8 +48,4 @@ class Groups::MilestonesController < Groups::ApplicationController
def milestone_path(title)
group_milestone_path(@group, title.to_slug.to_s, title: title)
end
def projects
@projects ||= @group.projects
end
end
......@@ -5,16 +5,15 @@ class GroupsController < Groups::ApplicationController
respond_to :html
skip_before_action :authenticate_user!, only: [:index, :show, :issues, :merge_requests]
before_action :authenticate_user!, only: [:new, :create]
before_action :group, except: [:index, :new, :create]
# Authorize
before_action :authorize_read_group!, except: [:index, :new, :create]
before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create]
# Load group projects
before_action :load_projects, except: [:index, :new, :create, :projects, :edit, :update, :autocomplete]
before_action :group_projects, only: [:show, :projects, :activity, :issues, :merge_requests]
before_action :event_filter, only: [:activity]
layout :determine_layout
......@@ -39,12 +38,13 @@ class GroupsController < Groups::ApplicationController
def show
@last_push = current_user.recent_push if current_user
@projects = @projects.includes(:namespace)
@projects = filter_projects(@projects)
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page]).per(PER_PAGE) if params[:filter_projects].blank?
@shared_projects = @group.shared_projects
@shared_projects = GroupProjectsFinder.new(group, shared: true).execute(current_user)
respond_to do |format|
format.html
......@@ -77,7 +77,7 @@ class GroupsController < Groups::ApplicationController
end
def projects
@projects = @group.projects.page(params[:page])
@projects = @projects.sorted_by_activity.page(params[:page])
end
def update
......@@ -96,15 +96,6 @@ class GroupsController < Groups::ApplicationController
protected
def group
@group ||= Group.find_by(path: params[:id])
@group || render_404
end
def load_projects
@projects ||= ProjectsFinder.new.execute(current_user, group: group).sorted_by_activity
end
def authorize_create_group!
unless can?(current_user, :create_group, nil)
return render_404
......
class Projects::ApplicationController < ApplicationController
before_action :project
before_action :repository
skip_before_action :authenticate_user!
before_action :project, :repository
layout 'project'
def authenticate_user!
# Restrict access to Projects area only
# for non-signed users
if !current_user
helper_method :repository, :can_collaborate_with_project?
private
def project
unless @project
namespace = params[:namespace_id]
id = params[:project_id] || params[:id]
project_with_namespace = "#{params[:namespace_id]}/#{id}"
@project = Project.find_with_namespace(project_with_namespace)
return if @project && @project.public?
# Redirect from
# localhost/group/project.git
# to
# localhost/group/project
#
if id =~ /\.git\Z/
redirect_to request.original_url.gsub(/\.git\/?\Z/, '')
return
end
project_path = "#{namespace}/#{id}"
@project = Project.find_with_namespace(project_path)
if @project && can?(current_user, :read_project, @project)
if @project.path_with_namespace != project_path
redirect_to request.original_url.gsub(project_path, @project.path_with_namespace)
end
else
@project = nil
if current_user.nil?
authenticate_user!
else
render_404
end
end
end
@project
end
def repository
@repository ||= project.repository
end
def can_collaborate_with_project?(project = nil)
project ||= @project
can?(current_user, :push_code, project) ||
(current_user && current_user.already_forked?(project))
end
def authorize_project!(action)
return access_denied! unless can?(current_user, action, project)
end
def method_missing(method_sym, *arguments, &block)
if method_sym.to_s =~ /\Aauthorize_(.*)!\z/
authorize_project!($1.to_sym)
else
super
end
end
super
def require_non_empty_project
redirect_to @project if @project.empty_repo?
end
def require_branch_head
......@@ -26,8 +79,6 @@ class Projects::ApplicationController < ApplicationController
end
end
private
def apply_diff_view_cookie!
view = params[:view] || cookies[:diff_view]
cookies.permanent[:diff_view] = params[:view] = view if view
......
class Projects::AvatarsController < Projects::ApplicationController
include BlobHelper
before_action :project
before_action :authorize_admin_project!, only: [:destroy]
def show
@blob = @repository.blob_at_branch('master', @project.avatar_in_git)
......
class Projects::UploadsController < Projects::ApplicationController
skip_before_action :authenticate_user!, :reject_blocked!, :project,
skip_before_action :reject_blocked!, :project,
:repository, if: -> { action_name == 'show' && image? }
before_action :authenticate_user!, only: [:create]
def create
link_to_file = ::Projects::UploadService.new(project, params[:file]).
execute
......@@ -26,6 +28,8 @@ class Projects::UploadsController < Projects::ApplicationController
send_file uploader.file.path, disposition: disposition
end
private
def uploader
return @uploader if defined?(@uploader)
......
class ProjectsController < ApplicationController
class ProjectsController < Projects::ApplicationController
include ExtractsPath
skip_before_action :authenticate_user!, only: [:show, :activity]
before_action :authenticate_user!, except: [:show, :activity]
before_action :project, except: [:new, :create]
before_action :repository, except: [:new, :create]
before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists?
......
class ContributedProjectsFinder
class ContributedProjectsFinder < UnionFinder
def initialize(user)
@user = user
end
......@@ -10,27 +10,20 @@ class ContributedProjectsFinder
# visible by this user.
#
# Returns an ActiveRecord::Relation.
def execute(current_user = nil)
if current_user
relation = projects_visible_to_user(current_user)
else
relation = public_projects
end
segments = all_projects(current_user)
relation.includes(:namespace).order_id_desc
find_union(segments, Project).includes(:namespace).order_id_desc
end
private
def projects_visible_to_user(current_user)
authorized = @user.contributed_projects.visible_to_user(current_user)
union = Gitlab::SQL::Union.new([authorized.select(:id), public_projects.select(:id)])
def all_projects(current_user)
projects = []
Project.where("projects.id IN (#{union.to_sql})")
end
projects << @user.contributed_projects.visible_to_user(current_user) if current_user
projects << @user.contributed_projects.public_to_user(current_user)
def public_projects
@user.contributed_projects.public_only
projects
end
end
class GroupProjectsFinder < UnionFinder
def initialize(group, options = {})
@group = group
@options = options
end
def execute(current_user = nil)
segments = group_projects(current_user)
find_union(segments, Project)
end
private
def group_projects(current_user)
include_owned = @options.fetch(:owned, true)
include_shared = @options.fetch(:shared, true)
projects = []
if current_user
if @group.users.include?(current_user)
projects << @group.projects if include_owned
projects << @group.shared_projects if include_shared
else
if include_owned
projects << @group.projects.visible_to_user(current_user)
projects << @group.projects.public_to_user(current_user)
end
if include_shared
projects << @group.shared_projects.visible_to_user(current_user)
projects << @group.shared_projects.public_to_user(current_user)
end
end
else
projects << @group.projects.public_only if include_owned
projects << @group.shared_projects.public_only if include_shared
end
projects
end
end
class GroupsFinder
class GroupsFinder < UnionFinder
def execute(current_user = nil)
segments = all_groups(current_user)
if segments.length > 1
union = Gitlab::SQL::Union.new(segments.map { |s| s.select(:id) })
Group.where("namespaces.id IN (#{union.to_sql})").order_id_desc
else
segments.first
end
find_union(segments, Group).order_id_desc
end
private
def all_groups(current_user)
if current_user
user_groups(current_user)
else
[Group.unscoped.public_only]
end
end
groups = []
groups << current_user.authorized_groups if current_user
groups << Group.unscoped.public_to_user(current_user)
def user_groups(current_user)
if current_user.external?
[current_user.authorized_groups, Group.unscoped.public_only]
else
[current_user.authorized_groups, Group.unscoped.public_and_internal_only]
end
groups
end
end
......@@ -81,7 +81,7 @@ class IssuableFinder
elsif current_user && params[:authorized_only].presence && !current_user_related?
@projects = current_user.authorized_projects.reorder(nil)
else
@projects = ProjectsFinder.new.execute(current_user, group: group).
@projects = GroupProjectsFinder.new(group).execute(current_user).
reorder(nil)
end
end
......@@ -170,7 +170,7 @@ class IssuableFinder
end
def by_scope(items)
case params[:scope]
case params[:scope] || 'all'
when 'created-by-me', 'authored' then
items.where(author_id: current_user.id)
when 'all' then
......
#Shows only authorized groups of a user
class JoinedGroupsFinder
class JoinedGroupsFinder < UnionFinder
def initialize(user)
@user = user
end
......@@ -12,34 +11,19 @@ class JoinedGroupsFinder
#
# Returns an ActiveRecord::Relation.
def execute(current_user = nil)
if current_user
relation = groups_visible_to_user(current_user)
else
relation = public_groups
end
segments = all_groups(current_user)
relation.order_id_desc
find_union(segments, Group).order_id_desc
end
private
# Returns the groups the user in "current_user" can see.
#
# This list includes all public/internal projects as well as the projects of
# "@user" that "current_user" also has access to.
def groups_visible_to_user(current_user)
base = @user.authorized_groups.visible_to_user(current_user)
extra = current_user.external? ? public_groups : public_and_internal_groups
union = Gitlab::SQL::Union.new([base.select(:id), extra.select(:id)])
Group.where("namespaces.id IN (#{union.to_sql})")
end
def all_groups(current_user)
groups = []
def public_groups
@user.authorized_groups.public_only
end
groups << @user.authorized_groups.visible_to_user(current_user) if current_user
groups << @user.authorized_groups.public_to_user(current_user)
def public_and_internal_groups
@user.authorized_groups.public_and_internal_only
groups
end
end
class PersonalProjectsFinder
class PersonalProjectsFinder < UnionFinder
def initialize(user)
@user = user
end
......@@ -11,38 +11,19 @@ class PersonalProjectsFinder
#
# Returns an ActiveRecord::Relation.
def execute(current_user = nil)
if current_user
relation = projects_visible_to_user(current_user)
else
relation = public_projects
end
segments = all_projects(current_user)
relation.includes(:namespace).order_id_desc
find_union(segments, Project).includes(:namespace).order_id_desc
end
private
def projects_visible_to_user(current_user)
union = Gitlab::SQL::Union.new(projects_for_user_ids(current_user))
def all_projects(current_user)
projects = []
Project.where("projects.id IN (#{union.to_sql})")
end
def public_projects
@user.personal_projects.public_only
end
def public_and_internal_projects
@user.personal_projects.public_and_internal_only
end
def projects_for_user_ids(current_user)
authorized = @user.personal_projects.visible_to_user(current_user)
projects << @user.personal_projects.visible_to_user(current_user) if current_user
projects << @user.personal_projects.public_to_user(current_user)
if current_user.external?
[authorized.select(:id), public_projects.select(:id)]
else
[authorized.select(:id), public_and_internal_projects.select(:id)]
end
projects
end
end
class ProjectsFinder
# Returns all projects, optionally including group projects a user has access
# to.
#
# ## Examples
#
# Retrieving all public projects:
#
# ProjectsFinder.new.execute
#
# Retrieving all public/internal projects and those the given user has access
# to:
#
# ProjectsFinder.new.execute(some_user)
#
# Retrieving all public/internal projects as well as the group's projects the
# user has access to:
#
# ProjectsFinder.new.execute(some_user, group: some_group)
#
# Returns an ActiveRecord::Relation.
class ProjectsFinder < UnionFinder
def execute(current_user = nil, options = {})
group = options[:group]
segments = all_projects(current_user)
if group
segments = group_projects(current_user, group)
else
segments = all_projects(current_user)
end
if segments.length > 1
union = Gitlab::SQL::Union.new(segments.map { |s| s.select(:id) })
Project.where("projects.id IN (#{union.to_sql})")
else
segments.first
end
find_union(segments, Project)
end
private
def group_projects(current_user, group)
return [group.projects.public_only] unless current_user
user_group_projects = [
group_projects_for_user(current_user, group),
group.shared_projects.visible_to_user(current_user)
]
if current_user.external?
user_group_projects << group.projects.public_only
else
user_group_projects << group.projects.public_and_internal_only
end
end
def all_projects(current_user)
return [public_projects] unless current_user
projects = []
if current_user.external?
[current_user.authorized_projects, public_projects]
else
[current_user.authorized_projects, public_and_internal_projects]
end
end
def group_projects_for_user(current_user, group)
if group.users.include?(current_user)
group.projects
else
group.projects.visible_to_user(current_user)
end
end
def public_projects
Project.unscoped.public_only
end
projects << current_user.authorized_projects if current_user
projects << Project.unscoped.public_to_user(current_user)
def public_and_internal_projects
Project.unscoped.public_and_internal_only
projects
end
end
class UnionFinder
def find_union(segments, klass)
if segments.length > 1
union = Gitlab::SQL::Union.new(segments.map { |s| s.select(:id) })
klass.where("#{klass.table_name}.id IN (#{union.to_sql})")
else
segments.first
end
end
end
......@@ -43,8 +43,4 @@ module GroupsHelper
full_title
end
end
def group_visibility_description(group)
"#{visibility_level_label(group.visibility_level)} - #{group_visibility_level_description(group.visibility_level)}"
end
end
......@@ -63,6 +63,14 @@ module VisibilityLevelHelper
end
end
def group_visibility_icon_description(group)
"#{visibility_level_label(group.visibility_level)} - #{group_visibility_level_description(group.visibility_level)}"
end
def project_visibility_icon_description(project)
"#{visibility_level_label(project.visibility_level)} - #{project_visibility_level_description(project.visibility_level)}"
end
def visibility_level_label(level)
Project.visibility_levels.key(level)
end
......
......@@ -114,6 +114,13 @@ class Ability
# Push abilities on the users team role
rules.push(*project_team_rules(project.team, user))
if project.owner == user ||
(project.group && project.group.has_owner?(user)) ||
user.admin?
rules.push(*project_owner_rules)
end
if project.public? || (project.internal? && !user.external?)
rules.push(*public_project_rules)
......@@ -121,14 +128,6 @@ class Ability
rules << :read_build if project.public_builds?
end
if project.owner == user || user.admin?
rules.push(*project_admin_rules)
end
if project.group && project.group.has_owner?(user)
rules.push(*project_admin_rules)
end
if project.archived?
rules -= project_archived_rules
end
......@@ -228,8 +227,8 @@ class Ability
]
end
def project_admin_rules
@project_admin_rules ||= project_master_rules + [
def project_owner_rules
@project_owner_rules ||= project_master_rules + [
:change_namespace,
:change_visibility_level,
:rename_project,
......@@ -275,7 +274,7 @@ class Ability
rules << :read_group if can_read_group?(user, group)
# Only group masters and group owners can create new projects and change permission level
# Only group masters and group owners can create new projects
if group.has_master?(user) || group.has_owner?(user) || user.admin?
rules += [
:create_projects,
......@@ -298,7 +297,7 @@ class Ability
def can_read_group?(user, group)
user.admin? || group.public? || (group.internal? && !user.external?) || group.users.include?(user) ||
ProjectsFinder.new.execute(user, group: group).any?
GroupProjectsFinder.new(group).execute(user).any?
end
def namespace_abilities(user, namespace)
......
......@@ -83,16 +83,9 @@ class Group < Namespace
end
def visibility_level_allowed_by_projects
unless visibility_level_allowed?
level_name = Gitlab::VisibilityLevel.level_name(visibility_level).downcase
self.errors.add(:visibility_level, "#{level_name} is not allowed since there are projects with higher visibility.")
end
end
def visibility_level_allowed?
projects_visibility = self.projects.pluck(:visibility_level)
allowed_by_projects = projects_visibility.none? { |project_visibility| self.visibility_level < project_visibility }
allowed_by_projects = projects_visibility.all? { |project_visibility| self.visibility_level >= project_visibility }
unless allowed_by_projects
level_name = Gitlab::VisibilityLevel.level_name(visibility_level).downcase
......
......@@ -197,7 +197,8 @@ class Project < ActiveRecord::Base
validate :avatar_type,
if: ->(project) { project.avatar.present? && project.avatar_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
validate :visibility_level_allowed_in_group
validate :visibility_level_allowed_by_group
validate :visibility_level_allowed_as_fork
add_authentication_token_field :runners_token
before_save :ensure_runners_token
......@@ -441,16 +442,25 @@ class Project < ActiveRecord::Base
def check_limit
unless creator.can_create_project? or namespace.kind == 'group'
errors[:limit_reached] << ("Your project limit is #{creator.projects_limit} projects! Please contact your administrator to increase it")
self.errors.add(:limit_reached, "Your project limit is #{creator.projects_limit} projects! Please contact your administrator to increase it")
end
rescue
errors[:base] << ("Can't check your ability to create project")
self.errors.add(:base, "Can't check your ability to create project")
end
def visibility_level_allowed_in_group
unless visibility_level_allowed?
self.errors.add(:visibility_level, "#{self.visibility_level} is not allowed in a #{self.group.visibility_level} group.")
end
def visibility_level_allowed_by_group
return if visibility_level_allowed_by_group?
level_name = Gitlab::VisibilityLevel.level_name(self.visibility_level).downcase
group_level_name = Gitlab::VisibilityLevel.level_name(self.group.visibility_level).downcase
self.errors.add(:visibility_level, "#{level_name} is not allowed in a #{group_level_name} group.")
end
def visibility_level_allowed_as_fork
return if visibility_level_allowed_as_fork?
level_name = Gitlab::VisibilityLevel.level_name(self.visibility_level).downcase
self.errors.add(:visibility_level, "#{level_name} is not allowed since the fork source project has lower visibility.")
end
def to_param
......@@ -965,22 +975,22 @@ class Project < ActiveRecord::Base
issues.opened.count
end
def visibility_level_allowed?(level = self.visibility_level)
allowed_by_forks = if forked? && forked_project_link.forked_from_project_id.present?
from_project = eager_load_forked_from_project
Gitlab::VisibilityLevel.allowed_fork_levels(from_project.visibility_level).include?(level)
else
true
end
def visibility_level_allowed_as_fork?(level = self.visibility_level)
return true unless forked? && forked_project_link.forked_from_project_id.present?
from_project = self.forked_from_project
from_project ||= Project.find(forked_project_link.forked_from_project_id)
Gitlab::VisibilityLevel.allowed_fork_levels(from_project.visibility_level).include?(level)
end
allowed_by_groups = group.present? ? level <= group.visibility_level : true
def visibility_level_allowed_by_group?(level = self.visibility_level)
return true unless group
allowed_by_forks && allowed_by_groups
level <= group.visibility_level
end
#Necessary to retrieve many-to-many associations on new forks before validating visibility level
def eager_load_forked_from_project
Project.find(forked_project_link.forked_from_project_id)
def visibility_level_allowed?(level = self.visibility_level)
visibility_level_allowed_as_fork?(level) && visibility_level_allowed_by_group?(level)
end
def runners_token
......
......@@ -43,12 +43,9 @@ class BaseService
def deny_visibility_level(model, denied_visibility_level = nil)
denied_visibility_level ||= model.visibility_level
level_name = Gitlab::VisibilityLevel.level_name(denied_visibility_level)
level_name = Gitlab::VisibilityLevel.level_name(denied_visibility_level).downcase
model.errors.add(
:visibility_level,
"#{level_name} visibility has been restricted by your GitLab administrator"
)
model.errors.add(:visibility_level, "#{level_name} has been restricted by your GitLab administrator")
end
private
......
......@@ -6,8 +6,7 @@ class CreateSnippetService < BaseService
snippet = project.snippets.build(params)
end
unless Gitlab::VisibilityLevel.allowed_for?(current_user,
params[:visibility_level])
unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
deny_visibility_level(snippet)
return snippet
end
......
module Groups
class BaseService
class BaseService < BaseService
attr_accessor :group, :current_user, :params
def initialize(group, user, params = {})
@group, @current_user, @params = group, user, params.dup
end
private
def visibility_allowed_for_user?
level = group.visibility_level
allowed_by_user = Gitlab::VisibilityLevel.allowed_for?(current_user, level)
group.errors.add(:visibility_level, "#{level} has been restricted by your GitLab administrator.") unless allowed_by_user
allowed_by_user
end
end
end
......@@ -7,7 +7,10 @@ module Groups
def execute
@group = Group.new(params)
return @group unless visibility_allowed_for_user?
unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
deny_visibility_level(@group)
return @group
end
@group.name = @group.path.dup unless @group.name
@group.save
......
......@@ -5,9 +5,18 @@
module Groups
class UpdateService < Groups::BaseService
def execute
group.assign_attributes(params)
# check that user is allowed to set specified visibility_level
new_visibility = params[:visibility_level]
if new_visibility && new_visibility.to_i != group.visibility_level
unless can?(current_user, :change_visibility_level, group) &&
Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
deny_visibility_level(group, new_visibility)
return group
end
end
return false unless visibility_allowed_for_user?
group.assign_attributes(params)
group.save
end
......
......@@ -10,7 +10,7 @@ module Projects
@project = Project.new(params)
# Make sure that the user is allowed to use the specified visibility level
unless visibility_level_allowed?
unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
deny_visibility_level(@project)
return @project
end
......@@ -96,9 +96,5 @@ module Projects
@project.import_start if @project.import?
end
def visibility_level_allowed?
Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level]) && @project.visibility_level_allowed?(@project.visibility_level)
end
end
end
......@@ -3,16 +3,13 @@ module Projects
def execute
# check that user is allowed to set specified visibility_level
new_visibility = params[:visibility_level]
if new_visibility
if new_visibility.to_i != project.visibility_level
unless can?(current_user, :change_visibility_level, project) &&
Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
deny_visibility_level(project, new_visibility)
return project
end
if new_visibility && new_visibility.to_i != project.visibility_level
unless can?(current_user, :change_visibility_level, project) &&
Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
deny_visibility_level(project, new_visibility)
return project
end
return false unless visibility_level_allowed?(new_visibility)
end
new_branch = params[:default_branch]
......@@ -27,19 +24,5 @@ module Projects
end
end
end
private
def visibility_level_allowed?(level)
return true if project.visibility_level_allowed?(level)
level_name = Gitlab::VisibilityLevel.level_name(level)
project.errors.add(
:visibility_level,
"#{level_name} could not be set as visibility level of this project - parent project settings are more restrictive"
)
false
end
end
end
......@@ -9,7 +9,6 @@ class UpdateSnippetService < BaseService
def execute
# check that user is allowed to set specified visibility_level
new_visibility = params[:visibility_level]
if new_visibility && new_visibility.to_i != snippet.visibility_level
unless Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
deny_visibility_level(snippet, new_visibility)
......
......@@ -17,7 +17,7 @@
.cover-title
%h1
= @group.name
%span.visibility-icon.has_tooltip{ data: { container: 'body', placement: 'left' }, title: group_visibility_description(@group) }
%span.visibility-icon.has_tooltip{ data: { container: 'body' }, title: group_visibility_icon_description(@group) }
= visibility_level_icon(@group.visibility_level, fw: false)
.cover-desc.username
......@@ -27,34 +27,29 @@
.cover-desc.description
= markdown(@group.description, pipeline: :description)
- if can?(current_user, :read_group, @group)
%div{ class: container_class }
.top-area
%ul.nav-links
%li.active
= link_to "#projects", 'data-toggle' => 'tab' do
All Projects
- if @shared_projects.present?
%li
= link_to "#shared", 'data-toggle' => 'tab' do
Shared Projects
.nav-controls
= form_tag request.original_url, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f|
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
= render 'shared/projects/dropdown'
- if can? current_user, :create_projects, @group
= link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new pull-right' do
= icon('plus')
New Project
.tab-content
.tab-pane.active#projects
= render "projects", projects: @projects
%div{ class: container_class }
.top-area
%ul.nav-links
%li.active
= link_to "#projects", 'data-toggle' => 'tab' do
All Projects
- if @shared_projects.present?
.tab-pane#shared
= render "shared_projects", projects: @shared_projects
- else
%p.nav-links.no-top
No projects to show
%li
= link_to "#shared", 'data-toggle' => 'tab' do
Shared Projects
.nav-controls
= form_tag request.original_url, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f|
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
= render 'shared/projects/dropdown'
- if can? current_user, :create_projects, @group
= link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new pull-right' do
= icon('plus')
New Project
.tab-content
.tab-pane.active#projects
= render "projects", projects: @projects
- if @shared_projects.present?
.tab-pane#shared
= render "shared_projects", projects: @shared_projects
......@@ -12,40 +12,38 @@
= icon('group fw')
%span
Group
- if can?(current_user, :read_group, @group)
= nav_link(path: 'groups#activity') do
= link_to activity_group_path(@group), title: 'Activity' do
= icon('dashboard fw')
%span
Activity
- if current_user
= nav_link(controller: [:group, :milestones]) do
= link_to group_milestones_path(@group), title: 'Milestones' do
= icon('clock-o fw')
%span
Milestones
= nav_link(path: 'groups#issues') do
= link_to issues_group_path(@group), title: 'Issues' do
= icon('exclamation-circle fw')
%span
Issues
- if current_user
%span.count= number_with_delimiter(Issue.opened.of_group(@group).count)
= nav_link(path: 'groups#merge_requests') do
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
= icon('tasks fw')
%span
Merge Requests
- if current_user
%span.count= number_with_delimiter(MergeRequest.opened.of_group(@group).count)
= nav_link(controller: [:group_members]) do
= link_to group_group_members_path(@group), title: 'Members' do
= icon('users fw')
= nav_link(path: 'groups#activity') do
= link_to activity_group_path(@group), title: 'Activity' do
= icon('dashboard fw')
%span
Activity
= nav_link(controller: [:group, :milestones]) do
= link_to group_milestones_path(@group), title: 'Milestones' do
= icon('clock-o fw')
%span
Milestones
= nav_link(path: 'groups#issues') do
= link_to issues_group_path(@group), title: 'Issues' do
= icon('exclamation-circle fw')
%span
Issues
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
%span.count= number_with_delimiter(issues.count)
= nav_link(path: 'groups#merge_requests') do
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
= icon('tasks fw')
%span
Merge Requests
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened').execute
%span.count= number_with_delimiter(merge_requests.count)
= nav_link(controller: [:group_members]) do
= link_to group_group_members_path(@group), title: 'Members' do
= icon('users fw')
%span
Members
- if can?(current_user, :admin_group, @group)
= nav_link(html_options: { class: "separate-item" }) do
= link_to edit_group_path(@group), title: 'Settings' do
= icon ('cogs fw')
%span
Members
- if can?(current_user, :admin_group, @group)
= nav_link(html_options: { class: "separate-item" }) do
= link_to edit_group_path(@group), title: 'Settings' do
= icon ('cogs fw')
%span
Settings
Settings
......@@ -2,21 +2,21 @@
.project-home-panel.cover-block.clearfix{:class => ("empty-project" if empty_repo)}
.project-identicon-holder
= project_icon(@project, alt: '', class: 'project-avatar avatar s90')
.cover-title#project-home-desc
.cover-title.project-home-desc
%h1
= @project.name
%span.visibility-icon.has_tooltip{data: { container: 'body' },
title: "#{visibility_level_label(@project.visibility_level)} - #{project_visibility_level_description(@project.visibility_level)}"}
%span.visibility-icon.has_tooltip{data: { container: 'body' }, title: project_visibility_icon_description(@project)}
= visibility_level_icon(@project.visibility_level, fw: false)
- if @project.description.present?
- if @project.description.present?
.cover-desc.project-home-desc
= markdown(@project.description, pipeline: :description)
- if forked_from_project = @project.forked_from_project
%p
Forked from
= link_to project_path(forked_from_project) do
= forked_from_project.namespace.try(:name)
- if forked_from_project = @project.forked_from_project
.cover-desc
Forked from
= link_to project_path(forked_from_project) do
= forked_from_project.namespace.try(:name)
.cover-controls
- if current_user
......
......@@ -21,7 +21,7 @@
= icon('users')
= number_with_delimiter(group.users.count)
%span{title: group_visibility_description(group)}
%span.visibility-icon.has_tooltip{data: { container: 'body', placement: 'left' }, title: group_visibility_icon_description(group)}
= visibility_level_icon(group.visibility_level, fw: false)
= image_tag group_icon(group), class: "avatar s40 hidden-xs"
......
......@@ -27,8 +27,7 @@
%span
= icon('star')
= project.star_count
%span.visibility-icon.has_tooltip{data: { container: 'body', placement: 'left' },
title: "#{visibility_level_label(project.visibility_level)} - #{project_visibility_level_description(project.visibility_level)}"}
%span.visibility-icon.has_tooltip{data: { container: 'body', placement: 'left' }, title: project_visibility_icon_description(project)}
= visibility_level_icon(project.visibility_level, fw: false)
.title
......
......@@ -5,7 +5,7 @@
class AddDefaultGroupVisibilityToApplicationSettings < ActiveRecord::Migration
def up
add_column :application_settings, :default_group_visibility, :integer
execute("update application_settings set default_group_visibility = #{allowed_visibility_level}")
execute("UPDATE application_settings SET default_group_visibility = #{allowed_visibility_level}")
end
def down
......@@ -15,6 +15,7 @@ class AddDefaultGroupVisibilityToApplicationSettings < ActiveRecord::Migration
private
def allowed_visibility_level
# TODO: Don't use `current_application_settings`
allowed_levels = Gitlab::VisibilityLevel.values - current_application_settings.restricted_visibility_levels
allowed_levels.max
end
......
......@@ -590,8 +590,8 @@ ActiveRecord::Schema.define(version: 20160316204731) do
t.string "type"
t.string "description", default: "", null: false
t.string "avatar"
t.integer "visibility_level", default: 0, null: false
t.boolean "share_with_group_lock", default: false
t.integer "visibility_level", default: 20, null: false
end
add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree
......
......@@ -111,6 +111,7 @@ Parameters:
- `name` (required) - The name of the group
- `path` (required) - The path of the group
- `description` (optional) - The group's description
- `visibility_level` (optional) - The group's visibility. 0 for private, 10 for internal, 20 for public.
## Transfer project to group
......
......@@ -31,7 +31,7 @@ module API
authorize! :create_group, current_user
required_attributes! [:name, :path]
attrs = attributes_for_keys [:name, :path, :description]
attrs = attributes_for_keys [:name, :path, :description, :visibility_level]
@group = Group.new(attrs)
if @group.save
......
......@@ -11,6 +11,8 @@ module Gitlab
included do
scope :public_only, -> { where(visibility_level: PUBLIC) }
scope :public_and_internal_only, -> { where(visibility_level: [PUBLIC, INTERNAL] ) }
scope :public_to_user, -> (user) { user && !user.external ? public_and_internal_only : public_only }
end
PRIVATE = 0 unless const_defined?(:PRIVATE)
......
......@@ -20,43 +20,4 @@ describe GroupsController do
end
end
end
describe 'GET show' do
let(:group) { create(:group, visibility_level: 20) }
it 'checks if group can be read' do
expect(controller).to receive(:authorize_read_group!)
get :show, id: group.path
end
end
describe 'POST create' do
before { sign_in(create(:user)) }
it 'checks if group can be created' do
expect(controller).to receive(:authorize_create_group!)
post :create, { group: { name: "any params" } }
end
end
describe 'DELETE destroy' do
before { sign_in(create(:user)) }
let(:group) { create(:group, visibility_level: 20) }
it 'checks if group can be deleted' do
expect(controller).to receive(:authorize_admin_group!)
delete :destroy, id: group.path
end
end
describe 'PUT update' do
before { sign_in(create(:user)) }
let(:group) { create(:group, visibility_level: 20) }
it 'checks if group can be updated' do
expect_any_instance_of(Groups::UpdateService).to receive(:execute)
expect(controller).to receive(:authorize_admin_group!)
put :update, id: group.path, group: { name: 'test' }
end
end
end
......@@ -15,12 +15,11 @@ describe NamespacesController do
end
context "when the namespace belongs to a group" do
let!(:group) { create(:group, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
let!(:project) { create(:project, namespace: group) }
let!(:group) { create(:group) }
context "when the group has public projects" do
context "when the group is public" do
before do
project.update_attribute(:visibility_level, Project::PUBLIC)
group.update_attribute(:visibility_level, Group::PUBLIC)
end
context "when not signed in" do
......@@ -44,27 +43,27 @@ describe NamespacesController do
end
end
context "when the project doesn't have public projects" do
context "when the group is private" do
context "when not signed in" do
it "does not redirect to the sign in page" do
get :show, id: group.path
expect(response).not_to redirect_to(new_user_session_path)
end
end
context "when signed in" do
before do
sign_in(user)
end
context "when the user has access to the project" do
context "when the user has access to the group" do
before do
project.team << [user, :master]
group.add_developer(user)
end
context "when the user is blocked" do
before do
user.block
project.team << [user, :master]
end
it "redirects to the sign in page" do
......@@ -83,11 +82,11 @@ describe NamespacesController do
end
end
context "when the user doesn't have access to the project" do
it "redirects to the group's page" do
context "when the user doesn't have access to the group" do
it "responds with status 404" do
get :show, id: group.path
expect(response).to redirect_to(group_path(group))
expect(response.status).to eq(404)
end
end
end
......
......@@ -127,12 +127,10 @@ describe UploadsController do
context "when viewing a group avatar" do
let!(:group) { create(:group, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
let!(:project) { create(:project, namespace: group) }
context "when the group has public projects" do
context "when the group is public" do
before do
group.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PUBLIC)
project.update_attribute(:visibility_level, Project::PUBLIC)
end
context "when not signed in" do
......@@ -156,7 +154,7 @@ describe UploadsController do
end
end
context "when the project doesn't have public projects" do
context "when the group is private" do
context "when signed in" do
before do
sign_in(user)
......@@ -164,13 +162,12 @@ describe UploadsController do
context "when the user has access to the project" do
before do
project.team << [user, :master]
project.add_developer(user)
end
context "when the user is blocked" do
before do
user.block
project.team << [user, :master]
end
it "redirects to the sign in page" do
......
......@@ -12,25 +12,25 @@ feature 'Project', feature: true do
it 'parses Markdown' do
project.update_attribute(:description, 'This is **my** project')
visit path
expect(page).to have_css('.cover-title > p > strong')
expect(page).to have_css('.project-home-desc > p > strong')
end
it 'passes through html-pipeline' do
project.update_attribute(:description, 'This project is the :poop:')
visit path
expect(page).to have_css('.cover-title > p > img')
expect(page).to have_css('.project-home-desc > p > img')
end
it 'sanitizes unwanted tags' do
project.update_attribute(:description, "```\ncode\n```")
visit path
expect(page).not_to have_css('.cover-title code')
expect(page).not_to have_css('.project-home-desc code')
end
it 'permits `rel` attribute on links' do
project.update_attribute(:description, 'https://google.com/')
visit path
expect(page).to have_css('.cover-title a[rel]')
expect(page).to have_css('.project-home-desc a[rel]')
end
end
......
require 'rails_helper'
describe 'Internal group access', feature: true do
describe 'Internal Group access', feature: true do
include AccessMatchers
include GroupAccessHelper
describe 'GET /groups/:path' do
subject { group_path(group(Gitlab::VisibilityLevel::INTERNAL)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
let(:group) { create(:group, :internal) }
let(:project) { create(:project, :internal, group: group) }
end
let(:owner) { create(:user) }
let(:master) { create(:user) }
let(:developer) { create(:user) }
let(:reporter) { create(:user) }
let(:guest) { create(:user) }
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to_not be_allowed_for :visitor }
end
let(:project_guest) { create(:user) }
before do
group.add_user(owner, Gitlab::Access::OWNER)
group.add_user(master, Gitlab::Access::MASTER)
group.add_user(developer, Gitlab::Access::DEVELOPER)
group.add_user(reporter, Gitlab::Access::REPORTER)
group.add_user(guest, Gitlab::Access::GUEST)
project.team << [project_guest, :guest]
end
describe 'GET /groups/:path/issues' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::INTERNAL)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
describe "Group should be internal" do
describe '#internal?' do
subject { group.internal? }
it { is_expected.to be_truthy }
end
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to_not be_allowed_for :visitor }
end
describe 'GET /groups/:path' do
subject { group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
describe 'GET /groups/:path/merge_requests' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::INTERNAL)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
end
describe 'GET /groups/:path/issues' do
subject { issues_group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to_not be_allowed_for :visitor }
end
describe 'GET /groups/:path/merge_requests' do
subject { merge_requests_group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
describe 'GET /groups/:path/group_members' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::INTERNAL)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to_not be_allowed_for :visitor }
end
subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
describe 'GET /groups/:path/edit' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::INTERNAL)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to_not be_allowed_for :visitor }
end
subject { edit_group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_denied_for master }
it { is_expected.to be_denied_for developer }
it { is_expected.to be_denied_for reporter }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for project_guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
end
end
require 'rails_helper'
describe 'Private group access', feature: true do
describe 'Private Group access', feature: true do
include AccessMatchers
include GroupAccessHelper
let(:group) { create(:group, :private) }
let(:project) { create(:project, :private, group: group) }
let(:owner) { create(:user) }
let(:master) { create(:user) }
let(:developer) { create(:user) }
let(:reporter) { create(:user) }
let(:guest) { create(:user) }
describe 'GET /groups/:path' do
subject { group_path(group(Gitlab::VisibilityLevel::PRIVATE)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
end
let(:project_guest) { create(:user) }
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to_not be_allowed_for :visitor }
end
before do
group.add_user(owner, Gitlab::Access::OWNER)
group.add_user(master, Gitlab::Access::MASTER)
group.add_user(developer, Gitlab::Access::DEVELOPER)
group.add_user(reporter, Gitlab::Access::REPORTER)
group.add_user(guest, Gitlab::Access::GUEST)
project.team << [project_guest, :guest]
end
describe 'GET /groups/:path/issues' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::PRIVATE)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
describe "Group should be private" do
describe '#private?' do
subject { group.private? }
it { is_expected.to be_truthy }
end
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to_not be_allowed_for :visitor }
end
describe 'GET /groups/:path' do
subject { group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
describe 'GET /groups/:path/merge_requests' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::PRIVATE)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
end
describe 'GET /groups/:path/issues' do
subject { issues_group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to_not be_allowed_for :visitor }
end
describe 'GET /groups/:path/merge_requests' do
subject { merge_requests_group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
describe 'GET /groups/:path/group_members' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::PRIVATE)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to_not be_allowed_for :visitor }
end
subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
describe 'GET /groups/:path/edit' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::PRIVATE)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to_not be_allowed_for :visitor }
end
subject { edit_group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_denied_for master }
it { is_expected.to be_denied_for developer }
it { is_expected.to be_denied_for reporter }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for project_guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
end
end
require 'rails_helper'
describe 'Public group access', feature: true do
describe 'Public Group access', feature: true do
include AccessMatchers
include GroupAccessHelper
let(:group) { create(:group, :public) }
let(:project) { create(:project, :public, group: group) }
let(:owner) { create(:user) }
let(:master) { create(:user) }
let(:developer) { create(:user) }
let(:reporter) { create(:user) }
let(:guest) { create(:user) }
describe 'GET /groups/:path' do
subject { group_path(group(Gitlab::VisibilityLevel::PUBLIC)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
it { is_expected.to be_allowed_for :external }
end
let(:project_guest) { create(:user) }
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to be_allowed_for :visitor }
end
before do
group.add_user(owner, Gitlab::Access::OWNER)
group.add_user(master, Gitlab::Access::MASTER)
group.add_user(developer, Gitlab::Access::DEVELOPER)
group.add_user(reporter, Gitlab::Access::REPORTER)
group.add_user(guest, Gitlab::Access::GUEST)
project.team << [project_guest, :guest]
end
describe 'GET /groups/:path/issues' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::PUBLIC)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
it { is_expected.to be_allowed_for :external }
describe "Group should be public" do
describe '#public?' do
subject { group.public? }
it { is_expected.to be_truthy }
end
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to be_allowed_for :visitor }
end
describe 'GET /groups/:path' do
subject { group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
describe 'GET /groups/:path/merge_requests' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::PUBLIC)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
it { is_expected.to be_allowed_for :external }
end
describe 'GET /groups/:path/issues' do
subject { issues_group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to be_allowed_for :visitor }
end
describe 'GET /groups/:path/merge_requests' do
subject { merge_requests_group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
describe 'GET /groups/:path/group_members' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::PUBLIC)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
it { is_expected.to be_allowed_for :external }
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to be_allowed_for :visitor }
end
subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for project_guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
describe 'GET /groups/:path/edit' do
subject { issues_group_path(group(Gitlab::VisibilityLevel::PUBLIC)) }
context "when user not in group project" do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for external_guest }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
it { is_expected.to be_allowed_for :external }
end
context "when user in group project" do
it { is_expected.to be_allowed_for project_group_member(:user) }
it { is_expected.to be_allowed_for :visitor }
end
subject { edit_group_path(group) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_denied_for master }
it { is_expected.to be_denied_for developer }
it { is_expected.to be_denied_for reporter }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for project_guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
it { is_expected.to be_denied_for :external }
end
end
require 'rails_helper'
describe 'Group access', feature: true do
include AccessMatchers
def group
@group ||= create(:group, visibility_level: Gitlab::VisibilityLevel::PUBLIC)
end
def create_project(access_level)
if access_level == :mixed
create(:empty_project, :public, group: group)
create(:empty_project, :internal, group: group)
else
create(:empty_project, access_level, group: group)
end
end
def group_member(access_level, grp = group())
level = Object.const_get("Gitlab::Access::#{access_level.upcase}")
create(:user).tap do |user|
grp.add_user(user, level)
end
end
describe 'GET /groups/new' do
subject { new_group_path }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
end
describe 'GET /groups/:path' do
subject { group_path(group) }
context 'with public projects' do
let!(:project) { create_project(:public) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with mixed projects' do
let!(:project) { create_project(:mixed) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with internal projects' do
let!(:project) { create_project(:internal) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with no projects' do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
end
describe 'GET /groups/:path/issues' do
subject { issues_group_path(group) }
context 'with public projects' do
let!(:project) { create_project(:public) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with mixed projects' do
let!(:project) { create_project(:mixed) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with internal projects' do
let!(:project) { create_project(:internal) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with no projects' do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
end
describe 'GET /groups/:path/merge_requests' do
subject { merge_requests_group_path(group) }
context 'with public projects' do
let!(:project) { create_project(:public) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with mixed projects' do
let!(:project) { create_project(:mixed) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with internal projects' do
let!(:project) { create_project(:internal) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with no projects' do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
end
describe 'GET /groups/:path/group_members' do
subject { group_group_members_path(group) }
context 'with public projects' do
let!(:project) { create_project(:public) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with mixed projects' do
let!(:project) { create_project(:mixed) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with internal projects' do
let!(:project) { create_project(:internal) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with no projects' do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_allowed_for group_member(:master) }
it { is_expected.to be_allowed_for group_member(:reporter) }
it { is_expected.to be_allowed_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
end
describe 'GET /groups/:path/edit' do
subject { edit_group_path(group) }
context 'with public projects' do
let!(:project) { create_project(:public) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_denied_for group_member(:master) }
it { is_expected.to be_denied_for group_member(:reporter) }
it { is_expected.to be_denied_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with mixed projects' do
let!(:project) { create_project(:mixed) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_denied_for group_member(:master) }
it { is_expected.to be_denied_for group_member(:reporter) }
it { is_expected.to be_denied_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with internal projects' do
let!(:project) { create_project(:internal) }
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_denied_for group_member(:master) }
it { is_expected.to be_denied_for group_member(:reporter) }
it { is_expected.to be_denied_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
context 'with no projects' do
it { is_expected.to be_allowed_for group_member(:owner) }
it { is_expected.to be_denied_for group_member(:master) }
it { is_expected.to be_denied_for group_member(:reporter) }
it { is_expected.to be_denied_for group_member(:guest) }
it { is_expected.to be_allowed_for :admin }
end
end
end
......@@ -18,19 +18,4 @@ describe GroupsHelper do
expect(group_icon(group.path)).to match('group_avatar.png')
end
end
describe 'permissions' do
let(:group) { create(:group) }
let!(:user) { create(:user) }
before do
allow(self).to receive(:current_user).and_return(user)
allow(self).to receive(:can?) { true }
end
it 'checks user ability to change permissions' do
expect(self).to receive(:can?).with(user, :change_visibility_level, group)
can_change_group_visibility_level?(group)
end
end
end
module GroupAccessHelper
def group(visibility_level=0)
@group ||= create(:group, visibility_level: visibility_level)
end
def project_group_member(access_level)
project = create(:project, visibility_level: group.visibility_level, group: group, name: 'B', path: 'B')
create(:user).tap { |user| project.team.add_user(user, Gitlab::Access::DEVELOPER) }
end
def group_member(access_level, grp=group())
level = Object.const_get("Gitlab::Access::#{access_level.upcase}")
create(:user).tap { |user| grp.add_user(user, level) }
end
def external_guest(grp=group())
create(:user, external: true).tap { |user| grp.add_user(user, Gitlab::Access::GUEST) }
end
end
......@@ -28,7 +28,7 @@ module AccessMatchers
if user.kind_of?(User)
# User#inspect displays too much information for RSpec's description
# messages
"be #{type} for supplied User"
"be #{type} for the specified user"
else
"be #{type} for #{user}"
end
......
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