diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 7e4776d2d753d7a1f215e2f2e1f44cc29f2dae33..86e4a7cbd6b9d15d88f33ad2ecc69caad22d8866 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -1,11 +1,4 @@
 class Projects::ApplicationController < ApplicationController
-
-  before_filter :authorize_admin_team_member!
-
-  protected
-
-  def user_team
-    @team ||= UserTeam.find_by_path(params[:id])
-  end
-
+  before_filter :project
+  before_filter :repository
 end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1165fa1c583a2734f6225b6807b6c2c6ca49e813
--- /dev/null
+++ b/app/controllers/projects/snippets_controller.rb
@@ -0,0 +1,91 @@
+class Projects::SnippetsController < Projects::ApplicationController
+  before_filter :module_enabled
+  before_filter :snippet, only: [:show, :edit, :destroy, :update, :raw]
+
+  # Allow read any snippet
+  before_filter :authorize_read_project_snippet!
+
+  # Allow write(create) snippet
+  before_filter :authorize_write_project_snippet!, only: [:new, :create]
+
+  # Allow modify snippet
+  before_filter :authorize_modify_project_snippet!, only: [:edit, :update]
+
+  # Allow destroy snippet
+  before_filter :authorize_admin_project_snippet!, only: [:destroy]
+
+  layout 'project_resource'
+
+  respond_to :html
+
+  def index
+    @snippets = @project.snippets.fresh.non_expired
+  end
+
+  def new
+    @snippet = @project.snippets.build
+  end
+
+  def create
+    @snippet = @project.snippets.build(params[:project_snippet])
+    @snippet.author = current_user
+
+    if @snippet.save
+      redirect_to project_snippet_path(@project, @snippet)
+    else
+      respond_with(@snippet)
+    end
+  end
+
+  def edit
+  end
+
+  def update
+    if @snippet.update_attributes(params[:project_snippet])
+      redirect_to project_snippet_path(@project, @snippet)
+    else
+      respond_with(@snippet)
+    end
+  end
+
+  def show
+    @note = @project.notes.new(noteable: @snippet)
+    @target_type = :snippet
+    @target_id = @snippet.id
+  end
+
+  def destroy
+    return access_denied! unless can?(current_user, :admin_project_snippet, @snippet)
+
+    @snippet.destroy
+
+    redirect_to project_snippets_path(@project)
+  end
+
+  def raw
+    send_data(
+      @snippet.content,
+      type: "text/plain",
+      disposition: 'inline',
+      filename: @snippet.file_name
+    )
+  end
+
+  protected
+
+  def snippet
+    @snippet ||= @project.snippets.find(params[:id])
+  end
+
+  def authorize_modify_project_snippet!
+    return render_404 unless can?(current_user, :modify_project_snippet, @snippet)
+  end
+
+  def authorize_admin_project_snippet!
+    return render_404 unless can?(current_user, :admin_project_snippet, @snippet)
+  end
+
+  def module_enabled
+    return render_404 unless @project.snippets_enabled
+  end
+end
diff --git a/app/controllers/projects/teams_controller.rb b/app/controllers/projects/teams_controller.rb
index 17e7367364a43019bfa8f64e9d65fa5dbc5e4f95..c7d51b84fc4c19714ed548e09a7fb8d6684785df 100644
--- a/app/controllers/projects/teams_controller.rb
+++ b/app/controllers/projects/teams_controller.rb
@@ -1,5 +1,7 @@
 class Projects::TeamsController < Projects::ApplicationController
 
+  before_filter :authorize_admin_team_member!
+
   def available
     @teams = current_user.is_admin? ? UserTeam.scoped : current_user.user_teams
     @teams = @teams.without_project(project)
@@ -24,4 +26,9 @@ def resign
     redirect_to project_team_index_path(project)
   end
 
+  protected
+
+  def user_team
+    @team ||= UserTeam.find_by_path(params[:id])
+  end
 end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index a2e22a670a31ed44910c6b11edc0e72daf154a5d..70525beea1507b6845589788b3ca3ec104ef8e29 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -1,13 +1,6 @@
-class SnippetsController < ProjectResourceController
-  before_filter :module_enabled
+class SnippetsController < ApplicationController
   before_filter :snippet, only: [:show, :edit, :destroy, :update, :raw]
 
-  # Allow read any snippet
-  before_filter :authorize_read_snippet!
-
-  # Allow write(create) snippet
-  before_filter :authorize_write_snippet!, only: [:new, :create]
-
   # Allow modify snippet
   before_filter :authorize_modify_snippet!, only: [:edit, :update]
 
@@ -17,22 +10,38 @@ class SnippetsController < ProjectResourceController
   respond_to :html
 
   def index
-    @snippets = @project.snippets.fresh.non_expired
+    @snippets = Snippet.public.fresh.non_expired.page(params[:page]).per(20)
+  end
+
+  def user_index
+    @user = User.find_by_username(params[:username])
+
+    @snippets = @current_user.snippets.fresh.non_expired
+
+    @snippets = case params[:scope]
+                when 'public' then
+                  @snippets.public
+                when 'private' then
+                  @snippets.private
+                else
+                  @snippets
+                end
+
+    @snippets = @snippets.page(params[:page]).per(20)
   end
 
   def new
-    @snippet = @project.snippets.new
+    @snippet = PersonalSnippet.new
   end
 
   def create
-    @snippet = @project.snippets.new(params[:snippet])
+    @snippet = PersonalSnippet.new(params[:personal_snippet])
     @snippet.author = current_user
-    @snippet.save
 
-    if @snippet.valid?
-      redirect_to [@project, @snippet]
+    if @snippet.save
+      redirect_to snippet_path(@snippet)
     else
-      respond_with(@snippet)
+      respond_with @snippet
     end
   end
 
@@ -40,27 +49,22 @@ def edit
   end
 
   def update
-    @snippet.update_attributes(params[:snippet])
-
-    if @snippet.valid?
-      redirect_to [@project, @snippet]
+    if @snippet.update_attributes(params[:personal_snippet])
+      redirect_to snippet_path(@snippet)
     else
-      respond_with(@snippet)
+      respond_with @snippet
     end
   end
 
   def show
-    @note = @project.notes.new(noteable: @snippet)
-    @target_type = :snippet
-    @target_id = @snippet.id
   end
 
   def destroy
-    return access_denied! unless can?(current_user, :admin_snippet, @snippet)
+    return access_denied! unless can?(current_user, :admin_personal_snippet, @snippet)
 
     @snippet.destroy
 
-    redirect_to project_snippets_path(@project)
+    redirect_to snippets_path
   end
 
   def raw
@@ -75,18 +79,14 @@ def raw
   protected
 
   def snippet
-    @snippet ||= @project.snippets.find(params[:id])
+    @snippet ||= PersonalSnippet.find(params[:id])
   end
 
   def authorize_modify_snippet!
-    return render_404 unless can?(current_user, :modify_snippet, @snippet)
+    return render_404 unless can?(current_user, :modify_personal_snippet, @snippet)
   end
 
   def authorize_admin_snippet!
-    return render_404 unless can?(current_user, :admin_snippet, @snippet)
-  end
-
-  def module_enabled
-    return render_404 unless @project.snippets_enabled
+    return render_404 unless can?(current_user, :admin_personal_snippet, @snippet)
   end
 end
diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb
index d2be4b1a7e6efa0f099db2b6ffde2f6d381ef914..19aba0f5f6da6eae60328a3ef8e23b74884d91b8 100644
--- a/app/helpers/tab_helper.rb
+++ b/app/helpers/tab_helper.rb
@@ -73,7 +73,7 @@ def nav_link(options = {}, &block)
   end
 
   def project_tab_class
