summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/dashboard_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb20
-rw-r--r--app/helpers/search_helper.rb4
-rw-r--r--app/models/ability.rb37
-rw-r--r--app/models/project.rb12
-rw-r--r--app/views/dashboard/projects.html.haml4
-rw-r--r--app/views/projects/_home_panel.html.haml4
-rw-r--r--app/views/projects/edit.html.haml27
-rw-r--r--config/routes.rb2
-rw-r--r--db/migrate/20131129154016_add_archived_to_projects.rb5
-rw-r--r--db/schema.rb1
-rw-r--r--features/dashboard/archived_projects.feature16
-rw-r--r--features/project/archived_projects.feature39
-rw-r--r--features/steps/dashboard/dashboard_with_archived_projects.rb22
-rw-r--r--features/steps/project/project_archived.rb37
-rw-r--r--features/steps/shared/project.rb7
-rw-r--r--spec/models/project_spec.rb1
-rw-r--r--spec/requests/api/internal_spec.rb27
18 files changed, 251 insertions, 16 deletions
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 045e5805bd0..aaab4b40c4c 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -73,6 +73,6 @@ class DashboardController < ApplicationController
protected
def load_projects
- @projects = current_user.authorized_projects.sorted_by_activity
+ @projects = current_user.authorized_projects.sorted_by_activity.non_archived
end
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 1835671fe98..e1c55e7d913 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -5,7 +5,7 @@ class ProjectsController < ApplicationController
# Authorize
before_filter :authorize_read_project!, except: [:index, :new, :create]
- before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer]
+ before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive]
before_filter :require_non_empty_project, only: [:blob, :tree, :graph]
layout 'navless', only: [:new, :create, :fork]
@@ -116,6 +116,24 @@ class ProjectsController < ApplicationController
end
end
+ def archive
+ return access_denied! unless can?(current_user, :archive_project, project)
+ project.archive!
+
+ respond_to do |format|
+ format.html { redirect_to @project }
+ end
+ end
+
+ def unarchive
+ return access_denied! unless can?(current_user, :archive_project, project)
+ project.unarchive!
+
+ respond_to do |format|
+ format.html { redirect_to @project }
+ end
+ end
+
private
def set_title
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 109acfd192b..f24156e4d85 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -73,14 +73,14 @@ module SearchHelper
# Autocomplete results for the current user's projects
def projects_autocomplete
- current_user.authorized_projects.map do |p|
+ current_user.authorized_projects.non_archived.map do |p|
{ label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
end
end
# Autocomplete results for the current user's projects
def public_projects_autocomplete
- Project.public_or_internal_only(current_user).map do |p|
+ Project.public_or_internal_only(current_user).non_archived.map do |p|
{ label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
end
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 6df56eed5b8..cf925141f2d 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -59,31 +59,35 @@ class Ability
# Rules based on role in project
if team.masters.include?(user)
- rules << project_master_rules
+ rules += project_master_rules
elsif team.developers.include?(user)
- rules << project_dev_rules
+ rules += project_dev_rules
elsif team.reporters.include?(user)
- rules << project_report_rules
+ rules += project_report_rules
elsif team.guests.include?(user)
- rules << project_guest_rules
+ rules += project_guest_rules
end
if project.public? || project.internal?
- rules << public_project_rules
+ rules += public_project_rules
end
if project.owner == user || user.admin?
- rules << project_admin_rules
+ rules += project_admin_rules
end
if project.group && project.group.has_owner?(user)
- rules << project_admin_rules
+ rules += project_admin_rules
end
- rules.flatten
+ if project.archived?
+ rules -= project_archived_rules
+ end
+
+ rules
end
def public_project_rules
@@ -125,6 +129,16 @@ class Ability
]
end
+ def project_archived_rules
+ [
+ :write_merge_request,
+ :push_code,
+ :push_code_to_protected_branches,
+ :modify_merge_request,
+ :admin_merge_request
+ ]
+ end
+
def project_master_rules
project_dev_rules + [
:push_code_to_protected_branches,
@@ -147,7 +161,8 @@ class Ability
:change_namespace,
:change_visibility_level,
:rename_project,
- :remove_project
+ :remove_project,
+ :archive_project
]
end
@@ -160,7 +175,7 @@ class Ability
# Only group owner and administrators can manage group
if group.has_owner?(user) || user.admin?
- rules << [
+ rules += [
:manage_group,
:manage_namespace
]
@@ -174,7 +189,7 @@ class Ability
# Only namespace owner and administrators can manage it
if namespace.owner == user || user.admin?
- rules << [
+ rules += [
:manage_namespace
]
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 506f34ca6b6..d389579b3a1 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -116,6 +116,8 @@ class Project < ActiveRecord::Base
scope :public_only, -> { where(visibility_level: PUBLIC) }
scope :public_or_internal_only, ->(user) { where("visibility_level IN (:levels)", levels: user ? [ INTERNAL, PUBLIC ] : [ PUBLIC ]) }
+ scope :non_archived, -> { where(archived: false) }
+
enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab
class << self
@@ -132,7 +134,7 @@ class Project < ActiveRecord::Base
end
def search query
- joins(:namespace).where("projects.name LIKE :query OR projects.path LIKE :query OR namespaces.name LIKE :query OR projects.description LIKE :query", query: "%#{query}%")
+ joins(:namespace).where("projects.archived = ?", false).where("projects.name LIKE :query OR projects.path LIKE :query OR namespaces.name LIKE :query OR projects.description LIKE :query", query: "%#{query}%")
end
def find_with_namespace(id)
@@ -472,4 +474,12 @@ class Project < ActiveRecord::Base
def visibility_level_field
visibility_level
end
+
+ def archive!
+ update_attribute(:archived, true)
+ end
+
+ def unarchive!
+ update_attribute(:archived, false)
+ end
end
diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml
index b42bbf58dc4..23d78720881 100644
--- a/app/views/dashboard/projects.html.haml
+++ b/app/views/dashboard/projects.html.haml
@@ -82,6 +82,10 @@
= link_to project.forked_from_project.name_with_namespace, project_path(project.forked_from_project)
.project-info
.pull-right
+ - if project.archived?
+ %span.label
+ %i.icon-book
+ Archived
- project.labels.each do |label|
%span.label.label-info
%i.icon-tag
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 19c150b54fb..ae5deb0b6de 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -7,6 +7,10 @@
%span.visibility-level-label
= visibility_level_icon(@project.visibility_level)
= visibility_level_label(@project.visibility_level)
+ - if @project.archived?
+ %span.visibility-level-label
+ %i.icon-book
+ Archived
.span7
- unless empty_repo
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 57936cff10f..c56919e792c 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -98,6 +98,33 @@
%i.icon-chevron-down
.js-toggle-visibility-container.hide
+ - if can? current_user, :archive_project, @project
+ .ui-box.ui-box-danger
+ .title
+ - if @project.archived?
+ Unarchive project
+ - else
+ Archive project
+ .ui-box-body
+ - if @project.archived?
+ %p
+ Unarchiving the project will mark its repository as active.
+ %br
+ The project can be committed to.
+ %br
+ %strong Once active this project shows up in the search and on the dashboard.
+ = link_to 'Unarchive', unarchive_project_path(@project), confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be comitted to again.", method: :post, class: "btn btn-remove"
+ - else
+ %p
+ Archiving the project will mark its repository as read-only.
+ %br
+ It is hidden from the dashboard and doesn't show up in searches.
+ %br
+ %strong Archived projects cannot be committed to!
+ = link_to 'Archive', archive_project_path(@project), confirm: "Are you sure that you want to archive this project?\nAn archived project cannot be committed to.", method: :post, class: "btn btn-remove"
+ - else
+ %p.nothing_here_message Only the project owner can archive a project
+
- if can?(current_user, :change_namespace, @project)
.ui-box.ui-box-danger
.title Transfer project
diff --git a/config/routes.rb b/config/routes.rb
index 188d2099997..8322d6a9d4e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -170,6 +170,8 @@ Gitlab::Application.routes.draw do
member do
put :transfer
post :fork
+ post :archive
+ post :unarchive
get :autocomplete_sources
end
diff --git a/db/migrate/20131129154016_add_archived_to_projects.rb b/db/migrate/20131129154016_add_archived_to_projects.rb
new file mode 100644
index 00000000000..917e690ba47
--- /dev/null
+++ b/db/migrate/20131129154016_add_archived_to_projects.rb
@@ -0,0 +1,5 @@
+class AddArchivedToProjects < ActiveRecord::Migration
+ def change
+ add_column :projects, :archived, :boolean, default: false, null: false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index e7b3bf09d2d..77d245913e2 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -192,6 +192,7 @@ ActiveRecord::Schema.define(version: 20131214224427) do
t.boolean "imported", default: false, null: false
t.string "import_url"
t.integer "visibility_level", default: 0, null: false
+ t.boolean "archived", default: false, null: false
end
add_index "projects", ["creator_id"], name: "index_projects_on_owner_id", using: :btree
diff --git a/features/dashboard/archived_projects.feature b/features/dashboard/archived_projects.feature
new file mode 100644
index 00000000000..399c9b53d81
--- /dev/null
+++ b/features/dashboard/archived_projects.feature
@@ -0,0 +1,16 @@
+Feature: Dashboard with archived projects
+ Background:
+ Given I sign in as a user
+ And I own project "Shop"
+ And I own project "Forum"
+ And project "Forum" is archived
+ And I visit dashboard page
+
+ Scenario: I should see non-archived projects on dashboard
+ Then I should see "Shop" project link
+ And I should not see "Forum" project link
+
+ Scenario: I should see all projects on projects page
+ And I visit dashboard projects page
+ Then I should see "Shop" project link
+ And I should see "Forum" project link
diff --git a/features/project/archived_projects.feature b/features/project/archived_projects.feature
new file mode 100644
index 00000000000..9aac29384ba
--- /dev/null
+++ b/features/project/archived_projects.feature
@@ -0,0 +1,39 @@
+Feature: Project Archived
+ Background:
+ Given I sign in as a user
+ And I own project "Shop"
+ And I own project "Forum"
+
+ Scenario: I should not see archived on project page of not-archive project
+ And project "Forum" is archived
+ And I visit project "Shop" page
+ Then I should not see "Archived"
+
+ Scenario: I should see archived on project page of archive project
+ And project "Forum" is archived
+ And I visit project "Forum" page
+ Then I should see "Archived"
+
+ Scenario: I should not see archived on projects page with no archived projects
+ And I visit dashboard projects page
+ Then I should not see "Archived"
+
+ Scenario: I should see archived on projects page with archived projects
+ And project "Forum" is archived
+ And I visit dashboard projects page
+ Then I should see "Archived"
+
+ Scenario: I archive project
+ When project "Shop" has push event
+ And I visit project "Shop" page
+ And I visit edit project "Shop" page
+ And I set project archived
+ Then I should see "Archived"
+
+ Scenario: I unarchive project
+ When project "Shop" has push event
+ And project "Shop" is archived
+ And I visit project "Shop" page
+ And I visit edit project "Shop" page
+ And I set project unarchived
+ Then I should not see "Archived"
diff --git a/features/steps/dashboard/dashboard_with_archived_projects.rb b/features/steps/dashboard/dashboard_with_archived_projects.rb
new file mode 100644
index 00000000000..700f4b426c3
--- /dev/null
+++ b/features/steps/dashboard/dashboard_with_archived_projects.rb
@@ -0,0 +1,22 @@
+class DashboardWithArchivedProjects < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+ include SharedProject
+
+ When 'project "Forum" is archived' do
+ project = Project.find_by_name "Forum"
+ project.update_attribute(:archived, true)
+ end
+
+ Then 'I should see "Shop" project link' do
+ page.should have_link "Shop"
+ end
+
+ Then 'I should not see "Forum" project link' do
+ page.should_not have_link "Forum"
+ end
+
+ Then 'I should see "Forum" project link' do
+ page.should have_link "Forum"
+ end
+end
diff --git a/features/steps/project/project_archived.rb b/features/steps/project/project_archived.rb
new file mode 100644
index 00000000000..149d293cd08
--- /dev/null
+++ b/features/steps/project/project_archived.rb
@@ -0,0 +1,37 @@
+class ProjectArchived < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ When 'project "Forum" is archived' do
+ project = Project.find_by_name "Forum"
+ project.update_attribute(:archived, true)
+ end
+
+ When 'project "Shop" is archived' do
+ project = Project.find_by_name "Shop"
+ project.update_attribute(:archived, true)
+ end
+
+ When 'I visit project "Forum" page' do
+ project = Project.find_by_name "Forum"
+ visit project_path(project)
+ end
+
+ Then 'I should not see "Archived"' do
+ page.should_not have_content "Archived"
+ end
+
+ Then 'I should see "Archived"' do
+ page.should have_content "Archived"
+ end
+
+ When 'I set project archived' do
+ click_link "Archive"
+ end
+
+ When 'I set project unarchived' do
+ click_link "Unarchive"
+ end
+
+end \ No newline at end of file
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index cef66b038db..3dc4932a09a 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -14,6 +14,13 @@ module SharedProject
@project.team << [@user, :master]
end
+ # Create another specific project called "Forum"
+ And 'I own project "Forum"' do
+ @project = Project.find_by_name "Forum"
+ @project ||= create(:project_with_code, name: "Forum", namespace: @user.namespace, path: 'forum_project')
+ @project.team << [@user, :master]
+ end
+
And 'project "Shop" has push event' do
@project = Project.find_by_name("Shop")
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 1e05d188234..8aa4c7fed1a 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -21,6 +21,7 @@
# imported :boolean default(FALSE), not null
# import_url :string(255)
# visibility_level :integer default(0), not null
+# archived :boolean default(FALSE), not null
#
require 'spec_helper'
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index e8870f4d5d8..5f6dff92c0a 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -103,6 +103,33 @@ describe API::API do
end
end
+ context "archived project" do
+ let(:personal_project) { create(:project, namespace: user.namespace) }
+
+ before do
+ project.team << [user, :developer]
+ project.archive!
+ end
+
+ context "git pull" do
+ it do
+ pull(key, project)
+
+ response.status.should == 200
+ response.body.should == 'true'
+ end
+ end
+
+ context "git push" do
+ it do
+ push(key, project)
+
+ response.status.should == 200
+ response.body.should == 'false'
+ end
+ end
+ end
+
context "deploy key" do
let(:key) { create(:deploy_key) }