Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorDouwe Maan <douwe@selenight.nl>2016-03-20 23:03:53 +0300
committerDouwe Maan <douwe@selenight.nl>2016-03-20 23:04:07 +0300
commit8db1292139cfdac4c29c03b876b68b9e752cf75a (patch)
tree2fcf67ada482ecf4ac90f39c858334a62b709618 /app
parent2eb19ea3ea36916bbea72a8ccab3e6d15f602ac9 (diff)
Tweaks, refactoring, and specs
Diffstat (limited to 'app')
-rw-r--r--app/assets/stylesheets/framework/mobile.scss2
-rw-r--r--app/controllers/application_controller.rb61
-rw-r--r--app/controllers/groups/application_controller.rb27
-rw-r--r--app/controllers/groups/avatars_controller.rb2
-rw-r--r--app/controllers/groups/group_members_controller.rb3
-rw-r--r--app/controllers/groups/milestones_controller.rb12
-rw-r--r--app/controllers/groups_controller.rb19
-rw-r--r--app/controllers/projects/application_controller.rb75
-rw-r--r--app/controllers/projects/avatars_controller.rb2
-rw-r--r--app/controllers/projects/uploads_controller.rb6
-rw-r--r--app/controllers/projects_controller.rb4
-rw-r--r--app/finders/contributed_projects_finder.rb23
-rw-r--r--app/finders/group_projects_finder.rb43
-rw-r--r--app/finders/groups_finder.rb26
-rw-r--r--app/finders/issuable_finder.rb4
-rw-r--r--app/finders/joined_groups_finder.rb32
-rw-r--r--app/finders/personal_projects_finder.rb35
-rw-r--r--app/finders/projects_finder.rb77
-rw-r--r--app/finders/union_finder.rb11
-rw-r--r--app/helpers/groups_helper.rb4
-rw-r--r--app/helpers/visibility_level_helper.rb8
-rw-r--r--app/models/ability.rb23
-rw-r--r--app/models/group.rb9
-rw-r--r--app/models/project.rb48
-rw-r--r--app/services/base_service.rb7
-rw-r--r--app/services/create_snippet_service.rb3
-rw-r--r--app/services/groups/base_service.rb13
-rw-r--r--app/services/groups/create_service.rb5
-rw-r--r--app/services/groups/update_service.rb13
-rw-r--r--app/services/projects/create_service.rb6
-rw-r--r--app/services/projects/update_service.rb29
-rw-r--r--app/services/update_snippet_service.rb1
-rw-r--r--app/views/groups/show.html.haml57
-rw-r--r--app/views/layouts/nav/_group.html.haml70
-rw-r--r--app/views/projects/_home_panel.html.haml18
-rw-r--r--app/views/shared/groups/_group.html.haml2
-rw-r--r--app/views/shared/projects/_project.html.haml3
37 files changed, 342 insertions, 441 deletions
diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss
index bf874b9b822..5ea4f9a49db 100644
--- a/app/assets/stylesheets/framework/mobile.scss
+++ b/app/assets/stylesheets/framework/mobile.scss
@@ -48,7 +48,7 @@
display: block;
}
- #project-home-desc {
+ .project-home-desc {
font-size: 21px;
}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 1f55b18e0b1..3a0eb96a460 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -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
diff --git a/app/controllers/groups/application_controller.rb b/app/controllers/groups/application_controller.rb
index 795ce50fe92..949b4a6c25a 100644
--- a/app/controllers/groups/application_controller.rb
+++ b/app/controllers/groups/application_controller.rb
@@ -1,21 +1,32 @@
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!
diff --git a/app/controllers/groups/avatars_controller.rb b/app/controllers/groups/avatars_controller.rb
index 76c87366baa..ad2c20b42db 100644
--- a/app/controllers/groups/avatars_controller.rb
+++ b/app/controllers/groups/avatars_controller.rb
@@ -1,4 +1,6 @@
class Groups::AvatarsController < Groups::ApplicationController
+ before_action :authorize_admin_group!
+
def destroy
@group.remove_avatar!
@group.save
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index 0e902c4bb43..d5ef33888c6 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -1,8 +1,5 @@
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
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index 0c2a350bc39..0028f072d5b 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -1,10 +1,10 @@
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
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index b635fb150ae..48565f44ffb 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -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
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index a326bc58215..276f80f800a 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -1,20 +1,73 @@
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
diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb
index a6bebc46b06..72921b3aa14 100644
--- a/app/controllers/projects/avatars_controller.rb
+++ b/app/controllers/projects/avatars_controller.rb
@@ -1,7 +1,7 @@
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)
diff --git a/app/controllers/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb
index e1fe7ea2114..94c51eeb94d 100644
--- a/app/controllers/projects/uploads_controller.rb
+++ b/app/controllers/projects/uploads_controller.rb
@@ -1,7 +1,9 @@
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)
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index c9930480770..928817ba811 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -1,7 +1,7 @@
-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?
diff --git a/app/finders/contributed_projects_finder.rb b/app/finders/contributed_projects_finder.rb
index f8b04dfa2aa..a685719555c 100644
--- a/app/finders/contributed_projects_finder.rb
+++ b/app/finders/contributed_projects_finder.rb
@@ -1,4 +1,4 @@
-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
diff --git a/app/finders/group_projects_finder.rb b/app/finders/group_projects_finder.rb
new file mode 100644
index 00000000000..84fe468ae5d
--- /dev/null
+++ b/app/finders/group_projects_finder.rb
@@ -0,0 +1,43 @@
+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
diff --git a/app/finders/groups_finder.rb b/app/finders/groups_finder.rb
index 30698f80231..4e43f42e9e1 100644
--- a/app/finders/groups_finder.rb
+++ b/app/finders/groups_finder.rb
@@ -1,30 +1,18 @@
-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
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 19e8c7a92be..7510f6e9e29 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -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
diff --git a/app/finders/joined_groups_finder.rb b/app/finders/joined_groups_finder.rb
index 867eb661682..2a3f0296d37 100644
--- a/app/finders/joined_groups_finder.rb
+++ b/app/finders/joined_groups_finder.rb
@@ -1,5 +1,4 @@
-#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
diff --git a/app/finders/personal_projects_finder.rb b/app/finders/personal_projects_finder.rb
index 34f33e2353b..3ad4bd5f066 100644
--- a/app/finders/personal_projects_finder.rb
+++ b/app/finders/personal_projects_finder.rb
@@ -1,4 +1,4 @@
-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
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index 3a5fc5b5907..2f0a9659d15 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -1,81 +1,18 @@
-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
diff --git a/app/finders/union_finder.rb b/app/finders/union_finder.rb
new file mode 100644
index 00000000000..33cd1a491f3
--- /dev/null
+++ b/app/finders/union_finder.rb
@@ -0,0 +1,11 @@
+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
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 42e09149bd7..b1f0a765bb9 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -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
diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb
index 7fa18ba9079..5b1bfb261a5 100644
--- a/app/helpers/visibility_level_helper.rb
+++ b/app/helpers/visibility_level_helper.rb
@@ -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
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 88d7ecf3a16..de9253fcdd8 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -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)
diff --git a/app/models/group.rb b/app/models/group.rb
index 17c69af4d1b..900fcd71ff3 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -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
diff --git a/app/models/project.rb b/app/models/project.rb
index c1374fc9b3c..ab31a635a82 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -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
diff --git a/app/services/base_service.rb b/app/services/base_service.rb
index 8563633816c..0d55ba5a981 100644
--- a/app/services/base_service.rb
+++ b/app/services/base_service.rb
@@ -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
diff --git a/app/services/create_snippet_service.rb b/app/services/create_snippet_service.rb
index 101a3df5eee..9884cb96661 100644
--- a/app/services/create_snippet_service.rb
+++ b/app/services/create_snippet_service.rb
@@ -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
diff --git a/app/services/groups/base_service.rb b/app/services/groups/base_service.rb
index 1db81216084..1642115583d 100644
--- a/app/services/groups/base_service.rb
+++ b/app/services/groups/base_service.rb
@@ -1,20 +1,9 @@
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
diff --git a/app/services/groups/create_service.rb b/app/services/groups/create_service.rb
index f605ccca81b..46c2a53e1f6 100644
--- a/app/services/groups/create_service.rb
+++ b/app/services/groups/create_service.rb
@@ -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
diff --git a/app/services/groups/update_service.rb b/app/services/groups/update_service.rb
index 0b0c5a35d37..b70e2e4aaa9 100644
--- a/app/services/groups/update_service.rb
+++ b/app/services/groups/update_service.rb
@@ -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
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index c4b8420f9f2..501e58c1407 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -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
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index 895e089bea3..941df08995c 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -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
diff --git a/app/services/update_snippet_service.rb b/app/services/update_snippet_service.rb
index e9328bb7323..93af8f21972 100644
--- a/app/services/update_snippet_service.rb
+++ b/app/services/update_snippet_service.rb
@@ -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)
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index 222c3e4a40e..5a9fa5d9a4d 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -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
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index 59411ae1da1..55940741dc0 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -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
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index e8434b5292c..d4bbafbd40f 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -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
diff --git a/app/views/shared/groups/_group.html.haml b/app/views/shared/groups/_group.html.haml
index 67a59f420f3..03103d46bb9 100644
--- a/app/views/shared/groups/_group.html.haml
+++ b/app/views/shared/groups/_group.html.haml
@@ -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"
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index 872d2bdf46d..3b987987676 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -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