-    return "active" if current_page?(controller: "projects", action: :edit, id: @project)
+    return "active" if current_page?(controller: "/projects", action: :edit, id: @project)
 
     if ['services', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name
      "active"
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 8f0a6141b7500b73ca206f65728ec469bf5e9159..3e781839d57d7aa3293ed4f5dbdbe4ee20ed3092 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -7,7 +7,8 @@ def allowed(user, subject)
       when "Project" then project_abilities(user, subject)
       when "Issue" then issue_abilities(user, subject)
       when "Note" then note_abilities(user, subject)
-      when "Snippet" then snippet_abilities(user, subject)
+      when "ProjectSnippet" then project_snippet_abilities(user, subject)
+      when "PersonalSnippet" then personal_snippet_abilities(user, subject)
       when "MergeRequest" then merge_request_abilities(user, subject)
       when "Group", "Namespace" then group_abilities(user, subject)
       when "UserTeam" then user_team_abilities(user, subject)
@@ -54,7 +55,7 @@ def project_guest_rules
         :read_wiki,
         :read_issue,
         :read_milestone,
-        :read_snippet,
+        :read_project_snippet,
         :read_team_member,
         :read_merge_request,
         :read_note,
@@ -67,8 +68,8 @@ def project_guest_rules
     def project_report_rules
       project_guest_rules + [
         :download_code,
-        :write_snippet,
-        :fork_project
+        :fork_project,
+        :write_project_snippet
       ]
     end
 
@@ -84,11 +85,11 @@ def project_master_rules
       project_dev_rules + [
         :push_code_to_protected_branches,
         :modify_issue,
-        :modify_snippet,
+        :modify_project_snippet,
         :modify_merge_request,
         :admin_issue,
         :admin_milestone,
-        :admin_snippet,
+        :admin_project_snippet,
         :admin_team_member,
         :admin_merge_request,
         :admin_note,
@@ -135,8 +136,7 @@ def user_team_abilities user, team
       rules.flatten
     end
 
-
-    [:issue, :note, :snippet, :merge_request].each do |name|
+    [:issue, :note, :project_snippet, :personal_snippet, :merge_request].each do |name|
       define_method "#{name}_abilities" do |user, subject|
         if subject.author == user
           [
diff --git a/app/models/event.rb b/app/models/event.rb
index 97f96ac8f9e5cfd880ef621c6975b6e976a5a453..4b75087dc2a9198e8cfc404e0c19d2861b190b15 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -241,6 +241,10 @@ def note_commit?
     target.noteable_type == "Commit"
   end
 
+  def note_project_snippet?
+    target.noteable_type == "Snippet"
+  end
+
   def note_target
     target.noteable
   end
diff --git a/app/models/note.rb b/app/models/note.rb
index 7b7e6e99df4b553e6cc014b9d8404a5fbfc5d168..9a3481faaaa4cdee0599fa7a4b8b3df2de563ca7 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -159,4 +159,10 @@ def noteable_type_name
       "wall"
     end
   end
+
+  # FIXME: Hack for polymorphic associations with STI
+  #        For more information wisit http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Polymorphic+Associations
+  def noteable_type=(sType)
+    super(sType.to_s.classify.constantize.base_class.to_s)
+  end
 end
diff --git a/app/models/personal_snippet.rb b/app/models/personal_snippet.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d581c6092aa1271719dcf1eb280d970fc0d40ca2
--- /dev/null
+++ b/app/models/personal_snippet.rb
@@ -0,0 +1,18 @@
+# == Schema Information
+#
+# Table name: snippets
+#
+#  id         :integer          not null, primary key
+#  title      :string(255)
+#  content    :text
+#  author_id  :integer          not null
+#  project_id :integer          not null
+#  created_at :datetime         not null
+#  updated_at :datetime         not null
+#  file_name  :string(255)
+#  expires_at :datetime
+#  type       :string(255)
+#  private    :boolean
+
+class PersonalSnippet < Snippet
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index 9147aed3d40854c6f02325bb7f480e5b74cd6d66..8cb290f6601aa94bdea671324ec717e88c2e7eca 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -57,7 +57,7 @@ class Project < ActiveRecord::Base
   has_many :milestones,         dependent: :destroy
   has_many :users_projects,     dependent: :destroy
   has_many :notes,              dependent: :destroy
-  has_many :snippets,           dependent: :destroy
+  has_many :snippets,           dependent: :destroy, class_name: "ProjectSnippet"
   has_many :hooks,              dependent: :destroy, class_name: "ProjectHook"
   has_many :protected_branches, dependent: :destroy
   has_many :user_team_project_relationships, dependent: :destroy
diff --git a/app/models/project_snippet.rb b/app/models/project_snippet.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a86f2e7a32fb95970d93fc2cdc6f8bb4a120c4c2
--- /dev/null
+++ b/app/models/project_snippet.rb
@@ -0,0 +1,27 @@
+# == Schema Information
+#
+# Table name: snippets
+#
+#  id         :integer          not null, primary key
+#  title      :string(255)
+#  content    :text
+#  author_id  :integer          not null
+#  project_id :integer          not null
+#  created_at :datetime         not null
+#  updated_at :datetime         not null
+#  file_name  :string(255)
+#  expires_at :datetime
+#  type       :string(255)
+#  private    :boolean
+
+class ProjectSnippet < Snippet
+  belongs_to :project
+  belongs_to :author, class_name: "User"
+
+  validates :project, presence: true
+
+  # Scopes
+  scope :fresh, -> { order("created_at DESC") }
+  scope :non_expired, -> { where(["expires_at IS NULL OR expires_at > ?", Time.current]) }
+  scope :expired, -> { where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) }
+end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index c4ee35e055696f1df901ae5a27364b2386b8c077..1b37ffe83392c8dcb004e8132ec1d4246fde39a3 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -11,29 +11,31 @@
 #  updated_at :datetime         not null
 #  file_name  :string(255)
 #  expires_at :datetime
-#
+#  type       :string(255)
+#  private    :boolean
 
 class Snippet < ActiveRecord::Base
   include Linguist::BlobHelper
 
-  attr_accessible :title, :content, :file_name, :expires_at
+  attr_accessible :title, :content, :file_name, :expires_at, :private
 
-  belongs_to :project
   belongs_to :author, class_name: "User"
+
   has_many :notes, as: :noteable, dependent: :destroy
 
   delegate :name, :email, to: :author, prefix: true, allow_nil: true
 
   validates :author, presence: true
-  validates :project, presence: true
   validates :title, presence: true, length: { within: 0..255 }
   validates :file_name, presence: true, length: { within: 0..255 }
   validates :content, presence: true
 
   # Scopes
-  scope :fresh, -> { order("created_at DESC") }
-  scope :non_expired, -> { where(["expires_at IS NULL OR expires_at > ?", Time.current]) }
+  scope :public,  -> { where(private: false) }
+  scope :private, -> { where(private: true) }
+  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]) }
 
   def self.content_types
     [
diff --git a/app/models/user.rb b/app/models/user.rb
index 82a49c8dcca9af65b4f6bbec22f859c9f6d9d54c..0aed0ada7570054e75e892f25cac5e8485687841 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -78,6 +78,7 @@ class User < ActiveRecord::Base
   has_many :team_projects,                   through: :user_team_project_relationships
 
   # Projects
+  has_many :snippets,                 dependent: :destroy, foreign_key: :author_id, class_name: "Snippet"
   has_many :users_projects,           dependent: :destroy
   has_many :issues,                   dependent: :destroy, foreign_key: :author_id
   has_many :notes,                    dependent: :destroy, foreign_key: :author_id
diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml
index 8bcfa95ff62a7db737d7aa221443e72b1a52f6b0..81b8ff9bf24536c51cdc5fc88f6c0898b6e9040c 100644
--- a/app/views/events/event/_note.html.haml
+++ b/app/views/events/event/_note.html.haml
@@ -5,6 +5,10 @@
     - if event.note_commit?
       = event.note_target_type
       = link_to event.note_short_commit_id, project_commit_path(event.project, event.note_commit_id), class: "commit_short_id"
+    - if event.note_project_snippet?
+      = link_to project_snippet_path(event.project, event.note_target) do
+        %strong
+          #{event.note_target_type} ##{truncate event.note_target_id}
     - else
       = link_to [event.project, event.note_target] do
         %strong
diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml
index 2ea6c3e46d93385130a2e171e141024281bf0a18..b214d51bc29443305f7822a65cdd005fd41147df 100644
--- a/app/views/layouts/_head_panel.html.haml
+++ b/app/views/layouts/_head_panel.html.haml
@@ -18,6 +18,9 @@
         %li
           = link_to public_root_path, title: "Public area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do
             %i.icon-globe
+        %li
+          = link_to snippets_path, title: "Snippets area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do
+            %i.icon-paste
         - if current_user.is_admin?
           %li
             = link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do
diff --git a/app/views/layouts/snippets.html.haml b/app/views/layouts/snippets.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..147c9d96ce69fea48dc5e43f5fd2598ef4aca1fc
--- /dev/null
+++ b/app/views/layouts/snippets.html.haml
@@ -0,0 +1,23 @@
+!!! 5
+%html{ lang: "en"}
+  = render "layouts/head", title: "Snipepts"
+  %body{class: "#{app_theme} application"}
+    = render "layouts/head_panel", title: "Snippets"
+    = render "layouts/flash"
+    %nav.main-nav
+      .container
+        %ul
+          = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do
+            = link_to root_path, title: "Back to dashboard" do
+              %i.icon-home
+          = nav_link(path: 'snippet#new') do
+            = link_to new_snippet_path do
+              New snippet
+          = nav_link(path: 'snippets#user_index') do
+            = link_to user_snippets_path(@current_user) do
+              My snippets
+          = nav_link(path: 'snippets#index') do
+            = link_to snippets_path do
+              Discover snippets
+    .container
+      .content= yield
diff --git a/app/views/projects/snippets/_blob.html.haml b/app/views/projects/snippets/_blob.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..017a33b34f343fdba99596bf6cdecaff8e8a2ca6
--- /dev/null
+++ b/app/views/projects/snippets/_blob.html.haml
@@ -0,0 +1,12 @@
+.file_holder
+  .file_title
+    %i.icon-file
+    %strong= @snippet.file_name
+    %span.options
+      = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn btn-tiny", target: "_blank"
+  .file_content.code
+    - unless @snippet.content.empty?
+      %div{class: user_color_scheme_class}
+        = raw @snippet.colorize(formatter: :gitlab)
+    - else
+      %p.nothing_here_message Empty file
diff --git a/app/views/projects/snippets/_form.html.haml b/app/views/projects/snippets/_form.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..99a8761daef573d3017b9134b7ffe05967654415
--- /dev/null
+++ b/app/views/projects/snippets/_form.html.haml
@@ -0,0 +1,41 @@
+%h3.page_title
+  = @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}"
+%hr
+.snippet-form-holder
+  = form_for [@project, @snippet], as: :project_snippet, url: url do |f|
+    -if @snippet.errors.any?
+      .alert.alert-error
+        %ul
+          - @snippet.errors.full_messages.each do |msg|
+            %li= msg
+
+    .clearfix
+      = f.label :title
+      .input= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true
+    .clearfix
+      = f.label "Lifetime"
+      .input= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'}
+    .clearfix
+      .file-editor
+        = f.label :file_name, "File"
+        .input
+          .file_holder.snippet
+            .file_title
+              = f.text_field :file_name, placeholder: "example.rb", class: 'snippet-file-name', required: true
+            .file_content.code
+              %pre#editor= @snippet.content
+              = f.hidden_field :content, class: 'snippet-file-content'
+
+    .form-actions
+      = f.submit 'Save', class: "btn-save btn"
+      = link_to "Cancel", project_snippets_path(@project), class: " btn"
+      - unless @snippet.new_record?
+        .pull-right= link_to 'Destroy', project_snippet_path(@project, @snippet), confirm: 'Are you sure?', method: :delete, class: "btn pull-right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}"
+
+
+:javascript
+  var editor = ace.edit("editor");
+  $(".snippet-form-holder form").submit(function(){
+    $(".snippet-file-content").val(editor.getValue());
+  });
+
diff --git a/app/views/projects/snippets/_snippet.html.haml b/app/views/projects/snippets/_snippet.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..a576500c15dd2f6676862d6432d2da0d50a0f71d
--- /dev/null
+++ b/app/views/projects/snippets/_snippet.html.haml
@@ -0,0 +1,13 @@
+%tr
+  %td
+    = image_tag gravatar_icon(snippet.author_email), class: "avatar s24"
+    %a{href: project_snippet_path(snippet.project, snippet)}
+      %strong= truncate(snippet.title, length: 60)
+  %td
+    = snippet.file_name
+  %td
+    %span.cgray
+      - if snippet.expires_at
+        = snippet.expires_at.to_date.to_s(:short)
+      - else
+        Never
diff --git a/app/views/projects/snippets/edit.html.haml b/app/views/projects/snippets/edit.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..e28b7d4937e9cff41b0d996ff6e0af0ab04974db
--- /dev/null
+++ b/app/views/projects/snippets/edit.html.haml
@@ -0,0 +1 @@
+= render "projects/snippets/form", url: project_snippet_path(@project, @snippet)
diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..5971e3ffaac5bc2ff71de792f665f6a70043559a
--- /dev/null
+++ b/app/views/projects/snippets/index.html.haml
@@ -0,0 +1,19 @@
+%h3.page_title
+  Snippets
+  %small share code pastes with others out of git repository
+
+  - if can? current_user, :write_project_snippet, @project
+    = link_to new_project_snippet_path(@project), class: "btn btn-small add_new pull-right", title: "New Snippet" do
+      Add new snippet
+%br
+%table
+  %thead
+    %tr
+      %th Title
+      %th File Name
+      %th Expires At
+  = render partial: "projects/snippets/snippet", collection: @snippets
+  - if @snippets.empty?
+    %tr
+      %td{colspan: 3}
+        %h3.nothing_here_message Nothing here.
diff --git a/app/views/projects/snippets/new.html.haml b/app/views/projects/snippets/new.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..460af34f67605d0d4efc5eeb9cb0a26768b0097e
--- /dev/null
+++ b/app/views/projects/snippets/new.html.haml
@@ -0,0 +1 @@
+= render "projects/snippets/form", url: project_snippets_path(@project, @snippet)
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..db5a721dc456493ed86288cf8ce87036d71addfd
--- /dev/null
+++ b/app/views/projects/snippets/show.html.haml
@@ -0,0 +1,9 @@
+%h3.page_title
+  = @snippet.title
+  %small= @snippet.file_name
+  - if can?(current_user, :admin_project_snippet, @project) || @snippet.author == current_user
+    = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small pull-right", title: 'Edit Snippet'
+
+%br
+%div= render 'projects/snippets/blob'
+%div#notes= render "notes/notes_with_form"
diff --git a/app/views/snippets/_blob.html.haml b/app/views/snippets/_blob.html.haml
index 017a33b34f343fdba99596bf6cdecaff8e8a2ca6..56e62f0d6b31975f01031cc689da96bbc38bf658 100644
--- a/app/views/snippets/_blob.html.haml
+++ b/app/views/snippets/_blob.html.haml
@@ -3,7 +3,7 @@
     %i.icon-file
     %strong= @snippet.file_name
     %span.options
