From 47f539f5a6a930b2cfd4f9834b4d1bd5e1c180cb Mon Sep 17 00:00:00 2001
From: Valery Sizov <valery@gitlab.com>
Date: Wed, 8 Oct 2014 16:44:25 +0300
Subject: [PATCH] Snippets: public/internal/private

---
 .../projects/snippets_controller.rb           |  7 +-
 app/controllers/snippets_controller.rb        | 42 +++++----
 app/finders/snippets_finder.rb                | 61 ++++++++++++
 app/helpers/visibility_level_helper.rb        | 17 ++++
 app/models/project_team.rb                    |  4 +
 app/models/snippet.rb                         | 16 +++-
 app/views/shared/snippets/_form.html.haml     | 18 +---
 .../snippets/_visibility_level.html.haml      | 27 ++++++
 .../snippets/current_user_index.html.haml     |  5 +
 app/views/snippets/index.html.haml            | 10 +-
 app/views/snippets/user_index.html.haml       |  5 +-
 ...7100818_add_visibility_level_to_snippet.rb | 21 +++++
 db/schema.rb                                  |  7 +-
 features/snippets/discover.feature            |  2 +
 features/snippets/user.feature                | 13 ++-
 features/steps/shared/snippet.rb              | 16 +++-
 features/steps/snippets/discover.rb           |  4 +
 features/steps/snippets/user.rb               | 14 +++
 spec/finders/snippets_finder_spec.rb          | 94 +++++++++++++++++++
 spec/models/project_team_spec.rb              |  4 +
 20 files changed, 332 insertions(+), 55 deletions(-)
 create mode 100644 app/finders/snippets_finder.rb
 create mode 100644 app/views/shared/snippets/_visibility_level.html.haml
 create mode 100644 db/migrate/20141007100818_add_visibility_level_to_snippet.rb
 create mode 100644 spec/finders/snippets_finder_spec.rb

diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index cba058fe214..9d5dd8a95cc 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -17,7 +17,10 @@ class Projects::SnippetsController < Projects::ApplicationController
   respond_to :html
 
   def index
-    @snippets = @project.snippets.fresh.non_expired
+    @snippets = SnippetsFinder.new.execute(current_user, {
+      filter: :by_project,
+      project: @project
+    })
   end
 
   def new
@@ -88,6 +91,6 @@ class Projects::SnippetsController < Projects::ApplicationController
   end
 
   def snippet_params
-    params.require(:project_snippet).permit(:title, :content, :file_name, :private)
+    params.require(:project_snippet).permit(:title, :content, :file_name, :private, :visibility_level)
   end
 end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 5904dbbceda..30fb4c5552d 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -9,12 +9,14 @@ class SnippetsController < ApplicationController
 
   before_filter :set_title
 
+  skip_before_filter :authenticate_user!, only: [:index, :user_index]
+
   respond_to :html
 
-  layout 'navless'
+  layout :determine_layout
 
   def index
-    @snippets = Snippet.are_internal.fresh.non_expired.page(params[:page]).per(20)
+    @snippets = SnippetsFinder.new.execute(current_user, filter: :all).page(params[:page]).per(20)
   end
 
   def user_index
@@ -22,22 +24,11 @@ class SnippetsController < ApplicationController
 
     render_404 and return unless @user
 
-    @snippets = @user.snippets.fresh.non_expired
-
-    if @user == current_user
-      @snippets = case params[:scope]
-                  when 'are_internal' then
-                    @snippets.are_internal
-                  when 'are_private' then
-                    @snippets.are_private
-                  else
-                    @snippets
-                  end
-    else
-      @snippets = @snippets.are_internal
-    end
-
-    @snippets = @snippets.page(params[:page]).per(20)
+    @snippets = SnippetsFinder.new.execute(current_user, {
+      filter: :by_user,
+      user: @user,
+      scope: params[:scope]}).
+    page(params[:page]).per(20)
 
     if @user == current_user
       render 'current_user_index'
@@ -95,7 +86,14 @@ class SnippetsController < ApplicationController
   protected
 
   def snippet
-    @snippet ||= PersonalSnippet.where('author_id = :user_id or private is false', user_id: current_user.id).find(params[:id])
+    @snippet ||= if current_user
+                   PersonalSnippet.where("author_id = ? OR visibility_level IN (?)",
+                     current_user.id,
+                     [Snippet::PUBLIC, Snippet::INTERNAL]).
+                     find(params[:id])
+                 else
+                   PersonalSnippet.are_public.find(params[:id])
+                 end
   end
 
   def authorize_modify_snippet!
