Commit 4c44c5ef9a569c65bca8e70078205ef2ce7d6396

Authored by Stephen Lottermoser
Committed by Stephen Lottermoser
1 parent 4f5aae1d

Internally public projects

Public projects listed in the public section will be linked to the
actual project's page. Public projects now give any user Guest
permissions to the project, allowing them to download the code, read
and create issues, and view anything else in the project's pages.

Ample access tests have been added to the project_access_spec to
verify correct permissions and behavior on public projects.
- Visitors to the site who are not logged in still cannot view the
  project's pages.
- Logged-in users visiting a public project where they are not a team
  member can create issues, but not snippets. They can view the projects
  code, issues, merge requests, etc, just as if they were a Guest member
  of the project.
- Since this is a public project, the user is also granted :download_code
  permissions, a permission normally reserved for Reporters, since they
  can clone the repo anyways and browse commits and branches locally.
app/controllers/application_controller.rb
... ... @@ -88,7 +88,7 @@ class ApplicationController < ActionController::Base
88 88 end
89 89  
90 90 def authorize_code_access!
91   - return access_denied! unless can?(current_user, :download_code, project)
  91 + return access_denied! unless can?(current_user, :download_code, project) or project.public?
92 92 end
93 93  
94 94 def authorize_create_team!
... ...
app/models/ability.rb
... ... @@ -37,7 +37,7 @@ class Ability
37 37 elsif team.reporters.include?(user)
38 38 rules << project_report_rules
39 39  
40   - elsif team.guests.include?(user)
  40 + elsif team.guests.include?(user) or project.public?
41 41 rules << project_guest_rules
42 42 end
43 43  
... ...
app/views/projects/_form.html.haml
... ... @@ -48,7 +48,7 @@
48 48 Public mode:
49 49 .control-group
50 50 = f.label :public, class: 'control-label' do
51   - %span Public clone access
  51 + %span Public access
52 52 .controls
53 53 = f.check_box :public
54 54 %span.descr
... ... @@ -56,6 +56,8 @@
56 56 %em without any
57 57 authentication.
58 58 It will also be listed on the #{link_to "public access directory", public_root_path}.
  59 + %em Any
  60 + user will have #{link_to "Guest", help_permissions_path} permissions on the repository.
59 61  
60 62 %fieldset.features
61 63 %legend
... ...
app/views/public/projects/index.html.haml
... ... @@ -9,7 +9,7 @@
9 9 %li.clearfix
10 10 %h5
11 11 %i.icon-share
12   - = project.name_with_namespace
  12 + = link_to_project project
13 13 .pull-right
14 14 %pre.dark.tiny git clone #{project.http_url_to_repo}
15 15 %p.description
... ...
features/project/public_projects.feature 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +Feature: Public Projects
  2 + Background:
  3 + Given I sign in as a user
  4 +
  5 + Scenario: I should see the list of public projects
  6 + When I visit the public projects area
  7 + Then I should see the list of public projects
  8 +
... ...
features/steps/project/public_projects.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class PublicProjects < Spinach::FeatureSteps
  2 + include SharedAuthentication
  3 + include SharedProject
  4 + include SharedPaths
  5 +
  6 + Then 'I should see the list of public projects' do
  7 + page.should have_content "Public Projects"
  8 + end
  9 +end
... ...
features/steps/shared/paths.rb
... ... @@ -263,6 +263,14 @@ module SharedPaths
263 263 visit project_wiki_path(@project, :home)
264 264 end
265 265  
  266 + # ----------------------------------------
  267 + # Public Projects
  268 + # ----------------------------------------
  269 +
  270 + Given 'I visit the public projects area' do
  271 + visit public_root_path
  272 + end
  273 +