-      = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn btn-tiny", target: "_blank"
+      = link_to "raw", raw_snippet_path(@snippet), class: "btn btn-tiny", target: "_blank"
   .file_content.code
     - unless @snippet.content.empty?
       %div{class: user_color_scheme_class}
diff --git a/app/views/snippets/_form.html.haml b/app/views/snippets/_form.html.haml
index 993a20058c63e6ea46646958da7ab6fc87d41bb2..95e9e0357bc9c233630a8762e43f6f6c6e3d7a1f 100644
--- a/app/views/snippets/_form.html.haml
+++ b/app/views/snippets/_form.html.haml
@@ -2,7 +2,7 @@
   = @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}"
 %hr
 .snippet-form-holder
-  = form_for [@project, @snippet] do |f|
+  = form_for @snippet, as: :personal_snippet, url: url do |f|
     -if @snippet.errors.any?
       .alert.alert-error
         %ul
@@ -12,6 +12,9 @@
     .clearfix
       = f.label :title
       .input= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true
+    .clearfix
+      = f.label "Private?"
+      .input= f.check_box :private, {class: ''}
     .clearfix
       = f.label "Lifetime"
       .input= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'}
@@ -28,9 +31,9 @@
 
     .form-actions
       = f.submit 'Save', class: "btn-save btn"