@@ -111,6 +109,10 @@ class SnippetsController < ApplicationController
   end
 
   def snippet_params
-    params.require(:personal_snippet).permit(:title, :content, :file_name, :private)
+    params.require(:personal_snippet).permit(:title, :content, :file_name, :private, :visibility_level)
+  end
+
+  def determine_layout
+    current_user ? 'navless' : 'public_users'
   end
 end
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
new file mode 100644
index 00000000000..fda375aca2f
--- /dev/null
+++ b/app/finders/snippets_finder.rb
@@ -0,0 +1,61 @@
+class SnippetsFinder
+  def execute(current_user, params = {})
+    filter = params[:filter]
+
+    case filter
+    when :all then
+      snippets(current_user).fresh.non_expired
+    when :by_user then
+      by_user(current_user, params[:user], params[:scope])
+    when :by_project
+      by_project(current_user, params[:project])
+    end
+  end
+
+  private
+
+  def snippets(current_user)
+    if current_user
+      Snippet.public_and_internal
+    else
+      # Not authenticated
+      #
+      # Return only:
+      #   public snippets
+      Snippet.are_public
+    end
+  end
+
+  def by_user(current_user, user, scope)
+    snippets = user.snippets.fresh.non_expired
+
+    if user == current_user
+      snippets = case scope
+                 when 'are_internal' then
+                   snippets.are_internal
+                 when 'are_private' then
+                   snippets.are_private
+                 when 'are_public' then
+                   snippets.are_public
+                 else
+                   snippets
+                 end
+    else
+      snippets = snippets.public_and_internal
+    end
+  end
+
+  def by_project(current_user, project)
+    snippets = project.snippets.fresh.non_expired
+
+    if current_user
+      if project.team.member?(current_user.id)
+        snippets
+      else
+        snippets.public_and_internal
+      end
+    else
+      snippets.are_public
+    end
+  end
+end
diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb
index 8b83b8ff640..deb9c8b4d49 100644
--- a/app/helpers/visibility_level_helper.rb
+++ b/app/helpers/visibility_level_helper.rb
@@ -28,6 +28,23 @@ module VisibilityLevelHelper
     end
   end
 
+  def snippet_visibility_level_description(level)
+    capture_haml do
+      haml_tag :span do
+        case level
+        when Gitlab::VisibilityLevel::PRIVATE
+          haml_concat "The snippet is visible only for me"
+        when Gitlab::VisibilityLevel::INTERNAL
+          haml_concat "The snippet is visible for any logged in user."
+        when Gitlab::VisibilityLevel::PUBLIC
+          haml_concat "The snippet can be accessed"
+          haml_concat "without any"
+          haml_concat "authentication."
+        end
+      end
+    end
+  end
+
   def visibility_level_icon(level)
     case level
     when Gitlab::VisibilityLevel::PRIVATE
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index e065554d3b8..657ee23ae23 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -133,6 +133,10 @@ class ProjectTeam
     max_tm_access(user.id) == Gitlab::Access::MASTER
   end
 
+  def member?(user_id)
+    !!find_tm(user_id)
+  end
+
   def max_tm_access(user_id)
     access = []
     access << project.project_members.find_by(user_id: user_id).try(:access_field)
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index addde2d106a..974c239da5c 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -17,8 +17,9 @@
 
 class Snippet < ActiveRecord::Base
   include Linguist::BlobHelper
+  include Gitlab::VisibilityLevel
 
-  default_value_for :private, true
+  default_value_for :visibility_level, Snippet::PRIVATE
 
   belongs_to :author, class_name: "User"
 
@@ -30,10 +31,13 @@ class Snippet < ActiveRecord::Base
   validates :title, presence: true, length: { within: 0..255 }
   validates :file_name, presence: true, length: { within: 0..255 }
   validates :content, presence: true
+  validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values }
 
   # Scopes
-  scope :are_internal,  -> { where(private: false) }
-  scope :are_private, -> { where(private: true) }
+  scope :are_internal,  -> { where(visibility_level: Snippet::INTERNAL) }
+  scope :are_private, -> { where(visibility_level: Snippet::PRIVATE) }
+  scope :are_public, -> { where(visibility_level: Snippet::PUBLIC) }
+  scope :public_and_internal, -> { where(visibility_level: [Snippet::PUBLIC, Snippet::INTERNAL]) }
   scope :fresh,   -> { order("created_at DESC") }
   scope :expired, -> { where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) }
   scope :non_expired, -> { where(["expires_at IS NULL OR expires_at > ?", Time.current]) }
