summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/controllers/admin_controller.rb12
-rw-r--r--app/controllers/application.rb10
-rw-r--r--app/controllers/projects_controller.rb23
-rw-r--r--app/controllers/reports_controller.rb8
-rw-r--r--app/controllers/users_controller.rb2
-rw-r--r--app/helpers/admin_helper.rb4
-rw-r--r--app/models/project.rb40
-rw-r--r--app/models/query.rb6
-rw-r--r--app/models/user.rb2
-rw-r--r--app/sweepers/project_sweeper.rb40
-rw-r--r--app/views/admin/projects.rhtml26
-rw-r--r--app/views/my/blocks/_issuesassignedtome.rhtml2
-rw-r--r--app/views/my/blocks/_issuesreportedbyme.rhtml2
-rw-r--r--app/views/my/blocks/_issueswatched.rhtml2
-rw-r--r--app/views/projects/calendar.rhtml2
-rw-r--r--app/views/projects/destroy.rhtml4
-rw-r--r--app/views/projects/gantt.rhtml2
-rw-r--r--app/views/projects/show.rhtml2
18 files changed, 153 insertions, 36 deletions
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
index 1c10722de..19efb28cc 100644
--- a/app/controllers/admin_controller.rb
+++ b/app/controllers/admin_controller.rb
@@ -27,12 +27,18 @@ class AdminController < ApplicationController
def projects
sort_init 'name', 'asc'
- sort_update
- @project_count = Project.count
+ sort_update
+
+ @status = params[:status] ? params[:status].to_i : 0
+ conditions = nil
+ conditions = ["status=?", @status] unless @status == 0
+
+ @project_count = Project.count(:conditions => conditions)
@project_pages = Paginator.new self, @project_count,
- 15,
+ 25,
params['page']
@projects = Project.find :all, :order => sort_clause,
+ :conditions => conditions,
:limit => @project_pages.items_per_page,
:offset => @project_pages.current.offset
diff --git a/app/controllers/application.rb b/app/controllers/application.rb
index 54e4768b6..58193ba8f 100644
--- a/app/controllers/application.rb
+++ b/app/controllers/application.rb
@@ -86,6 +86,11 @@ class ApplicationController < ActionController::Base
# authorizes the user for the requested action.
def authorize(ctrl = params[:controller], action = params[:action])
+ unless @project.active?
+ @project = nil
+ render_404
+ return false
+ end
# check if action is allowed on public projects
if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ ctrl, action ]
return true
@@ -105,6 +110,11 @@ class ApplicationController < ActionController::Base
# make sure that the user is a member of the project (or admin) if project is private
# used as a before_filter for actions that do not require any particular permission on the project
def check_project_privacy
+ unless @project.active?
+ @project = nil
+ render_404
+ return false
+ end
return true if @project.is_public?
return false unless logged_in_user
return true if logged_in_user.admin? || logged_in_user_membership
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index debb0a00a..1de3788ac 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -19,9 +19,11 @@ require 'csv'
class ProjectsController < ApplicationController
layout 'base'
- before_filter :find_project, :authorize, :except => [ :index, :list, :add ]
- before_filter :require_admin, :only => [ :add, :destroy ]
+ before_filter :find_project, :except => [ :index, :list, :add ]
+ before_filter :authorize, :except => [ :index, :list, :add, :archive, :unarchive, :destroy ]
+ before_filter :require_admin, :only => [ :add, :archive, :unarchive, :destroy ]
+ cache_sweeper :project_sweeper, :only => [ :add, :edit, :archive, :unarchive, :destroy ]
cache_sweeper :issue_sweeper, :only => [ :add_issue ]
helper :sort
@@ -86,7 +88,7 @@ class ProjectsController < ApplicationController
def show
@custom_values = @project.custom_values.find(:all, :include => :custom_field)
@members_by_role = @project.members.find(:all, :include => [:user, :role], :order => 'position').group_by {|m| m.role}
- @subprojects = @project.children if @project.children.size > 0
+ @subprojects = @project.active_children
@news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
@trackers = Tracker.find(:all, :order => 'position')
@open_issues_by_tracker = Issue.count(:group => :tracker, :joins => "INNER JOIN #{IssueStatus.table_name} ON #{IssueStatus.table_name}.id = #{Issue.table_name}.status_id", :conditions => ["project_id=? and #{IssueStatus.table_name}.is_closed=?", @project.id, false])
@@ -138,12 +140,25 @@ class ProjectsController < ApplicationController
end
end
+ def archive
+ @project.archive if request.post? && @project.active?
+ redirect_to :controller => 'admin', :action => 'projects'
+ end
+
+ def unarchive
+ @project.unarchive if request.post? && !@project.active?
+ redirect_to :controller => 'admin', :action => 'projects'
+ end
+
# Delete @project
def destroy
+ @project_to_destroy = @project
if request.post? and params[:confirm]
- @project.destroy
+ @project_to_destroy.destroy
redirect_to :controller => 'admin', :action => 'projects'
end
+ # hide project in layout
+ @project = nil
end
# Add a new issue category to @project
diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb
index 7c0b34773..59f13d7a5 100644
--- a/app/controllers/reports_controller.rb
+++ b/app/controllers/reports_controller.rb
@@ -55,7 +55,7 @@ class ReportsController < ApplicationController
render :template => "reports/issue_report_details"
when "subproject"
@field = "project_id"
- @rows = @project.children
+ @rows = @project.active_children
@data = issues_by_subproject
@report_title = l(:field_subproject)
render :template => "reports/issue_report_details"
@@ -66,7 +66,7 @@ class ReportsController < ApplicationController
@priorities = Enumeration::get_values('IPRI')
@categories = @project.issue_categories
@authors = @project.members.collect { |m| m.user }
- @subprojects = @project.children
+ @subprojects = @project.active_children
issues_by_tracker
issues_by_version
issues_by_priority
@@ -207,8 +207,8 @@ private
#{Issue.table_name} i, #{IssueStatus.table_name} s
where
i.status_id=s.id
- and i.project_id IN (#{@project.children.collect{|p| p.id}.join(',')})
- group by s.id, s.is_closed, i.project_id") if @project.children.any?
+ and i.project_id IN (#{@project.active_children.collect{|p| p.id}.join(',')})
+ group by s.id, s.is_closed, i.project_id") if @project.active_children.any?
@issues_by_subproject ||= []
end
end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 93b3a4d25..908001b1a 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -88,7 +88,7 @@ class UsersController < ApplicationController
end
@auth_sources = AuthSource.find(:all)
@roles = Role.find(:all, :order => 'position')
- @projects = Project.find(:all) - @user.projects
+ @projects = Project.find(:all, :order => 'name', :conditions => "status=#{Project::STATUS_ACTIVE}") - @user.projects
@membership ||= Member.new
end
diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb
index 4f82a3790..1b41d8374 100644
--- a/app/helpers/admin_helper.rb
+++ b/app/helpers/admin_helper.rb
@@ -16,4 +16,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module AdminHelper
+ def project_status_options_for_select(selected)
+ options_for_select([[l(:label_all), "*"],
+ [l(:status_active), 1]], selected)
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 6dd6b2644..bf83c1389 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -16,6 +16,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Project < ActiveRecord::Base
+ # Project statuses
+ STATUS_ACTIVE = 1
+ STATUS_ARCHIVED = 9
+
has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
has_many :members, :dependent => :delete_all, :include => :user, :conditions => "#{User.table_name}.status=#{User::STATUS_ACTIVE}"
has_many :users, :through => :members
@@ -32,6 +36,8 @@ class Project < ActiveRecord::Base
has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :association_foreign_key => 'custom_field_id'
acts_as_tree :order => "name", :counter_cache => true
+ attr_protected :status
+
validates_presence_of :name, :description, :identifier
validates_uniqueness_of :name, :identifier
validates_associated :custom_values, :on => :update
@@ -52,12 +58,11 @@ class Project < ActiveRecord::Base
def issues_with_subprojects(include_subprojects=false)
conditions = nil
- if include_subprojects && children.size > 0
- ids = [id] + children.collect {|c| c.id}
+ if include_subprojects && !active_children.empty?
+ ids = [id] + active_children.collect {|c| c.id}
conditions = ["#{Issue.table_name}.project_id IN (#{ids.join(',')})"]
- else
- conditions = ["#{Issue.table_name}.project_id = ?", id]
end
+ conditions ||= ["#{Issue.table_name}.project_id = ?", id]
Issue.with_scope :find => { :conditions => conditions } do
yield
end
@@ -71,12 +76,33 @@ class Project < ActiveRecord::Base
def self.visible_by(user=nil)
if user && user.admin?
- return nil
+ return ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"]
elsif user && !user.memberships.empty?
- return ["#{Project.table_name}.is_public = ? or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')})", true]
+ return ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND (#{Project.table_name}.is_public = ? or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')}))", true]
else
- return ["#{Project.table_name}.is_public = ?", true]
+ return ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = ?", true]
+ end
+ end
+
+ def active?
+ self.status == STATUS_ACTIVE
+ end
+
+ def archive
+ # Archive subprojects if any
+ children.each do |subproject|
+ subproject.archive
end
+ update_attribute :status, STATUS_ARCHIVED
+ end
+
+ def unarchive
+ return false if parent && !parent.active?
+ update_attribute :status, STATUS_ACTIVE
+ end
+
+ def active_children
+ children.select {|child| child.active?}
end
# Returns an array of all custom fields enabled for project issues
diff --git a/app/models/query.rb b/app/models/query.rb
index 47468ba12..145ff851a 100644
--- a/app/models/query.rb
+++ b/app/models/query.rb
@@ -95,8 +95,8 @@ class Query < ActiveRecord::Base
@available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values }
@available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } }
@available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } }
- unless @project.children.empty?
- @available_filters["subproject_id"] = { :type => :list_one_or_more, :order => 13, :values => @project.children.collect{|s| [s.name, s.id.to_s] } }
+ unless @project.active_children.empty?
+ @available_filters["subproject_id"] = { :type => :list_one_or_more, :order => 13, :values => @project.active_children.collect{|s| [s.name, s.id.to_s] } }
end
@project.all_custom_fields.select(&:is_filter?).each do |field|
case field.field_format
@@ -164,7 +164,7 @@ class Query < ActiveRecord::Base
if operator_for("subproject_id") == "="
subproject_ids = values_for("subproject_id").each(&:to_i)
else
- subproject_ids = project.children.collect{|p| p.id}
+ subproject_ids = project.active_children.collect{|p| p.id}
end
sql << " AND #{Issue.table_name}.project_id IN (%d,%s)" % [project.id, subproject_ids.join(",")] if project
else
diff --git a/app/models/user.rb b/app/models/user.rb
index d025651c4..917745b22 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -23,7 +23,7 @@ class User < ActiveRecord::Base
STATUS_REGISTERED = 2
STATUS_LOCKED = 3
- has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :order => "#{Project.table_name}.name", :dependent => :delete_all
+ has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :conditions => "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}", :order => "#{Project.table_name}.name", :dependent => :delete_all
has_many :projects, :through => :memberships
has_many :custom_values, :dependent => :delete_all, :as => :customized
has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
diff --git a/app/sweepers/project_sweeper.rb b/app/sweepers/project_sweeper.rb
new file mode 100644
index 000000000..f64f6f564
--- /dev/null
+++ b/app/sweepers/project_sweeper.rb
@@ -0,0 +1,40 @@
+# redMine - project management software
+# Copyright (C) 2006-2007 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+class ProjectSweeper < ActionController::Caching::Sweeper
+ observe Project
+
+ def before_save(project)
+ if project.new_record?
+ expire_cache_for(project.parent) if project.parent
+ else
+ project_before_update = Project.find(project.id)
+ return if project_before_update.parent_id == project.parent_id && project_before_update.status == project.status
+ expire_cache_for(project.parent) if project.parent
+ expire_cache_for(project_before_update.parent) if project_before_update.parent
+ end
+ end
+
+ def after_destroy(project)
+ expire_cache_for(project.parent) if project.parent
+ end
+
+private
+ def expire_cache_for(project)
+ expire_fragment(Regexp.new("projects/(calendar|gantt)/#{project.id}\\."))
+ end
+end
diff --git a/app/views/admin/projects.rhtml b/app/views/admin/projects.rhtml
index 9c0595eb7..a850d0918 100644
--- a/app/views/admin/projects.rhtml
+++ b/app/views/admin/projects.rhtml
@@ -4,6 +4,15 @@
<h2><%=l(:label_project_plural)%></h2>
+<% form_tag() do %>
+<fieldset><legend><%= l(:label_filter_plural) %></legend>
+<label><%= l(:field_status) %> :</label>
+<%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %>
+<%= submit_tag l(:button_apply), :class => "small" %>
+</fieldset>
+<% end %>
+&nbsp;
+
<table class="list">
<thead><tr>
<%= sort_header_tag('name', :caption => l(:label_project)) %>
@@ -12,22 +21,29 @@
<th><%=l(:label_subproject_plural)%></th>
<%= sort_header_tag('created_on', :caption => l(:field_created_on)) %>
<th></th>
+ <th></th>
</tr></thead>
<tbody>
<% for project in @projects %>
<tr class="<%= cycle("odd", "even") %>">
- <td><%= link_to project.name, :controller => 'projects', :action => 'settings', :id => project %>
+ <td><%= project.active? ? link_to(project.name, :controller => 'projects', :action => 'settings', :id => project) : h(project.name) %>
<td><%=h project.description %>
<td align="center"><%= image_tag 'true.png' if project.is_public? %>
<td align="center"><%= project.children.size %>
<td align="center"><%= format_date(project.created_on) %>
- <td align="center">
- <%= button_to l(:button_delete), { :controller => 'projects', :action => 'destroy', :id => project }, :class => "button-small" %>
+ <td align="center" style="width:10%">
+ <small>
+ <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project }, :method => :post, :class => 'icon icon-lock') if project.active? %>
+ <%= link_to(l(:button_unarchive), { :controller => 'projects', :action => 'unarchive', :id => project }, :method => :post, :class => 'icon icon-unlock') if !project.active? && (project.parent.nil? || project.parent.active?) %>
+ </small>
+ </td>
+ <td align="center" style="width:10%">
+ <small><%= link_to(l(:button_delete), { :controller => 'projects', :action => 'destroy', :id => project }, :class => 'icon icon-del') %></small>
</td>
</tr>
<% end %>
</tbody>
</table>
-<p><%= pagination_links_full @project_pages %>
-[ <%= @project_pages.current.first_item %> - <%= @project_pages.current.last_item %> / <%= @project_count %> ]</p> \ No newline at end of file
+<p><%= pagination_links_full @project_pages, :status => @status %>
+[ <%= @project_pages.current.first_item %> - <%= @project_pages.current.last_item %> / <%= @project_count %> ]</p>
diff --git a/app/views/my/blocks/_issuesassignedtome.rhtml b/app/views/my/blocks/_issuesassignedtome.rhtml
index b75382218..0d49279f4 100644
--- a/app/views/my/blocks/_issuesassignedtome.rhtml
+++ b/app/views/my/blocks/_issuesassignedtome.rhtml
@@ -1,6 +1,6 @@
<h3><%=l(:label_assigned_to_me_issues)%></h3>
<% assigned_issues = Issue.find(:all,
- :conditions => ["assigned_to_id=? AND #{IssueStatus.table_name}.is_closed=?", user.id, false],
+ :conditions => ["assigned_to_id=? AND #{IssueStatus.table_name}.is_closed=? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id, false],
:limit => 10,
:include => [ :status, :project, :tracker ],
:order => "#{Issue.table_name}.updated_on DESC") %>
diff --git a/app/views/my/blocks/_issuesreportedbyme.rhtml b/app/views/my/blocks/_issuesreportedbyme.rhtml
index 3c6eb4a38..250e8265d 100644
--- a/app/views/my/blocks/_issuesreportedbyme.rhtml
+++ b/app/views/my/blocks/_issuesreportedbyme.rhtml
@@ -1,6 +1,6 @@
<h3><%=l(:label_reported_issues)%></h3>
<% reported_issues = Issue.find(:all,
- :conditions => ["author_id=?", user.id],
+ :conditions => ["author_id=? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id],
:limit => 10,
:include => [ :status, :project, :tracker ],
:order => "#{Issue.table_name}.updated_on DESC") %>
diff --git a/app/views/my/blocks/_issueswatched.rhtml b/app/views/my/blocks/_issueswatched.rhtml
index 7324e9a47..e5c2f23ab 100644
--- a/app/views/my/blocks/_issueswatched.rhtml
+++ b/app/views/my/blocks/_issueswatched.rhtml
@@ -2,7 +2,7 @@
<% watched_issues = Issue.find(:all,
:include => [:status, :project, :tracker, :watchers],
:limit => 10,
- :conditions => ["#{Watcher.table_name}.user_id = ?", user.id],
+ :conditions => ["#{Watcher.table_name}.user_id = ? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id],
:order => "#{Issue.table_name}.updated_on DESC") %>
<%= render :partial => 'issues/list_simple', :locals => { :issues => watched_issues } %>
<% if watched_issues.length > 0 %>
diff --git a/app/views/projects/calendar.rhtml b/app/views/projects/calendar.rhtml
index 48fdaf64d..6fb8a1365 100644
--- a/app/views/projects/calendar.rhtml
+++ b/app/views/projects/calendar.rhtml
@@ -23,7 +23,7 @@
<%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %>
<%= tracker.name %><br />
<% end %>
- <% if @project.children.any? %>
+ <% if @project.active_children.any? %>
<p><strong><%=l(:label_subproject_plural)%></strong></p>
<%= check_box_tag "with_subprojects", 1, params[:with_subprojects] %> <%= l(:general_text_Yes) %>
<% end %>
diff --git a/app/views/projects/destroy.rhtml b/app/views/projects/destroy.rhtml
index cb159216d..8ef23197d 100644
--- a/app/views/projects/destroy.rhtml
+++ b/app/views/projects/destroy.rhtml
@@ -1,11 +1,11 @@
<h2><%=l(:label_confirmation)%></h2>
<div class="box">
<center>
-<p><strong><%= @project.name %></strong><br />
+<p><strong><%= @project_to_destroy.name %></strong><br />
<%=l(:text_project_destroy_confirmation)%></p>
<p>
- <% form_tag({:controller => 'projects', :action => 'destroy', :id => @project}) do %>
+ <% form_tag({:controller => 'projects', :action => 'destroy', :id => @project_to_destroy}) do %>
<%= hidden_field_tag "confirm", 1 %>
<%= submit_tag l(:button_delete) %>
<% end %>
diff --git a/app/views/projects/gantt.rhtml b/app/views/projects/gantt.rhtml
index ccc9a019a..c46ef9f5f 100644
--- a/app/views/projects/gantt.rhtml
+++ b/app/views/projects/gantt.rhtml
@@ -49,7 +49,7 @@ t_height = g_height + headers_height
<%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %>
<%= tracker.name %><br />
<% end %>
- <% if @project.children.any? %>
+ <% if @project.active_children.any? %>
<p><strong><%=l(:label_subproject_plural)%></strong></p>
<%= check_box_tag "with_subprojects", 1, params[:with_subprojects] %> <%= l(:general_text_Yes) %>
<% end %>
diff --git a/app/views/projects/show.rhtml b/app/views/projects/show.rhtml
index 2afeb8253..92668ad71 100644
--- a/app/views/projects/show.rhtml
+++ b/app/views/projects/show.rhtml
@@ -45,7 +45,7 @@
<% end %>
</div>
- <% if @subprojects %>
+ <% if @subprojects.any? %>
<div class="box">
<h3 class="icon22 icon22-projects"><%=l(:label_subproject_plural)%></h3>
<%= @subprojects.collect{|p| link_to(p.name, :action => 'show', :id => p)}.join(", ") %>