-      = link_to "Cancel", project_snippets_path(@project), class: " btn"
+      = link_to "Cancel", snippets_path(@project), class: " btn"
       - unless @snippet.new_record?
-        .pull-right= link_to 'Destroy', [@project, @snippet], confirm: 'Removed snippet cannot be restored! Are you sure?', method: :delete, class: "btn pull-right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}"
+        .pull-right= link_to 'Destroy', snippet_path(@snippet), confirm: 'Removed snippet cannot be restored! Are you sure?', method: :delete, class: "btn pull-right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}"
 
 
 :javascript
diff --git a/app/views/snippets/_snippet.html.haml b/app/views/snippets/_snippet.html.haml
index a576500c15dd2f6676862d6432d2da0d50a0f71d..77d9d211d8d891430bb170d522f69e8a38e5fda1 100644
--- a/app/views/snippets/_snippet.html.haml
+++ b/app/views/snippets/_snippet.html.haml
@@ -1,8 +1,16 @@
 %tr
   %td
+    - if snippet.private?
+      %i.icon-lock
+    - else
+      %i.icon-globe
     = image_tag gravatar_icon(snippet.author_email), class: "avatar s24"
-    %a{href: project_snippet_path(snippet.project, snippet)}
-      %strong= truncate(snippet.title, length: 60)
+    - if snippet.project_id?
+      %a{href: project_snippet_path(snippet.project, snippet)}
+        %strong= truncate(snippet.title, length: 60)
+    - else
+      %a{href: snippet_path(snippet)}
+        %strong= truncate(snippet.title, length: 60)
   %td
     = snippet.file_name
   %td
@@ -11,3 +19,6 @@
         = snippet.expires_at.to_date.to_s(:short)
       - else
         Never
+  %td
+    - if snippet.project_id?
+      = link_to snippet.project.name, project_path(snippet.project)
diff --git a/app/views/snippets/_snippets.html.haml b/app/views/snippets/_snippets.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..192cb6aa94a2542f21f267aefac80510bed27c8e
--- /dev/null
+++ b/app/views/snippets/_snippets.html.haml
@@ -0,0 +1,15 @@
+%table
+  %thead
+    %tr
+      %th Title
+      %th File Name
+      %th Expires At
+      %th Project
+
+  = render partial: 'snippet', collection: @snippets
+  - if @snippets.empty?
+    %tr
+      %td{colspan: 4}
+        %h3.nothing_here_message Nothing here.
+
+= paginate @snippets
diff --git a/app/views/snippets/edit.html.haml b/app/views/snippets/edit.html.haml
index f81c0b8bc647a76eda32278b880a9ce6f7890469..1b88a85faf1e4add09fdeb94acd3ca1d14d3029b 100644
--- a/app/views/snippets/edit.html.haml
+++ b/app/views/snippets/edit.html.haml
@@ -1 +1 @@
-= render "snippets/form"
+= render "snippets/form", url: snippet_path(@snippet)
diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml
index bacf23d8f8de33de5858ba58cb32e6c74903919a..97f7b39877e4f7b580402412880d326c69a8e052 100644
--- a/app/views/snippets/index.html.haml
+++ b/app/views/snippets/index.html.haml
@@ -1,19 +1,11 @@
 %h3.page_title
-  Snippets
+  Public snippets
   %small share code pastes with others out of git repository
+  = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do
+    Add new snippet
+
+%hr
+.row
+  .span12
+    = render 'snippets'
 
-  - if can? current_user, :write_snippet, @project
-    = link_to new_project_snippet_path(@project), class: "btn btn-small add_new pull-right", title: "New Snippet" do
-      Add new snippet
-%br
-%table
-  %thead
-    %tr
-      %th Title
-      %th File Name
-      %th Expires At
-  = render @snippets
-  - if @snippets.empty?
-    %tr
-      %td{colspan: 3}
-        %h3.nothing_here_message Nothing here.
diff --git a/app/views/snippets/new.html.haml b/app/views/snippets/new.html.haml
index f81c0b8bc647a76eda32278b880a9ce6f7890469..90e0a1f79dac2414e41861f156fa58f772ca49e6 100644
--- a/app/views/snippets/new.html.haml
+++ b/app/views/snippets/new.html.haml
@@ -1 +1 @@
-= render "snippets/form"
+= render "snippets/form", url: snippets_path(@snippet)
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index 12534edf8ba5b5b556d2b9b8f6e951f88f03aa6c..18348fb10679ecbe87ee24684c001ea68a9dc975 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -1,9 +1,13 @@
 %h3.page_title
+  - if @snippet.private?
+    %i.icon-lock
+  - else
+    %i.icon-globe
+
   = @snippet.title
   %small= @snippet.file_name
-  - if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user
-    = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small pull-right", title: 'Edit Snippet'
+  - if @snippet.author == current_user
+    = link_to "Edit", edit_snippet_path(@snippet), class: "btn btn-small pull-right", title: 'Edit Snippet'
 
 %br
 %div= render 'blob'
-%div#notes= render "notes/notes_with_form"
diff --git a/app/views/snippets/user_index.html.haml b/app/views/snippets/user_index.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..2f2cce26af43bf8296eab9b462bbd1a01284cffc
--- /dev/null
+++ b/app/views/snippets/user_index.html.haml
@@ -0,0 +1,20 @@
+%h3.page_title
+  Snippets by
+  = @user.name
+  %small share code pastes with others out of git repository
+  = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do
+    Add new snippet
+
+%hr
+.row
+  .span3
+    %ul.nav.nav-pills.nav-stacked
+      = nav_tab :scope, nil do
+        = link_to "All", user_snippets_path(@user)
+      = nav_tab :scope, 'private' do
+        = link_to "Private", user_snippets_path(@user, scope: 'private')
+      = nav_tab :scope, 'public' do
+        = link_to "Public", user_snippets_path(@user, scope: 'public')
+
+  .span9
+    = render 'snippets'
diff --git a/config/routes.rb b/config/routes.rb
index 3609ac0189135e63907e8d92cc75c5c25a977c8c..c802c60382dc01789cd7108681930d47dde9fdf4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -38,6 +38,16 @@
   get 'help/web_hooks'      => 'help#web_hooks'
   get 'help/workflow'       => 'help#workflow'
 
+  #
+  # Global snippets
+  #
+  resources :snippets do
+    member do
+      get "raw"
+    end
+  end
+  get "/s/:username" => "snippets#user_index", as: :user_snippets, constraints: { username: /.*/ }
+
   #
   # Public namespace
   #
@@ -182,6 +192,14 @@
     resources :graph,   only: [:show], constraints: {id: /(?:[^.]|\.(?!json$))+/, format: /json/}
     match "/compare/:from...:to" => "compare#show", as: "compare", via: [:get, :post], constraints: {from: /.+/, to: /.+/}
 
+    scope module: :projects do
+      resources :snippets do
+        member do
+          get "raw"
+        end
+      end
+    end
+
     resources :wikis, only: [:show, :edit, :destroy, :create] do
       collection do
         get :pages
@@ -255,19 +273,12 @@
       end
     end
 
-    resources :snippets do
-      member do
-        get "raw"
-      end
-    end
-
     resources :hooks, only: [:index, :create, :destroy] do
       member do
         get :test
       end
     end
 