@@ -66,6 +70,10 @@ class Snippet < ActiveRecord::Base
     expires_at && expires_at < Time.current
   end
 
+  def visibility_level_field
+    visibility_level
+  end 
+
   class << self
     def search(query)
       where('(title LIKE :query OR file_name LIKE :query)', query: "%#{query}%")
@@ -76,7 +84,7 @@ class Snippet < ActiveRecord::Base
     end
 
     def accessible_to(user)
-      where('private = ? OR author_id = ?', false, user)
+      where('visibility_level IN (?) OR author_id = ?', [Snippet::INTERNAL, Snippet::PUBLIC], user)
     end
   end
 end
diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml
index f4d74045f77..f729f129e45 100644
--- a/app/views/shared/snippets/_form.html.haml
+++ b/app/views/shared/snippets/_form.html.haml
@@ -10,22 +10,8 @@
       = f.label :title, class: 'control-label'
       .col-sm-10= f.text_field :title, placeholder: "Example Snippet", class: 'form-control', required: true
 
-    - unless @snippet.respond_to?(:project)
-      .form-group
-        = f.label "Access", class: 'control-label'
-        .col-sm-10
-          = f.label :private_true, class: 'radio-label' do
-            = f.radio_button :private, true
-            %span
-              %strong Private
-              (only you can see this snippet)
-          %br
-          = f.label :private_false, class: 'radio-label' do
-            = f.radio_button :private, false
-            %span
-              %strong Internal
-              (GitLab users can see this snippet)
-
+    = render "shared/snippets/visibility_level", f: f, visibility_level: gitlab_config.default_projects_features.visibility_level, can_change_visibility_level: true
+    
     .form-group
       .file-editor
         = f.label :file_name, "File", class: 'control-label'
diff --git a/app/views/shared/snippets/_visibility_level.html.haml b/app/views/shared/snippets/_visibility_level.html.haml
new file mode 100644
index 00000000000..9acff18e450
--- /dev/null
+++ b/app/views/shared/snippets/_visibility_level.html.haml
@@ -0,0 +1,27 @@
+.form-group.project-visibility-level-holder
+  = f.label :visibility_level, class: 'control-label' do
+    Visibility Level
+    = link_to "(?)", help_page_path("public_access", "public_access")
+  .col-sm-10
+    - if can_change_visibility_level
+      - Gitlab::VisibilityLevel.values.each do |level|
+        .radio
+          - restricted = restricted_visibility_levels.include?(level)
+          = f.radio_button :visibility_level, level, disabled: restricted
+          = label "#{dom_class(@snippet)}_visibility_level", level do
+            = visibility_level_icon(level)
+            .option-title
+              = visibility_level_label(level)
+            .option-descr
+              = snippet_visibility_level_description(level)
+      - unless restricted_visibility_levels.empty?
+        .col-sm-10
+          %span.info
+            Some visibility level settings have been restricted by the administrator.
+    - else
+      .col-sm-10
+        %span.info
+          = visibility_level_icon(visibility_level)
+          %strong
+            = visibility_level_label(visibility_level)
+          .light= visibility_level_description(visibility_level)
diff --git a/app/views/snippets/current_user_index.html.haml b/app/views/snippets/current_user_index.html.haml
index 14b5b072ec2..b2b7ea4df0e 100644
--- a/app/views/snippets/current_user_index.html.haml
+++ b/app/views/snippets/current_user_index.html.haml
@@ -28,6 +28,11 @@
           Internal
           %span.pull-right
             = @user.snippets.are_internal.count
+      = nav_tab :scope, 'are_public' do
+        = link_to user_snippets_path(@user, scope: 'are_public') do
+          Public
+          %span.pull-right
+            = @user.snippets.are_public.count
 
   .col-md-9.my-snippets
     = render 'snippets'
diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml
index cea2517a8e1..0d71c41e2e7 100644
--- a/app/views/snippets/index.html.haml
+++ b/app/views/snippets/index.html.haml
@@ -2,10 +2,12 @@
   Public snippets
 
   .pull-right
