Commit d9bb4230 authored by Jason Hollingsworth's avatar Jason Hollingsworth

Adding authenticated public mode (internal).

Added visibility_level icons to project view (rather than just text).
Added public projects to search results.
Added ability to restrict visibility levels standard users can set.
parent 51b5509b
......@@ -365,6 +365,10 @@ table {
&.input-large {
width: 210px;
}
&.input-clamp {
max-width: 100%;
}
}
.user-result {
......
......@@ -6,6 +6,7 @@
.cblue { color: #29A }
.cblack { color: #111 }
.cdark { color: #444 }
.camber { color: #ffc000 }
.cwhite { color: #fff!important }
.bgred { background: #F2DEDE!important }
......
......@@ -20,6 +20,15 @@
label { width: 110px; }
.controls { margin-left: 130px; }
.form-actions { padding-left: 130px; background: #fff }
.visibility-levels {
.controls {
margin-bottom: 9px;
}
i {
color: inherit;
}
}
}
.broadcast-messages {
......
......@@ -18,6 +18,12 @@
border-bottom: 1px solid #DDD;
padding-bottom: 25px;
margin-bottom: 30px;
&.empty-project {
border-bottom: 0px;
padding-bottom: 15px;
margin-bottom: 0px;
}
.project-home-title {
font-size: 18px;
......@@ -45,7 +51,7 @@
}
}
.public-label {
.visibility-level-label {
font-size: 14px;
background: #f1f1f1;
padding: 8px 10px;
......@@ -53,6 +59,10 @@
margin-left: 10px;
color: #888;
text-shadow: 0 1px 1px #FFF;
i {
color: inherit;
}
}
}
......@@ -87,9 +97,33 @@
}
}
.project-public-holder {
.help-inline {
padding-top: 7px;
.project-visibility-level-holder {
.controls {
padding-bottom: 9px;
}
.controls {
input {
float: left;
}
.descr {
display: block;
margin-left: 1.5em;
&.restricted {
color: #888;
}
}
.info {
display: block;
margin-top: 5px;
}
strong {
display: inline-block;
width: 4em;
}
}
i {
color: inherit;
}
}
......@@ -130,7 +164,8 @@ ul.nav.nav-projects-tabs {
margin: 0px;
}
.my-projects {
.my-projects,
.public-projects {
li {
.project-info {
margin-bottom: 10px;
......
......@@ -8,6 +8,11 @@ module Projects
# get namespace id
namespace_id = params.delete(:namespace_id)
# check that user is allowed to set specified visibility_level
unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
params.delete(:visibility_level)
end
# Load default feature settings
default_features = Gitlab.config.gitlab.default_projects_features
......@@ -17,7 +22,7 @@ module Projects
wall_enabled: default_features.wall,
snippets_enabled: default_features.snippets,
merge_requests_enabled: default_features.merge_requests,
public: default_features.public
visibility_level: default_features.visibility_level
}.stringify_keys
@project = Project.new(default_opts.merge(params))
......
......@@ -2,7 +2,11 @@ module Projects
class UpdateContext < BaseContext
def execute(role = :default)
params[:project].delete(:namespace_id)
params[:project].delete(:public) unless can?(current_user, :change_public_mode, project)
# check that user is allowed to set specified visibility_level
unless can?(current_user, :change_visibility_level, project) && Gitlab::VisibilityLevel.allowed_for?(current_user, params[:project][:visibility_level])
params[:project].delete(:visibility_level)
end
new_branch = params[:project].delete(:default_branch)
if project.repository.exists? && new_branch != project.repository.root_ref
......
class SearchContext
attr_accessor :project_ids, :params
attr_accessor :project_ids, :current_user, :params
def initialize(project_ids, params)
@project_ids, @params = project_ids, params.dup
def initialize(project_ids, user, params)
@project_ids, @current_user, @params = project_ids, user, params.dup
end
def execute
......@@ -10,7 +10,8 @@ class SearchContext
query = Shellwords.shellescape(query) if query.present?
return result unless query.present?
result[:projects] = Project.where("projects.id in (?) OR projects.public = true", project_ids).search(query).limit(20)
visibility_levels = @current_user ? [ Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC ] : [ Gitlab::VisibilityLevel::PUBLIC ]
result[:projects] = Project.where("projects.id in (?) OR projects.visibility_level in (?)", project_ids, visibility_levels).search(query).limit(20)
# Search inside single project
single_project_search(Project.where(id: project_ids), query)
......
......@@ -8,7 +8,7 @@ class Admin::ProjectsController < Admin::ApplicationController
user = User.find_by_id(owner_id)
@projects = user ? user.owned_projects : Project.scoped
@projects = @projects.where(public: true) if params[:public_only].present?
@projects = @projects.where("visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present?
@projects = @projects.with_push if params[:with_push].present?
@projects = @projects.abandoned if params[:abandoned].present?
@projects = @projects.search(params[:name]) if params[:name].present?
......
......@@ -102,7 +102,7 @@ class ApplicationController < ActionController::Base
end
def authorize_code_access!
return access_denied! unless can?(current_user, :download_code, project) or project.public?
return access_denied! unless can?(current_user, :download_code, project)
end
def authorize_push!
......
......@@ -10,7 +10,7 @@ class Projects::ApplicationController < ApplicationController
id = params[:project_id] || params[:id]
@project = Project.find_with_namespace(id)
return if @project && @project.public
return if @project && @project.public?
end
super
......
......@@ -55,7 +55,7 @@ class ProjectsController < ApplicationController
end
def show
return authenticate_user! unless @project.public || current_user
return authenticate_user! unless @project.public? || current_user
limit = (params[:limit] || 20).to_i
@events = @project.events.recent
......
......@@ -6,7 +6,7 @@ class Public::ProjectsController < ApplicationController
layout 'public'
def index
@projects = Project.public_only
@projects = Project.public_or_internal_only(current_user)
@projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
end
......
......@@ -14,7 +14,7 @@ class SearchController < ApplicationController
project_ids.select! { |id| id == project_id.to_i}
end
result = SearchContext.new(project_ids, params).execute
result = SearchContext.new(project_ids, current_user, params).execute
@projects = result[:projects]
@merge_requests = result[:merge_requests]
......
......@@ -11,6 +11,10 @@ module IconsHelper
content_tag :i, nil, class: 'icon-globe cblue'
end
def internal_icon
content_tag :i, nil, class: 'icon-shield camber'
end
def private_icon
content_tag :i, nil, class: 'icon-lock cgreen'
end
......
module SearchHelper
def search_autocomplete_source
return unless current_user
[
groups_autocomplete,
projects_autocomplete,
public_projects_autocomplete,
default_autocomplete,
project_autocomplete,
help_autocomplete
......@@ -75,4 +75,11 @@ module SearchHelper
{ label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
end
end
# Autocomplete results for the current user's projects
def public_projects_autocomplete
Project.public_or_internal_only(current_user).map do |p|
{ label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
end
end
end
module VisibilityLevelHelper
def visibility_level_color(level)
case level
when Gitlab::VisibilityLevel::PRIVATE
'cgreen'
when Gitlab::VisibilityLevel::INTERNAL
'camber'
when Gitlab::VisibilityLevel::PUBLIC
'cblue'
end
end
def visibility_level_description(level)
capture_haml do
haml_tag :span do
case level
when Gitlab::VisibilityLevel::PRIVATE
haml_concat "Project access must be granted explicitly for each user."
when Gitlab::VisibilityLevel::INTERNAL
haml_concat "The project can be cloned by"
haml_tag :em, "any logged in user."
haml_concat "It will also be listed on the #{link_to "public access directory", public_root_path} for logged in users."
haml_tag :em, "Any logged in user"
haml_concat "will have #{link_to "Guest", help_permissions_path} permissions on the repository."
when Gitlab::VisibilityLevel::PUBLIC
haml_concat "The project can be cloned"
haml_tag :em, "without any"
haml_concat "authentication."
haml_concat "It will also be listed on the #{link_to "public access directory", public_root_path}."
haml_tag :em, "Any logged in user"
haml_concat "will have #{link_to "Guest", help_permissions_path} permissions on the repository."
end
end
end
end
def visibility_level_icon(level)
case level
when Gitlab::VisibilityLevel::PRIVATE
private_icon
when Gitlab::VisibilityLevel::INTERNAL
internal_icon
when Gitlab::VisibilityLevel::PUBLIC
public_icon
end
end
def visibility_level_label(level)
Project.visibility_levels.key(level)
end
def restricted_visibility_levels
current_user.is_admin? ? [] : gitlab_config.restricted_visibility_levels
end
end
\ No newline at end of file
......@@ -29,7 +29,7 @@ class Ability
nil
end
if project && project.public
if project && project.public?
[
:read_project,
:read_wiki,
......@@ -71,7 +71,7 @@ class Ability
rules << project_guest_rules
end
if project.public?
if project.public? || project.internal?
rules << public_project_rules
end
......@@ -89,7 +89,7 @@ class Ability
def public_project_rules
project_guest_rules + [
:download_code,
:fork_project,
:fork_project
]
end
......@@ -145,7 +145,7 @@ class Ability
def project_admin_rules
project_master_rules + [
:change_namespace,
:change_public_mode,
:change_visibility_level,
:rename_project,
:remove_project
]
......
......@@ -14,24 +14,25 @@
# merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null
# namespace_id :integer
# public :boolean default(FALSE), not null
# issues_tracker :string(255) default("gitlab"), not null
# issues_tracker_id :string(255)
# snippets_enabled :boolean default(TRUE), not null
# last_activity_at :datetime
# imported :boolean default(FALSE), not null
# import_url :string(255)
# visibility_level :integer default(0), not null
#
class Project < ActiveRecord::Base
include Gitlab::ShellAdapter
include Gitlab::VisibilityLevel
extend Enumerize
ActsAsTaggableOn.strict_case_match = true
attr_accessible :name, :path, :description, :issues_tracker, :label_list,
:issues_enabled, :wall_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id,
:wiki_enabled, :public, :import_url, :last_activity_at, as: [:default, :admin]
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, as: [:default, :admin]
attr_accessible :namespace_id, :creator_id, as: :admin
......@@ -108,7 +109,8 @@ class Project < ActiveRecord::Base
scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
scope :public_only, -> { where(public: true) }
scope :public_only, -> { where(visibility_level: PUBLIC) }
scope :public_or_internal_only, ->(user) { where("visibility_level IN (:levels)", levels: user ? [ INTERNAL, PUBLIC ] : [ PUBLIC ]) }
enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab
......@@ -140,6 +142,10 @@ class Project < ActiveRecord::Base
where(path: id, namespace_id: nil).last
end
end
def visibility_levels
Gitlab::VisibilityLevel.options
end
end
def team
......@@ -451,4 +457,8 @@ class Project < ActiveRecord::Base
def default_branch
@default_branch ||= repository.root_ref if repository.exists?
end
def visibility_level_field
visibility_level
end
end
......@@ -10,11 +10,15 @@
.control-group
= label_tag :owner_id, 'Owner:', class: 'control-label'
.controls
= users_select_tag :owner_id, selected: params[:owner_id], class: 'input-large'
.control-group
= label_tag :public_only, 'Public Only', class: 'control-label'
.controls
= check_box_tag :public_only, 1, params[:public_only]
= users_select_tag :owner_id, selected: params[:owner_id], class: 'input-large input-clamp'
.control-group.visibility-levels
= label_tag :visibility_level, 'Visibility Levels', class: 'control-label'
- Project.visibility_levels.each do |label, level|
.controls
= check_box_tag 'visibility_levels[]', level, params[:visibility_levels].present? && params[:visibility_levels].include?(level.to_s)
%span.descr
= visibility_level_icon(level)
= label
.control-group
= label_tag :with_push, 'Not empty', class: 'control-label'
.controls
......@@ -42,10 +46,7 @@
%ul.well-list
- @projects.each do |project|
%li
- if project.public
= public_icon
- else
= private_icon
= visibility_level_icon(project.visibility_level)
= link_to project.name_with_namespace, [:admin, project]
.pull-right
= link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
......
......@@ -66,14 +66,10 @@
%li
%span.light access:
%strong
- if @project.public
%span.cblue
%i.icon-share
Public
- else
%span.cgreen
%i.icon-lock
Private
%span{ class: visibility_level_color(@project.visibility_level) }
= visibility_level_icon(@project.visibility_level)
= visibility_level_label(@project.visibility_level)
.ui-box
.title
Transfer project
......@@ -88,9 +84,6 @@
.controls
= f.submit 'Transfer', class: 'btn btn-primary'
.span6
- if @group
.ui-box
......
......@@ -58,10 +58,10 @@
%h4.project-title
= link_to project_path(project), class: dom_class(project) do
= project.name_with_namespace
- if project.public
- unless project.private?
%small.access-icon
= public_icon
Public
= visibility_level_icon(project.visibility_level)
= visibility_level_label(project.visibility_level)
- if current_user.can_leave_project?(project)
.pull-right
......
......@@ -51,10 +51,7 @@
%ul.well-list
- @group.projects.each do |project|
%li
- if project.public
= public_icon
- else
= private_icon
= visibility_level_icon(project.visibility_level)
= link_to project.name_with_namespace, project
.pull-right
= link_to 'Members', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
......
......@@ -143,7 +143,7 @@
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Switch public mode
%td Switch visibility level
%td
%td
%td
......
......@@ -2,14 +2,20 @@
%h3.page-title Public Access
%p
GitLab allows you to open selected projects to be accessed publicly.
These projects will be cloneable
GitLab allows you to open selected projects to be accessed publicly or internally.
Projects with either of these visibility levels will be listed in the #{link_to "public access directory", public_root_path}. Internal projects will only be available to authenticated users.
%p
= public_icon
Public projects will be cloneable
%em without any
authentication.
Also they will be listed on the #{link_to "public access directory", public_root_path}.
%p
= internal_icon
Internal projects will be cloneable by
%em any authenticated user.
%ol
%li Go to your project dashboard
%li Click on the "Edit" tab
%li Select "Public clone access"
%li Change "Visibility Level"
- empty_repo = @project.empty_repo?
.project-home-panel{:class => ("empty-project" if empty_repo)}
.row
.span5
%h4.project-home-title
= @project.name_with_namespace
%span.visibility-level-label
= visibility_level_icon(@project.visibility_level)
= visibility_level_label(@project.visibility_level)
.span7
- unless empty_repo
.project-home-dropdown
= render "dropdown"
.form-horizontal
= render "shared/clone_panel"
.project-home-extra.clearfix
.project-home-desc
- if @project.description.present?
= @project.description
- if can?(current_user, :admin_project, @project)
&ndash;
%strong= link_to 'Edit', edit_project_path
- unless empty_repo
.project-home-links
= link_to pluralize(@repository.round_commit_count, 'commit'), project_commits_path(@project, @ref || @repository.root_ref)
= link_to pluralize(@repository.branch_names.count, 'branch'), project_branches_path(@project)
= link_to pluralize(@repository.tag_names.count, 'tag'), project_tags_path(@project)
%span.light.prepend-left-20= repository_size
\ No newline at end of file
.control-group.project-visibility-level-holder
= f.label :visibility_level, "Visibility Level"
- if can_change_visibility_level
- Gitlab::VisibilityLevel.values.each do |level|
- restricted = restricted_visibility_levels.include?(level)
.controls
= f.radio_button :visibility_level, level, checked: (visibility_level == level), disabled: restricted
%span.descr{:class => ("restricted" if restricted)}
= visibility_level_icon(level)
%strong
= visibility_level_label(level)
= visibility_level_description(level)
- unless restricted_visibility_levels.empty?
.controls
%span.info
Some visibility level settings have been restricted by the administrator.
- else
.controls
%span.info
= visibility_level_icon(visibility_level)
%strong
= visibility_level_label(visibility_level)
= visibility_level_description(visibility_level)
\ No newline at end of file
......@@ -29,22 +29,7 @@
.controls= f.select(:default_branch, @repository.branch_names, {}, {class: 'chosen'})
- if can?(current_user, :change_public_mode, @project)
%fieldset.public-mode
%legend
Public mode:
.control-group
= f.label :public, class: 'control-label' do
%span Public access
.controls
= f.check_box :public
%span.descr
If checked, this project can be cloned
%em without any
authentication.
It will also be listed on the #{link_to "public access directory", public_root_path}.
%em Any
user will have #{link_to "Guest", help_permissions_path} permissions on the repository.
= render "visibility_level", f: f, visibility_level: @project.visibility_level, can_change_visibility_level: can?(current_user, :change_visibility_level, @project)
%fieldset.features
%legend
......
%h3.page-title
= @project.name_with_namespace
.form-horizontal.pull-right
= render "shared/clone_panel"
= render "home_panel"
- if @project.import? && !@project.imported
.save-project-loader
......
......@@ -47,12 +47,7 @@
%span.light (optional)
.controls
= f.text_area :description, placeholder: "Awesome project", class: "input-xlarge", rows: 3, maxlength: 250, tabindex: 3
.control-group.project-public-holder
= f.label :public do
%span Public project
.controls
= f.check_box :public, { checked: gitlab_config.default_projects_features.public }, true, false
%span.help-inline Make project visible to everyone
= render "visibility_level", f: f, visibility_level: gitlab_config.default_projects_features.visibility_level, can_change_visibility_level: true
.form-actions
= f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4
......
.project-home-panel
.row
.span5
%h4.project-home-title
= @project.name_with_namespace
- if @project.public
%span.public-label Public
- else
%span.public-label Private
.span7
.project-home-dropdown
= render "dropdown"
.form-horizontal
= render "shared/clone_panel"
.project-home-extra.clearfix
.project-home-desc
- if @project.description.present?
= @project.description
- if can?(current_user, :admin_project, @project)
&ndash;
%strong= link_to 'Edit', edit_project_path
.project-home-links
= link_to pluralize(@repository.round_commit_count, 'commit'), project_commits_path(@project, @ref || @repository.root_ref)
= link_to pluralize(@repository.branch_names.count, 'branch'), project_branches_path(@project)
= link_to pluralize(@repository.tag_names.count, 'tag'), project_tags_path(@project)
%span.light.prepend-left-20= repository_size
= render "home_panel"
.row
.span9
......
......@@ -19,6 +19,10 @@
%h4
= link_to project_path(project) do
= project.name_with_namespace
- if project.internal?
%small.access-icon
= internal_icon
Internal
.pull-right
%pre.public-clone git clone #{project.http_url_to_repo}
......
......@@ -55,6 +55,10 @@ production: &base
# default: false - Account passwords are not sent via the email if signup is enabled.
# signup_enabled: true
# Restrict setting visibility levels for non-admin users.
# The default is to allow all levels.
#restricted_visibility_levels: [ "public" ]