-
     resources :team, controller: 'team_members', only: [:index]
     resources :milestones, except: [:destroy]
 
diff --git a/db/migrate/20130323174317_add_private_to_snippets.rb b/db/migrate/20130323174317_add_private_to_snippets.rb
new file mode 100644
index 0000000000000000000000000000000000000000..92f3a5c70118f7b4506aa0ac5d0fc63b3955bf78
--- /dev/null
+++ b/db/migrate/20130323174317_add_private_to_snippets.rb
@@ -0,0 +1,5 @@
+class AddPrivateToSnippets < ActiveRecord::Migration
+  def change
+    add_column :snippets, :private, :boolean, null: false, default: true
+  end
+end
diff --git a/db/migrate/20130324151736_add_type_to_snippets.rb b/db/migrate/20130324151736_add_type_to_snippets.rb
new file mode 100644
index 0000000000000000000000000000000000000000..276aab2ca1578e77c1c73e50e685c40f427de2ec
--- /dev/null
+++ b/db/migrate/20130324151736_add_type_to_snippets.rb
@@ -0,0 +1,5 @@
+class AddTypeToSnippets < ActiveRecord::Migration
+  def change
+    add_column :snippets, :type, :string
+  end
+end
diff --git a/db/migrate/20130324172327_change_project_id_to_null_in_snipepts.rb b/db/migrate/20130324172327_change_project_id_to_null_in_snipepts.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4c992bac4d114eb2220ffbf7daccc404ea5e7009
--- /dev/null
+++ b/db/migrate/20130324172327_change_project_id_to_null_in_snipepts.rb
@@ -0,0 +1,9 @@
+class ChangeProjectIdToNullInSnipepts < ActiveRecord::Migration
+  def up
+    change_column :snippets, :project_id, :integer, :null => true
+  end
+
+  def down
+    change_column :snippets, :project_id, :integer, :null => false
+  end
+end
diff --git a/db/migrate/20130324203535_add_type_value_for_snippets.rb b/db/migrate/20130324203535_add_type_value_for_snippets.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8c05dd2cc717946e6352968e219cd121e458e439
--- /dev/null
+++ b/db/migrate/20130324203535_add_type_value_for_snippets.rb
@@ -0,0 +1,8 @@
+class AddTypeValueForSnippets < ActiveRecord::Migration
+  def up
+    Snippet.where("project_id IS NOT NULL").update_all(type: 'ProjectSnippet')
+  end
+
+  def down
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 6a16caf59d85e205ab1674a62016889ad4ad8954..21e553dd612125a5f982fc94cf25f0b73f618fdc 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -203,12 +203,14 @@
   create_table "snippets", :force => true do |t|
     t.string   "title"
     t.text     "content"
-    t.integer  "author_id",  :null => false
-    t.integer  "project_id", :null => false
-    t.datetime "created_at", :null => false
-    t.datetime "updated_at", :null => false
+    t.integer  "author_id",                    :null => false
+    t.integer  "project_id"
+    t.datetime "created_at",                   :null => false
+    t.datetime "updated_at",                   :null => false
     t.string   "file_name"
     t.datetime "expires_at"
+    t.boolean  "private",    :default => true, :null => false
+    t.string   "type"
   end
 
   add_index "snippets", ["created_at"], :name => "index_snippets_on_created_at"
diff --git a/features/project/snippets.feature b/features/project/snippets.feature
new file mode 100644
index 0000000000000000000000000000000000000000..a26c8dc84747f3561666611bd81fb1ae5757319e
--- /dev/null
+++ b/features/project/snippets.feature
@@ -0,0 +1,35 @@
+Feature: Project Snippets
+  Background:
+    Given I sign in as a user
+    And I own project "Shop"
+    And project "Shop" have "Snippet one" snippet
+    And project "Shop" have no "Snippet two" snippet
+    And I visit project "Shop" snippets page
+
+  Scenario: I should see snippets
+    Given I visit project "Shop" snippets page
+    Then I should see "Snippet one" in snippets
+    And I should not see "Snippet two" in snippets
+
+  Scenario: I create new project snippet
+    Given I click link "New Snippet"
+    And I submit new snippet "Snippet three"
+    Then I should see snippet "Snippet three"
+
+  @javascript
+  Scenario: I comment on a snippet "Snippet one"
+    Given I visit snippet page "Snippet one"
+    And I leave a comment like "Good snippet!"
+    Then I should see comment "Good snippet!"
+
+  Scenario: I update "Snippet one"
+    Given I visit snippet page "Snippet one"
+    And I click link "Edit"
+    And I submit new title "Snippet new title"
+    Then I should see "Snippet new title"
+
+  Scenario: I destroy "Snippet one"
+    Given I visit snippet page "Snippet one"
+    And I click link "Edit"
+    And I click link "Destroy"
+    Then I should not see "Snippet one" in snippets
diff --git a/features/snippets/discover_snippets.feature b/features/snippets/discover_snippets.feature
new file mode 100644
index 0000000000000000000000000000000000000000..d6fd2cd7808b4566cccbfd58152da57bd6dbbfa8
--- /dev/null
+++ b/features/snippets/discover_snippets.feature
@@ -0,0 +1,10 @@
+Feature: Discover Snippets
+  Background:
+    Given I sign in as a user
+    And I have public "Personal snippet one" snippet
+    And I have private "Personal snippet private" snippet
+
+  Scenario: I should see snippets
+    Given I visit snippets page
+    Then I should see "Personal snippet one" in snippets
+    And I should not see "Personal snippet private" in snippets
diff --git a/features/snippets/snippets.feature b/features/snippets/snippets.feature
new file mode 100644
index 0000000000000000000000000000000000000000..1119defa17dc63fb0ac46717ac03c4d22603dab2
--- /dev/null
+++ b/features/snippets/snippets.feature
@@ -0,0 +1,28 @@
+Feature: Snippets Feature
+  Background:
+    Given I sign in as a user
+    And I have public "Personal snippet one" snippet
+    And I have private "Personal snippet private" snippet
+
+  Scenario: I create new snippet
+    Given I visit new snippet page
+    And I submit new snippet "Personal snippet three"
+    Then I should see snippet "Personal snippet three"
+
+  Scenario: I update "Personal snippet one"
+    Given I visit snippet page "Personal snippet one"
+    And I click link "Edit"
+    And I submit new title "Personal snippet new title"
+    Then I should see "Personal snippet new title"
+
+  Scenario: Set "Personal snippet one" public
+    Given I visit snippet page "Personal snippet one"
+    And I click link "Edit"
+    And I uncheck "Private" checkbox
+    Then I should see "Personal snippet one" public
+
+  Scenario: I destroy "Personal snippet one"
+    Given I visit snippet page "Personal snippet one"
+    And I click link "Edit"
+    And I click link "Destroy"
+    Then I should not see "Personal snippet one" in snippets
diff --git a/features/snippets/user_snippets.feature b/features/snippets/user_snippets.feature
new file mode 100644
index 0000000000000000000000000000000000000000..4c8a91501c40503b7481359f4a7441bb5b3fc2e0
--- /dev/null
+++ b/features/snippets/user_snippets.feature
@@ -0,0 +1,22 @@
+Feature: User Snippets
+  Background:
+    Given I sign in as a user
+    And I have public "Personal snippet one" snippet
+    And I have private "Personal snippet private" 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
+
+  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 see "Personal snippet private" in snippets
+
+  Scenario: I can see only my public snippets
+    Given I visit my snippets page
+    And I click "Public" filter
+    Then I should see "Personal snippet one" in snippets
+    And I should not see "Personal snippet private" in snippets
diff --git a/features/steps/project/project_snippets.rb b/features/steps/project/project_snippets.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c8580d6fd3099c94e46c042b16196e789bebd8f4
--- /dev/null
+++ b/features/steps/project/project_snippets.rb
@@ -0,0 +1,100 @@
+class ProjectSnippets < Spinach::FeatureSteps
+  include SharedAuthentication
+  include SharedProject
+  include SharedNote
+  include SharedPaths
+
+  And 'project "Shop" have "Snippet one" snippet' do
+    create(:project_snippet,
+           title: "Snippet one",
+           content: "Test content",
+           file_name: "snippet.rb",
+           project: project,
+           author: project.users.first)
+  end
+
+  And 'project "Shop" have no "Snippet two" snippet' do
+    create(:snippet,
+           title: "Snippet two",
+           content: "Test content",
+           file_name: "snippet.rb",
+           author: project.users.first)
+  end
+
+  Given 'I click link "New Snippet"' do
+    click_link "Add new snippet"
+  end
+
+  Given 'I click link "Snippet one"' do
+    click_link "Snippet one"
+  end
+
+  Then 'I should see "Snippet one" in snippets' do
+    page.should have_content "Snippet one"
+  end
+
+  And 'I should not see "Snippet two" in snippets' do
+    page.should_not have_content "Snippet two"
+  end
+
+  And 'I should not see "Snippet one" in snippets' do
+    page.should_not have_content "Snippet one"
+  end
+
+  And 'I click link "Edit"' do
+    within ".page_title" do
+      click_link "Edit"
+    end
+  end
+
+  And 'I click link "Destroy"' do
+    click_link "Destroy"
+  end
+
+  And 'I submit new snippet "Snippet three"' do
+    fill_in "project_snippet_title", :with => "Snippet three"
+    select "forever", :from => "project_snippet_expires_at"
+    fill_in "project_snippet_file_name", :with => "my_snippet.rb"
+    within('.file-editor') do
+      find(:xpath, "//input[@id='project_snippet_content']").set 'Content of snippet three'
+    end
+    click_button "Save"
+  end
+
+  Then 'I should see snippet "Snippet three"' do
+    page.should have_content "Snippet three"
+    page.should have_content "Content of snippet three"
+  end
+
+  And 'I submit new title "Snippet new title"' do
+    fill_in "project_snippet_title", :with => "Snippet new title"
+    click_button "Save"
+  end
+
+  Then 'I should see "Snippet new title"' do
+    page.should have_content "Snippet new title"
+  end
+
+  And 'I leave a comment like "Good snippet!"' do
+    within('.js-main-target-form') do
+      fill_in "note_note", with: "Good snippet!"
+      click_button "Add Comment"
+    end
+  end
+
+  Then 'I should see comment "Good snippet!"' do
+    page.should have_content "Good snippet!"
+  end
+
+  And 'I visit snippet page "Snippet one"' do
+    visit project_snippet_path(project, project_snippet)
+  end
+
+  def project
+    @project ||= Project.find_by_name!("Shop")
+  end
+
+  def project_snippet
+    @project_snippet ||= ProjectSnippet.find_by_title!("Snippet One")
+  end
+end
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index 628a179ae9de9acb02ed265474d682004d91d3ae..3641e78866298661f9a49768c11f50bb0339c1a9 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -275,6 +275,22 @@ module SharedPaths
     visit public_root_path
   end
 
