Commit fa7d62494a24584c0d27d52344aae8e382304936
Exists in
master
and in
4 other branches
Merge branch 'authenticated_public_mode' of https://github.com/jhollingsworth/gi…
…tlabhq into feature/internal_projects Conflicts: app/models/project.rb Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Showing
50 changed files
with
955 additions
and
156 deletions
Show diff stats
app/assets/stylesheets/common.scss
app/assets/stylesheets/gitlab_bootstrap/common.scss
@@ -6,6 +6,7 @@ | @@ -6,6 +6,7 @@ | ||
6 | .cblue { color: #29A } | 6 | .cblue { color: #29A } |
7 | .cblack { color: #111 } | 7 | .cblack { color: #111 } |
8 | .cdark { color: #444 } | 8 | .cdark { color: #444 } |
9 | +.camber { color: #ffc000 } | ||
9 | .cwhite { color: #fff!important } | 10 | .cwhite { color: #fff!important } |
10 | .bgred { background: #F2DEDE!important } | 11 | .bgred { background: #F2DEDE!important } |
11 | 12 |
app/assets/stylesheets/sections/admin.scss
@@ -20,6 +20,15 @@ | @@ -20,6 +20,15 @@ | ||
20 | label { width: 110px; } | 20 | label { width: 110px; } |
21 | .controls { margin-left: 130px; } | 21 | .controls { margin-left: 130px; } |
22 | .form-actions { padding-left: 130px; background: #fff } | 22 | .form-actions { padding-left: 130px; background: #fff } |
23 | + .visibility-levels { | ||
24 | + .controls { | ||
25 | + margin-bottom: 9px; | ||
26 | + } | ||
27 | + | ||
28 | + i { | ||
29 | + color: inherit; | ||
30 | + } | ||
31 | + } | ||
23 | } | 32 | } |
24 | 33 | ||
25 | .broadcast-messages { | 34 | .broadcast-messages { |
app/assets/stylesheets/sections/projects.scss
@@ -18,6 +18,12 @@ | @@ -18,6 +18,12 @@ | ||
18 | border-bottom: 1px solid #DDD; | 18 | border-bottom: 1px solid #DDD; |
19 | padding-bottom: 25px; | 19 | padding-bottom: 25px; |
20 | margin-bottom: 30px; | 20 | margin-bottom: 30px; |
21 | + | ||
22 | + &.empty-project { | ||
23 | + border-bottom: 0px; | ||
24 | + padding-bottom: 15px; | ||
25 | + margin-bottom: 0px; | ||
26 | + } | ||
21 | 27 | ||
22 | .project-home-title { | 28 | .project-home-title { |
23 | font-size: 18px; | 29 | font-size: 18px; |
@@ -45,7 +51,7 @@ | @@ -45,7 +51,7 @@ | ||
45 | } | 51 | } |
46 | } | 52 | } |
47 | 53 | ||
48 | - .public-label { | 54 | + .visibility-level-label { |
49 | font-size: 14px; | 55 | font-size: 14px; |
50 | background: #f1f1f1; | 56 | background: #f1f1f1; |
51 | padding: 8px 10px; | 57 | padding: 8px 10px; |
@@ -53,6 +59,10 @@ | @@ -53,6 +59,10 @@ | ||
53 | margin-left: 10px; | 59 | margin-left: 10px; |
54 | color: #888; | 60 | color: #888; |
55 | text-shadow: 0 1px 1px #FFF; | 61 | text-shadow: 0 1px 1px #FFF; |
62 | + | ||
63 | + i { | ||
64 | + color: inherit; | ||
65 | + } | ||
56 | } | 66 | } |
57 | } | 67 | } |
58 | 68 | ||
@@ -87,9 +97,33 @@ | @@ -87,9 +97,33 @@ | ||
87 | } | 97 | } |
88 | } | 98 | } |
89 | 99 | ||
90 | -.project-public-holder { | ||
91 | - .help-inline { | ||
92 | - padding-top: 7px; | 100 | +.project-visibility-level-holder { |
101 | + .controls { | ||
102 | + padding-bottom: 9px; | ||
103 | + } | ||
104 | + | ||
105 | + .controls { | ||
106 | + input { | ||
107 | + float: left; | ||
108 | + } | ||
109 | + .descr { | ||
110 | + display: block; | ||
111 | + margin-left: 1.5em; | ||
112 | + &.restricted { | ||
113 | + color: #888; | ||
114 | + } | ||
115 | + } | ||
116 | + .info { | ||
117 | + display: block; | ||
118 | + margin-top: 5px; | ||
119 | + } | ||
120 | + strong { | ||
121 | + display: inline-block; | ||
122 | + width: 4em; | ||
123 | + } | ||
124 | + } | ||
125 | + i { | ||
126 | + color: inherit; | ||
93 | } | 127 | } |
94 | } | 128 | } |
95 | 129 | ||
@@ -130,7 +164,8 @@ ul.nav.nav-projects-tabs { | @@ -130,7 +164,8 @@ ul.nav.nav-projects-tabs { | ||
130 | margin: 0px; | 164 | margin: 0px; |
131 | } | 165 | } |
132 | 166 | ||
133 | -.my-projects { | 167 | +.my-projects, |
168 | +.public-projects { | ||
134 | li { | 169 | li { |
135 | .project-info { | 170 | .project-info { |
136 | margin-bottom: 10px; | 171 | margin-bottom: 10px; |
app/contexts/projects/create_context.rb
@@ -8,6 +8,11 @@ module Projects | @@ -8,6 +8,11 @@ module Projects | ||
8 | # get namespace id | 8 | # get namespace id |
9 | namespace_id = params.delete(:namespace_id) | 9 | namespace_id = params.delete(:namespace_id) |
10 | 10 | ||
11 | + # check that user is allowed to set specified visibility_level | ||
12 | + unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level]) | ||
13 | + params.delete(:visibility_level) | ||
14 | + end | ||
15 | + | ||
11 | # Load default feature settings | 16 | # Load default feature settings |
12 | default_features = Gitlab.config.gitlab.default_projects_features | 17 | default_features = Gitlab.config.gitlab.default_projects_features |
13 | 18 | ||
@@ -17,7 +22,7 @@ module Projects | @@ -17,7 +22,7 @@ module Projects | ||
17 | wall_enabled: default_features.wall, | 22 | wall_enabled: default_features.wall, |
18 | snippets_enabled: default_features.snippets, | 23 | snippets_enabled: default_features.snippets, |
19 | merge_requests_enabled: default_features.merge_requests, | 24 | merge_requests_enabled: default_features.merge_requests, |
20 | - public: default_features.public | 25 | + visibility_level: default_features.visibility_level |
21 | }.stringify_keys | 26 | }.stringify_keys |
22 | 27 | ||
23 | @project = Project.new(default_opts.merge(params)) | 28 | @project = Project.new(default_opts.merge(params)) |
app/contexts/projects/update_context.rb
@@ -2,7 +2,11 @@ module Projects | @@ -2,7 +2,11 @@ module Projects | ||
2 | class UpdateContext < BaseContext | 2 | class UpdateContext < BaseContext |
3 | def execute(role = :default) | 3 | def execute(role = :default) |
4 | params[:project].delete(:namespace_id) | 4 | params[:project].delete(:namespace_id) |
5 | - params[:project].delete(:public) unless can?(current_user, :change_public_mode, project) | 5 | + # check that user is allowed to set specified visibility_level |
6 | + unless can?(current_user, :change_visibility_level, project) && Gitlab::VisibilityLevel.allowed_for?(current_user, params[:project][:visibility_level]) | ||
7 | + params[:project].delete(:visibility_level) | ||
8 | + end | ||
9 | + | ||
6 | new_branch = params[:project].delete(:default_branch) | 10 | new_branch = params[:project].delete(:default_branch) |
7 | 11 | ||
8 | if project.repository.exists? && new_branch != project.default_branch | 12 | if project.repository.exists? && new_branch != project.default_branch |
app/contexts/search_context.rb
1 | class SearchContext | 1 | class SearchContext |
2 | - attr_accessor :project_ids, :params | 2 | + attr_accessor :project_ids, :current_user, :params |
3 | 3 | ||
4 | - def initialize(project_ids, params) | ||
5 | - @project_ids, @params = project_ids, params.dup | 4 | + def initialize(project_ids, user, params) |
5 | + @project_ids, @current_user, @params = project_ids, user, params.dup | ||
6 | end | 6 | end |
7 | 7 | ||
8 | def execute | 8 | def execute |
@@ -10,7 +10,8 @@ class SearchContext | @@ -10,7 +10,8 @@ class SearchContext | ||
10 | query = Shellwords.shellescape(query) if query.present? | 10 | query = Shellwords.shellescape(query) if query.present? |
11 | 11 | ||
12 | return result unless query.present? | 12 | return result unless query.present? |
13 | - result[:projects] = Project.where("projects.id in (?) OR projects.public = true", project_ids).search(query).limit(20) | 13 | + visibility_levels = @current_user ? [ Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC ] : [ Gitlab::VisibilityLevel::PUBLIC ] |
14 | + result[:projects] = Project.where("projects.id in (?) OR projects.visibility_level in (?)", project_ids, visibility_levels).search(query).limit(20) | ||
14 | 15 | ||
15 | # Search inside single project | 16 | # Search inside single project |
16 | single_project_search(Project.where(id: project_ids), query) | 17 | single_project_search(Project.where(id: project_ids), query) |
app/controllers/admin/projects_controller.rb
@@ -8,7 +8,7 @@ class Admin::ProjectsController < Admin::ApplicationController | @@ -8,7 +8,7 @@ class Admin::ProjectsController < Admin::ApplicationController | ||
8 | user = User.find_by_id(owner_id) | 8 | user = User.find_by_id(owner_id) |
9 | 9 | ||
10 | @projects = user ? user.owned_projects : Project.scoped | 10 | @projects = user ? user.owned_projects : Project.scoped |
11 | - @projects = @projects.where(public: true) if params[:public_only].present? | 11 | + @projects = @projects.where("visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present? |
12 | @projects = @projects.with_push if params[:with_push].present? | 12 | @projects = @projects.with_push if params[:with_push].present? |
13 | @projects = @projects.abandoned if params[:abandoned].present? | 13 | @projects = @projects.abandoned if params[:abandoned].present? |
14 | @projects = @projects.search(params[:name]) if params[:name].present? | 14 | @projects = @projects.search(params[:name]) if params[:name].present? |
app/controllers/application_controller.rb
@@ -102,7 +102,7 @@ class ApplicationController < ActionController::Base | @@ -102,7 +102,7 @@ class ApplicationController < ActionController::Base | ||
102 | end | 102 | end |
103 | 103 | ||
104 | def authorize_code_access! | 104 | def authorize_code_access! |
105 | - return access_denied! unless can?(current_user, :download_code, project) or project.public? | 105 | + return access_denied! unless can?(current_user, :download_code, project) |
106 | end | 106 | end |
107 | 107 | ||
108 | def authorize_push! | 108 | def authorize_push! |
app/controllers/projects/application_controller.rb
@@ -10,7 +10,7 @@ class Projects::ApplicationController < ApplicationController | @@ -10,7 +10,7 @@ class Projects::ApplicationController < ApplicationController | ||
10 | id = params[:project_id] || params[:id] | 10 | id = params[:project_id] || params[:id] |
11 | @project = Project.find_with_namespace(id) | 11 | @project = Project.find_with_namespace(id) |
12 | 12 | ||
13 | - return if @project && @project.public | 13 | + return if @project && @project.public? |
14 | end | 14 | end |
15 | 15 | ||
16 | super | 16 | super |
app/controllers/projects_controller.rb
@@ -55,7 +55,7 @@ class ProjectsController < ApplicationController | @@ -55,7 +55,7 @@ class ProjectsController < ApplicationController | ||
55 | end | 55 | end |
56 | 56 | ||
57 | def show | 57 | def show |
58 | - return authenticate_user! unless @project.public || current_user | 58 | + return authenticate_user! unless @project.public? || current_user |
59 | 59 | ||
60 | limit = (params[:limit] || 20).to_i | 60 | limit = (params[:limit] || 20).to_i |
61 | @events = @project.events.recent | 61 | @events = @project.events.recent |
app/controllers/public/projects_controller.rb
@@ -6,7 +6,7 @@ class Public::ProjectsController < ApplicationController | @@ -6,7 +6,7 @@ class Public::ProjectsController < ApplicationController | ||
6 | layout 'public' | 6 | layout 'public' |
7 | 7 | ||
8 | def index | 8 | def index |
9 | - @projects = Project.public_only | 9 | + @projects = Project.public_or_internal_only(current_user) |
10 | @projects = @projects.search(params[:search]) if params[:search].present? | 10 | @projects = @projects.search(params[:search]) if params[:search].present? |
11 | @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) | 11 | @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) |
12 | end | 12 | end |
app/controllers/search_controller.rb
@@ -14,7 +14,7 @@ class SearchController < ApplicationController | @@ -14,7 +14,7 @@ class SearchController < ApplicationController | ||
14 | project_ids.select! { |id| id == project_id.to_i} | 14 | project_ids.select! { |id| id == project_id.to_i} |
15 | end | 15 | end |
16 | 16 | ||
17 | - result = SearchContext.new(project_ids, params).execute | 17 | + result = SearchContext.new(project_ids, current_user, params).execute |
18 | 18 | ||
19 | @projects = result[:projects] | 19 | @projects = result[:projects] |
20 | @merge_requests = result[:merge_requests] | 20 | @merge_requests = result[:merge_requests] |
app/helpers/icons_helper.rb
@@ -11,6 +11,10 @@ module IconsHelper | @@ -11,6 +11,10 @@ module IconsHelper | ||
11 | content_tag :i, nil, class: 'icon-globe cblue' | 11 | content_tag :i, nil, class: 'icon-globe cblue' |
12 | end | 12 | end |
13 | 13 | ||
14 | + def internal_icon | ||
15 | + content_tag :i, nil, class: 'icon-shield camber' | ||
16 | + end | ||
17 | + | ||
14 | def private_icon | 18 | def private_icon |
15 | content_tag :i, nil, class: 'icon-lock cgreen' | 19 | content_tag :i, nil, class: 'icon-lock cgreen' |
16 | end | 20 | end |
app/helpers/search_helper.rb
1 | module SearchHelper | 1 | module SearchHelper |
2 | def search_autocomplete_source | 2 | def search_autocomplete_source |
3 | return unless current_user | 3 | return unless current_user |
4 | - | ||
5 | [ | 4 | [ |
6 | groups_autocomplete, | 5 | groups_autocomplete, |
7 | projects_autocomplete, | 6 | projects_autocomplete, |
7 | + public_projects_autocomplete, | ||
8 | default_autocomplete, | 8 | default_autocomplete, |
9 | project_autocomplete, | 9 | project_autocomplete, |
10 | help_autocomplete | 10 | help_autocomplete |
@@ -75,4 +75,11 @@ module SearchHelper | @@ -75,4 +75,11 @@ module SearchHelper | ||
75 | { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) } | 75 | { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) } |
76 | end | 76 | end |
77 | end | 77 | end |
78 | + | ||
79 | + # Autocomplete results for the current user's projects | ||
80 | + def public_projects_autocomplete | ||
81 | + Project.public_or_internal_only(current_user).map do |p| | ||
82 | + { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) } | ||
83 | + end | ||
84 | + end | ||
78 | end | 85 | end |
@@ -0,0 +1,55 @@ | @@ -0,0 +1,55 @@ | ||
1 | +module VisibilityLevelHelper | ||
2 | + def visibility_level_color(level) | ||
3 | + case level | ||
4 | + when Gitlab::VisibilityLevel::PRIVATE | ||
5 | + 'cgreen' | ||
6 | + when Gitlab::VisibilityLevel::INTERNAL | ||
7 | + 'camber' | ||
8 | + when Gitlab::VisibilityLevel::PUBLIC | ||
9 | + 'cblue' | ||
10 | + end | ||
11 | + end | ||
12 | + | ||
13 | + def visibility_level_description(level) | ||
14 | + capture_haml do | ||
15 | + haml_tag :span do | ||
16 | + case level | ||
17 | + when Gitlab::VisibilityLevel::PRIVATE | ||
18 | + haml_concat "Project access must be granted explicitly for each user." | ||
19 | + when Gitlab::VisibilityLevel::INTERNAL | ||
20 | + haml_concat "The project can be cloned by" | ||
21 | + haml_tag :em, "any logged in user." | ||
22 | + haml_concat "It will also be listed on the #{link_to "public access directory", public_root_path} for logged in users." | ||
23 | + haml_tag :em, "Any logged in user" | ||
24 | + haml_concat "will have #{link_to "Guest", help_permissions_path} permissions on the repository." | ||
25 | + when Gitlab::VisibilityLevel::PUBLIC | ||
26 | + haml_concat "The project can be cloned" | ||
27 | + haml_tag :em, "without any" | ||
28 | + haml_concat "authentication." | ||
29 | + haml_concat "It will also be listed on the #{link_to "public access directory", public_root_path}." | ||
30 | + haml_tag :em, "Any logged in user" | ||
31 | + haml_concat "will have #{link_to "Guest", help_permissions_path} permissions on the repository." | ||
32 | + end | ||
33 | + end | ||
34 | + end | ||
35 | + end | ||
36 | + | ||
37 | + def visibility_level_icon(level) | ||
38 | + case level | ||
39 | + when Gitlab::VisibilityLevel::PRIVATE | ||
40 | + private_icon | ||
41 | + when Gitlab::VisibilityLevel::INTERNAL | ||
42 | + internal_icon | ||
43 | + when Gitlab::VisibilityLevel::PUBLIC | ||
44 | + public_icon | ||
45 | + end | ||
46 | + end | ||
47 | + | ||
48 | + def visibility_level_label(level) | ||
49 | + Project.visibility_levels.key(level) | ||
50 | + end | ||
51 | + | ||
52 | + def restricted_visibility_levels | ||
53 | + current_user.is_admin? ? [] : gitlab_config.restricted_visibility_levels | ||
54 | + end | ||
55 | +end | ||
0 | \ No newline at end of file | 56 | \ No newline at end of file |
app/models/ability.rb
@@ -29,7 +29,7 @@ class Ability | @@ -29,7 +29,7 @@ class Ability | ||
29 | nil | 29 | nil |
30 | end | 30 | end |
31 | 31 | ||
32 | - if project && project.public | 32 | + if project && project.public? |
33 | [ | 33 | [ |
34 | :read_project, | 34 | :read_project, |
35 | :read_wiki, | 35 | :read_wiki, |
@@ -71,7 +71,7 @@ class Ability | @@ -71,7 +71,7 @@ class Ability | ||
71 | rules << project_guest_rules | 71 | rules << project_guest_rules |
72 | end | 72 | end |
73 | 73 | ||
74 | - if project.public? | 74 | + if project.public? || project.internal? |
75 | rules << public_project_rules | 75 | rules << public_project_rules |
76 | end | 76 | end |
77 | 77 | ||
@@ -89,7 +89,7 @@ class Ability | @@ -89,7 +89,7 @@ class Ability | ||
89 | def public_project_rules | 89 | def public_project_rules |
90 | project_guest_rules + [ | 90 | project_guest_rules + [ |
91 | :download_code, | 91 | :download_code, |
92 | - :fork_project, | 92 | + :fork_project |
93 | ] | 93 | ] |
94 | end | 94 | end |
95 | 95 | ||
@@ -145,7 +145,7 @@ class Ability | @@ -145,7 +145,7 @@ class Ability | ||
145 | def project_admin_rules | 145 | def project_admin_rules |
146 | project_master_rules + [ | 146 | project_master_rules + [ |
147 | :change_namespace, | 147 | :change_namespace, |
148 | - :change_public_mode, | 148 | + :change_visibility_level, |
149 | :rename_project, | 149 | :rename_project, |
150 | :remove_project | 150 | :remove_project |
151 | ] | 151 | ] |
app/models/project.rb
@@ -14,24 +14,25 @@ | @@ -14,24 +14,25 @@ | ||
14 | # merge_requests_enabled :boolean default(TRUE), not null | 14 | # merge_requests_enabled :boolean default(TRUE), not null |
15 | # wiki_enabled :boolean default(TRUE), not null | 15 | # wiki_enabled :boolean default(TRUE), not null |
16 | # namespace_id :integer | 16 | # namespace_id :integer |
17 | -# public :boolean default(FALSE), not null | ||
18 | # issues_tracker :string(255) default("gitlab"), not null | 17 | # issues_tracker :string(255) default("gitlab"), not null |
19 | # issues_tracker_id :string(255) | 18 | # issues_tracker_id :string(255) |
20 | # snippets_enabled :boolean default(TRUE), not null | 19 | # snippets_enabled :boolean default(TRUE), not null |
21 | # last_activity_at :datetime | 20 | # last_activity_at :datetime |
22 | # imported :boolean default(FALSE), not null | 21 | # imported :boolean default(FALSE), not null |
23 | # import_url :string(255) | 22 | # import_url :string(255) |
23 | +# visibility_level :integer default(0), not null | ||
24 | # | 24 | # |
25 | 25 | ||
26 | class Project < ActiveRecord::Base | 26 | class Project < ActiveRecord::Base |
27 | include Gitlab::ShellAdapter | 27 | include Gitlab::ShellAdapter |
28 | + include Gitlab::VisibilityLevel | ||
28 | extend Enumerize | 29 | extend Enumerize |
29 | 30 | ||
30 | ActsAsTaggableOn.strict_case_match = true | 31 | ActsAsTaggableOn.strict_case_match = true |
31 | 32 | ||
32 | attr_accessible :name, :path, :description, :issues_tracker, :label_list, | 33 | attr_accessible :name, :path, :description, :issues_tracker, :label_list, |
33 | :issues_enabled, :wall_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, | 34 | :issues_enabled, :wall_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, |
34 | - :wiki_enabled, :public, :import_url, :last_activity_at, as: [:default, :admin] | 35 | + :wiki_enabled, :visibility_level, :import_url, :last_activity_at, as: [:default, :admin] |
35 | 36 | ||
36 | attr_accessible :namespace_id, :creator_id, as: :admin | 37 | attr_accessible :namespace_id, :creator_id, as: :admin |
37 | 38 | ||
@@ -108,7 +109,8 @@ class Project < ActiveRecord::Base | @@ -108,7 +109,8 @@ class Project < ActiveRecord::Base | ||
108 | scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") } | 109 | scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") } |
109 | scope :personal, ->(user) { where(namespace_id: user.namespace_id) } | 110 | scope :personal, ->(user) { where(namespace_id: user.namespace_id) } |
110 | scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } | 111 | scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } |
111 | - scope :public_only, -> { where(public: true) } | 112 | + scope :public_only, -> { where(visibility_level: PUBLIC) } |
113 | + scope :public_or_internal_only, ->(user) { where("visibility_level IN (:levels)", levels: user ? [ INTERNAL, PUBLIC ] : [ PUBLIC ]) } | ||
112 | 114 | ||
113 | enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab | 115 | enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab |
114 | 116 | ||
@@ -140,6 +142,10 @@ class Project < ActiveRecord::Base | @@ -140,6 +142,10 @@ class Project < ActiveRecord::Base | ||
140 | where(path: id, namespace_id: nil).last | 142 | where(path: id, namespace_id: nil).last |
141 | end | 143 | end |
142 | end | 144 | end |
145 | + | ||
146 | + def visibility_levels | ||
147 | + Gitlab::VisibilityLevel.options | ||
148 | + end | ||
143 | end | 149 | end |
144 | 150 | ||
145 | def team | 151 | def team |
@@ -456,4 +462,8 @@ class Project < ActiveRecord::Base | @@ -456,4 +462,8 @@ class Project < ActiveRecord::Base | ||
456 | @default_branch = nil | 462 | @default_branch = nil |
457 | default_branch | 463 | default_branch |
458 | end | 464 | end |
465 | + | ||
466 | + def visibility_level_field | ||
467 | + visibility_level | ||
468 | + end | ||
459 | end | 469 | end |
app/views/admin/projects/index.html.haml
@@ -10,11 +10,15 @@ | @@ -10,11 +10,15 @@ | ||
10 | .control-group | 10 | .control-group |
11 | = label_tag :owner_id, 'Owner:', class: 'control-label' | 11 | = label_tag :owner_id, 'Owner:', class: 'control-label' |
12 | .controls | 12 | .controls |
13 | - = users_select_tag :owner_id, selected: params[:owner_id], class: 'input-large' | ||
14 | - .control-group | ||
15 | - = label_tag :public_only, 'Public Only', class: 'control-label' | ||
16 | - .controls | ||
17 | - = check_box_tag :public_only, 1, params[:public_only] | 13 | + = users_select_tag :owner_id, selected: params[:owner_id], class: 'input-large input-clamp' |
14 | + .control-group.visibility-levels | ||
15 | + = label_tag :visibility_level, 'Visibility Levels', class: 'control-label' | ||
16 | + - Project.visibility_levels.each do |label, level| | ||
17 | + .controls | ||
18 | + = check_box_tag 'visibility_levels[]', level, params[:visibility_levels].present? && params[:visibility_levels].include?(level.to_s) | ||
19 | + %span.descr | ||
20 | + = visibility_level_icon(level) | ||
21 | + = label | ||
18 | .control-group | 22 | .control-group |
19 | = label_tag :with_push, 'Not empty', class: 'control-label' | 23 | = label_tag :with_push, 'Not empty', class: 'control-label' |
20 | .controls | 24 | .controls |
@@ -42,10 +46,7 @@ | @@ -42,10 +46,7 @@ | ||
42 | %ul.well-list | 46 | %ul.well-list |
43 | - @projects.each do |project| | 47 | - @projects.each do |project| |
44 | %li | 48 | %li |
45 | - - if project.public | ||
46 | - = public_icon | ||
47 | - - else | ||
48 | - = private_icon | 49 | + = visibility_level_icon(project.visibility_level) |
49 | = link_to project.name_with_namespace, [:admin, project] | 50 | = link_to project.name_with_namespace, [:admin, project] |
50 | .pull-right | 51 | .pull-right |
51 | = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" | 52 | = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" |
app/views/admin/projects/show.html.haml
@@ -66,14 +66,10 @@ | @@ -66,14 +66,10 @@ | ||
66 | %li | 66 | %li |
67 | %span.light access: | 67 | %span.light access: |
68 | %strong | 68 | %strong |
69 | - - if @project.public | ||
70 | - %span.cblue | ||
71 | - %i.icon-share | ||
72 | - Public | ||
73 | - - else | ||
74 | - %span.cgreen | ||
75 | - %i.icon-lock | ||
76 | - Private | 69 | + %span{ class: visibility_level_color(@project.visibility_level) } |
70 | + = visibility_level_icon(@project.visibility_level) | ||
71 | + = visibility_level_label(@project.visibility_level) | ||
72 | + | ||
77 | .ui-box | 73 | .ui-box |
78 | .title | 74 | .title |
79 | Transfer project | 75 | Transfer project |
@@ -88,9 +84,6 @@ | @@ -88,9 +84,6 @@ | ||
88 | .controls | 84 | .controls |
89 | = f.submit 'Transfer', class: 'btn btn-primary' | 85 | = f.submit 'Transfer', class: 'btn btn-primary' |
90 | 86 | ||
91 | - | ||
92 | - | ||
93 | - | ||
94 | .span6 | 87 | .span6 |
95 | - if @group | 88 | - if @group |
96 | .ui-box | 89 | .ui-box |
app/views/dashboard/projects.html.haml
@@ -58,10 +58,10 @@ | @@ -58,10 +58,10 @@ | ||
58 | %h4.project-title | 58 | %h4.project-title |
59 | = link_to project_path(project), class: dom_class(project) do | 59 | = link_to project_path(project), class: dom_class(project) do |
60 | = project.name_with_namespace | 60 | = project.name_with_namespace |
61 | - - if project.public | 61 | + - unless project.private? |
62 | %small.access-icon | 62 | %small.access-icon |
63 | - = public_icon | ||
64 | - Public | 63 | + = visibility_level_icon(project.visibility_level) |
64 | + = visibility_level_label(project.visibility_level) | ||
65 | 65 | ||
66 | - if current_user.can_leave_project?(project) | 66 | - if current_user.can_leave_project?(project) |
67 | .pull-right | 67 | .pull-right |
app/views/groups/edit.html.haml
@@ -51,10 +51,7 @@ | @@ -51,10 +51,7 @@ | ||
51 | %ul.well-list | 51 | %ul.well-list |
52 | - @group.projects.each do |project| | 52 | - @group.projects.each do |project| |
53 | %li | 53 | %li |
54 | - - if project.public | ||
55 | - = public_icon | ||
56 | - - else | ||
57 | - = private_icon | 54 | + = visibility_level_icon(project.visibility_level) |
58 | = link_to project.name_with_namespace, project | 55 | = link_to project.name_with_namespace, project |
59 | .pull-right | 56 | .pull-right |
60 | = link_to 'Members', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" | 57 | = link_to 'Members', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" |
app/views/help/permissions.html.haml
app/views/help/public_access.html.haml
@@ -2,14 +2,20 @@ | @@ -2,14 +2,20 @@ | ||
2 | %h3.page-title Public Access | 2 | %h3.page-title Public Access |
3 | 3 | ||
4 | %p | 4 | %p |
5 | - GitLab allows you to open selected projects to be accessed publicly. | ||
6 | - These projects will be cloneable | 5 | + GitLab allows you to open selected projects to be accessed publicly or internally. |
6 | + 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. | ||
7 | + %p | ||
8 | + = public_icon | ||
9 | + Public projects will be cloneable | ||
7 | %em without any | 10 | %em without any |
8 | authentication. | 11 | authentication. |
9 | - Also they will be listed on the #{link_to "public access directory", public_root_path}. | 12 | + %p |
13 | + = internal_icon | ||
14 | + Internal projects will be cloneable by | ||
15 | + %em any authenticated user. | ||
10 | 16 | ||
11 | %ol | 17 | %ol |
12 | %li Go to your project dashboard | 18 | %li Go to your project dashboard |
13 | %li Click on the "Edit" tab | 19 | %li Click on the "Edit" tab |
14 | - %li Select "Public clone access" | 20 | + %li Change "Visibility Level" |
15 | 21 |
@@ -0,0 +1,31 @@ | @@ -0,0 +1,31 @@ | ||
1 | +- empty_repo = @project.empty_repo? | ||
2 | +.project-home-panel{:class => ("empty-project" if empty_repo)} | ||
3 | + .row | ||
4 | + .span5 | ||
5 | + %h4.project-home-title | ||
6 | + = @project.name_with_namespace | ||
7 | + %span.visibility-level-label | ||
8 | + = visibility_level_icon(@project.visibility_level) | ||
9 | + = visibility_level_label(@project.visibility_level) | ||
10 | + | ||
11 | + .span7 | ||
12 | + - unless empty_repo | ||
13 | + .project-home-dropdown | ||
14 | + = render "dropdown" | ||
15 | + .form-horizontal | ||
16 | + = render "shared/clone_panel" | ||
17 | + | ||
18 | + .project-home-extra.clearfix | ||
19 | + .project-home-desc | ||
20 | + - if @project.description.present? | ||
21 | + = @project.description | ||
22 | + - if can?(current_user, :admin_project, @project) | ||
23 | + – | ||
24 | + %strong= link_to 'Edit', edit_project_path | ||
25 | + | ||
26 | + - unless empty_repo | ||
27 | + .project-home-links | ||
28 | + = link_to pluralize(@repository.round_commit_count, 'commit'), project_commits_path(@project, @ref || @repository.root_ref) | ||
29 | + = link_to pluralize(@repository.branch_names.count, 'branch'), project_branches_path(@project) | ||
30 | + = link_to pluralize(@repository.tag_names.count, 'tag'), project_tags_path(@project) | ||
31 | + %span.light.prepend-left-20= repository_size | ||
0 | \ No newline at end of file | 32 | \ No newline at end of file |
@@ -0,0 +1,23 @@ | @@ -0,0 +1,23 @@ | ||
1 | +.control-group.project-visibility-level-holder | ||
2 | + = f.label :visibility_level, "Visibility Level" | ||
3 | + - if can_change_visibility_level | ||
4 | + - Gitlab::VisibilityLevel.values.each do |level| | ||
5 | + - restricted = restricted_visibility_levels.include?(level) | ||
6 | + .controls | ||
7 | + = f.radio_button :visibility_level, level, checked: (visibility_level == level), disabled: restricted | ||
8 | + %span.descr{:class => ("restricted" if restricted)} | ||
9 | + = visibility_level_icon(level) | ||
10 | + %strong | ||
11 | + = visibility_level_label(level) | ||
12 | + = visibility_level_description(level) | ||
13 | + - unless restricted_visibility_levels.empty? | ||
14 | + .controls | ||
15 | + %span.info | ||
16 | + Some visibility level settings have been restricted by the administrator. | ||
17 | + - else | ||
18 | + .controls | ||
19 | + %span.info | ||
20 | + = visibility_level_icon(visibility_level) | ||
21 | + %strong | ||
22 | + = visibility_level_label(visibility_level) | ||
23 | + = visibility_level_description(visibility_level) | ||
0 | \ No newline at end of file | 24 | \ No newline at end of file |
app/views/projects/edit.html.haml
@@ -29,22 +29,7 @@ | @@ -29,22 +29,7 @@ | ||
29 | .controls= f.select(:default_branch, @repository.branch_names, {}, {class: 'chosen'}) | 29 | .controls= f.select(:default_branch, @repository.branch_names, {}, {class: 'chosen'}) |
30 | 30 | ||
31 | 31 | ||
32 | - - if can?(current_user, :change_public_mode, @project) | ||
33 | - %fieldset.public-mode | ||
34 | - %legend | ||
35 | - Public mode: | ||
36 | - .control-group | ||
37 | - = f.label :public, class: 'control-label' do | ||
38 | - %span Public access | ||
39 | - .controls | ||
40 | - = f.check_box :public | ||
41 | - %span.descr | ||
42 | - If checked, this project can be cloned | ||
43 | - %em without any | ||
44 | - authentication. | ||
45 | - It will also be listed on the #{link_to "public access directory", public_root_path}. | ||
46 | - %em Any | ||
47 | - user will have #{link_to "Guest", help_permissions_path} permissions on the repository. | 32 | + = render "visibility_level", f: f, visibility_level: @project.visibility_level, can_change_visibility_level: can?(current_user, :change_visibility_level, @project) |
48 | 33 | ||
49 | %fieldset.features | 34 | %fieldset.features |
50 | %legend | 35 | %legend |
app/views/projects/empty.html.haml
app/views/projects/new.html.haml
@@ -47,12 +47,7 @@ | @@ -47,12 +47,7 @@ | ||
47 | %span.light (optional) | 47 | %span.light (optional) |
48 | .controls | 48 | .controls |
49 | = f.text_area :description, placeholder: "Awesome project", class: "input-xlarge", rows: 3, maxlength: 250, tabindex: 3 | 49 | = f.text_area :description, placeholder: "Awesome project", class: "input-xlarge", rows: 3, maxlength: 250, tabindex: 3 |
50 | - .control-group.project-public-holder | ||
51 | - = f.label :public do | ||
52 | - %span Public project | ||
53 | - .controls | ||
54 | - = f.check_box :public, { checked: gitlab_config.default_projects_features.public }, true, false | ||
55 | - %span.help-inline Make project visible to everyone | 50 | + = render "visibility_level", f: f, visibility_level: gitlab_config.default_projects_features.visibility_level, can_change_visibility_level: true |
56 | 51 | ||
57 | .form-actions | 52 | .form-actions |
58 | = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4 | 53 | = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4 |
app/views/projects/show.html.haml
1 | -.project-home-panel | ||
2 | - .row | ||
3 | - .span5 | ||
4 | - %h4.project-home-title | ||
5 | - = @project.name_with_namespace | ||
6 | - - if @project.public | ||
7 | - %span.public-label Public | ||
8 | - - else | ||
9 | - %span.public-label Private | ||
10 | - | ||
11 | - .span7 | ||
12 | - .project-home-dropdown | ||
13 | - = render "dropdown" | ||
14 | - .form-horizontal | ||
15 | - = render "shared/clone_panel" | ||
16 | - | ||
17 | - .project-home-extra.clearfix | ||
18 | - .project-home-desc | ||
19 | - - if @project.description.present? | ||
20 | - = @project.description | ||
21 | - - if can?(current_user, :admin_project, @project) | ||
22 | - – | ||
23 | - %strong= link_to 'Edit', edit_project_path | ||
24 | - | ||
25 | - .project-home-links | ||
26 | - = link_to pluralize(@repository.round_commit_count, 'commit'), project_commits_path(@project, @ref || @repository.root_ref) | ||
27 | - = link_to pluralize(@repository.branch_names.count, 'branch'), project_branches_path(@project) | ||
28 | - = link_to pluralize(@repository.tag_names.count, 'tag'), project_tags_path(@project) | ||
29 | - %span.light.prepend-left-20= repository_size | 1 | += render "home_panel" |
30 | 2 | ||
31 | .row | 3 | .row |
32 | .span9 | 4 | .span9 |
app/views/public/projects/index.html.haml
@@ -19,6 +19,10 @@ | @@ -19,6 +19,10 @@ | ||
19 | %h4 | 19 | %h4 |
20 | = link_to project_path(project) do | 20 | = link_to project_path(project) do |
21 | = project.name_with_namespace | 21 | = project.name_with_namespace |
22 | + - if project.internal? | ||
23 | + %small.access-icon | ||
24 | + = internal_icon | ||
25 | + Internal | ||
22 | .pull-right | 26 | .pull-right |
23 | %pre.public-clone git clone #{project.http_url_to_repo} | 27 | %pre.public-clone git clone #{project.http_url_to_repo} |
24 | 28 |
config/gitlab.yml.example
@@ -55,6 +55,10 @@ production: &base | @@ -55,6 +55,10 @@ production: &base | ||
55 | # default: false - Account passwords are not sent via the email if signup is enabled. | 55 | # default: false - Account passwords are not sent via the email if signup is enabled. |
56 | # signup_enabled: true | 56 | # signup_enabled: true |
57 | 57 | ||
58 | + # Restrict setting visibility levels for non-admin users. | ||
59 | + # The default is to allow all levels. | ||
60 | + #restricted_visibility_levels: [ "public" ] | ||
61 | + | ||
58 | ## Automatic issue closing | 62 | ## Automatic issue closing |
59 | # If a commit message matches this regular expression, all issues referenced from the matched text will be closed. | 63 | # If a commit message matches this regular expression, all issues referenced from the matched text will be closed. |
60 | # This happens when the commit is pushed or merged into the default branch of a project. | 64 | # This happens when the commit is pushed or merged into the default branch of a project. |
@@ -68,7 +72,7 @@ production: &base | @@ -68,7 +72,7 @@ production: &base | ||
68 | wiki: true | 72 | wiki: true |
69 | wall: false | 73 | wall: false |
70 | snippets: false | 74 | snippets: false |
71 | - public: false | 75 | + visibility_level: "private" # can be "private" | "internal" | "public" |
72 | 76 | ||
73 | ## External issues trackers | 77 | ## External issues trackers |
74 | issues_tracker: | 78 | issues_tracker: |
config/initializers/1_settings.rb
@@ -30,6 +30,29 @@ class Settings < Settingslogic | @@ -30,6 +30,29 @@ class Settings < Settingslogic | ||
30 | gitlab.relative_url_root | 30 | gitlab.relative_url_root |
31 | ].join('') | 31 | ].join('') |
32 | end | 32 | end |
33 | + | ||
34 | + # check that values in `current` (string or integer) is a contant in `modul`. | ||
35 | + def verify_constant_array(modul, current, default) | ||
36 | + values = default || [] | ||
37 | + if !current.nil? | ||
38 | + values = [] | ||
39 | + current.each do |constant| | ||
40 | + values.push(verify_constant(modul, constant, nil)) | ||
41 | + end | ||
42 | + values.delete_if { |value| value.nil? } | ||
43 | + end | ||
44 | + values | ||
45 | + end | ||
46 | + | ||
47 | + # check that `current` (string or integer) is a contant in `modul`. | ||
48 | + def verify_constant(modul, current, default) | ||
49 | + constant = modul.constants.find{ |name| modul.const_get(name) == current } | ||
50 | + value = constant.nil? ? default : modul.const_get(constant) | ||
51 | + if current.is_a? String | ||
52 | + value = modul.const_get(current.upcase) rescue default | ||
53 | + end | ||
54 | + value | ||
55 | + end | ||
33 | end | 56 | end |
34 | end | 57 | end |
35 | 58 | ||
@@ -68,6 +91,7 @@ rescue ArgumentError # no user configured | @@ -68,6 +91,7 @@ rescue ArgumentError # no user configured | ||
68 | '/home/' + Settings.gitlab['user'] | 91 | '/home/' + Settings.gitlab['user'] |
69 | end | 92 | end |
70 | Settings.gitlab['signup_enabled'] ||= false | 93 | Settings.gitlab['signup_enabled'] ||= false |
94 | +Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], []) | ||
71 | Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? | 95 | Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? |
72 | Settings.gitlab['issue_closing_pattern'] = '([Cc]loses|[Ff]ixes) #(\d+)' if Settings.gitlab['issue_closing_pattern'].nil? | 96 | Settings.gitlab['issue_closing_pattern'] = '([Cc]loses|[Ff]ixes) #(\d+)' if Settings.gitlab['issue_closing_pattern'].nil? |
73 | Settings.gitlab['default_projects_features'] ||= {} | 97 | Settings.gitlab['default_projects_features'] ||= {} |
@@ -76,7 +100,7 @@ Settings.gitlab.default_projects_features['merge_requests'] = true if Settings.g | @@ -76,7 +100,7 @@ Settings.gitlab.default_projects_features['merge_requests'] = true if Settings.g | ||
76 | Settings.gitlab.default_projects_features['wiki'] = true if Settings.gitlab.default_projects_features['wiki'].nil? | 100 | Settings.gitlab.default_projects_features['wiki'] = true if Settings.gitlab.default_projects_features['wiki'].nil? |
77 | Settings.gitlab.default_projects_features['wall'] = false if Settings.gitlab.default_projects_features['wall'].nil? | 101 | Settings.gitlab.default_projects_features['wall'] = false if Settings.gitlab.default_projects_features['wall'].nil? |
78 | Settings.gitlab.default_projects_features['snippets'] = false if Settings.gitlab.default_projects_features['snippets'].nil? | 102 | Settings.gitlab.default_projects_features['snippets'] = false if Settings.gitlab.default_projects_features['snippets'].nil? |
79 | -Settings.gitlab.default_projects_features['public'] = false if Settings.gitlab.default_projects_features['public'].nil? | 103 | +Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE) |
80 | 104 | ||
81 | # | 105 | # |
82 | # Gravatar | 106 | # Gravatar |
db/migrate/20131112220935_add_visibility_level_to_projects.rb
0 → 100644
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +class AddVisibilityLevelToProjects < ActiveRecord::Migration | ||
2 | + def self.up | ||
3 | + add_column :projects, :visibility_level, :integer, :default => 0, :null => false | ||
4 | + Project.where(public: true).update_all(visibility_level: Gitlab::VisibilityLevel::PUBLIC) | ||
5 | + remove_column :projects, :public | ||
6 | + end | ||
7 | + | ||
8 | + def self.down | ||
9 | + add_column :projects, :public, :boolean, :default => false, :null => false | ||
10 | + Project.where(visibility_level: Gitlab::VisibilityLevel::PUBLIC).update_all(public: true) | ||
11 | + remove_column :projects, :visibility_level | ||
12 | + end | ||
13 | +end |
db/schema.rb
@@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
11 | # | 11 | # |
12 | # It's strongly recommended to check this file into your version control system. | 12 | # It's strongly recommended to check this file into your version control system. |
13 | 13 | ||
14 | -ActiveRecord::Schema.define(:version => 20131112114325) do | 14 | +ActiveRecord::Schema.define(:version => 20131112220935) do |
15 | 15 | ||
16 | create_table "broadcast_messages", :force => true do |t| | 16 | create_table "broadcast_messages", :force => true do |t| |
17 | t.text "message", :null => false | 17 | t.text "message", :null => false |
@@ -185,13 +185,13 @@ ActiveRecord::Schema.define(:version => 20131112114325) do | @@ -185,13 +185,13 @@ ActiveRecord::Schema.define(:version => 20131112114325) do | ||
185 | t.boolean "merge_requests_enabled", :default => true, :null => false | 185 | t.boolean "merge_requests_enabled", :default => true, :null => false |
186 | t.boolean "wiki_enabled", :default => true, :null => false | 186 | t.boolean "wiki_enabled", :default => true, :null => false |
187 | t.integer "namespace_id" | 187 | t.integer "namespace_id" |
188 | - t.boolean "public", :default => false, :null => false | ||
189 | t.string "issues_tracker", :default => "gitlab", :null => false | 188 | t.string "issues_tracker", :default => "gitlab", :null => false |
190 | t.string "issues_tracker_id" | 189 | t.string "issues_tracker_id" |
191 | t.boolean "snippets_enabled", :default => true, :null => false | 190 | t.boolean "snippets_enabled", :default => true, :null => false |
192 | t.datetime "last_activity_at" | 191 | t.datetime "last_activity_at" |
193 | t.boolean "imported", :default => false, :null => false | 192 | t.boolean "imported", :default => false, :null => false |
194 | t.string "import_url" | 193 | t.string "import_url" |
194 | + t.integer "visibility_level", :default => 0, :null => false | ||
195 | end | 195 | end |
196 | 196 | ||
197 | add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" | 197 | add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" |
doc/api/projects.md
@@ -15,6 +15,7 @@ GET /projects | @@ -15,6 +15,7 @@ GET /projects | ||
15 | "description": null, | 15 | "description": null, |
16 | "default_branch": "master", | 16 | "default_branch": "master", |
17 | "public": false, | 17 | "public": false, |
18 | + "visibility_level": 0, | ||
18 | "ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git", | 19 | "ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git", |
19 | "http_url_to_repo": "http://example.com/diaspora/diaspora-client.git", | 20 | "http_url_to_repo": "http://example.com/diaspora/diaspora-client.git", |
20 | "web_url": "http://example.com/diaspora/diaspora-client", | 21 | "web_url": "http://example.com/diaspora/diaspora-client", |
@@ -49,6 +50,7 @@ GET /projects | @@ -49,6 +50,7 @@ GET /projects | ||
49 | "description": null, | 50 | "description": null, |
50 | "default_branch": "master", | 51 | "default_branch": "master", |
51 | "public": false, | 52 | "public": false, |
53 | + "visibility_level": 0, | ||
52 | "ssh_url_to_repo": "git@example.com:brightbox/puppet.git", | 54 | "ssh_url_to_repo": "git@example.com:brightbox/puppet.git", |
53 | "http_url_to_repo": "http://example.com/brightbox/puppet.git", | 55 | "http_url_to_repo": "http://example.com/brightbox/puppet.git", |
54 | "web_url": "http://example.com/brightbox/puppet", | 56 | "web_url": "http://example.com/brightbox/puppet", |
@@ -117,6 +119,7 @@ Parameters: | @@ -117,6 +119,7 @@ Parameters: | ||
117 | "description": null, | 119 | "description": null, |
118 | "default_branch": "master", | 120 | "default_branch": "master", |
119 | "public": false, | 121 | "public": false, |
122 | + "visibility_level": 0, | ||
120 | "ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git", | 123 | "ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git", |
121 | "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git", | 124 | "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git", |
122 | "web_url": "http://example.com/diaspora/diaspora-project-site", | 125 | "web_url": "http://example.com/diaspora/diaspora-project-site", |
@@ -234,7 +237,8 @@ Parameters: | @@ -234,7 +237,8 @@ Parameters: | ||
234 | + `merge_requests_enabled` (optional) | 237 | + `merge_requests_enabled` (optional) |
235 | + `wiki_enabled` (optional) | 238 | + `wiki_enabled` (optional) |
236 | + `snippets_enabled` (optional) | 239 | + `snippets_enabled` (optional) |
237 | -+ `public` (optional) | 240 | ++ `public` (optional) - if `true` same as setting visibility_level = 20 |
241 | ++ `visibility_level` (optional) | ||
238 | 242 | ||
239 | 243 | ||
240 | ### Create project for user | 244 | ### Create project for user |
@@ -256,7 +260,8 @@ Parameters: | @@ -256,7 +260,8 @@ Parameters: | ||
256 | + `merge_requests_enabled` (optional) | 260 | + `merge_requests_enabled` (optional) |
257 | + `wiki_enabled` (optional) | 261 | + `wiki_enabled` (optional) |
258 | + `snippets_enabled` (optional) | 262 | + `snippets_enabled` (optional) |
259 | -+ `public` (optional) | 263 | ++ `public` (optional) - if `true` same as setting visibility_level = 20 |
264 | ++ `visibility_level` (optional) | ||
260 | 265 | ||
261 | 266 | ||
262 | ## Remove project | 267 | ## Remove project |
features/public/public_projects.feature
1 | Feature: Public Projects Feature | 1 | Feature: Public Projects Feature |
2 | Background: | 2 | Background: |
3 | Given public project "Community" | 3 | Given public project "Community" |
4 | + And internal project "Internal" | ||
4 | And private project "Enterprise" | 5 | And private project "Enterprise" |
5 | 6 | ||
6 | Scenario: I visit public area | 7 | Scenario: I visit public area |
7 | When I visit the public projects area | 8 | When I visit the public projects area |
8 | Then I should see project "Community" | 9 | Then I should see project "Community" |
10 | + And I should not see project "Internal" | ||
9 | And I should not see project "Enterprise" | 11 | And I should not see project "Enterprise" |
10 | 12 | ||
11 | Scenario: I visit public project page | 13 | Scenario: I visit public project page |
12 | When I visit project "Community" page | 14 | When I visit project "Community" page |
13 | Then I should see project "Community" home page | 15 | Then I should see project "Community" home page |
14 | 16 | ||
17 | + Scenario: I visit internal project page | ||
18 | + When I visit project "Internal" page | ||
19 | + Then page status code should be 404 | ||
20 | + | ||
21 | + Scenario: I visit private project page | ||
22 | + When I visit project "Enterprise" page | ||
23 | + Then page status code should be 404 | ||
24 | + | ||
15 | Scenario: I visit an empty public project page | 25 | Scenario: I visit an empty public project page |
16 | Given public empty project "Empty Public Project" | 26 | Given public empty project "Empty Public Project" |
17 | When I visit empty project page | 27 | When I visit empty project page |
18 | Then I should see empty public project details | 28 | Then I should see empty public project details |
29 | + | ||
30 | + Scenario: I visit public area as user | ||
31 | + Given I sign in as a user | ||
32 | + When I visit the public projects area | ||
33 | + Then I should see project "Community" | ||
34 | + And I should see project "Internal" | ||
35 | + And I should not see project "Enterprise" | ||
36 | + | ||
37 | + Scenario: I visit internal project page as user | ||
38 | + Given I sign in as a user | ||
39 | + When I visit project "Internal" page | ||
40 | + Then I should see project "Internal" home page |
features/steps/public/projects_feature.rb
1 | class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps | 1 | class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps |
2 | + include SharedAuthentication | ||
2 | include SharedPaths | 3 | include SharedPaths |
4 | + include SharedProject | ||
3 | 5 | ||
4 | step 'I should see project "Community"' do | 6 | step 'I should see project "Community"' do |
5 | page.should have_content "Community" | 7 | page.should have_content "Community" |
@@ -23,11 +25,11 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps | @@ -23,11 +25,11 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps | ||
23 | end | 25 | end |
24 | 26 | ||
25 | step 'public project "Community"' do | 27 | step 'public project "Community"' do |
26 | - create :project_with_code, name: 'Community', public: true | 28 | + create :project_with_code, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC |
27 | end | 29 | end |
28 | 30 | ||
29 | step 'public empty project "Empty Public Project"' do | 31 | step 'public empty project "Empty Public Project"' do |
30 | - create :project, name: 'Empty Public Project', public: true | 32 | + create :project, name: 'Empty Public Project', visibility_level: Gitlab::VisibilityLevel::PUBLIC |
31 | end | 33 | end |
32 | 34 | ||
33 | step 'I visit empty project page' do | 35 | step 'I visit empty project page' do |
@@ -48,16 +50,38 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps | @@ -48,16 +50,38 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps | ||
48 | create :project, name: 'Enterprise' | 50 | create :project, name: 'Enterprise' |
49 | end | 51 | end |
50 | 52 | ||
53 | + step 'I visit project "Enterprise" page' do | ||
54 | + project = Project.find_by_name('Enterprise') | ||
55 | + visit project_path(project) | ||
56 | + end | ||
57 | + | ||
51 | step 'I should see project "Community" home page' do | 58 | step 'I should see project "Community" home page' do |
52 | within '.project-home-title' do | 59 | within '.project-home-title' do |
53 | page.should have_content 'Community' | 60 | page.should have_content 'Community' |
54 | end | 61 | end |
55 | end | 62 | end |
56 | 63 | ||
57 | - private | 64 | + step 'internal project "Internal"' do |
65 | + create :project_with_code, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL | ||
66 | + end | ||
58 | 67 | ||
59 | - def project | ||
60 | - @project ||= Project.find_by_name("Community") | 68 | + step 'I should see project "Internal"' do |
69 | + page.should have_content "Internal" | ||
70 | + end | ||
71 | + | ||
72 | + step 'I should not see project "Internal"' do | ||
73 | + page.should_not have_content "Internal" | ||
74 | + end | ||
75 | + | ||
76 | + step 'I visit project "Internal" page' do | ||
77 | + project = Project.find_by_name('Internal') | ||
78 | + visit project_path(project) | ||
79 | + end | ||
80 | + | ||
81 | + step 'I should see project "Internal" home page' do | ||
82 | + within '.project-home-title' do | ||
83 | + page.should have_content 'Internal' | ||
84 | + end | ||
61 | end | 85 | end |
62 | end | 86 | end |
63 | 87 |
lib/api/entities.rb
@@ -31,11 +31,13 @@ module API | @@ -31,11 +31,13 @@ module API | ||
31 | end | 31 | end |
32 | 32 | ||
33 | class Project < Grape::Entity | 33 | class Project < Grape::Entity |
34 | - expose :id, :description, :default_branch, :public, :ssh_url_to_repo, :http_url_to_repo, :web_url | 34 | + expose :id, :description, :default_branch |
35 | + expose :public?, as: :public | ||
36 | + expose :visibility_level, :ssh_url_to_repo, :http_url_to_repo, :web_url | ||
35 | expose :owner, using: Entities::UserBasic | 37 | expose :owner, using: Entities::UserBasic |
36 | expose :name, :name_with_namespace | 38 | expose :name, :name_with_namespace |
37 | expose :path, :path_with_namespace | 39 | expose :path, :path_with_namespace |
38 | - expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :snippets_enabled, :created_at, :last_activity_at, :public | 40 | + expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :snippets_enabled, :created_at, :last_activity_at |
39 | expose :namespace | 41 | expose :namespace |
40 | expose :forked_from_project, using: Entities::ForkedFromProject, :if => lambda{ | project, options | project.forked? } | 42 | expose :forked_from_project, using: Entities::ForkedFromProject, :if => lambda{ | project, options | project.forked? } |
41 | end | 43 | end |
lib/api/projects.rb
@@ -11,6 +11,13 @@ module API | @@ -11,6 +11,13 @@ module API | ||
11 | end | 11 | end |
12 | not_found! | 12 | not_found! |
13 | end | 13 | end |
14 | + | ||
15 | + def map_public_to_visibility_level(attrs) | ||
16 | + publik = attrs.delete(:public) | ||
17 | + publik = [ true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON' ].include?(publik) | ||
18 | + attrs[:visibility_level] = Gitlab::VisibilityLevel::PUBLIC if !attrs[:visibility_level].present? && publik == true | ||
19 | + attrs | ||
20 | + end | ||
14 | end | 21 | end |
15 | 22 | ||
16 | # Get a projects list for authenticated user | 23 | # Get a projects list for authenticated user |
@@ -76,7 +83,8 @@ module API | @@ -76,7 +83,8 @@ module API | ||
76 | # wiki_enabled (optional) | 83 | # wiki_enabled (optional) |
77 | # snippets_enabled (optional) | 84 | # snippets_enabled (optional) |
78 | # namespace_id (optional) - defaults to user namespace | 85 | # namespace_id (optional) - defaults to user namespace |
79 | - # public (optional) - false by default | 86 | + # public (optional) - if true same as setting visibility_level = 20 |
87 | + # visibility_level (optional) - 0 by default | ||
80 | # Example Request | 88 | # Example Request |
81 | # POST /projects | 89 | # POST /projects |
82 | post do | 90 | post do |
@@ -90,7 +98,9 @@ module API | @@ -90,7 +98,9 @@ module API | ||
90 | :wiki_enabled, | 98 | :wiki_enabled, |
91 | :snippets_enabled, | 99 | :snippets_enabled, |
92 | :namespace_id, | 100 | :namespace_id, |
93 | - :public] | 101 | + :public, |
102 | + :visibility_level] | ||
103 | + attrs = map_public_to_visibility_level(attrs) | ||
94 | @project = ::Projects::CreateContext.new(current_user, attrs).execute | 104 | @project = ::Projects::CreateContext.new(current_user, attrs).execute |
95 | if @project.saved? | 105 | if @project.saved? |
96 | present @project, with: Entities::Project | 106 | present @project, with: Entities::Project |
@@ -114,7 +124,8 @@ module API | @@ -114,7 +124,8 @@ module API | ||
114 | # merge_requests_enabled (optional) | 124 | # merge_requests_enabled (optional) |
115 | # wiki_enabled (optional) | 125 | # wiki_enabled (optional) |
116 | # snippets_enabled (optional) | 126 | # snippets_enabled (optional) |
117 | - # public (optional) | 127 | + # public (optional) - if true same as setting visibility_level = 20 |
128 | + # visibility_level (optional) | ||
118 | # Example Request | 129 | # Example Request |
119 | # POST /projects/user/:user_id | 130 | # POST /projects/user/:user_id |
120 | post "user/:user_id" do | 131 | post "user/:user_id" do |
@@ -128,7 +139,9 @@ module API | @@ -128,7 +139,9 @@ module API | ||
128 | :merge_requests_enabled, | 139 | :merge_requests_enabled, |
129 | :wiki_enabled, | 140 | :wiki_enabled, |
130 | :snippets_enabled, | 141 | :snippets_enabled, |
131 | - :public] | 142 | + :public, |
143 | + :visibility_level] | ||
144 | + attrs = map_public_to_visibility_level(attrs) | ||
132 | @project = ::Projects::CreateContext.new(user, attrs).execute | 145 | @project = ::Projects::CreateContext.new(user, attrs).execute |
133 | if @project.saved? | 146 | if @project.saved? |
134 | present @project, with: Entities::Project | 147 | present @project, with: Entities::Project |
@@ -290,7 +303,8 @@ module API | @@ -290,7 +303,8 @@ module API | ||
290 | # GET /projects/search/:query | 303 | # GET /projects/search/:query |
291 | get "/search/:query" do | 304 | get "/search/:query" do |
292 | ids = current_user.authorized_projects.map(&:id) | 305 | ids = current_user.authorized_projects.map(&:id) |
293 | - projects = Project.where("(id in (?) OR public = true) AND (name LIKE (?))", ids, "%#{params[:query]}%") | 306 | + visibility_levels = [ Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC ] |
307 | + projects = Project.where("(id in (?) OR visibility_level in (?)) AND (name LIKE (?))", ids, visibility_levels, "%#{params[:query]}%") | ||
294 | present paginate(projects), with: Entities::Project | 308 | present paginate(projects), with: Entities::Project |
295 | end | 309 | end |
296 | end | 310 | end |
lib/gitlab/backend/grack_auth.rb
@@ -58,7 +58,7 @@ module Grack | @@ -58,7 +58,7 @@ module Grack | ||
58 | end | 58 | end |
59 | 59 | ||
60 | else | 60 | else |
61 | - return unauthorized unless project.public | 61 | + return unauthorized unless project.public? |
62 | end | 62 | end |
63 | 63 | ||
64 | if authorized_git_request? | 64 | if authorized_git_request? |
@@ -80,7 +80,7 @@ module Grack | @@ -80,7 +80,7 @@ module Grack | ||
80 | def authorize_request(service) | 80 | def authorize_request(service) |
81 | case service | 81 | case service |
82 | when 'git-upload-pack' | 82 | when 'git-upload-pack' |
83 | - project.public || can?(user, :download_code, project) | 83 | + can?(user, :download_code, project) |
84 | when'git-receive-pack' | 84 | when'git-receive-pack' |
85 | refs.each do |ref| | 85 | refs.each do |ref| |
86 | action = if project.protected_branch?(ref) | 86 | action = if project.protected_branch?(ref) |
@@ -0,0 +1,42 @@ | @@ -0,0 +1,42 @@ | ||
1 | +# Gitlab::VisibilityLevel module | ||
2 | +# | ||
3 | +# Define allowed public modes that can be used for | ||
4 | +# GitLab projects to determine project public mode | ||
5 | +# | ||
6 | +module Gitlab | ||
7 | + module VisibilityLevel | ||
8 | + PRIVATE = 0 | ||
9 | + INTERNAL = 10 | ||
10 | + PUBLIC = 20 | ||
11 | + | ||
12 | + class << self | ||
13 | + def values | ||
14 | + options.values | ||
15 | + end | ||
16 | + | ||
17 | + def options | ||
18 | + { | ||
19 | + 'Private' => PRIVATE, | ||
20 | + 'Internal' => INTERNAL, | ||
21 | + 'Public' => PUBLIC | ||
22 | + } | ||
23 | + end | ||
24 | + | ||
25 | + def allowed_for?(user, level) | ||
26 | + user.is_admin? || !Gitlab.config.gitlab.restricted_visibility_levels.include?(level) | ||
27 | + end | ||
28 | + end | ||
29 | + | ||
30 | + def private? | ||
31 | + visibility_level_field == PRIVATE | ||
32 | + end | ||
33 | + | ||
34 | + def internal? | ||
35 | + visibility_level_field == INTERNAL | ||
36 | + end | ||
37 | + | ||
38 | + def public? | ||
39 | + visibility_level_field == PUBLIC | ||
40 | + end | ||
41 | + end | ||
42 | +end |
spec/contexts/projects_create_context_spec.rb
@@ -7,6 +7,7 @@ describe Projects::CreateContext do | @@ -7,6 +7,7 @@ describe Projects::CreateContext do | ||
7 | describe :create_by_user do | 7 | describe :create_by_user do |
8 | before do | 8 | before do |
9 | @user = create :user | 9 | @user = create :user |
10 | + @admin = create :user, admin: true | ||
10 | @opts = { | 11 | @opts = { |
11 | name: "GitLab", | 12 | name: "GitLab", |
12 | namespace: @user.namespace | 13 | namespace: @user.namespace |
@@ -37,7 +38,7 @@ describe Projects::CreateContext do | @@ -37,7 +38,7 @@ describe Projects::CreateContext do | ||
37 | it { @project.namespace.should == @group } | 38 | it { @project.namespace.should == @group } |
38 | end | 39 | end |
39 | 40 | ||
40 | - context 'respect configured public setting' do | 41 | + context 'respect configured visibility setting' do |
41 | before(:each) do | 42 | before(:each) do |
42 | @settings = double("settings") | 43 | @settings = double("settings") |
43 | @settings.stub(:issues) { true } | 44 | @settings.stub(:issues) { true } |
@@ -46,25 +47,90 @@ describe Projects::CreateContext do | @@ -46,25 +47,90 @@ describe Projects::CreateContext do | ||
46 | @settings.stub(:wall) { true } | 47 | @settings.stub(:wall) { true } |
47 | @settings.stub(:snippets) { true } | 48 | @settings.stub(:snippets) { true } |
48 | stub_const("Settings", Class.new) | 49 | stub_const("Settings", Class.new) |
50 | + @restrictions = double("restrictions") | ||
51 | + @restrictions.stub(:restricted_visibility_levels) { [] } | ||
52 | + Settings.stub_chain(:gitlab).and_return(@restrictions) | ||
49 | Settings.stub_chain(:gitlab, :default_projects_features).and_return(@settings) | 53 | Settings.stub_chain(:gitlab, :default_projects_features).and_return(@settings) |
50 | end | 54 | end |
51 | 55 | ||
52 | context 'should be public when setting is public' do | 56 | context 'should be public when setting is public' do |
53 | before do | 57 | before do |
54 | - @settings.stub(:public) { true } | 58 | + @settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PUBLIC } |
55 | @project = create_project(@user, @opts) | 59 | @project = create_project(@user, @opts) |
56 | end | 60 | end |
57 | 61 | ||
58 | - it { @project.public.should be_true } | 62 | + it { @project.public?.should be_true } |
59 | end | 63 | end |
60 | 64 | ||
61 | - context 'should be private when setting is not public' do | 65 | + context 'should be private when setting is private' do |
62 | before do | 66 | before do |
63 | - @settings.stub(:public) { false } | 67 | + @settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PRIVATE } |
64 | @project = create_project(@user, @opts) | 68 | @project = create_project(@user, @opts) |
65 | end | 69 | end |
66 | 70 | ||
67 | - it { @project.public.should be_false } | 71 | + it { @project.private?.should be_true } |
72 | + end | ||
73 | + | ||
74 | + context 'should be internal when setting is internal' do | ||
75 | + before do | ||
76 | + @settings.stub(:visibility_level) { Gitlab::VisibilityLevel::INTERNAL } | ||
77 | + @project = create_project(@user, @opts) | ||
78 | + end | ||
79 | + | ||
80 | + it { @project.internal?.should be_true } | ||
81 | + end | ||
82 | + end | ||
83 | + | ||
84 | + context 'respect configured visibility restrictions setting' do | ||
85 | + before(:each) do | ||
86 | + @settings = double("settings") | ||
87 | + @settings.stub(:issues) { true } | ||
88 | + @settings.stub(:merge_requests) { true } | ||
89 | + @settings.stub(:wiki) { true } | ||
90 | + @settings.stub(:wall) { true } | ||
91 | + @settings.stub(:snippets) { true } | ||
92 | + @settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PRIVATE } | ||
93 | + stub_const("Settings", Class.new) | ||
94 | + @restrictions = double("restrictions") | ||
95 | + @restrictions.stub(:restricted_visibility_levels) { [ Gitlab::VisibilityLevel::PUBLIC ] } | ||
96 | + Settings.stub_chain(:gitlab).and_return(@restrictions) | ||
97 | + Settings.stub_chain(:gitlab, :default_projects_features).and_return(@settings) | ||
98 | + end | ||
99 | + | ||
100 | + context 'should be private when option is public' do | ||
101 | + before do | ||
102 | + @opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) | ||
103 | + @project = create_project(@user, @opts) | ||
104 | + end | ||
105 | + | ||
106 | + it { @project.private?.should be_true } | ||
107 | + end | ||
108 | + | ||
109 | + context 'should be public when option is public for admin' do | ||
110 | + before do | ||
111 | + @opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) | ||
112 | + @project = create_project(@admin, @opts) | ||
113 | + end | ||
114 | + | ||
115 | + it { @project.public?.should be_true } | ||
116 | + end | ||
117 | + | ||
118 | + context 'should be private when option is private' do | ||
119 | + before do | ||
120 | + @opts.merge!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) | ||
121 | + @project = create_project(@user, @opts) | ||
122 | + end | ||
123 | + | ||
124 | + it { @project.private?.should be_true } | ||
125 | + end | ||
126 | + | ||
127 | + context 'should be internal when option is internal' do | ||
128 | + before do | ||
129 | + @opts.merge!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) | ||
130 | + @project = create_project(@user, @opts) | ||
131 | + end | ||
132 | + | ||
133 | + it { @project.internal?.should be_true } | ||
68 | end | 134 | end |
69 | end | 135 | end |
70 | end | 136 | end |
@@ -73,3 +139,4 @@ describe Projects::CreateContext do | @@ -73,3 +139,4 @@ describe Projects::CreateContext do | ||
73 | Projects::CreateContext.new(user, opts).execute | 139 | Projects::CreateContext.new(user, opts).execute |
74 | end | 140 | end |
75 | end | 141 | end |
142 | + |
@@ -0,0 +1,111 @@ | @@ -0,0 +1,111 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe Projects::UpdateContext do | ||
4 | + before(:each) { ActiveRecord::Base.observers.enable(:user_observer) } | ||
5 | + after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } | ||
6 | + | ||
7 | + describe :update_by_user do | ||
8 | + before do | ||
9 | + @user = create :user | ||
10 | + @admin = create :user, admin: true | ||
11 | + @project = create :project, creator_id: @user.id, namespace: @user.namespace | ||
12 | + @opts = { project: {} } | ||
13 | + end | ||
14 | + | ||
15 | + context 'should be private when updated to private' do | ||
16 | + before do | ||
17 | + @created_private = @project.private? | ||
18 | + | ||
19 | + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) | ||
20 | + update_project(@project, @user, @opts) | ||
21 | + end | ||
22 | + | ||
23 | + it { @created_private.should be_true } | ||
24 | + it { @project.private?.should be_true } | ||
25 | + end | ||
26 | + | ||
27 | + context 'should be internal when updated to internal' do | ||
28 | + before do | ||
29 | + @created_private = @project.private? | ||
30 | + | ||
31 | + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) | ||
32 | + update_project(@project, @user, @opts) | ||
33 | + end | ||
34 | + | ||
35 | + it { @created_private.should be_true } | ||
36 | + it { @project.internal?.should be_true } | ||
37 | + end | ||
38 | + | ||
39 | + context 'should be public when updated to public' do | ||
40 | + before do | ||
41 | + @created_private = @project.private? | ||
42 | + | ||
43 | + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) | ||
44 | + update_project(@project, @user, @opts) | ||
45 | + end | ||
46 | + | ||
47 | + it { @created_private.should be_true } | ||
48 | + it { @project.public?.should be_true } | ||
49 | + end | ||
50 | + | ||
51 | + context 'respect configured visibility restrictions setting' do | ||
52 | + before(:each) do | ||
53 | + @restrictions = double("restrictions") | ||
54 | + @restrictions.stub(:restricted_visibility_levels) { [ Gitlab::VisibilityLevel::PUBLIC ] } | ||
55 | + Settings.stub_chain(:gitlab).and_return(@restrictions) | ||
56 | + end | ||
57 | + | ||
58 | + context 'should be private when updated to private' do | ||
59 | + before do | ||
60 | + @created_private = @project.private? | ||
61 | + | ||
62 | + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) | ||
63 | + update_project(@project, @user, @opts) | ||
64 | + end | ||
65 | + | ||
66 | + it { @created_private.should be_true } | ||
67 | + it { @project.private?.should be_true } | ||
68 | + end | ||
69 | + | ||
70 | + context 'should be internal when updated to internal' do | ||
71 | + before do | ||
72 | + @created_private = @project.private? | ||
73 | + | ||
74 | + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) | ||
75 | + update_project(@project, @user, @opts) | ||
76 | + end | ||
77 | + | ||
78 | + it { @created_private.should be_true } | ||
79 | + it { @project.internal?.should be_true } | ||
80 | + end | ||
81 | + | ||
82 | + context 'should be private when updated to public' do | ||
83 | + before do | ||
84 | + @created_private = @project.private? | ||
85 | + | ||
86 | + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) | ||
87 | + update_project(@project, @user, @opts) | ||
88 | + end | ||
89 | + | ||
90 | + it { @created_private.should be_true } | ||
91 | + it { @project.private?.should be_true } | ||
92 | + end | ||
93 | + | ||
94 | + context 'should be public when updated to public by admin' do | ||
95 | + before do | ||
96 | + @created_private = @project.private? | ||
97 | + | ||
98 | + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) | ||
99 | + update_project(@project, @admin, @opts) | ||
100 | + end | ||
101 | + | ||
102 | + it { @created_private.should be_true } | ||
103 | + it { @project.public?.should be_true } | ||
104 | + end | ||
105 | + end | ||
106 | + end | ||
107 | + | ||
108 | + def update_project(project, user, opts) | ||
109 | + Projects::UpdateContext.new(project, user, opts).execute | ||
110 | + end | ||
111 | +end | ||
0 | \ No newline at end of file | 112 | \ No newline at end of file |
spec/contexts/search_context_spec.rb
@@ -3,23 +3,39 @@ require 'spec_helper' | @@ -3,23 +3,39 @@ require 'spec_helper' | ||
3 | describe SearchContext do | 3 | describe SearchContext do |
4 | let(:found_namespace) { create(:namespace, name: 'searchable namespace', path:'another_thing') } | 4 | let(:found_namespace) { create(:namespace, name: 'searchable namespace', path:'another_thing') } |
5 | let(:user) { create(:user, namespace: found_namespace) } | 5 | let(:user) { create(:user, namespace: found_namespace) } |
6 | - let!(:found_project) { create(:project, name: 'searchable_project', creator_id: user.id, namespace: found_namespace, public: false) } | 6 | + let!(:found_project) { create(:project, name: 'searchable_project', creator_id: user.id, namespace: found_namespace, visibility_level: Gitlab::VisibilityLevel::PRIVATE) } |
7 | 7 | ||
8 | let(:unfound_namespace) { create(:namespace, name: 'unfound namespace', path: 'yet_something_else') } | 8 | let(:unfound_namespace) { create(:namespace, name: 'unfound namespace', path: 'yet_something_else') } |
9 | - let!(:unfound_project) { create(:project, name: 'unfound_project', creator_id: user.id, namespace: unfound_namespace, public: false) } | ||
10 | - let(:public_namespace) { create(:namespace, path: 'something_else',name: 'searchable public namespace') } | ||
11 | - let(:other_user) { create(:user, namespace: public_namespace) } | ||
12 | - let!(:public_project) { create(:project, name: 'searchable_public_project', creator_id: other_user.id, namespace: public_namespace, public: true) } | 9 | + let!(:unfound_project) { create(:project, name: 'unfound_project', creator_id: user.id, namespace: unfound_namespace, visibility_level: Gitlab::VisibilityLevel::PRIVATE) } |
10 | + | ||
11 | + let(:internal_namespace) { create(:namespace, path: 'something_internal',name: 'searchable internal namespace') } | ||
12 | + let(:internal_user) { create(:user, namespace: internal_namespace) } | ||
13 | + let!(:internal_project) { create(:project, name: 'searchable_internal_project', creator_id: internal_user.id, namespace: internal_namespace, visibility_level: Gitlab::VisibilityLevel::INTERNAL) } | ||
14 | + | ||
15 | + let(:public_namespace) { create(:namespace, path: 'something_public',name: 'searchable public namespace') } | ||
16 | + let(:public_user) { create(:user, namespace: public_namespace) } | ||
17 | + let!(:public_project) { create(:project, name: 'searchable_public_project', creator_id: public_user.id, namespace: public_namespace, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } | ||
13 | 18 | ||
14 | describe '#execute' do | 19 | describe '#execute' do |
15 | it 'public projects should be searchable' do | 20 | it 'public projects should be searchable' do |
16 | - context = SearchContext.new([found_project.id], {search_code: false, search: "searchable"}) | 21 | + context = SearchContext.new([found_project.id], nil, {search_code: false, search: "searchable"}) |
17 | results = context.execute | 22 | results = context.execute |
18 | results[:projects].should == [found_project, public_project] | 23 | results[:projects].should == [found_project, public_project] |
19 | end | 24 | end |
20 | 25 | ||
26 | + it 'internal projects should be searchable' do | ||
27 | + context = SearchContext.new([found_project.id], user, {search_code: false, search: "searchable"}) | ||
28 | + results = context.execute | ||
29 | + # can't seem to rely on the return order, so check this way | ||
30 | + #subject { results[:projects] } | ||
31 | + results[:projects].should have(3).items | ||
32 | + results[:projects].should include(found_project) | ||
33 | + results[:projects].should include(internal_project) | ||
34 | + results[:projects].should include(public_project) | ||
35 | + end | ||
36 | + | ||
21 | it 'namespace name should be searchable' do | 37 | it 'namespace name should be searchable' do |
22 | - context = SearchContext.new([found_project.id], {search_code: false, search: "searchable namespace"}) | 38 | + context = SearchContext.new([found_project.id], user, {search_code: false, search: "searchable namespace"}) |
23 | results = context.execute | 39 | results = context.execute |
24 | results[:projects].should == [found_project] | 40 | results[:projects].should == [found_project] |
25 | end | 41 | end |
@@ -0,0 +1,251 @@ | @@ -0,0 +1,251 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Internal Project Access" do | ||
4 | + let(:project) { create(:project_with_code) } | ||
5 | + | ||
6 | + let(:master) { create(:user) } | ||
7 | + let(:guest) { create(:user) } | ||
8 | + let(:reporter) { create(:user) } | ||
9 | + | ||
10 | + before do | ||
11 | + # internal project | ||
12 | + project.visibility_level = Gitlab::VisibilityLevel::INTERNAL | ||
13 | + project.save! | ||
14 | + | ||
15 | + # full access | ||
16 | + project.team << [master, :master] | ||
17 | + | ||
18 | + # readonly | ||
19 | + project.team << [reporter, :reporter] | ||
20 | + | ||
21 | + end | ||
22 | + | ||
23 | + describe "Project should be internal" do | ||
24 | + subject { project } | ||
25 | + | ||
26 | + its(:internal?) { should be_true } | ||
27 | + end | ||
28 | + | ||
29 | + describe "GET /:project_path" do | ||
30 | + subject { project_path(project) } | ||
31 | + | ||
32 | + it { should be_allowed_for master } | ||
33 | + it { should be_allowed_for reporter } | ||
34 | + it { should be_allowed_for :admin } | ||
35 | + it { should be_allowed_for guest } | ||
36 | + it { should be_allowed_for :user } | ||
37 | + it { should be_denied_for :visitor } | ||
38 | + end | ||
39 | + | ||
40 | + describe "GET /:project_path/tree/master" do | ||
41 | + subject { project_tree_path(project, project.repository.root_ref) } | ||
42 | + | ||
43 | + it { should be_allowed_for master } | ||
44 | + it { should be_allowed_for reporter } | ||
45 | + it { should be_allowed_for :admin } | ||
46 | + it { should be_allowed_for guest } | ||
47 | + it { should be_allowed_for :user } | ||
48 | + it { should be_denied_for :visitor } | ||
49 | + end | ||
50 | + | ||
51 | + describe "GET /:project_path/commits/master" do | ||
52 | + subject { project_commits_path(project, project.repository.root_ref, limit: 1) } | ||
53 | + | ||
54 | + it { should be_allowed_for master } | ||
55 | + it { should be_allowed_for reporter } | ||
56 | + it { should be_allowed_for :admin } | ||
57 | + it { should be_allowed_for guest } | ||
58 | + it { should be_allowed_for :user } | ||
59 | + it { should be_denied_for :visitor } | ||
60 | + end | ||
61 | + | ||
62 | + describe "GET /:project_path/commit/:sha" do | ||
63 | + subject { project_commit_path(project, project.repository.commit) } | ||
64 | + | ||
65 | + it { should be_allowed_for master } | ||
66 | + it { should be_allowed_for reporter } | ||
67 | + it { should be_allowed_for :admin } | ||
68 | + it { should be_allowed_for guest } | ||
69 | + it { should be_allowed_for :user } | ||
70 | + it { should be_denied_for :visitor } | ||
71 | + end | ||
72 | + | ||
73 | + describe "GET /:project_path/compare" do | ||
74 | + subject { project_compare_index_path(project) } | ||
75 | + | ||
76 | + it { should be_allowed_for master } | ||
77 | + it { should be_allowed_for reporter } | ||
78 | + it { should be_allowed_for :admin } | ||
79 | + it { should be_allowed_for guest } | ||
80 | + it { should be_allowed_for :user } | ||
81 | + it { should be_denied_for :visitor } | ||
82 | + end | ||
83 | + | ||
84 | + describe "GET /:project_path/team" do | ||
85 | + subject { project_team_index_path(project) } | ||
86 | + | ||
87 | + it { should be_allowed_for master } | ||
88 | + it { should be_denied_for reporter } | ||
89 | + it { should be_allowed_for :admin } | ||
90 | + it { should be_denied_for guest } | ||
91 | + it { should be_denied_for :user } | ||
92 | + it { should be_denied_for :visitor } | ||
93 | + end | ||
94 | + | ||
95 | + describe "GET /:project_path/wall" do | ||
96 | + subject { project_wall_path(project) } | ||
97 | + | ||
98 | + it { should be_allowed_for master } | ||
99 | + it { should be_allowed_for reporter } | ||
100 | + it { should be_allowed_for :admin } | ||
101 | + it { should be_allowed_for guest } | ||
102 | + it { should be_allowed_for :user } | ||
103 | + it { should be_denied_for :visitor } | ||
104 | + end | ||
105 | + | ||
106 | + describe "GET /:project_path/blob" do | ||
107 | + before do | ||
108 | + commit = project.repository.commit | ||
109 | + path = commit.tree.contents.select { |i| i.is_a?(Grit::Blob) }.first.name | ||
110 | + @blob_path = project_blob_path(project, File.join(commit.id, path)) | ||
111 | + end | ||
112 | + | ||
113 | + it { @blob_path.should be_allowed_for master } | ||
114 | + it { @blob_path.should be_allowed_for reporter } | ||
115 | + it { @blob_path.should be_allowed_for :admin } | ||
116 | + it { @blob_path.should be_allowed_for guest } | ||
117 | + it { @blob_path.should be_allowed_for :user } | ||
118 | + it { @blob_path.should be_denied_for :visitor } | ||
119 | + end | ||
120 | + | ||
121 | + describe "GET /:project_path/edit" do | ||
122 | + subject { edit_project_path(project) } | ||
123 | + | ||
124 | + it { should be_allowed_for master } | ||
125 | + it { should be_denied_for reporter } | ||
126 | + it { should be_allowed_for :admin } | ||
127 | + it { should be_denied_for guest } | ||
128 | + it { should be_denied_for :user } | ||
129 | + it { should be_denied_for :visitor } | ||
130 | + end | ||
131 | + | ||
132 | + describe "GET /:project_path/deploy_keys" do | ||
133 | + subject { project_deploy_keys_path(project) } | ||
134 | + | ||
135 | + it { should be_allowed_for master } | ||
136 | + it { should be_denied_for reporter } | ||
137 | + it { should be_allowed_for :admin } | ||
138 | + it { should be_denied_for guest } | ||
139 | + it { should be_denied_for :user } | ||
140 | + it { should be_denied_for :visitor } | ||
141 | + end | ||
142 | + | ||
143 | + describe "GET /:project_path/issues" do | ||
144 | + subject { project_issues_path(project) } | ||
145 | + | ||
146 | + it { should be_allowed_for master } | ||
147 | + it { should be_allowed_for reporter } | ||
148 | + it { should be_allowed_for :admin } | ||
149 | + it { should be_allowed_for guest } | ||
150 | + it { should be_allowed_for :user } | ||
151 | + it { should be_denied_for :visitor } | ||
152 | + end | ||
153 | + | ||
154 | + describe "GET /:project_path/snippets" do | ||
155 | + subject { project_snippets_path(project) } | ||
156 | + | ||
157 | + it { should be_allowed_for master } | ||
158 | + it { should be_allowed_for reporter } | ||
159 | + it { should be_allowed_for :admin } | ||
160 | + it { should be_allowed_for guest } | ||
161 | + it { should be_allowed_for :user } | ||
162 | + it { should be_denied_for :visitor } | ||
163 | + end | ||
164 | + | ||
165 | + describe "GET /:project_path/snippets/new" do | ||
166 | + subject { new_project_snippet_path(project) } | ||
167 | + | ||
168 | + it { should be_allowed_for master } | ||
169 | + it { should be_allowed_for reporter } | ||
170 | + it { should be_allowed_for :admin } | ||
171 | + it { should be_denied_for guest } | ||
172 | + it { should be_denied_for :user } | ||
173 | + it { should be_denied_for :visitor } | ||
174 | + end | ||
175 | + | ||
176 | + describe "GET /:project_path/merge_requests" do | ||
177 | + subject { project_merge_requests_path(project) } | ||
178 | + | ||
179 | + it { should be_allowed_for master } | ||
180 | + it { should be_allowed_for reporter } | ||
181 | + it { should be_allowed_for :admin } | ||
182 | + it { should be_allowed_for guest } | ||
183 | + it { should be_allowed_for :user } | ||
184 | + it { should be_denied_for :visitor } | ||
185 | + end | ||
186 | + | ||
187 | + describe "GET /:project_path/merge_requests/new" do | ||
188 | + subject { new_project_merge_request_path(project) } | ||
189 | + | ||
190 | + it { should be_allowed_for master } | ||
191 | + it { should be_denied_for reporter } | ||
192 | + it { should be_allowed_for :admin } | ||
193 | + it { should be_denied_for guest } | ||
194 | + it { should be_denied_for :user } | ||
195 | + it { should be_denied_for :visitor } | ||
196 | + end | ||
197 | + | ||
198 | + describe "GET /:project_path/branches/recent" do | ||
199 | + subject { recent_project_branches_path(project) } | ||
200 | + | ||
201 | + it { should be_allowed_for master } | ||
202 | + it { should be_allowed_for reporter } | ||
203 | + it { should be_allowed_for :admin } | ||
204 | + it { should be_allowed_for guest } | ||
205 | + it { should be_allowed_for :user } | ||
206 | + it { should be_denied_for :visitor } | ||
207 | + end | ||
208 | + | ||
209 | + describe "GET /:project_path/branches" do | ||
210 | + subject { project_branches_path(project) } | ||
211 | + | ||
212 | + before do | ||
213 | + # Speed increase | ||
214 | + Project.any_instance.stub(:branches).and_return([]) | ||
215 | + end | ||
216 | + | ||
217 | + it { should be_allowed_for master } | ||
218 | + it { should be_allowed_for reporter } | ||
219 | + it { should be_allowed_for :admin } | ||
220 | + it { should be_allowed_for guest } | ||
221 | + it { should be_allowed_for :user } | ||
222 | + it { should be_denied_for :visitor } | ||
223 | + end | ||
224 | + | ||
225 | + describe "GET /:project_path/tags" do | ||
226 | + subject { project_tags_path(project) } | ||
227 | + | ||
228 | + before do | ||
229 | + # Speed increase | ||
230 | + Project.any_instance.stub(:tags).and_return([]) | ||
231 | + end | ||
232 | + | ||
233 | + it { should be_allowed_for master } | ||
234 | + it { should be_allowed_for reporter } | ||
235 | + it { should be_allowed_for :admin } | ||
236 | + it { should be_allowed_for guest } | ||
237 | + it { should be_allowed_for :user } | ||
238 | + it { should be_denied_for :visitor } | ||
239 | + end | ||
240 | + | ||
241 | + describe "GET /:project_path/hooks" do | ||
242 | + subject { project_hooks_path(project) } | ||
243 | + | ||
244 | + it { should be_allowed_for master } | ||
245 | + it { should be_denied_for reporter } | ||
246 | + it { should be_allowed_for :admin } | ||
247 | + it { should be_denied_for guest } | ||
248 | + it { should be_denied_for :user } | ||
249 | + it { should be_denied_for :visitor } | ||
250 | + end | ||
251 | +end |
spec/features/security/project/private_access_spec.rb
@@ -15,6 +15,12 @@ describe "Private Project Access" do | @@ -15,6 +15,12 @@ describe "Private Project Access" do | ||
15 | project.team << [reporter, :reporter] | 15 | project.team << [reporter, :reporter] |
16 | end | 16 | end |
17 | 17 | ||
18 | + describe "Project should be private" do | ||
19 | + subject { project } | ||
20 | + | ||
21 | + its(:private?) { should be_true } | ||
22 | + end | ||
23 | + | ||
18 | describe "GET /:project_path" do | 24 | describe "GET /:project_path" do |
19 | subject { project_path(project) } | 25 | subject { project_path(project) } |
20 | 26 |
spec/features/security/project/public_access_spec.rb
@@ -9,7 +9,7 @@ describe "Public Project Access" do | @@ -9,7 +9,7 @@ describe "Public Project Access" do | ||
9 | 9 | ||
10 | before do | 10 | before do |
11 | # public project | 11 | # public project |
12 | - project.public = true | 12 | + project.visibility_level = Gitlab::VisibilityLevel::PUBLIC |
13 | project.save! | 13 | project.save! |
14 | 14 | ||
15 | # full access | 15 | # full access |
spec/models/project_spec.rb
@@ -14,13 +14,13 @@ | @@ -14,13 +14,13 @@ | ||
14 | # merge_requests_enabled :boolean default(TRUE), not null | 14 | # merge_requests_enabled :boolean default(TRUE), not null |
15 | # wiki_enabled :boolean default(TRUE), not null | 15 | # wiki_enabled :boolean default(TRUE), not null |
16 | # namespace_id :integer | 16 | # namespace_id :integer |
17 | -# public :boolean default(FALSE), not null | ||
18 | # issues_tracker :string(255) default("gitlab"), not null | 17 | # issues_tracker :string(255) default("gitlab"), not null |
19 | # issues_tracker_id :string(255) | 18 | # issues_tracker_id :string(255) |
20 | # snippets_enabled :boolean default(TRUE), not null | 19 | # snippets_enabled :boolean default(TRUE), not null |
21 | # last_activity_at :datetime | 20 | # last_activity_at :datetime |
22 | # imported :boolean default(FALSE), not null | 21 | # imported :boolean default(FALSE), not null |
23 | # import_url :string(255) | 22 | # import_url :string(255) |
23 | +# visibility_level :integer default(0), not null | ||
24 | # | 24 | # |
25 | 25 | ||
26 | require 'spec_helper' | 26 | require 'spec_helper' |
spec/requests/api/projects_spec.rb
@@ -132,15 +132,45 @@ describe API::API do | @@ -132,15 +132,45 @@ describe API::API do | ||
132 | end | 132 | end |
133 | 133 | ||
134 | it "should set a project as public" do | 134 | it "should set a project as public" do |
135 | + project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PUBLIC }) | ||
136 | + post api("/projects", user), project | ||
137 | + json_response['public'].should be_true | ||
138 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC | ||
139 | + end | ||
140 | + | ||
141 | + it "should set a project as public using :public" do | ||
135 | project = attributes_for(:project, { public: true }) | 142 | project = attributes_for(:project, { public: true }) |
136 | post api("/projects", user), project | 143 | post api("/projects", user), project |
137 | json_response['public'].should be_true | 144 | json_response['public'].should be_true |
145 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC | ||
146 | + end | ||
147 | + | ||
148 | + it "should set a project as internal" do | ||
149 | + project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::INTERNAL }) | ||
150 | + post api("/projects", user), project | ||
151 | + json_response['public'].should be_false | ||
152 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL | ||
153 | + end | ||
154 | + | ||
155 | + it "should set a project as internal overriding :public" do | ||
156 | + project = attributes_for(:project, { public: true, visibility_level: Gitlab::VisibilityLevel::INTERNAL }) | ||
157 | + post api("/projects", user), project | ||
158 | + json_response['public'].should be_false | ||
159 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL | ||
138 | end | 160 | end |
139 | 161 | ||
140 | it "should set a project as private" do | 162 | it "should set a project as private" do |
163 | + project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PRIVATE }) | ||
164 | + post api("/projects", user), project | ||
165 | + json_response['public'].should be_false | ||
166 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE | ||
167 | + end | ||
168 | + | ||
169 | + it "should set a project as private using :public" do | ||
141 | project = attributes_for(:project, { public: false }) | 170 | project = attributes_for(:project, { public: false }) |
142 | post api("/projects", user), project | 171 | post api("/projects", user), project |
143 | json_response['public'].should be_false | 172 | json_response['public'].should be_false |
173 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE | ||
144 | end | 174 | end |
145 | end | 175 | end |
146 | 176 | ||
@@ -183,19 +213,46 @@ describe API::API do | @@ -183,19 +213,46 @@ describe API::API do | ||
183 | end | 213 | end |
184 | 214 | ||
185 | it "should set a project as public" do | 215 | it "should set a project as public" do |
216 | + project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PUBLIC }) | ||
217 | + post api("/projects/user/#{user.id}", admin), project | ||
218 | + json_response['public'].should be_true | ||
219 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC | ||
220 | + end | ||
221 | + | ||
222 | + it "should set a project as public using :public" do | ||
186 | project = attributes_for(:project, { public: true }) | 223 | project = attributes_for(:project, { public: true }) |
187 | post api("/projects/user/#{user.id}", admin), project | 224 | post api("/projects/user/#{user.id}", admin), project |
188 | json_response['public'].should be_true | 225 | json_response['public'].should be_true |
226 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC | ||
227 | + end | ||
189 | 228 | ||
229 | + it "should set a project as internal" do | ||
230 | + project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::INTERNAL }) | ||
231 | + post api("/projects/user/#{user.id}", admin), project | ||
232 | + json_response['public'].should be_false | ||
233 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL | ||
190 | end | 234 | end |
191 | 235 | ||
192 | - it "should set a project as private" do | ||
193 | - project = attributes_for(:project, { public: false }) | 236 | + it "should set a project as internal overriding :public" do |
237 | + project = attributes_for(:project, { public: true, visibility_level: Gitlab::VisibilityLevel::INTERNAL }) | ||
194 | post api("/projects/user/#{user.id}", admin), project | 238 | post api("/projects/user/#{user.id}", admin), project |
195 | json_response['public'].should be_false | 239 | json_response['public'].should be_false |
240 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL | ||
241 | + end | ||
196 | 242 | ||
243 | + it "should set a project as private" do | ||
244 | + project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PRIVATE }) | ||
245 | + post api("/projects/user/#{user.id}", admin), project | ||
246 | + json_response['public'].should be_false | ||
247 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE | ||
197 | end | 248 | end |
198 | 249 | ||
250 | + it "should set a project as private using :public" do | ||
251 | + project = attributes_for(:project, { public: false }) | ||
252 | + post api("/projects/user/#{user.id}", admin), project | ||
253 | + json_response['public'].should be_false | ||
254 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE | ||
255 | + end | ||
199 | end | 256 | end |
200 | 257 | ||
201 | describe "GET /projects/:id" do | 258 | describe "GET /projects/:id" do |
@@ -649,10 +706,10 @@ describe API::API do | @@ -649,10 +706,10 @@ describe API::API do | ||
649 | 706 | ||
650 | describe :fork_admin do | 707 | describe :fork_admin do |
651 | let(:project_fork_target) { create(:project) } | 708 | let(:project_fork_target) { create(:project) } |
652 | - let(:project_fork_source) { create(:project, public: true) } | 709 | + let(:project_fork_source) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } |
653 | 710 | ||
654 | describe "POST /projects/:id/fork/:forked_from_id" do | 711 | describe "POST /projects/:id/fork/:forked_from_id" do |
655 | - let(:new_project_fork_source) { create(:project, public: true) } | 712 | + let(:new_project_fork_source) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } |
656 | 713 | ||
657 | it "shouldn't available for non admin users" do | 714 | it "shouldn't available for non admin users" do |
658 | post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user) | 715 | post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user) |
@@ -721,8 +778,10 @@ describe API::API do | @@ -721,8 +778,10 @@ describe API::API do | ||
721 | let!(:post) { create(:project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } | 778 | let!(:post) { create(:project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } |
722 | let!(:pre_post) { create(:project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } | 779 | let!(:pre_post) { create(:project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } |
723 | let!(:unfound) { create(:project, name: 'unfound', creator_id: user.id, namespace: user.namespace) } | 780 | let!(:unfound) { create(:project, name: 'unfound', creator_id: user.id, namespace: user.namespace) } |
724 | - let!(:public) { create(:project, name: "another #{query}",public: true) } | ||
725 | - let!(:unfound_public) { create(:project, name: 'unfound public', public: true) } | 781 | + let!(:internal) { create(:project, name: "internal #{query}", visibility_level: Gitlab::VisibilityLevel::INTERNAL) } |
782 | + let!(:unfound_internal) { create(:project, name: 'unfound internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL) } | ||
783 | + let!(:public) { create(:project, name: "public #{query}", visibility_level: Gitlab::VisibilityLevel::PUBLIC) } | ||
784 | + let!(:unfound_public) { create(:project, name: 'unfound public', visibility_level: Gitlab::VisibilityLevel::PUBLIC) } | ||
726 | 785 | ||
727 | context "when unauthenticated" do | 786 | context "when unauthenticated" do |
728 | it "should return authentication error" do | 787 | it "should return authentication error" do |
@@ -736,7 +795,7 @@ describe API::API do | @@ -736,7 +795,7 @@ describe API::API do | ||
736 | get api("/projects/search/#{query}",user) | 795 | get api("/projects/search/#{query}",user) |
737 | response.status.should == 200 | 796 | response.status.should == 200 |
738 | json_response.should be_an Array | 797 | json_response.should be_an Array |
739 | - json_response.size.should == 5 | 798 | + json_response.size.should == 6 |
740 | json_response.each {|project| project['name'].should =~ /.*query.*/} | 799 | json_response.each {|project| project['name'].should =~ /.*query.*/} |
741 | end | 800 | end |
742 | end | 801 | end |
@@ -746,8 +805,8 @@ describe API::API do | @@ -746,8 +805,8 @@ describe API::API do | ||
746 | get api("/projects/search/#{query}", user2) | 805 | get api("/projects/search/#{query}", user2) |
747 | response.status.should == 200 | 806 | response.status.should == 200 |
748 | json_response.should be_an Array | 807 | json_response.should be_an Array |
749 | - json_response.size.should == 1 | ||
750 | - json_response.first['name'].should == "another #{query}" | 808 | + json_response.size.should == 2 |
809 | + json_response.each {|project| project['name'].should =~ /(internal|public) query/} | ||
751 | end | 810 | end |
752 | end | 811 | end |
753 | end | 812 | end |