-    = link_to new_snippet_path, class: "btn btn-new btn-grouped", title: "New Snippet" do
-      Add new snippet
-    = link_to user_snippets_path(current_user), class: "btn btn-grouped"  do
-      My snippets
+    
+    - if current_user
+      = link_to new_snippet_path, class: "btn btn-new btn-grouped", title: "New Snippet" do
+        Add new snippet
+      = link_to user_snippets_path(current_user), class: "btn btn-grouped"  do
+        My snippets
 
 %p.light
   Public snippets created by you and other users are listed here
diff --git a/app/views/snippets/user_index.html.haml b/app/views/snippets/user_index.html.haml
index 1cb53ec6a25..67f3a68aa22 100644
--- a/app/views/snippets/user_index.html.haml
+++ b/app/views/snippets/user_index.html.haml
@@ -4,8 +4,9 @@
   %span
     \/
     Snippets
-  = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do
-    Add new snippet
+  - if current_user
+    = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do
+      Add new snippet
 
 %hr
 
diff --git a/db/migrate/20141007100818_add_visibility_level_to_snippet.rb b/db/migrate/20141007100818_add_visibility_level_to_snippet.rb
new file mode 100644
index 00000000000..7f125acb5d1
--- /dev/null
+++ b/db/migrate/20141007100818_add_visibility_level_to_snippet.rb
@@ -0,0 +1,21 @@
+class AddVisibilityLevelToSnippet < ActiveRecord::Migration
+  def up
+    add_column :snippets, :visibility_level, :integer, :default => 0, :null => false
+
+    Snippet.where(private: true).update_all(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+    Snippet.where(private: false).update_all(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
+
+    add_index :snippets, :visibility_level
+
+    remove_column :snippets, :private
+  end
+
+  def down
+    add_column :snippets, :private, :boolean, :default => false, :null => false
+    
+    Snippet.where(visibility_level: Gitlab::VisibilityLevel::INTERNAL).update_all(private: false)
+    Snippet.where(visibility_level: Gitlab::VisibilityLevel::PRIVATE).update_all(private: true)
+    
+    remove_column :snippets, :visibility_level
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 84fd1256677..8ddebc5132a 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20141006143943) do
+ActiveRecord::Schema.define(version: 20141007100818) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -293,20 +293,21 @@ ActiveRecord::Schema.define(version: 20141006143943) do
   create_table "snippets", force: true do |t|
     t.string   "title"
     t.text     "content"
-    t.integer  "author_id",                 null: false
+    t.integer  "author_id",                    null: false
     t.integer  "project_id"
     t.datetime "created_at"
     t.datetime "updated_at"
     t.string   "file_name"
     t.datetime "expires_at"
-    t.boolean  "private",    default: true, null: false
     t.string   "type"
+    t.integer  "visibility_level", default: 0, null: false
   end
 
   add_index "snippets", ["author_id"], name: "index_snippets_on_author_id", using: :btree
   add_index "snippets", ["created_at"], name: "index_snippets_on_created_at", using: :btree
   add_index "snippets", ["expires_at"], name: "index_snippets_on_expires_at", using: :btree
   add_index "snippets", ["project_id"], name: "index_snippets_on_project_id", using: :btree
+  add_index "snippets", ["visibility_level"], name: "index_snippets_on_visibility_level", using: :btree
 
   create_table "taggings", force: true do |t|
     t.integer  "tag_id"
diff --git a/features/snippets/discover.feature b/features/snippets/discover.feature
index 5094062c8c3..1a7e132ea25 100644
--- a/features/snippets/discover.feature
+++ b/features/snippets/discover.feature
@@ -4,8 +4,10 @@ Feature: Snippets Discover
     Given I sign in as a user
     And I have public "Personal snippet one" snippet
     And I have private "Personal snippet private" snippet
+    And I have internal "Personal snippet internal" snippet
 
   Scenario: I should see snippets
     Given I visit snippets page
     Then I should see "Personal snippet one" in snippets
+    And I should see "Personal snippet internal" in snippets
     And I should not see "Personal snippet private" in snippets
diff --git a/features/snippets/user.feature b/features/snippets/user.feature
index ae34e8e7ffa..5b5dadb7b39 100644
--- a/features/snippets/user.feature
+++ b/features/snippets/user.feature
@@ -4,20 +4,31 @@ Feature: Snippets User
     Given I sign in as a user
     And I have public "Personal snippet one" snippet
     And I have private "Personal snippet private" snippet
+    And I have internal "Personal snippet internal" snippet
 
   Scenario: I should see all my snippets
     Given I visit my snippets page
     Then I should see "Personal snippet one" in snippets
     And I should see "Personal snippet private" in snippets
+    And I should see "Personal snippet internal" in snippets
 
   Scenario: I can see only my private snippets
     Given I visit my snippets page
     And I click "Private" filter
     Then I should not see "Personal snippet one" in snippets
+    And I should not see "Personal snippet internal" in snippets
     And I should see "Personal snippet private" in snippets
 
   Scenario: I can see only my public snippets
     Given I visit my snippets page
-    And I click "Internal" filter
+    And I click "Public" filter
     Then I should see "Personal snippet one" in snippets
     And I should not see "Personal snippet private" in snippets
+    And I should not see "Personal snippet internal" in snippets
+
+  Scenario: I can see only my internal snippets
+    Given I visit my snippets page
+    And I click "Internal" filter
+    Then I should see "Personal snippet internal" in snippets
+    And I should not see "Personal snippet private" in snippets
+    And I should not see "Personal snippet one" in snippets
diff --git a/features/steps/shared/snippet.rb b/features/steps/shared/snippet.rb
index 5a27e8750cf..432f32defce 100644
--- a/features/steps/shared/snippet.rb
+++ b/features/steps/shared/snippet.rb
@@ -6,7 +6,7 @@ module SharedSnippet
            title: "Personal snippet one",
            content: "Test content",
            file_name: "snippet.rb",
-           private: false,
+           visibility_level: Snippet::PUBLIC,
            author: current_user)
   end
 