+  # ----------------------------------------
+  # Snippets
+  # ----------------------------------------
+
+  Given 'I visit project "Shop" snippets page' do
+    visit project_snippets_path(project)
+  end
+
+  Given 'I visit snippets page' do
+    visit snippets_path
+  end
+
+  Given 'I visit new snippet page' do
+    visit new_snippet_path
+  end
+
   def root_ref
     @project.repository.root_ref
   end
diff --git a/features/steps/shared/snippet.rb b/features/steps/shared/snippet.rb
new file mode 100644
index 0000000000000000000000000000000000000000..543e43196a5066209cdd72bb00aa13f41871f7af
--- /dev/null
+++ b/features/steps/shared/snippet.rb
@@ -0,0 +1,21 @@
+module SharedSnippet
+  include Spinach::DSL
+
+  And 'I have public "Personal snippet one" snippet' do
+    create(:personal_snippet,
+           title: "Personal snippet one",
+           content: "Test content",
+           file_name: "snippet.rb",
+           private: false,
+           author: current_user)
+  end
+
+  And 'I have private "Personal snippet private" snippet' do
+    create(:personal_snippet,
+           title: "Personal snippet private",
+           content: "Provate content",
+           file_name: "private_snippet.rb",
+           private: true,
+           author: current_user)
+  end
+end
diff --git a/features/steps/snippets/discover_snippets.rb b/features/steps/snippets/discover_snippets.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3afe019adf6db24795b0b73c23445613a0eae59d
--- /dev/null
+++ b/features/steps/snippets/discover_snippets.rb
@@ -0,0 +1,17 @@
+class DiscoverSnippets < Spinach::FeatureSteps
+  include SharedAuthentication
+  include SharedPaths
+  include SharedSnippet
+
+  Then 'I should see "Personal snippet one" in snippets' do
+    page.should have_content "Personal snippet one"
+  end
+
+  And 'I should not see "Personal snippet private" in snippets' do
+    page.should_not have_content "Personal snippet private"
+  end
+
+  def snippet
+    @snippet ||= PersonalSnippet.find_by_title!("Personal snippet one")
+  end
+end
diff --git a/features/steps/snippets/snippets.rb b/features/steps/snippets/snippets.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b185f6057286e5b4e6649f3ddbd1a00443028537
--- /dev/null
+++ b/features/steps/snippets/snippets.rb
@@ -0,0 +1,65 @@
+class SnippetsFeature < Spinach::FeatureSteps
+  include SharedAuthentication
+  include SharedPaths
+  include SharedProject
+  include SharedSnippet
+
+  Given 'I click link "Personal snippet one"' do
+    click_link "Personal snippet one"
+  end
+
+  And 'I should not see "Personal snippet one" in snippets' do
+    page.should_not have_content "Personal snippet one"
+  end
+
+  And 'I click link "Edit"' do
+    within ".page_title" do
+      click_link "Edit"
+    end
+  end
+
+  And 'I click link "Destroy"' do
+    click_link "Destroy"
+  end
+
+  And 'I submit new snippet "Personal snippet three"' do
+    fill_in "personal_snippet_title", :with => "Personal snippet three"
+    select "forever", :from => "personal_snippet_expires_at"
+    fill_in "personal_snippet_file_name", :with => "my_snippet.rb"
+    within('.file-editor') do
+      find(:xpath, "//input[@id='personal_snippet_content']").set 'Content of snippet three'
+    end
+    click_button "Save"
+  end
+
+  Then 'I should see snippet "Personal snippet three"' do
+    page.should have_content "Personal snippet three"
+    page.should have_content "Content of snippet three"
+  end
+
+  And 'I submit new title "Personal snippet new title"' do
+    fill_in "personal_snippet_title", :with => "Personal snippet new title"
+    click_button "Save"
+  end
+
+  Then 'I should see "Personal snippet new title"' do
+    page.should have_content "Personal snippet new title"
+  end
+
+  And 'I uncheck "Private" checkbox' do
+    find(:xpath, "//input[@id='personal_snippet_private']").set true
+    click_button "Save"
+  end
+
+  Then 'I should see "Personal snippet one" public' do
+    page.should have_no_xpath("//i[@class='public-snippet']")
+  end
+
+  And 'I visit snippet page "Personal snippet one"' do
+    visit snippet_path(snippet)
+  end
+
+  def snippet
+    @snippet ||= PersonalSnippet.find_by_title!("Personal snippet one")
+  end
+end
diff --git a/features/steps/snippets/user_snippets.rb b/features/steps/snippets/user_snippets.rb
new file mode 100644
index 0000000000000000000000000000000000000000..15d6da6db3d438172e453751b4e872301358140b
--- /dev/null
+++ b/features/steps/snippets/user_snippets.rb
@@ -0,0 +1,41 @@
+class UserSnippets < Spinach::FeatureSteps
+  include SharedAuthentication
+  include SharedPaths
+  include SharedSnippet
+
+  Given 'I visit my snippets page' do
+    visit user_snippets_path(current_user)
+  end
+
+  Then 'I should see "Personal snippet one" in snippets' do
+    page.should have_content "Personal snippet one"
+  end
+
+  And 'I should see "Personal snippet private" in snippets' do
+    page.should have_content "Personal snippet private"
+  end
+
+  Then 'I should not see "Personal snippet one" in snippets' do
+    page.should_not have_content "Personal snippet one"
+  end
+
+  And 'I should not see "Personal snippet private" in snippets' do
+    page.should_not have_content "Personal snippet private"
+  end
+
+  Given 'I click "Public" filter' do
+    within('.nav-stacked') do
+      click_link "Public"
+    end
+  end
+
+  Given 'I click "Private" filter' do
+    within('.nav-stacked') do
+      click_link "Private"
+    end
+  end
+
+  def snippet
+    @snippet ||= PersonalSnippet.find_by_title!("Personal snippet one")
+  end
+end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 3711057ecaac8fb3b5d46822c3a9c6ccd92bd4c7..8b20a2fcb1435fa992cc146bc78724b625344afa 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -328,7 +328,7 @@ def handle_project_member_errors(errors)
       # Example Request:
       #   POST /projects/:id/snippets
       post ":id/snippets" do