266 274 def root_ref
267 275 @project.repository.root_ref
268 276 end
... ...
spec/features/security/project_access_spec.rb
... ... @@ -229,4 +229,246 @@ describe &quot;Application access&quot; do
229 229 it { should be_denied_for :visitor }
230 230 end
231 231 end
  232 +
  233 +
  234 + describe "PublicProject" do
  235 + let(:project) { create(:project) }
  236 +
  237 + let(:master) { create(:user) }
  238 + let(:guest) { create(:user) }
  239 + let(:reporter) { create(:user) }
  240 +
  241 + let(:admin) { create(:user) }
  242 +
  243 + before do
  244 + # public project
  245 + project.public = true
  246 + project.save!
  247 +
  248 + # full access
  249 + project.team << [master, :master]
  250 +
  251 + # readonly
  252 + project.team << [reporter, :reporter]
  253 +
  254 + end
  255 +
  256 + describe "Project should be public" do
  257 + subject { project }
  258 +
  259 + its(:public?) { should be_true }
  260 + end
  261 +
  262 + describe "GET /project_code" do
  263 + subject { project_path(project) }
  264 +
  265 + it { should be_allowed_for master }
  266 + it { should be_allowed_for reporter }
  267 + it { should be_allowed_for admin }
  268 + it { should be_allowed_for guest }
  269 + it { should be_allowed_for :user }
  270 + it { should be_denied_for :visitor }
  271 + end
  272 +
  273 + describe "GET /project_code/tree/master" do
  274 + subject { project_tree_path(project, project.repository.root_ref) }
  275 +
  276 + it { should be_allowed_for master }
  277 + it { should be_allowed_for reporter }
  278 + it { should be_allowed_for :admin }
  279 + it { should be_allowed_for guest }
  280 + it { should be_allowed_for :user }
  281 + it { should be_denied_for :visitor }
  282 + end
  283 +
  284 + describe "GET /project_code/commits/master" do
  285 + subject { project_commits_path(project, project.repository.root_ref, limit: 1) }
  286 +
  287 + it { should be_allowed_for master }
  288 + it { should be_allowed_for reporter }
  289 + it { should be_allowed_for :admin }
  290 + it { should be_allowed_for guest }
  291 + it { should be_allowed_for :user }
  292 + it { should be_denied_for :visitor }
  293 + end
  294 +
  295 + describe "GET /project_code/commit/:sha" do
  296 + subject { project_commit_path(project, project.repository.commit) }
  297 +
  298 + it { should be_allowed_for master }
  299 + it { should be_allowed_for reporter }
  300 + it { should be_allowed_for :admin }
  301 + it { should be_allowed_for guest }
  302 + it { should be_allowed_for :user }
  303 + it { should be_denied_for :visitor }
  304 + end
  305 +
  306 + describe "GET /project_code/compare" do
  307 + subject { project_compare_index_path(project) }
  308 +
  309 + it { should be_allowed_for master }
  310 + it { should be_allowed_for reporter }
  311 + it { should be_allowed_for :admin }
  312 + it { should be_allowed_for guest }
  313 + it { should be_allowed_for :user }
  314 + it { should be_denied_for :visitor }
  315 + end
  316 +
  317 + describe "GET /project_code/team" do
  318 + subject { project_team_index_path(project) }
  319 +
  320 + it { should be_allowed_for master }
  321 + it { should be_allowed_for reporter }
  322 + it { should be_allowed_for :admin }
  323 + it { should be_allowed_for guest }
  324 + it { should be_allowed_for :user }
  325 + it { should be_denied_for :visitor }
  326 + end
  327 +
  328 + describe "GET /project_code/wall" do
  329 + subject { project_wall_path(project) }
  330 +
  331 + it { should be_allowed_for master }
  332 + it { should be_allowed_for reporter }
  333 + it { should be_allowed_for :admin }
  334 + it { should be_allowed_for guest }
  335 + it { should be_allowed_for :user }
  336 + it { should be_denied_for :visitor }
  337 + end
  338 +
  339 + describe "GET /project_code/blob" do
  340 + before do
  341 + commit = project.repository.commit
  342 + path = commit.tree.contents.select { |i| i.is_a?(Grit::Blob)}.first.name
  343 + @blob_path = project_blob_path(project, File.join(commit.id, path))
  344 + end
  345 +
  346 + it { @blob_path.should be_allowed_for master }
  347 + it { @blob_path.should be_allowed_for reporter }
  348 + it { @blob_path.should be_allowed_for :admin }
  349 + it { @blob_path.should be_allowed_for guest }
  350 + it { @blob_path.should be_allowed_for :user }
  351 + it { @blob_path.should be_denied_for :visitor }
  352 + end
  353 +
  354 + describe "GET /project_code/edit" do
  355 + subject { edit_project_path(project) }
  356 +
  357 + it { should be_allowed_for master }
  358 + it { should be_denied_for reporter }
  359 + it { should be_denied_for :admin }
  360 + it { should be_denied_for guest }
  361 + it { should be_denied_for :user }
  362 + it { should be_denied_for :visitor }
  363 + end
  364 +
  365 + describe "GET /project_code/deploy_keys" do
  366 + subject { project_deploy_keys_path(project) }
  367 +
  368 + it { should be_allowed_for master }
  369 + it { should be_denied_for reporter }
  370 + it { should be_denied_for :admin }
  371 + it { should be_denied_for guest }
  372 + it { should be_denied_for :user }
  373 + it { should be_denied_for :visitor }
  374 + end
  375 +
  376 + describe "GET /project_code/issues" do
  377 + subject { project_issues_path(project) }
  378 +
  379 + it { should be_allowed_for master }
  380 + it { should be_allowed_for reporter }
  381 + it { should be_allowed_for :admin }
  382 + it { should be_allowed_for guest }
  383 + it { should be_allowed_for :user }
  384 + it { should be_denied_for :visitor }
  385 + end
  386 +
  387 + describe "GET /project_code/snippets" do
  388 + subject { project_snippets_path(project) }
  389 +
  390 + it { should be_allowed_for master }
  391 + it { should be_allowed_for reporter }
  392 + it { should be_allowed_for :admin }
  393 + it { should be_allowed_for guest }
  394 + it { should be_allowed_for :user }
  395 + it { should be_denied_for :visitor }
  396 + end
  397 +
  398 + describe "GET /project_code/snippets/new" do
  399 + subject { new_project_snippet_path(project) }
  400 +
  401 + it { should be_allowed_for master }
  402 + it { should be_allowed_for reporter }
  403 + it { should be_denied_for :admin }
  404 + it { should be_denied_for guest }
  405 + it { should be_denied_for :user }
  406 + it { should be_denied_for :visitor }
  407 + end
  408 +
  409 + describe "GET /project_code/merge_requests" do
  410 + subject { project_merge_requests_path(project) }
  411 +
  412 + it { should be_allowed_for master }
  413 + it { should be_allowed_for reporter }
  414 + it { should be_allowed_for :admin }
  415 + it { should be_allowed_for guest }
  416 + it { should be_allowed_for :user }
  417 + it { should be_denied_for :visitor }
  418 + end
  419 +
  420 + describe "GET /project_code/repository" do
  421 + subject { project_repository_path(project) }
  422 +
  423 + it { should be_allowed_for master }
  424 + it { should be_allowed_for reporter }
  425 + it { should be_allowed_for :admin }
  426 + it { should be_allowed_for guest }
  427 + it { should be_allowed_for :user }
  428 + it { should be_denied_for :visitor }
  429 + end
  430 +
  431 + describe "GET /project_code/repository/branches" do
  432 + subject { branches_project_repository_path(project) }
  433 +
  434 + before do
  435 + # Speed increase
  436 + Project.any_instance.stub(:branches).and_return([])
  437 + end
  438 +
  439 + it { should be_allowed_for master }
  440 + it { should be_allowed_for reporter }
  441 + it { should be_allowed_for :admin }
  442 + it { should be_allowed_for guest }
  443 + it { should be_allowed_for :user }
  444 + it { should be_denied_for :visitor }
  445 + end
  446 +
  447 + describe "GET /project_code/repository/tags" do
  448 + subject { tags_project_repository_path(project) }
  449 +
  450 + before do
  451 + # Speed increase
  452 + Project.any_instance.stub(:tags).and_return([])
  453 + end
  454 +
  455 + it { should be_allowed_for master }
  456 + it { should be_allowed_for reporter }
  457 + it { should be_allowed_for :admin }
  458 + it { should be_allowed_for guest }
  459 + it { should be_allowed_for :user }
  460 + it { should be_denied_for :visitor }
  461 + end
  462 +
  463 + describe "GET /project_code/hooks" do
  464 + subject { project_hooks_path(project) }
  465 +
  466 + it { should be_allowed_for master }
  467 + it { should be_allowed_for reporter }
  468 + it { should be_allowed_for :admin }
  469 + it { should be_allowed_for guest }
  470 + it { should be_allowed_for :user }
  471 + it { should be_denied_for :visitor }
  472 + end
  473 + end
232 474 end
... ...