@@ -15,9 +15,19 @@ module SharedSnippet
            title: "Personal snippet private",
            content: "Provate content",
            file_name: "private_snippet.rb",
-           private: true,
+           visibility_level: Snippet::PRIVATE,
            author: current_user)
   end
+  
+  step 'I have internal "Personal snippet internal" snippet' do
+    create(:personal_snippet,
+           title: "Personal snippet internal",
+           content: "Provate content",
+           file_name: "internal_snippet.rb",
+           visibility_level: Snippet::INTERNAL,
+           author: current_user)
+  end
+  
   step 'I have a public many lined snippet' do
     create(:personal_snippet,
            title: 'Many lined snippet',
@@ -38,7 +48,7 @@ module SharedSnippet
              |line fourteen
            END
            file_name: 'many_lined_snippet.rb',
-           private: true,
+           visibility_level: Snippet::PUBLIC,
            author: current_user)
   end
 end
diff --git a/features/steps/snippets/discover.rb b/features/steps/snippets/discover.rb
index 42bccafcc84..2667c1e3d44 100644
--- a/features/steps/snippets/discover.rb
+++ b/features/steps/snippets/discover.rb
@@ -7,6 +7,10 @@ class Spinach::Features::SnippetsDiscover < Spinach::FeatureSteps
     page.should have_content "Personal snippet one"
   end
 
+  step 'I should see "Personal snippet internal" in snippets' do
+    page.should have_content "Personal snippet internal"
+  end
+
   step 'I should not see "Personal snippet private" in snippets' do
     page.should_not have_content "Personal snippet private"
   end
diff --git a/features/steps/snippets/user.rb b/features/steps/snippets/user.rb
index c41bc436142..866f637ab6c 100644
--- a/features/steps/snippets/user.rb
+++ b/features/steps/snippets/user.rb
@@ -15,6 +15,10 @@ class Spinach::Features::SnippetsUser < Spinach::FeatureSteps
     page.should have_content "Personal snippet private"
   end
 
+  step 'I should see "Personal snippet internal" in snippets' do
+    page.should have_content "Personal snippet internal"
+  end
+
   step 'I should not see "Personal snippet one" in snippets' do
     page.should_not have_content "Personal snippet one"
   end
@@ -23,6 +27,10 @@ class Spinach::Features::SnippetsUser < Spinach::FeatureSteps
     page.should_not have_content "Personal snippet private"
   end
 
+  step 'I should not see "Personal snippet internal" in snippets' do
+    page.should_not have_content "Personal snippet internal"
+  end
+
   step 'I click "Internal" filter' do
     within('.nav-stacked') do
       click_link "Internal"
@@ -35,6 +43,12 @@ class Spinach::Features::SnippetsUser < Spinach::FeatureSteps
     end
   end
 
+  step 'I click "Public" filter' do
+    within('.nav-stacked') do
+      click_link "Public"
+    end
+  end
+
   def snippet
     @snippet ||= PersonalSnippet.find_by!(title: "Personal snippet one")
   end
diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb
new file mode 100644
index 00000000000..5af76968183
--- /dev/null
+++ b/spec/finders/snippets_finder_spec.rb
@@ -0,0 +1,94 @@
+require 'spec_helper'
+
+describe SnippetsFinder do
+  let(:user) { create :user }
+  let(:user1) { create :user }
+  let(:group) { create :group }
+
+  let(:project1) { create(:empty_project, :public,   group: group) }
+  let(:project2) { create(:empty_project, :private,  group: group) }
+  
+
+  context ':all filter' do
+    before do
+      @snippet1 = create(:personal_snippet, visibility_level: Snippet::PRIVATE)
+      @snippet2 = create(:personal_snippet, visibility_level: Snippet::INTERNAL)
+      @snippet3 = create(:personal_snippet, visibility_level: Snippet::PUBLIC)
+    end
+
+    it "returns all private and internal snippets" do
+      snippets = SnippetsFinder.new.execute(user, filter: :all)
+      snippets.should include(@snippet2, @snippet3)
+      snippets.should_not include(@snippet1)
+    end
+
+    it "returns all public snippets" do
+      snippets = SnippetsFinder.new.execute(nil, filter: :all)
+      snippets.should include(@snippet3)
+      snippets.should_not include(@snippet1, @snippet2)
+    end
+  end
+
+  context ':by_user filter' do
+    before do
+      @snippet1 = create(:personal_snippet, visibility_level: Snippet::PRIVATE, author: user)
+      @snippet2 = create(:personal_snippet, visibility_level: Snippet::INTERNAL, author: user)
+      @snippet3 = create(:personal_snippet, visibility_level: Snippet::PUBLIC, author: user)
+    end
+
+    it "returns all public and internal snippets" do
+      snippets = SnippetsFinder.new.execute(user1, filter: :by_user, user: user)
+      snippets.should include(@snippet2, @snippet3)
+      snippets.should_not include(@snippet1)
+    end
+
+    it "returns internal snippets" do
+      snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_internal")
+      snippets.should include(@snippet2)
+      snippets.should_not include(@snippet1, @snippet3)
+    end
+
+    it "returns private snippets" do
+      snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_private")
+      snippets.should include(@snippet1)
+      snippets.should_not include(@snippet2, @snippet3)
+    end
+
+    it "returns public snippets" do
+      snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_public")
+      snippets.should include(@snippet3)
+      snippets.should_not include(@snippet1, @snippet2)
+    end
+
+    it "returns all snippets" do
+      snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user)
+      snippets.should include(@snippet1, @snippet2, @snippet3)
+    end
+  end
+
+  context 'by_project filter' do
+    before do
+      @snippet1 = create(:project_snippet, visibility_level: Snippet::PRIVATE, project: project1)
+      @snippet2 = create(:project_snippet, visibility_level: Snippet::INTERNAL, project: project1)
+      @snippet3 = create(:project_snippet, visibility_level: Snippet::PUBLIC, project: project1)
+    end
+
+    it "returns public snippets for unauthorized user" do
+      snippets = SnippetsFinder.new.execute(nil, filter: :by_project, project: project1)
+      snippets.should include(@snippet3)
+      snippets.should_not include(@snippet1, @snippet2)
+    end
+
+    it "returns public and internal snippets for none project members" do
+      snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
+      snippets.should include(@snippet2, @snippet3)
+      snippets.should_not include(@snippet1)
+    end
+
+    it "returns all snippets for project members" do
+      project1.team << [user, :developer] 
+      snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
+      snippets.should include(@snippet1, @snippet2, @snippet3)
+    end
+  end
+end
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 34c1a686c96..bbf50b654f4 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -27,6 +27,8 @@ describe ProjectTeam do
       it { project.team.master?(guest).should be_false }
       it { project.team.master?(reporter).should be_false }
       it { project.team.master?(nonmember).should be_false }
+      it { project.team.member?(nonmember).should be_false }
+      it { project.team.member?(guest).should be_true }
     end
   end
 
@@ -60,6 +62,8 @@ describe ProjectTeam do
       it { project.team.master?(guest).should be_true }
       it { project.team.master?(reporter).should be_false }
       it { project.team.master?(nonmember).should be_false }
+      it { project.team.member?(nonmember).should be_false }
+      it { project.team.member?(guest).should be_true }
     end
   end
 end
-- 
GitLab