Commit d9bb4230cc3aa161876df821c34d8e9c53d2e7a6
1 parent
51b5509b
Exists in
master
and in
4 other branches
Adding authenticated public mode (internal).
Added visibility_level icons to project view (rather than just text). Added public projects to search results. Added ability to restrict visibility levels standard users can set.
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
app/assets/stylesheets/sections/admin.scss
... | ... | @@ -20,6 +20,15 @@ |
20 | 20 | label { width: 110px; } |
21 | 21 | .controls { margin-left: 130px; } |
22 | 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 | 34 | .broadcast-messages { | ... | ... |
app/assets/stylesheets/sections/projects.scss
... | ... | @@ -18,6 +18,12 @@ |
18 | 18 | border-bottom: 1px solid #DDD; |
19 | 19 | padding-bottom: 25px; |
20 | 20 | margin-bottom: 30px; |
21 | + | |
22 | + &.empty-project { | |
23 | + border-bottom: 0px; | |
24 | + padding-bottom: 15px; | |
25 | + margin-bottom: 0px; | |
26 | + } | |
21 | 27 | |
22 | 28 | .project-home-title { |
23 | 29 | font-size: 18px; |
... | ... | @@ -45,7 +51,7 @@ |
45 | 51 | } |
46 | 52 | } |
47 | 53 | |
48 | - .public-label { | |
54 | + .visibility-level-label { | |
49 | 55 | font-size: 14px; |
50 | 56 | background: #f1f1f1; |
51 | 57 | padding: 8px 10px; |
... | ... | @@ -53,6 +59,10 @@ |
53 | 59 | margin-left: 10px; |
54 | 60 | color: #888; |
55 | 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 | 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 | 164 | margin: 0px; |
131 | 165 | } |
132 | 166 | |
133 | -.my-projects { | |
167 | +.my-projects, | |
168 | +.public-projects { | |
134 | 169 | li { |
135 | 170 | .project-info { |
136 | 171 | margin-bottom: 10px; | ... | ... |
app/contexts/projects/create_context.rb
... | ... | @@ -8,6 +8,11 @@ module Projects |
8 | 8 | # get namespace id |
9 | 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 | 16 | # Load default feature settings |
12 | 17 | default_features = Gitlab.config.gitlab.default_projects_features |
13 | 18 | |
... | ... | @@ -17,7 +22,7 @@ module Projects |
17 | 22 | wall_enabled: default_features.wall, |
18 | 23 | snippets_enabled: default_features.snippets, |
19 | 24 | merge_requests_enabled: default_features.merge_requests, |
20 | - public: default_features.public | |
25 | + visibility_level: default_features.visibility_level | |
21 | 26 | }.stringify_keys |
22 | 27 | |
23 | 28 | @project = Project.new(default_opts.merge(params)) | ... | ... |
app/contexts/projects/update_context.rb
... | ... | @@ -2,7 +2,11 @@ module Projects |
2 | 2 | class UpdateContext < BaseContext |
3 | 3 | def execute(role = :default) |
4 | 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 | 10 | new_branch = params[:project].delete(:default_branch) |
7 | 11 | |
8 | 12 | if project.repository.exists? && new_branch != project.repository.root_ref | ... | ... |
app/contexts/search_context.rb
1 | 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 | 6 | end |
7 | 7 | |
8 | 8 | def execute |
... | ... | @@ -10,7 +10,8 @@ class SearchContext |
10 | 10 | query = Shellwords.shellescape(query) if query.present? |
11 | 11 | |
12 | 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 | 16 | # Search inside single project |
16 | 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 | 8 | user = User.find_by_id(owner_id) |
9 | 9 | |
10 | 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 | 12 | @projects = @projects.with_push if params[:with_push].present? |
13 | 13 | @projects = @projects.abandoned if params[:abandoned].present? |
14 | 14 | @projects = @projects.search(params[:name]) if params[:name].present? | ... | ... |
app/controllers/application_controller.rb
... | ... | @@ -102,7 +102,7 @@ class ApplicationController < ActionController::Base |
102 | 102 | end |
103 | 103 | |
104 | 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 | 106 | end |
107 | 107 | |
108 | 108 | def authorize_push! | ... | ... |
app/controllers/projects/application_controller.rb
... | ... | @@ -10,7 +10,7 @@ class Projects::ApplicationController < ApplicationController |
10 | 10 | id = params[:project_id] || params[:id] |
11 | 11 | @project = Project.find_with_namespace(id) |
12 | 12 | |
13 | - return if @project && @project.public | |
13 | + return if @project && @project.public? | |
14 | 14 | end |
15 | 15 | |
16 | 16 | super | ... | ... |
app/controllers/projects_controller.rb
... | ... | @@ -55,7 +55,7 @@ class ProjectsController < ApplicationController |
55 | 55 | end |
56 | 56 | |
57 | 57 | def show |
58 | - return authenticate_user! unless @project.public || current_user | |
58 | + return authenticate_user! unless @project.public? || current_user | |
59 | 59 | |
60 | 60 | limit = (params[:limit] || 20).to_i |
61 | 61 | @events = @project.events.recent | ... | ... |
app/controllers/public/projects_controller.rb
... | ... | @@ -6,7 +6,7 @@ class Public::ProjectsController < ApplicationController |
6 | 6 | layout 'public' |
7 | 7 | |
8 | 8 | def index |
9 | - @projects = Project.public_only | |
9 | + @projects = Project.public_or_internal_only(current_user) | |
10 | 10 | @projects = @projects.search(params[:search]) if params[:search].present? |
11 | 11 | @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) |
12 | 12 | end | ... | ... |
app/controllers/search_controller.rb
... | ... | @@ -14,7 +14,7 @@ class SearchController < ApplicationController |
14 | 14 | project_ids.select! { |id| id == project_id.to_i} |
15 | 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 | 19 | @projects = result[:projects] |
20 | 20 | @merge_requests = result[:merge_requests] | ... | ... |
app/helpers/icons_helper.rb
app/helpers/search_helper.rb
1 | 1 | module SearchHelper |
2 | 2 | def search_autocomplete_source |
3 | 3 | return unless current_user |
4 | - | |
5 | 4 | [ |
6 | 5 | groups_autocomplete, |
7 | 6 | projects_autocomplete, |
7 | + public_projects_autocomplete, | |
8 | 8 | default_autocomplete, |
9 | 9 | project_autocomplete, |
10 | 10 | help_autocomplete |
... | ... | @@ -75,4 +75,11 @@ module SearchHelper |
75 | 75 | { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) } |
76 | 76 | end |
77 | 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 | 85 | end | ... | ... |
... | ... | @@ -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 | 56 | \ No newline at end of file | ... | ... |
app/models/ability.rb
... | ... | @@ -29,7 +29,7 @@ class Ability |
29 | 29 | nil |
30 | 30 | end |
31 | 31 | |
32 | - if project && project.public | |
32 | + if project && project.public? | |
33 | 33 | [ |
34 | 34 | :read_project, |
35 | 35 | :read_wiki, |
... | ... | @@ -71,7 +71,7 @@ class Ability |
71 | 71 | rules << project_guest_rules |
72 | 72 | end |
73 | 73 | |
74 | - if project.public? | |
74 | + if project.public? || project.internal? | |
75 | 75 | rules << public_project_rules |
76 | 76 | end |
77 | 77 | |
... | ... | @@ -89,7 +89,7 @@ class Ability |
89 | 89 | def public_project_rules |
90 | 90 | project_guest_rules + [ |
91 | 91 | :download_code, |
92 | - :fork_project, | |
92 | + :fork_project | |
93 | 93 | ] |
94 | 94 | end |
95 | 95 | |
... | ... | @@ -145,7 +145,7 @@ class Ability |
145 | 145 | def project_admin_rules |
146 | 146 | project_master_rules + [ |
147 | 147 | :change_namespace, |
148 | - :change_public_mode, | |
148 | + :change_visibility_level, | |
149 | 149 | :rename_project, |
150 | 150 | :remove_project |
151 | 151 | ] | ... | ... |
app/models/project.rb
... | ... | @@ -14,24 +14,25 @@ |
14 | 14 | # merge_requests_enabled :boolean default(TRUE), not null |
15 | 15 | # wiki_enabled :boolean default(TRUE), not null |
16 | 16 | # namespace_id :integer |
17 | -# public :boolean default(FALSE), not null | |
18 | 17 | # issues_tracker :string(255) default("gitlab"), not null |
19 | 18 | # issues_tracker_id :string(255) |
20 | 19 | # snippets_enabled :boolean default(TRUE), not null |
21 | 20 | # last_activity_at :datetime |
22 | 21 | # imported :boolean default(FALSE), not null |
23 | 22 | # import_url :string(255) |
23 | +# visibility_level :integer default(0), not null | |
24 | 24 | # |
25 | 25 | |
26 | 26 | class Project < ActiveRecord::Base |
27 | 27 | include Gitlab::ShellAdapter |
28 | + include Gitlab::VisibilityLevel | |
28 | 29 | extend Enumerize |
29 | 30 | |
30 | 31 | ActsAsTaggableOn.strict_case_match = true |
31 | 32 | |
32 | 33 | attr_accessible :name, :path, :description, :issues_tracker, :label_list, |
33 | 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 | 37 | attr_accessible :namespace_id, :creator_id, as: :admin |
37 | 38 | |
... | ... | @@ -108,7 +109,8 @@ class Project < ActiveRecord::Base |
108 | 109 | scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") } |
109 | 110 | scope :personal, ->(user) { where(namespace_id: user.namespace_id) } |
110 | 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 | 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 | 142 | where(path: id, namespace_id: nil).last |
141 | 143 | end |
142 | 144 | end |
145 | + | |
146 | + def visibility_levels | |
147 | + Gitlab::VisibilityLevel.options | |
148 | + end | |
143 | 149 | end |
144 | 150 | |
145 | 151 | def team |
... | ... | @@ -451,4 +457,8 @@ class Project < ActiveRecord::Base |
451 | 457 | def default_branch |
452 | 458 | @default_branch ||= repository.root_ref if repository.exists? |
453 | 459 | end |
460 | + | |
461 | + def visibility_level_field | |
462 | + visibility_level | |
463 | + end | |
454 | 464 | end | ... | ... |
app/views/admin/projects/index.html.haml
... | ... | @@ -10,11 +10,15 @@ |
10 | 10 | .control-group |
11 | 11 | = label_tag :owner_id, 'Owner:', class: 'control-label' |
12 | 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 | 22 | .control-group |
19 | 23 | = label_tag :with_push, 'Not empty', class: 'control-label' |
20 | 24 | .controls |
... | ... | @@ -42,10 +46,7 @@ |
42 | 46 | %ul.well-list |
43 | 47 | - @projects.each do |project| |
44 | 48 | %li |
45 | - - if project.public | |
46 | - = public_icon | |
47 | - - else | |
48 | - = private_icon | |
49 | + = visibility_level_icon(project.visibility_level) | |
49 | 50 | = link_to project.name_with_namespace, [:admin, project] |
50 | 51 | .pull-right |
51 | 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 | 66 | %li |
67 | 67 | %span.light access: |
68 | 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 | 73 | .ui-box |
78 | 74 | .title |
79 | 75 | Transfer project |
... | ... | @@ -88,9 +84,6 @@ |
88 | 84 | .controls |
89 | 85 | = f.submit 'Transfer', class: 'btn btn-primary' |
90 | 86 | |
91 | - | |
92 | - | |
93 | - | |
94 | 87 | .span6 |
95 | 88 | - if @group |
96 | 89 | .ui-box | ... | ... |
app/views/dashboard/projects.html.haml
... | ... | @@ -58,10 +58,10 @@ |
58 | 58 | %h4.project-title |
59 | 59 | = link_to project_path(project), class: dom_class(project) do |
60 | 60 | = project.name_with_namespace |
61 | - - if project.public | |
61 | + - unless project.private? | |
62 | 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 | 66 | - if current_user.can_leave_project?(project) |
67 | 67 | .pull-right | ... | ... |
app/views/groups/edit.html.haml
... | ... | @@ -51,10 +51,7 @@ |
51 | 51 | %ul.well-list |
52 | 52 | - @group.projects.each do |project| |
53 | 53 | %li |
54 | - - if project.public | |
55 | - = public_icon | |
56 | - - else | |
57 | - = private_icon | |
54 | + = visibility_level_icon(project.visibility_level) | |
58 | 55 | = link_to project.name_with_namespace, project |
59 | 56 | .pull-right |
60 | 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 | 2 | %h3.page-title Public Access |
3 | 3 | |
4 | 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 | 10 | %em without any |
8 | 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 | 17 | %ol |
12 | 18 | %li Go to your project dashboard |
13 | 19 | %li Click on the "Edit" tab |
14 | - %li Select "Public clone access" | |
20 | + %li Change "Visibility Level" | |
15 | 21 | ... | ... |
... | ... | @@ -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 | 32 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 | 24 | \ No newline at end of file | ... | ... |
app/views/projects/edit.html.haml
... | ... | @@ -29,22 +29,7 @@ |
29 | 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 | 34 | %fieldset.features |
50 | 35 | %legend | ... | ... |
app/views/projects/empty.html.haml
app/views/projects/new.html.haml
... | ... | @@ -47,12 +47,7 @@ |
47 | 47 | %span.light (optional) |
48 | 48 | .controls |
49 | 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 | 52 | .form-actions |
58 | 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 | 3 | .row |
32 | 4 | .span9 | ... | ... |
app/views/public/projects/index.html.haml
config/gitlab.yml.example
... | ... | @@ -55,6 +55,10 @@ production: &base |
55 | 55 | # default: false - Account passwords are not sent via the email if signup is enabled. |
56 | 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 | 62 | ## Automatic issue closing |
59 | 63 | # If a commit message matches this regular expression, all issues referenced from the matched text will be closed. |
60 | 64 | # This happens when the commit is pushed or merged into the default branch of a project. |
... | ... | @@ -68,7 +72,7 @@ production: &base |
68 | 72 | wiki: true |
69 | 73 | wall: false |
70 | 74 | snippets: false |
71 | - public: false | |
75 | + visibility_level: "private" # can be "private" | "internal" | "public" | |
72 | 76 | |
73 | 77 | ## External issues trackers |
74 | 78 | issues_tracker: | ... | ... |
config/initializers/1_settings.rb
... | ... | @@ -30,6 +30,29 @@ class Settings < Settingslogic |
30 | 30 | gitlab.relative_url_root |
31 | 31 | ].join('') |
32 | 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 | 56 | end |
34 | 57 | end |
35 | 58 | |
... | ... | @@ -68,6 +91,7 @@ rescue ArgumentError # no user configured |
68 | 91 | '/home/' + Settings.gitlab['user'] |
69 | 92 | end |
70 | 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 | 95 | Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? |
72 | 96 | Settings.gitlab['issue_closing_pattern'] = '([Cc]loses|[Ff]ixes) #(\d+)' if Settings.gitlab['issue_closing_pattern'].nil? |
73 | 97 | Settings.gitlab['default_projects_features'] ||= {} |
... | ... | @@ -76,7 +100,7 @@ Settings.gitlab.default_projects_features['merge_requests'] = true if Settings.g |
76 | 100 | Settings.gitlab.default_projects_features['wiki'] = true if Settings.gitlab.default_projects_features['wiki'].nil? |
77 | 101 | Settings.gitlab.default_projects_features['wall'] = false if Settings.gitlab.default_projects_features['wall'].nil? |
78 | 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 | 106 | # Gravatar | ... | ... |
db/migrate/20131112220935_add_visibility_level_to_projects.rb
0 → 100644
... | ... | @@ -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 | 11 | # |
12 | 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 | 16 | create_table "broadcast_messages", :force => true do |t| |
17 | 17 | t.text "message", :null => false |
... | ... | @@ -185,13 +185,13 @@ ActiveRecord::Schema.define(:version => 20131112114325) do |
185 | 185 | t.boolean "merge_requests_enabled", :default => true, :null => false |
186 | 186 | t.boolean "wiki_enabled", :default => true, :null => false |
187 | 187 | t.integer "namespace_id" |
188 | - t.boolean "public", :default => false, :null => false | |
189 | 188 | t.string "issues_tracker", :default => "gitlab", :null => false |
190 | 189 | t.string "issues_tracker_id" |
191 | 190 | t.boolean "snippets_enabled", :default => true, :null => false |
192 | 191 | t.datetime "last_activity_at" |
193 | 192 | t.boolean "imported", :default => false, :null => false |
194 | 193 | t.string "import_url" |
194 | + t.integer "visibility_level", :default => 0, :null => false | |
195 | 195 | end |
196 | 196 | |
197 | 197 | add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" | ... | ... |
doc/api/projects.md
... | ... | @@ -15,6 +15,7 @@ GET /projects |
15 | 15 | "description": null, |
16 | 16 | "default_branch": "master", |
17 | 17 | "public": false, |
18 | + "visibility_level": 0, | |
18 | 19 | "ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git", |
19 | 20 | "http_url_to_repo": "http://example.com/diaspora/diaspora-client.git", |
20 | 21 | "web_url": "http://example.com/diaspora/diaspora-client", |
... | ... | @@ -49,6 +50,7 @@ GET /projects |
49 | 50 | "description": null, |
50 | 51 | "default_branch": "master", |
51 | 52 | "public": false, |
53 | + "visibility_level": 0, | |
52 | 54 | "ssh_url_to_repo": "git@example.com:brightbox/puppet.git", |
53 | 55 | "http_url_to_repo": "http://example.com/brightbox/puppet.git", |
54 | 56 | "web_url": "http://example.com/brightbox/puppet", |
... | ... | @@ -117,6 +119,7 @@ Parameters: |
117 | 119 | "description": null, |
118 | 120 | "default_branch": "master", |
119 | 121 | "public": false, |
122 | + "visibility_level": 0, | |
120 | 123 | "ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git", |
121 | 124 | "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git", |
122 | 125 | "web_url": "http://example.com/diaspora/diaspora-project-site", |
... | ... | @@ -234,7 +237,8 @@ Parameters: |
234 | 237 | + `merge_requests_enabled` (optional) |
235 | 238 | + `wiki_enabled` (optional) |
236 | 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 | 244 | ### Create project for user |
... | ... | @@ -256,7 +260,8 @@ Parameters: |
256 | 260 | + `merge_requests_enabled` (optional) |
257 | 261 | + `wiki_enabled` (optional) |
258 | 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 | 267 | ## Remove project | ... | ... |
features/public/public_projects.feature
1 | 1 | Feature: Public Projects Feature |
2 | 2 | Background: |
3 | 3 | Given public project "Community" |
4 | + And internal project "Internal" | |
4 | 5 | And private project "Enterprise" |
5 | 6 | |
6 | 7 | Scenario: I visit public area |
7 | 8 | When I visit the public projects area |
8 | 9 | Then I should see project "Community" |
10 | + And I should not see project "Internal" | |
9 | 11 | And I should not see project "Enterprise" |
10 | 12 | |
11 | 13 | Scenario: I visit public project page |
12 | 14 | When I visit project "Community" page |
13 | 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 | 25 | Scenario: I visit an empty public project page |
16 | 26 | Given public empty project "Empty Public Project" |
17 | 27 | When I visit empty project page |
18 | 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 | 1 | class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps |
2 | + include SharedAuthentication | |
2 | 3 | include SharedPaths |
4 | + include SharedProject | |
3 | 5 | |
4 | 6 | step 'I should see project "Community"' do |
5 | 7 | page.should have_content "Community" |
... | ... | @@ -23,11 +25,11 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps |
23 | 25 | end |
24 | 26 | |
25 | 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 | 29 | end |
28 | 30 | |
29 | 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 | 33 | end |
32 | 34 | |
33 | 35 | step 'I visit empty project page' do |
... | ... | @@ -48,16 +50,38 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps |
48 | 50 | create :project, name: 'Enterprise' |
49 | 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 | 58 | step 'I should see project "Community" home page' do |
52 | 59 | within '.project-home-title' do |
53 | 60 | page.should have_content 'Community' |
54 | 61 | end |
55 | 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 | 85 | end |
62 | 86 | end |
63 | 87 | ... | ... |
lib/api/entities.rb
... | ... | @@ -31,11 +31,13 @@ module API |
31 | 31 | end |
32 | 32 | |
33 | 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 | 37 | expose :owner, using: Entities::UserBasic |
36 | 38 | expose :name, :name_with_namespace |
37 | 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 | 41 | expose :namespace |
40 | 42 | expose :forked_from_project, using: Entities::ForkedFromProject, :if => lambda{ | project, options | project.forked? } |
41 | 43 | end | ... | ... |
lib/api/projects.rb
... | ... | @@ -11,6 +11,13 @@ module API |
11 | 11 | end |
12 | 12 | not_found! |
13 | 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 | 21 | end |
15 | 22 | |
16 | 23 | # Get a projects list for authenticated user |
... | ... | @@ -76,7 +83,8 @@ module API |
76 | 83 | # wiki_enabled (optional) |
77 | 84 | # snippets_enabled (optional) |
78 | 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 | 88 | # Example Request |
81 | 89 | # POST /projects |
82 | 90 | post do |
... | ... | @@ -90,7 +98,9 @@ module API |
90 | 98 | :wiki_enabled, |
91 | 99 | :snippets_enabled, |
92 | 100 | :namespace_id, |
93 | - :public] | |
101 | + :public, | |
102 | + :visibility_level] | |
103 | + attrs = map_public_to_visibility_level(attrs) | |
94 | 104 | @project = ::Projects::CreateContext.new(current_user, attrs).execute |
95 | 105 | if @project.saved? |
96 | 106 | present @project, with: Entities::Project |
... | ... | @@ -114,7 +124,8 @@ module API |
114 | 124 | # merge_requests_enabled (optional) |
115 | 125 | # wiki_enabled (optional) |
116 | 126 | # snippets_enabled (optional) |
117 | - # public (optional) | |
127 | + # public (optional) - if true same as setting visibility_level = 20 | |
128 | + # visibility_level (optional) | |
118 | 129 | # Example Request |
119 | 130 | # POST /projects/user/:user_id |
120 | 131 | post "user/:user_id" do |
... | ... | @@ -128,7 +139,9 @@ module API |
128 | 139 | :merge_requests_enabled, |
129 | 140 | :wiki_enabled, |
130 | 141 | :snippets_enabled, |
131 | - :public] | |
142 | + :public, | |
143 | + :visibility_level] | |
144 | + attrs = map_public_to_visibility_level(attrs) | |
132 | 145 | @project = ::Projects::CreateContext.new(user, attrs).execute |
133 | 146 | if @project.saved? |
134 | 147 | present @project, with: Entities::Project |
... | ... | @@ -290,7 +303,8 @@ module API |
290 | 303 | # GET /projects/search/:query |
291 | 304 | get "/search/:query" do |
292 | 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 | 308 | present paginate(projects), with: Entities::Project |
295 | 309 | end |
296 | 310 | end | ... | ... |
lib/gitlab/backend/grack_auth.rb
... | ... | @@ -58,7 +58,7 @@ module Grack |
58 | 58 | end |
59 | 59 | |
60 | 60 | else |
61 | - return unauthorized unless project.public | |
61 | + return unauthorized unless project.public? | |
62 | 62 | end |
63 | 63 | |
64 | 64 | if authorized_git_request? |
... | ... | @@ -80,7 +80,7 @@ module Grack |
80 | 80 | def authorize_request(service) |
81 | 81 | case service |
82 | 82 | when 'git-upload-pack' |
83 | - project.public || can?(user, :download_code, project) | |
83 | + can?(user, :download_code, project) | |
84 | 84 | when'git-receive-pack' |
85 | 85 | refs.each do |ref| |
86 | 86 | action = if project.protected_branch?(ref) | ... | ... |
... | ... | @@ -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 | 7 | describe :create_by_user do |
8 | 8 | before do |
9 | 9 | @user = create :user |
10 | + @admin = create :user, admin: true | |
10 | 11 | @opts = { |
11 | 12 | name: "GitLab", |
12 | 13 | namespace: @user.namespace |
... | ... | @@ -37,7 +38,7 @@ describe Projects::CreateContext do |
37 | 38 | it { @project.namespace.should == @group } |
38 | 39 | end |
39 | 40 | |
40 | - context 'respect configured public setting' do | |
41 | + context 'respect configured visibility setting' do | |
41 | 42 | before(:each) do |
42 | 43 | @settings = double("settings") |
43 | 44 | @settings.stub(:issues) { true } |
... | ... | @@ -46,25 +47,90 @@ describe Projects::CreateContext do |
46 | 47 | @settings.stub(:wall) { true } |
47 | 48 | @settings.stub(:snippets) { true } |
48 | 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 | 53 | Settings.stub_chain(:gitlab, :default_projects_features).and_return(@settings) |
50 | 54 | end |
51 | 55 | |
52 | 56 | context 'should be public when setting is public' do |
53 | 57 | before do |
54 | - @settings.stub(:public) { true } | |
58 | + @settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PUBLIC } | |
55 | 59 | @project = create_project(@user, @opts) |
56 | 60 | end |
57 | 61 | |
58 | - it { @project.public.should be_true } | |
62 | + it { @project.public?.should be_true } | |
59 | 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 | 66 | before do |
63 | - @settings.stub(:public) { false } | |
67 | + @settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PRIVATE } | |
64 | 68 | @project = create_project(@user, @opts) |
65 | 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 | 134 | end |
69 | 135 | end |
70 | 136 | end |
... | ... | @@ -73,3 +139,4 @@ describe Projects::CreateContext do |
73 | 139 | Projects::CreateContext.new(user, opts).execute |
74 | 140 | end |
75 | 141 | end |
142 | + | ... | ... |
... | ... | @@ -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 | 112 | \ No newline at end of file | ... | ... |
spec/contexts/search_context_spec.rb
... | ... | @@ -3,23 +3,39 @@ require 'spec_helper' |
3 | 3 | describe SearchContext do |
4 | 4 | let(:found_namespace) { create(:namespace, name: 'searchable namespace', path:'another_thing') } |
5 | 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 | 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 | 19 | describe '#execute' do |
15 | 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 | 22 | results = context.execute |
18 | 23 | results[:projects].should == [found_project, public_project] |
19 | 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 | 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 | 39 | results = context.execute |
24 | 40 | results[:projects].should == [found_project] |
25 | 41 | end | ... | ... |
... | ... | @@ -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 | 15 | project.team << [reporter, :reporter] |
16 | 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 | 24 | describe "GET /:project_path" do |
19 | 25 | subject { project_path(project) } |
20 | 26 | ... | ... |
spec/features/security/project/public_access_spec.rb
spec/models/project_spec.rb
... | ... | @@ -14,13 +14,13 @@ |
14 | 14 | # merge_requests_enabled :boolean default(TRUE), not null |
15 | 15 | # wiki_enabled :boolean default(TRUE), not null |
16 | 16 | # namespace_id :integer |
17 | -# public :boolean default(FALSE), not null | |
18 | 17 | # issues_tracker :string(255) default("gitlab"), not null |
19 | 18 | # issues_tracker_id :string(255) |
20 | 19 | # snippets_enabled :boolean default(TRUE), not null |
21 | 20 | # last_activity_at :datetime |
22 | 21 | # imported :boolean default(FALSE), not null |
23 | 22 | # import_url :string(255) |
23 | +# visibility_level :integer default(0), not null | |
24 | 24 | # |
25 | 25 | |
26 | 26 | require 'spec_helper' | ... | ... |
spec/requests/api/projects_spec.rb
... | ... | @@ -132,15 +132,45 @@ describe API::API do |
132 | 132 | end |
133 | 133 | |
134 | 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 | 142 | project = attributes_for(:project, { public: true }) |
136 | 143 | post api("/projects", user), project |
137 | 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 | 160 | end |
139 | 161 | |
140 | 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 | 170 | project = attributes_for(:project, { public: false }) |
142 | 171 | post api("/projects", user), project |
143 | 172 | json_response['public'].should be_false |
173 | + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE | |
144 | 174 | end |
145 | 175 | end |
146 | 176 | |
... | ... | @@ -183,19 +213,46 @@ describe API::API do |
183 | 213 | end |
184 | 214 | |
185 | 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 | 223 | project = attributes_for(:project, { public: true }) |
187 | 224 | post api("/projects/user/#{user.id}", admin), project |
188 | 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 | 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 | 238 | post api("/projects/user/#{user.id}", admin), project |
195 | 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 | 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 | 256 | end |
200 | 257 | |
201 | 258 | describe "GET /projects/:id" do |
... | ... | @@ -649,10 +706,10 @@ describe API::API do |
649 | 706 | |
650 | 707 | describe :fork_admin do |
651 | 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 | 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 | 714 | it "shouldn't available for non admin users" do |
658 | 715 | post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user) |
... | ... | @@ -721,8 +778,10 @@ describe API::API do |
721 | 778 | let!(:post) { create(:project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } |
722 | 779 | let!(:pre_post) { create(:project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } |
723 | 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 | 786 | context "when unauthenticated" do |
728 | 787 | it "should return authentication error" do |
... | ... | @@ -736,7 +795,7 @@ describe API::API do |
736 | 795 | get api("/projects/search/#{query}",user) |
737 | 796 | response.status.should == 200 |
738 | 797 | json_response.should be_an Array |
739 | - json_response.size.should == 5 | |
798 | + json_response.size.should == 6 | |
740 | 799 | json_response.each {|project| project['name'].should =~ /.*query.*/} |
741 | 800 | end |
742 | 801 | end |
... | ... | @@ -746,8 +805,8 @@ describe API::API do |
746 | 805 | get api("/projects/search/#{query}", user2) |
747 | 806 | response.status.should == 200 |
748 | 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 | 810 | end |
752 | 811 | end |
753 | 812 | end | ... | ... |