-        authorize! :write_snippet, user_project
+        authorize! :write_project_snippet, user_project
         required_attributes! [:title, :file_name, :code]
 
         attrs = attributes_for_keys [:title, :file_name]
@@ -357,7 +357,7 @@ def handle_project_member_errors(errors)
       #   PUT /projects/:id/snippets/:snippet_id
       put ":id/snippets/:snippet_id" do
         @snippet = user_project.snippets.find(params[:snippet_id])
-        authorize! :modify_snippet, @snippet
+        authorize! :modify_project_snippet, @snippet
 
         attrs = attributes_for_keys [:title, :file_name]
         attrs[:expires_at] = params[:lifetime] if params[:lifetime].present?
@@ -380,7 +380,7 @@ def handle_project_member_errors(errors)
       delete ":id/snippets/:snippet_id" do
         begin
           @snippet = user_project.snippets.find(params[:snippet_id])
-          authorize! :modify_snippet, user_project
+          authorize! :modify_project_snippet, @snippet
           @snippet.destroy
         rescue
         end
diff --git a/spec/factories.rb b/spec/factories.rb
index f9e25382b61be5d784f6506a3ae38d0abfdff420..b596f80fa9ed34db5f84ac73a9714c3e4d66fca6 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -197,7 +197,7 @@
     url
   end
 
-  factory :snippet do
+  factory :project_snippet do
     project
     author
     title
@@ -205,6 +205,20 @@
     file_name
   end
 
+  factory :personal_snippet do
+    author
+    title
+    content
+    file_name
+  end
+
+  factory :snippet do
+    author
+    title
+    content
+    file_name
+  end
+
   factory :protected_branch do
     name
     project
diff --git a/spec/features/snippets_spec.rb b/spec/features/snippets_spec.rb
deleted file mode 100644
index 1a0f6eaeef4b9ef832d0d2a53f1f397de9f49924..0000000000000000000000000000000000000000
--- a/spec/features/snippets_spec.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-require 'spec_helper'
-
-describe "Snippets" do
-  let(:project) { create(:project) }
-
-  before do
-    login_as :user
-    project.team << [@user, :developer]
-  end
-
-  describe "GET /snippets" do
-    before do
-      @snippet = create(:snippet,
-                        author: @user,
-                        project: project)
-
-      visit project_snippets_path(project)
-    end
-
-    subject { page }
-
-    it { should have_content(@snippet.title[0..10]) }
-    it { should have_content(@snippet.project.name) }
-
-    describe "Destroy" do
-      before do
-        # admin access to remove snippet
-        @user.users_projects.destroy_all
-        project.team << [@user, :master]
-        visit edit_project_snippet_path(project, @snippet)
-      end
-
-      it "should remove entry" do
-        expect {
-          click_link "destroy_snippet_#{@snippet.id}"
-        }.to change { Snippet.count }.by(-1)
-      end
-    end
-  end
-
-  describe "New snippet" do
-    before do
-      visit project_snippets_path(project)
-      click_link "New Snippet"
-    end
-
-    it "should open new snippet popup" do
-      page.current_path.should == new_project_snippet_path(project)
-    end
-
-    describe "fill in", js: true do
-      before do
-        fill_in "snippet_title", with: "login function"
-        fill_in "snippet_file_name", with: "test.rb"
-        page.execute_script("editor.insert('def login; end');")
-      end
-
-      it { expect { click_button "Save" }.to change {Snippet.count}.by(1) }
-
-      it "should add new snippet to table" do
-        click_button "Save"
-        page.current_path.should == project_snippet_path(project, Snippet.last)
-        page.should have_content "login function"
-        page.should have_content "test.rb"
-      end
-    end
-  end
-
-  describe "Edit snippet" do
-    before do
-      @snippet = create(:snippet,
-                        author: @user,
-                        project: project)
-      visit project_snippet_path(project, @snippet)
-      click_link "Edit Snippet"
-    end
-
-    it "should open edit page" do
-      page.current_path.should == edit_project_snippet_path(project, @snippet)
-    end
-
-    describe "fill in" do
-      before do
-        fill_in "snippet_title", with: "login function"
-        fill_in "snippet_file_name", with: "test.rb"
-      end
-
-      it { expect { click_button "Save" }.to_not change {Snippet.count} }
-
-      it "should update snippet fields" do
-        click_button "Save"
-
-        page.current_path.should == project_snippet_path(project, @snippet)
-        page.should have_content "login function"
-        page.should have_content "test.rb"
-      end
-    end
-  end
-end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 23b18fbf0ebb2ff678c967ec1d5d034d2c0a7436..0f206f472346a17b039f831f48868e84727b9126 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -10,7 +10,7 @@
   let(:commit)        { project.repository.commit }
   let(:issue)         { create(:issue, project: project) }
   let(:merge_request) { create(:merge_request, project: project) }
-  let(:snippet)       { create(:snippet, project: project) }
+  let(:snippet)       { create(:project_snippet, project: project) }
   let(:member)        { project.users_projects.where(user_id: user).first }
 
   before do
@@ -190,8 +190,43 @@
     describe "referencing a snippet" do
       let(:object)    { snippet }
       let(:reference) { "$#{snippet.id}" }
+      let(:actual)   { "Reference to #{reference}" }
+      let(:expected) { project_snippet_path(project, object) }
+
+      it "should link using a valid id" do
+        gfm(actual).should match(expected)
+      end
+
+      it "should link with adjacent text" do
+        # Wrap the reference in parenthesis
+        gfm(actual.gsub(reference, "(#{reference})")).should match(expected)
+
+        # Append some text to the end of the reference
+        gfm(actual.gsub(reference, "#{reference}, right?")).should match(expected)
+      end
+
+      it "should keep whitespace intact" do
+        actual   = "Referenced #{reference} already."
+        expected = /Referenced <a.+>[^\s]+<\/a> already/
+        gfm(actual).should match(expected)
+      end
+
+      it "should not link with an invalid id" do
+        # Modify the reference string so it's still parsed, but is invalid
+        reference.gsub!(/^(.)(\d+)$/, '\1' + ('\2' * 2))
+        gfm(actual).should == actual
+      end
+
+      it "should include a title attribute" do
+        title = "Snippet: #{object.title}"
+        gfm(actual).should match(/title="#{title}"/)
+      end
+
+      it "should include standard gfm classes" do
+        css = object.class.to_s.underscore
+        gfm(actual).should match(/class="\s?gfm gfm-snippet\s?"/)
+      end
 
-      include_examples 'referenced object'
     end
 
     describe "referencing multiple objects" do
