Revision 549
Added by Jean-Philippe Lang over 18 years ago
Added the ability to archive projects:
- Only administrators can archive/unarchive projects.
- Once archived, the project is visible on the admin project listing only. It doesn't show up anywhere else in the app. Subprojects are also archived.
- Archive/unarchive preserve everything on the project (issues, members, ...).
- A subproject can not be unarchived if its parent project is archived.
| trunk/app/controllers/admin_controller.rb | ||
|---|---|---|
| 27 | 27 |
|
| 28 | 28 |
def projects |
| 29 | 29 |
sort_init 'name', 'asc' |
| 30 |
sort_update |
|
| 31 |
@project_count = Project.count |
|
| 30 |
sort_update |
|
| 31 |
|
|
| 32 |
@status = params[:status] ? params[:status].to_i : 0 |
|
| 33 |
conditions = nil |
|
| 34 |
conditions = ["status=?", @status] unless @status == 0 |
|
| 35 |
|
|
| 36 |
@project_count = Project.count(:conditions => conditions) |
|
| 32 | 37 |
@project_pages = Paginator.new self, @project_count, |
| 33 |
15,
|
|
| 38 |
25,
|
|
| 34 | 39 |
params['page'] |
| 35 | 40 |
@projects = Project.find :all, :order => sort_clause, |
| 41 |
:conditions => conditions, |
|
| 36 | 42 |
:limit => @project_pages.items_per_page, |
| 37 | 43 |
:offset => @project_pages.current.offset |
| 38 | 44 |
|
| trunk/app/controllers/application.rb | ||
|---|---|---|
| 86 | 86 |
|
| 87 | 87 |
# authorizes the user for the requested action. |
| 88 | 88 |
def authorize(ctrl = params[:controller], action = params[:action]) |
| 89 |
unless @project.active? |
|
| 90 |
@project = nil |
|
| 91 |
render_404 |
|
| 92 |
return false |
|
| 93 |
end |
|
| 89 | 94 |
# check if action is allowed on public projects |
| 90 | 95 |
if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ ctrl, action ] |
| 91 | 96 |
return true |
| ... | ... | |
| 105 | 110 |
# make sure that the user is a member of the project (or admin) if project is private |
| 106 | 111 |
# used as a before_filter for actions that do not require any particular permission on the project |
| 107 | 112 |
def check_project_privacy |
| 113 |
unless @project.active? |
|
| 114 |
@project = nil |
|
| 115 |
render_404 |
|
| 116 |
return false |
|
| 117 |
end |
|
| 108 | 118 |
return true if @project.is_public? |
| 109 | 119 |
return false unless logged_in_user |
| 110 | 120 |
return true if logged_in_user.admin? || logged_in_user_membership |
| trunk/app/controllers/projects_controller.rb | ||
|---|---|---|
| 19 | 19 |
|
| 20 | 20 |
class ProjectsController < ApplicationController |
| 21 | 21 |
layout 'base' |
| 22 |
before_filter :find_project, :authorize, :except => [ :index, :list, :add ] |
|
| 23 |
before_filter :require_admin, :only => [ :add, :destroy ] |
|
| 22 |
before_filter :find_project, :except => [ :index, :list, :add ] |
|
| 23 |
before_filter :authorize, :except => [ :index, :list, :add, :archive, :unarchive, :destroy ] |
|
| 24 |
before_filter :require_admin, :only => [ :add, :archive, :unarchive, :destroy ] |
|
| 24 | 25 |
|
| 26 |
cache_sweeper :project_sweeper, :only => [ :add, :edit, :archive, :unarchive, :destroy ] |
|
| 25 | 27 |
cache_sweeper :issue_sweeper, :only => [ :add_issue ] |
| 26 | 28 |
|
| 27 | 29 |
helper :sort |
| ... | ... | |
| 86 | 88 |
def show |
| 87 | 89 |
@custom_values = @project.custom_values.find(:all, :include => :custom_field) |
| 88 | 90 |
@members_by_role = @project.members.find(:all, :include => [:user, :role], :order => 'position').group_by {|m| m.role}
|
| 89 |
@subprojects = @project.children if @project.children.size > 0
|
|
| 91 |
@subprojects = @project.active_children
|
|
| 90 | 92 |
@news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
|
| 91 | 93 |
@trackers = Tracker.find(:all, :order => 'position') |
| 92 | 94 |
@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 | 140 |
end |
| 139 | 141 |
end |
| 140 | 142 |
|
| 143 |
def archive |
|
| 144 |
@project.archive if request.post? && @project.active? |
|
| 145 |
redirect_to :controller => 'admin', :action => 'projects' |
|
| 146 |
end |
|
| 147 |
|
|
| 148 |
def unarchive |
|
| 149 |
@project.unarchive if request.post? && [email protected]? |
|
| 150 |
redirect_to :controller => 'admin', :action => 'projects' |
|
| 151 |
end |
|
| 152 |
|
|
| 141 | 153 |
# Delete @project |
| 142 | 154 |
def destroy |
| 155 |
@project_to_destroy = @project |
|
| 143 | 156 |
if request.post? and params[:confirm] |
| 144 |
@project.destroy |
|
| 157 |
@project_to_destroy.destroy
|
|
| 145 | 158 |
redirect_to :controller => 'admin', :action => 'projects' |
| 146 | 159 |
end |
| 160 |
# hide project in layout |
|
| 161 |
@project = nil |
|
| 147 | 162 |
end |
| 148 | 163 |
|
| 149 | 164 |
# Add a new issue category to @project |
| trunk/app/controllers/reports_controller.rb | ||
|---|---|---|
| 55 | 55 |
render :template => "reports/issue_report_details" |
| 56 | 56 |
when "subproject" |
| 57 | 57 |
@field = "project_id" |
| 58 |
@rows = @project.children |
|
| 58 |
@rows = @project.active_children
|
|
| 59 | 59 |
@data = issues_by_subproject |
| 60 | 60 |
@report_title = l(:field_subproject) |
| 61 | 61 |
render :template => "reports/issue_report_details" |
| ... | ... | |
| 66 | 66 |
@priorities = Enumeration::get_values('IPRI')
|
| 67 | 67 |
@categories = @project.issue_categories |
| 68 | 68 |
@authors = @project.members.collect { |m| m.user }
|
| 69 |
@subprojects = @project.children |
|
| 69 |
@subprojects = @project.active_children
|
|
| 70 | 70 |
issues_by_tracker |
| 71 | 71 |
issues_by_version |
| 72 | 72 |
issues_by_priority |
| ... | ... | |
| 207 | 207 |
#{Issue.table_name} i, #{IssueStatus.table_name} s
|
| 208 | 208 |
where |
| 209 | 209 |
i.status_id=s.id |
| 210 |
and i.project_id IN (#{@project.children.collect{|p| p.id}.join(',')})
|
|
| 211 |
group by s.id, s.is_closed, i.project_id") if @project.children.any? |
|
| 210 |
and i.project_id IN (#{@project.active_children.collect{|p| p.id}.join(',')})
|
|
| 211 |
group by s.id, s.is_closed, i.project_id") if @project.active_children.any?
|
|
| 212 | 212 |
@issues_by_subproject ||= [] |
| 213 | 213 |
end |
| 214 | 214 |
end |
| trunk/app/controllers/users_controller.rb | ||
|---|---|---|
| 88 | 88 |
end |
| 89 | 89 |
@auth_sources = AuthSource.find(:all) |
| 90 | 90 |
@roles = Role.find(:all, :order => 'position') |
| 91 |
@projects = Project.find(:all) - @user.projects |
|
| 91 |
@projects = Project.find(:all, :order => 'name', :conditions => "status=#{Project::STATUS_ACTIVE}") - @user.projects
|
|
| 92 | 92 |
@membership ||= Member.new |
| 93 | 93 |
end |
| 94 | 94 |
|
| trunk/app/helpers/admin_helper.rb | ||
|---|---|---|
| 16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 17 | 17 |
|
| 18 | 18 |
module AdminHelper |
| 19 |
def project_status_options_for_select(selected) |
|
| 20 |
options_for_select([[l(:label_all), "*"], |
|
| 21 |
[l(:status_active), 1]], selected) |
|
| 22 |
end |
|
| 19 | 23 |
end |
| trunk/app/models/project.rb | ||
|---|---|---|
| 16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 17 | 17 |
|
| 18 | 18 |
class Project < ActiveRecord::Base |
| 19 |
# Project statuses |
|
| 20 |
STATUS_ACTIVE = 1 |
|
| 21 |
STATUS_ARCHIVED = 9 |
|
| 22 |
|
|
| 19 | 23 |
has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
|
| 20 | 24 |
has_many :members, :dependent => :delete_all, :include => :user, :conditions => "#{User.table_name}.status=#{User::STATUS_ACTIVE}"
|
| 21 | 25 |
has_many :users, :through => :members |
| ... | ... | |
| 32 | 36 |
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'
|
| 33 | 37 |
acts_as_tree :order => "name", :counter_cache => true |
| 34 | 38 |
|
| 39 |
attr_protected :status |
|
| 40 |
|
|
| 35 | 41 |
validates_presence_of :name, :description, :identifier |
| 36 | 42 |
validates_uniqueness_of :name, :identifier |
| 37 | 43 |
validates_associated :custom_values, :on => :update |
| ... | ... | |
| 52 | 58 |
|
| 53 | 59 |
def issues_with_subprojects(include_subprojects=false) |
| 54 | 60 |
conditions = nil |
| 55 |
if include_subprojects && children.size > 0
|
|
| 56 |
ids = [id] + children.collect {|c| c.id}
|
|
| 61 |
if include_subprojects && !active_children.empty?
|
|
| 62 |
ids = [id] + active_children.collect {|c| c.id}
|
|
| 57 | 63 |
conditions = ["#{Issue.table_name}.project_id IN (#{ids.join(',')})"]
|
| 58 |
else |
|
| 59 |
conditions = ["#{Issue.table_name}.project_id = ?", id]
|
|
| 60 | 64 |
end |
| 65 |
conditions ||= ["#{Issue.table_name}.project_id = ?", id]
|
|
| 61 | 66 |
Issue.with_scope :find => { :conditions => conditions } do
|
| 62 | 67 |
yield |
| 63 | 68 |
end |
| ... | ... | |
| 71 | 76 |
|
| 72 | 77 |
def self.visible_by(user=nil) |
| 73 | 78 |
if user && user.admin? |
| 74 |
return nil
|
|
| 79 |
return ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"]
|
|
| 75 | 80 |
elsif user && !user.memberships.empty? |
| 76 |
return ["#{Project.table_name}.is_public = ? or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')})", true]
|
|
| 81 |
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]
|
|
| 77 | 82 |
else |
| 78 |
return ["#{Project.table_name}.is_public = ?", true]
|
|
| 83 |
return ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = ?", true]
|
|
| 79 | 84 |
end |
| 80 | 85 |
end |
| 81 | 86 |
|
| 87 |
def active? |
|
| 88 |
self.status == STATUS_ACTIVE |
|
| 89 |
end |
|
| 90 |
|
|
| 91 |
def archive |
|
| 92 |
# Archive subprojects if any |
|
| 93 |
children.each do |subproject| |
|
| 94 |
subproject.archive |
|
| 95 |
end |
|
| 96 |
update_attribute :status, STATUS_ARCHIVED |
|
| 97 |
end |
|
| 98 |
|
|
| 99 |
def unarchive |
|
| 100 |
return false if parent && !parent.active? |
|
| 101 |
update_attribute :status, STATUS_ACTIVE |
|
| 102 |
end |
|
| 103 |
|
|
| 104 |
def active_children |
|
| 105 |
children.select {|child| child.active?}
|
|
| 106 |
end |
|
| 107 |
|
|
| 82 | 108 |
# Returns an array of all custom fields enabled for project issues |
| 83 | 109 |
# (explictly associated custom fields and custom fields enabled for all projects) |
| 84 | 110 |
def custom_fields_for_issues(tracker) |
| trunk/app/models/query.rb | ||
|---|---|---|
| 95 | 95 |
@available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values }
|
| 96 | 96 |
@available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } }
|
| 97 | 97 |
@available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } }
|
| 98 |
unless @project.children.empty? |
|
| 99 |
@available_filters["subproject_id"] = { :type => :list_one_or_more, :order => 13, :values => @project.children.collect{|s| [s.name, s.id.to_s] } }
|
|
| 98 |
unless @project.active_children.empty?
|
|
| 99 |
@available_filters["subproject_id"] = { :type => :list_one_or_more, :order => 13, :values => @project.active_children.collect{|s| [s.name, s.id.to_s] } }
|
|
| 100 | 100 |
end |
| 101 | 101 |
@project.all_custom_fields.select(&:is_filter?).each do |field| |
| 102 | 102 |
case field.field_format |
| ... | ... | |
| 164 | 164 |
if operator_for("subproject_id") == "="
|
| 165 | 165 |
subproject_ids = values_for("subproject_id").each(&:to_i)
|
| 166 | 166 |
else |
| 167 |
subproject_ids = project.children.collect{|p| p.id}
|
|
| 167 |
subproject_ids = project.active_children.collect{|p| p.id}
|
|
| 168 | 168 |
end |
| 169 | 169 |
sql << " AND #{Issue.table_name}.project_id IN (%d,%s)" % [project.id, subproject_ids.join(",")] if project
|
| 170 | 170 |
else |
| trunk/app/models/user.rb | ||
|---|---|---|
| 23 | 23 |
STATUS_REGISTERED = 2 |
| 24 | 24 |
STATUS_LOCKED = 3 |
| 25 | 25 |
|
| 26 |
has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :order => "#{Project.table_name}.name", :dependent => :delete_all
|
|
| 26 |
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
|
|
| 27 | 27 |
has_many :projects, :through => :memberships |
| 28 | 28 |
has_many :custom_values, :dependent => :delete_all, :as => :customized |
| 29 | 29 |
has_one :preference, :dependent => :destroy, :class_name => 'UserPreference' |
| trunk/app/sweepers/project_sweeper.rb | ||
|---|---|---|
| 1 |
# redMine - project management software |
|
| 2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang |
|
| 3 |
# |
|
| 4 |
# This program is free software; you can redistribute it and/or |
|
| 5 |
# modify it under the terms of the GNU General Public License |
|
| 6 |
# as published by the Free Software Foundation; either version 2 |
|
| 7 |
# of the License, or (at your option) any later version. |
|
| 8 |
# |
|
| 9 |
# This program is distributed in the hope that it will be useful, |
|
| 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 12 |
# GNU General Public License for more details. |
|
| 13 |
# |
|
| 14 |
# You should have received a copy of the GNU General Public License |
|
| 15 |
# along with this program; if not, write to the Free Software |
|
| 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 17 |
|
|
| 18 |
class ProjectSweeper < ActionController::Caching::Sweeper |
|
| 19 |
observe Project |
|
| 20 |
|
|
| 21 |
def before_save(project) |
|
| 22 |
if project.new_record? |
|
| 23 |
expire_cache_for(project.parent) if project.parent |
|
| 24 |
else |
|
| 25 |
project_before_update = Project.find(project.id) |
|
| 26 |
return if project_before_update.parent_id == project.parent_id && project_before_update.status == project.status |
|
| 27 |
expire_cache_for(project.parent) if project.parent |
|
| 28 |
expire_cache_for(project_before_update.parent) if project_before_update.parent |
|
| 29 |
end |
|
| 30 |
end |
|
| 31 |
|
|
| 32 |
def after_destroy(project) |
|
| 33 |
expire_cache_for(project.parent) if project.parent |
|
| 34 |
end |
|
| 35 |
|
|
| 36 |
private |
|
| 37 |
def expire_cache_for(project) |
|
| 38 |
expire_fragment(Regexp.new("projects/(calendar|gantt)/#{project.id}\\."))
|
|
| 39 |
end |
|
| 40 |
end |
|
| trunk/app/views/admin/projects.rhtml | ||
|---|---|---|
| 4 | 4 |
|
| 5 | 5 |
<h2><%=l(:label_project_plural)%></h2> |
| 6 | 6 |
|
| 7 |
<% form_tag() do %> |
|
| 8 |
<fieldset><legend><%= l(:label_filter_plural) %></legend> |
|
| 9 |
<label><%= l(:field_status) %> :</label> |
|
| 10 |
<%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> |
|
| 11 |
<%= submit_tag l(:button_apply), :class => "small" %> |
|
| 12 |
</fieldset> |
|
| 13 |
<% end %> |
|
| 14 |
|
|
| 15 |
|
|
| 7 | 16 |
<table class="list"> |
| 8 | 17 |
<thead><tr> |
| 9 | 18 |
<%= sort_header_tag('name', :caption => l(:label_project)) %>
|
| ... | ... | |
| 12 | 21 |
<th><%=l(:label_subproject_plural)%></th> |
| 13 | 22 |
<%= sort_header_tag('created_on', :caption => l(:field_created_on)) %>
|
| 14 | 23 |
<th></th> |
| 24 |
<th></th> |
|
| 15 | 25 |
</tr></thead> |
| 16 | 26 |
<tbody> |
| 17 | 27 |
<% for project in @projects %> |
| 18 | 28 |
<tr class="<%= cycle("odd", "even") %>">
|
| 19 |
<td><%= link_to project.name, :controller => 'projects', :action => 'settings', :id => project %>
|
|
| 29 |
<td><%= project.active? ? link_to(project.name, :controller => 'projects', :action => 'settings', :id => project) : h(project.name) %>
|
|
| 20 | 30 |
<td><%=h project.description %> |
| 21 | 31 |
<td align="center"><%= image_tag 'true.png' if project.is_public? %> |
| 22 | 32 |
<td align="center"><%= project.children.size %> |
| 23 | 33 |
<td align="center"><%= format_date(project.created_on) %> |
| 24 |
<td align="center"> |
|
| 25 |
<%= button_to l(:button_delete), { :controller => 'projects', :action => 'destroy', :id => project }, :class => "button-small" %>
|
|
| 34 |
<td align="center" style="width:10%"> |
|
| 35 |
<small> |
|
| 36 |
<%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project }, :method => :post, :class => 'icon icon-lock') if project.active? %>
|
|
| 37 |
<%= 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?) %>
|
|
| 38 |
</small> |
|
| 26 | 39 |
</td> |
| 40 |
<td align="center" style="width:10%"> |
|
| 41 |
<small><%= link_to(l(:button_delete), { :controller => 'projects', :action => 'destroy', :id => project }, :class => 'icon icon-del') %></small>
|
|
| 42 |
</td> |
|
| 27 | 43 |
</tr> |
| 28 | 44 |
<% end %> |
| 29 | 45 |
</tbody> |
| 30 | 46 |
</table> |
| 31 | 47 |
|
| 32 |
<p><%= pagination_links_full @project_pages %> |
|
| 33 |
[ <%= @project_pages.current.first_item %> - <%= @project_pages.current.last_item %> / <%= @project_count %> ]</p> |
|
| 48 |
<p><%= pagination_links_full @project_pages, :status => @status %> |
|
| 49 |
[ <%= @project_pages.current.first_item %> - <%= @project_pages.current.last_item %> / <%= @project_count %> ]</p> |
|
| trunk/app/views/my/blocks/_issuesassignedtome.rhtml | ||
|---|---|---|
| 1 | 1 |
<h3><%=l(:label_assigned_to_me_issues)%></h3> |
| 2 | 2 |
<% assigned_issues = Issue.find(:all, |
| 3 |
:conditions => ["assigned_to_id=? AND #{IssueStatus.table_name}.is_closed=?", user.id, false],
|
|
| 3 |
:conditions => ["assigned_to_id=? AND #{IssueStatus.table_name}.is_closed=? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id, false],
|
|
| 4 | 4 |
:limit => 10, |
| 5 | 5 |
:include => [ :status, :project, :tracker ], |
| 6 | 6 |
:order => "#{Issue.table_name}.updated_on DESC") %>
|
| trunk/app/views/my/blocks/_issuesreportedbyme.rhtml | ||
|---|---|---|
| 1 | 1 |
<h3><%=l(:label_reported_issues)%></h3> |
| 2 | 2 |
<% reported_issues = Issue.find(:all, |
| 3 |
:conditions => ["author_id=?", user.id], |
|
| 3 |
:conditions => ["author_id=? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id],
|
|
| 4 | 4 |
:limit => 10, |
| 5 | 5 |
:include => [ :status, :project, :tracker ], |
| 6 | 6 |
:order => "#{Issue.table_name}.updated_on DESC") %>
|
| trunk/app/views/my/blocks/_issueswatched.rhtml | ||
|---|---|---|
| 2 | 2 |
<% watched_issues = Issue.find(:all, |
| 3 | 3 |
:include => [:status, :project, :tracker, :watchers], |
| 4 | 4 |
:limit => 10, |
| 5 |
:conditions => ["#{Watcher.table_name}.user_id = ?", user.id],
|
|
| 5 |
:conditions => ["#{Watcher.table_name}.user_id = ? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id],
|
|
| 6 | 6 |
:order => "#{Issue.table_name}.updated_on DESC") %>
|
| 7 | 7 |
<%= render :partial => 'issues/list_simple', :locals => { :issues => watched_issues } %>
|
| 8 | 8 |
<% if watched_issues.length > 0 %> |
| trunk/app/views/projects/calendar.rhtml | ||
|---|---|---|
| 23 | 23 |
<%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %> |
| 24 | 24 |
<%= tracker.name %><br /> |
| 25 | 25 |
<% end %> |
| 26 |
<% if @project.children.any? %> |
|
| 26 |
<% if @project.active_children.any? %>
|
|
| 27 | 27 |
<p><strong><%=l(:label_subproject_plural)%></strong></p> |
| 28 | 28 |
<%= check_box_tag "with_subprojects", 1, params[:with_subprojects] %> <%= l(:general_text_Yes) %> |
| 29 | 29 |
<% end %> |
| trunk/app/views/projects/destroy.rhtml | ||
|---|---|---|
| 1 | 1 |
<h2><%=l(:label_confirmation)%></h2> |
| 2 | 2 |
<div class="box"> |
| 3 | 3 |
<center> |
| 4 |
<p><strong><%= @project.name %></strong><br /> |
|
| 4 |
<p><strong><%= @project_to_destroy.name %></strong><br />
|
|
| 5 | 5 |
<%=l(:text_project_destroy_confirmation)%></p> |
| 6 | 6 |
|
| 7 | 7 |
<p> |
| 8 |
<% form_tag({:controller => 'projects', :action => 'destroy', :id => @project}) do %>
|
|
| 8 |
<% form_tag({:controller => 'projects', :action => 'destroy', :id => @project_to_destroy}) do %>
|
|
| 9 | 9 |
<%= hidden_field_tag "confirm", 1 %> |
| 10 | 10 |
<%= submit_tag l(:button_delete) %> |
| 11 | 11 |
<% end %> |
| trunk/app/views/projects/gantt.rhtml | ||
|---|---|---|
| 49 | 49 |
<%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %> |
| 50 | 50 |
<%= tracker.name %><br /> |
| 51 | 51 |
<% end %> |
| 52 |
<% if @project.children.any? %> |
|
| 52 |
<% if @project.active_children.any? %>
|
|
| 53 | 53 |
<p><strong><%=l(:label_subproject_plural)%></strong></p> |
| 54 | 54 |
<%= check_box_tag "with_subprojects", 1, params[:with_subprojects] %> <%= l(:general_text_Yes) %> |
| 55 | 55 |
<% end %> |
| trunk/app/views/projects/show.rhtml | ||
|---|---|---|
| 45 | 45 |
<% end %> |
| 46 | 46 |
</div> |
| 47 | 47 |
|
| 48 |
<% if @subprojects %> |
|
| 48 |
<% if @subprojects.any? %>
|
|
| 49 | 49 |
<div class="box"> |
| 50 | 50 |
<h3 class="icon22 icon22-projects"><%=l(:label_subproject_plural)%></h3> |
| 51 | 51 |
<%= @subprojects.collect{|p| link_to(p.name, :action => 'show', :id => p)}.join(", ") %>
|
| trunk/db/migrate/051_add_project_status.rb | ||
|---|---|---|
| 1 |
class AddProjectStatus < ActiveRecord::Migration |
|
| 2 |
def self.up |
|
| 3 |
add_column :projects, :status, :integer, :default => 1, :null => false |
|
| 4 |
end |
|
| 5 |
|
|
| 6 |
def self.down |
|
| 7 |
remove_column :projects, :status |
|
| 8 |
end |
|
| 9 |
end |
|
| trunk/lang/bg.yml | ||
|---|---|---|
| 425 | 425 |
button_watch: Наблюдавай |
| 426 | 426 |
button_unwatch: Спри наблюдението |
| 427 | 427 |
button_reply: Reply |
| 428 |
button_archive: Archive |
|
| 429 |
button_unarchive: Unarchive |
|
| 428 | 430 |
|
| 429 | 431 |
status_active: активен |
| 430 | 432 |
status_registered: регистриран |
| trunk/lang/de.yml | ||
|---|---|---|
| 425 | 425 |
button_watch: Watch |
| 426 | 426 |
button_unwatch: Unwatch |
| 427 | 427 |
button_reply: Reply |
| 428 |
button_archive: Archive |
|
| 429 |
button_unarchive: Unarchive |
|
| 428 | 430 |
|
| 429 | 431 |
status_active: aktiv |
| 430 | 432 |
status_registered: angemeldet |
| trunk/lang/en.yml | ||
|---|---|---|
| 425 | 425 |
button_watch: Watch |
| 426 | 426 |
button_unwatch: Unwatch |
| 427 | 427 |
button_reply: Reply |
| 428 |
button_archive: Archive |
|
| 429 |
button_unarchive: Unarchive |
|
| 428 | 430 |
|
| 429 | 431 |
status_active: active |
| 430 | 432 |
status_registered: registered |
| trunk/lang/es.yml | ||
|---|---|---|
| 425 | 425 |
button_watch: Watch |
| 426 | 426 |
button_unwatch: Unwatch |
| 427 | 427 |
button_reply: Reply |
| 428 |
button_archive: Archive |
|
| 429 |
button_unarchive: Unarchive |
|
| 428 | 430 |
|
| 429 | 431 |
status_active: active |
| 430 | 432 |
status_registered: registered |
| trunk/lang/fr.yml | ||
|---|---|---|
| 425 | 425 |
button_watch: Surveiller |
| 426 | 426 |
button_unwatch: Ne plus surveiller |
| 427 | 427 |
button_reply: Répondre |
| 428 |
button_archive: Archiver |
|
| 429 |
button_unarchive: Désarchiver |
|
| 428 | 430 |
|
| 429 | 431 |
status_active: actif |
| 430 | 432 |
status_registered: enregistré |
| trunk/lang/it.yml | ||
|---|---|---|
| 425 | 425 |
button_watch: Watch |
| 426 | 426 |
button_unwatch: Unwatch |
| 427 | 427 |
button_reply: Reply |
| 428 |
button_archive: Archive |
|
| 429 |
button_unarchive: Unarchive |
|
| 428 | 430 |
|
| 429 | 431 |
status_active: attivo |
| 430 | 432 |
status_registered: registrato |
| trunk/lang/ja.yml | ||
|---|---|---|
| 426 | 426 |
button_watch: Watch |
| 427 | 427 |
button_unwatch: Unwatch |
| 428 | 428 |
button_reply: Reply |
| 429 |
button_archive: Archive |
|
| 430 |
button_unarchive: Unarchive |
|
| 429 | 431 |
|
| 430 | 432 |
status_active: 有効 |
| 431 | 433 |
status_registered: 登録 |
| trunk/lang/nl.yml | ||
|---|---|---|
| 425 | 425 |
button_watch: Monitor |
| 426 | 426 |
button_unwatch: Niet meer monitoren |
| 427 | 427 |
button_reply: Antwoord |
| 428 |
button_archive: Archive |
|
| 429 |
button_unarchive: Unarchive |
|
| 428 | 430 |
|
| 429 | 431 |
status_active: Actief |
| 430 | 432 |
status_registered: geregistreerd |
| trunk/lang/pt-br.yml | ||
|---|---|---|
| 425 | 425 |
button_watch: Watch |
| 426 | 426 |
button_unwatch: Unwatch |
| 427 | 427 |
button_reply: Reply |
| 428 |
button_archive: Archive |
|
| 429 |
button_unarchive: Unarchive |
|
| 428 | 430 |
|
| 429 | 431 |
status_active: ativo |
| 430 | 432 |
status_registered: registrado |
| trunk/lang/pt.yml | ||
|---|---|---|
| 425 | 425 |
button_watch: Observar |
| 426 | 426 |
button_unwatch: Não observar |
| 427 | 427 |
button_reply: Reply |
| 428 |
button_archive: Archive |
|
| 429 |
button_unarchive: Unarchive |
|
| 428 | 430 |
|
| 429 | 431 |
status_active: ativo |
| 430 | 432 |
status_registered: registrado |
| trunk/lang/zh.yml | ||
|---|---|---|
| 428 | 428 |
button_watch: Watch |
| 429 | 429 |
button_unwatch: Unwatch |
| 430 | 430 |
button_reply: Reply |
| 431 |
button_archive: Archive |
|
| 432 |
button_unarchive: Unarchive |
|
| 431 | 433 |
|
| 432 | 434 |
status_active: 激活 |
| 433 | 435 |
status_registered: 已注册 |
| trunk/public/stylesheets/application.css | ||
|---|---|---|
| 163 | 163 |
.icon-fav { background-image: url(../images/fav.png); }
|
| 164 | 164 |
.icon-fav-off { background-image: url(../images/fav_off.png); }
|
| 165 | 165 |
.icon-reload { background-image: url(../images/reload.png); }
|
| 166 |
.icon-lock { background-image: url(../images/locked.png); }
|
|
| 167 |
.icon-unlock { background-image: url(../images/unlock.png); }
|
|
| 166 | 168 |
|
| 167 | 169 |
.icon22-projects { background-image: url(../images/22x22/projects.png); }
|
| 168 | 170 |
.icon22-users { background-image: url(../images/22x22/users.png); }
|
| trunk/test/functional/projects_controller_test.rb | ||
|---|---|---|
| 1 | 1 |
# redMine - project management software |
| 2 |
# Copyright (C) 2006 Jean-Philippe Lang |
|
| 2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| ... | ... | |
| 125 | 125 |
assert_template 'activity' |
| 126 | 126 |
assert_not_nil assigns(:events_by_day) |
| 127 | 127 |
end |
| 128 |
|
|
| 129 |
def test_archive |
|
| 130 |
@request.session[:user_id] = 1 # admin |
|
| 131 |
post :archive, :id => 1 |
|
| 132 |
assert_redirected_to 'admin/projects' |
|
| 133 |
assert !Project.find(1).active? |
|
| 134 |
end |
|
| 135 |
|
|
| 136 |
def test_unarchive |
|
| 137 |
@request.session[:user_id] = 1 # admin |
|
| 138 |
Project.find(1).archive |
|
| 139 |
post :unarchive, :id => 1 |
|
| 140 |
assert_redirected_to 'admin/projects' |
|
| 141 |
assert Project.find(1).active? |
|
| 142 |
end |
|
| 128 | 143 |
end |
| trunk/test/integration/projects_test.rb | ||
|---|---|---|
| 1 |
# redMine - project management software |
|
| 2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang |
|
| 3 |
# |
|
| 4 |
# This program is free software; you can redistribute it and/or |
|
| 5 |
# modify it under the terms of the GNU General Public License |
|
| 6 |
# as published by the Free Software Foundation; either version 2 |
|
| 7 |
# of the License, or (at your option) any later version. |
|
| 8 |
# |
|
| 9 |
# This program is distributed in the hope that it will be useful, |
|
| 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 12 |
# GNU General Public License for more details. |
|
| 13 |
# |
|
| 14 |
# You should have received a copy of the GNU General Public License |
|
| 15 |
# along with this program; if not, write to the Free Software |
|
| 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 17 |
|
|
| 18 |
require "#{File.dirname(__FILE__)}/../test_helper"
|
|
| 19 |
|
|
| 20 |
class ProjectsTest < ActionController::IntegrationTest |
|
| 21 |
fixtures :projects, :users, :members |
|
| 22 |
|
|
| 23 |
def test_archive_project |
|
| 24 |
subproject = Project.find(1).children.first |
|
| 25 |
log_user("admin", "admin")
|
|
| 26 |
get "admin/projects" |
|
| 27 |
assert_response :success |
|
| 28 |
assert_template "admin/projects" |
|
| 29 |
post "projects/archive", :id => 1 |
|
| 30 |
assert_redirected_to "admin/projects" |
|
| 31 |
assert !Project.find(1).active? |
|
| 32 |
|
|
| 33 |
get "projects/show", :id => 1 |
|
| 34 |
assert_response :missing |
|
| 35 |
get "projects/show", :id => subproject.id |
|
| 36 |
assert_response :missing |
|
| 37 |
|
|
| 38 |
post "projects/unarchive", :id => 1 |
|
| 39 |
assert_redirected_to "admin/projects" |
|
| 40 |
assert Project.find(1).active? |
|
| 41 |
get "projects/show", :id => 1 |
|
| 42 |
assert_response :success |
|
| 43 |
end |
|
| 44 |
end |
|
| 0 | 45 | |
| trunk/test/unit/project_test.rb | ||
|---|---|---|
| 1 | 1 |
# redMine - project management software |
| 2 |
# Copyright (C) 2006 Jean-Philippe Lang |
|
| 2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| ... | ... | |
| 51 | 51 |
assert_equal true, public_projects[0].is_public? |
| 52 | 52 |
end |
| 53 | 53 |
|
| 54 |
def test_archive |
|
| 55 |
user = @ecookbook.members.first.user |
|
| 56 |
@ecookbook.archive |
|
| 57 |
@ecookbook.reload |
|
| 58 |
|
|
| 59 |
assert [email protected]? |
|
| 60 |
assert !user.projects.include?(@ecookbook) |
|
| 61 |
# Subproject are also archived |
|
| 62 |
assert [email protected]? |
|
| 63 |
assert @ecookbook.active_children.empty? |
|
| 64 |
end |
|
| 65 |
|
|
| 66 |
def test_unarchive |
|
| 67 |
user = @ecookbook.members.first.user |
|
| 68 |
@ecookbook.archive |
|
| 69 |
# A subproject of an archived project can not be unarchived |
|
| 70 |
assert !@ecookbook_sub1.unarchive |
|
| 71 |
|
|
| 72 |
# Unarchive project |
|
| 73 |
assert @ecookbook.unarchive |
|
| 74 |
@ecookbook.reload |
|
| 75 |
assert @ecookbook.active? |
|
| 76 |
assert user.projects.include?(@ecookbook) |
|
| 77 |
# Subproject can now be unarchived |
|
| 78 |
@ecookbook_sub1.reload |
|
| 79 |
assert @ecookbook_sub1.unarchive |
|
| 80 |
end |
|
| 81 |
|
|
| 54 | 82 |
def test_destroy |
| 55 | 83 |
@ecookbook.destroy |
| 56 | 84 |
assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
|
Also available in: Unified diff