diff --git a/spec/models/project_snippet_spec.rb b/spec/models/project_snippet_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..716fd81c91b42b0e2c82ddbf3c161347f3da0eb7
--- /dev/null
+++ b/spec/models/project_snippet_spec.rb
@@ -0,0 +1,30 @@
+# == Schema Information
+#
+# Table name: snippets
+#
+#  id         :integer          not null, primary key
+#  title      :string(255)
+#  content    :text
+#  author_id  :integer          not null
+#  project_id :integer          not null
+#  created_at :datetime         not null
+#  updated_at :datetime         not null
+#  file_name  :string(255)
+#  expires_at :datetime
+#
+
+require 'spec_helper'
+
+describe ProjectSnippet do
+  describe "Associations" do
+    it { should belong_to(:project) }
+  end
+
+  describe "Mass assignment" do
+    it { should_not allow_mass_assignment_of(:project_id) }
+  end
+
+  describe "Validation" do
+    it { should validate_presence_of(:project) }
+  end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 04b4ce1763e0ba3e31f807d6705d77376319600a..2e3870b1b6557a4947a856919641298f52c6c2f3 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -36,7 +36,7 @@
     it { should have_many(:milestones).dependent(:destroy) }
     it { should have_many(:users_projects).dependent(:destroy) }
     it { should have_many(:notes).dependent(:destroy) }
-    it { should have_many(:snippets).dependent(:destroy) }
+    it { should have_many(:snippets).class_name('ProjectSnippet').dependent(:destroy) }
     it { should have_many(:deploy_keys_projects).dependent(:destroy) }
     it { should have_many(:deploy_keys) }
     it { should have_many(:hooks).dependent(:destroy) }
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index e4d1934829f663f30462cfd5b52445fdd3d80eee..52355c38f0c8b2b8a258e451cd5fc93a64f8edfe 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -17,19 +17,16 @@
 
 describe Snippet do
   describe "Associations" do
-    it { should belong_to(:project) }
     it { should belong_to(:author).class_name('User') }
     it { should have_many(:notes).dependent(:destroy) }
   end
 
   describe "Mass assignment" do
     it { should_not allow_mass_assignment_of(:author_id) }
-    it { should_not allow_mass_assignment_of(:project_id) }
   end
 
   describe "Validation" do
     it { should validate_presence_of(:author) }
-    it { should validate_presence_of(:project) }
 
     it { should validate_presence_of(:title) }
     it { should ensure_length_of(:title).is_within(0..255) }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 7559c4cc3a1b0621904ef4ec7c86ab3d9514d624..9673854da53443538efa1a818b06f642c44f3cef 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -41,6 +41,7 @@
 describe User do
   describe "Associations" do
     it { should have_one(:namespace) }
+    it { should have_many(:snippets).class_name('Snippet').dependent(:destroy) }
     it { should have_many(:users_projects).dependent(:destroy) }
     it { should have_many(:groups) }
     it { should have_many(:keys).dependent(:destroy) }
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 78d55a7b4ed341da50f6dc98ddc69aa0daeb3376..11296aea73e0a0d183ab561b0fd42245ffda0cae 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -7,7 +7,7 @@
   let!(:project) { create(:project, namespace: user.namespace ) }
   let!(:issue) { create(:issue, project: project, author: user) }
   let!(:merge_request) { create(:merge_request, project: project, author: user) }
-  let!(:snippet) { create(:snippet, project: project, author: user) }
+  let!(:snippet) { create(:project_snippet, project: project, author: user) }
   let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) }
   let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
   let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index de0631d5b7068aea7793d9c6db0f722cde130633..031b1412b0c1baa7a913240421d56da4198a499f 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -10,7 +10,7 @@
   let(:admin) { create(:admin) }
   let!(:project) { create(:project_with_code, creator_id: user.id) }
   let!(:hook) { create(:project_hook, project: project, url: "http://example.com") }
-  let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') }
+  let!(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') }
   let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) }
   let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) }
 
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index f20a1ca51a44bb4ea4a25d2364368b6c06a5ba41..94f9480a4d03fb7e31c5eb5c890ac1e698e4f3a5 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -258,13 +258,37 @@
 #      project_snippet GET    /:project_id/snippets/:id(.:format)      snippets#show
 #                      PUT    /:project_id/snippets/:id(.:format)      snippets#update
 #                      DELETE /:project_id/snippets/:id(.:format)      snippets#destroy
-describe SnippetsController, "routing" do
+describe Project::SnippetsController, "routing" do
   it "to #raw" do
-    get("/gitlabhq/snippets/1/raw").should route_to('snippets#raw', project_id: 'gitlabhq', id: '1')
+    get("/gitlabhq/snippets/1/raw").should route_to('projects/snippets#raw', project_id: 'gitlabhq', id: '1')
   end
 
-  it_behaves_like "RESTful project resources" do
-    let(:controller) { 'snippets' }
+  it "to #index" do
+    get("/gitlabhq/snippets").should route_to("projects/snippets#index", project_id: 'gitlabhq')
+  end
+
+  it "to #create" do
+    post("/gitlabhq/snippets").should route_to("projects/snippets#create", project_id: 'gitlabhq')
+  end
+
+  it "to #new" do
+    get("/gitlabhq/snippets/new").should route_to("projects/snippets#new", project_id: 'gitlabhq')
+  end
+
+  it "to #edit" do
+    get("/gitlabhq/snippets/1/edit").should route_to("projects/snippets#edit", project_id: 'gitlabhq', id: '1')
+  end
+
+  it "to #show" do
+    get("/gitlabhq/snippets/1").should route_to("projects/snippets#show", project_id: 'gitlabhq', id: '1')
+  end
+
+  it "to #update" do
+    put("/gitlabhq/snippets/1").should route_to("projects/snippets#update", project_id: 'gitlabhq', id: '1')
+  end
+
+  it "to #destroy" do
+    delete("/gitlabhq/snippets/1").should route_to("projects/snippets#destroy", project_id: 'gitlabhq', id: '1')
   end
 end
 
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index b6135b4ca814c204a07dbc4698ad48c3b5e354a8..aa3952f74b68503abff4603d5b51d7ab6f3b004a 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -19,6 +19,51 @@
   end
 end
 
+#     snippets GET    /snippets(.:format)          snippets#index
+#          POST   /snippets(.:format)          snippets#create
+#  new_snippet GET    /snippets/new(.:format)      snippets#new
+# edit_snippet GET    /snippets/:id/edit(.:format) snippets#edit
+#      snippet GET    /snippets/:id(.:format)      snippets#show
+#          PUT    /snippets/:id(.:format)      snippets#update
+#          DELETE /snippets/:id(.:format)      snippets#destroy
+describe SnippetsController, "routing" do
+  it "to #user_index" do
+    get("/s/User").should route_to('snippets#user_index', username: 'User')
+  end
+
+  it "to #raw" do
+    get("/snippets/1/raw").should route_to('snippets#raw', id: '1')
+  end
+
+  it "to #index" do
+    get("/snippets").should route_to('snippets#index')
+  end
+
+  it "to #create" do
+    post("/snippets").should route_to('snippets#create')
+  end
+
+  it "to #new" do
+    get("/snippets/new").should route_to('snippets#new')
+  end
+
+  it "to #edit" do
+    get("/snippets/1/edit").should route_to('snippets#edit', id: '1')
+  end
+
+  it "to #show" do
+    get("/snippets/1").should route_to('snippets#show', id: '1')
+  end
+
+  it "to #update" do
+    put("/snippets/1").should route_to('snippets#update', id: '1')
+  end
+
+  it "to #destroy" do
+    delete("/snippets/1").should route_to('snippets#destroy', id: '1')
+  end
+end
+
 #              help GET    /help(.:format)              help#index
 #  help_permissions GET    /help/permissions(.:format)  help#permissions
 #     help_workflow GET    /help/workflow(.:format)     help#workflow