@@ -0,0 +1,40 | |||
|
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 |
@@ -0,0 +1,9 | |||
|
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 |
|
1 | NO CONTENT: new file 100644, binary diff hidden |
@@ -0,0 +1,44 | |||
|
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 |
@@ -27,12 +27,18 class AdminController < ApplicationController | |||
|
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 |
|
|
|
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 |
@@ -86,6 +86,11 class ApplicationController < ActionController::Base | |||
|
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,6 +110,11 class ApplicationController < ActionController::Base | |||
|
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 |
@@ -19,9 +19,11 require 'csv' | |||
|
19 | 19 | |
|
20 | 20 | class ProjectsController < ApplicationController |
|
21 | 21 | layout 'base' |
|
22 |
before_filter :find_project |
|
|
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,7 +88,7 class ProjectsController < ApplicationController | |||
|
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. |
|
|
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,12 +140,25 class ProjectsController < ApplicationController | |||
|
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? && !@project.active? | |
|
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 |
@@ -55,7 +55,7 class ReportsController < ApplicationController | |||
|
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,7 +66,7 class ReportsController < ApplicationController | |||
|
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,8 +207,8 private | |||
|
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 |
@@ -88,7 +88,7 class UsersController < ApplicationController | |||
|
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 |
@@ -16,4 +16,8 | |||
|
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 |
@@ -16,6 +16,10 | |||
|
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,6 +36,8 class Project < ActiveRecord::Base | |||
|
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,12 +58,11 class Project < ActiveRecord::Base | |||
|
52 | 58 | |
|
53 | 59 | def issues_with_subprojects(include_subprojects=false) |
|
54 | 60 | conditions = nil |
|
55 |
if include_subprojects && children. |
|
|
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,12 +76,33 class Project < ActiveRecord::Base | |||
|
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] | |
|
84 | end | |
|
85 | end | |
|
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 | |
|
79 | 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?} | |
|
80 | 106 | end |
|
81 | 107 | |
|
82 | 108 | # Returns an array of all custom fields enabled for project issues |
@@ -95,8 +95,8 class Query < ActiveRecord::Base | |||
|
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,7 +164,7 class Query < ActiveRecord::Base | |||
|
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 |
@@ -23,7 +23,7 class User < ActiveRecord::Base | |||
|
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' |
@@ -4,6 +4,15 | |||
|
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,22 +21,29 | |||
|
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 |
|
|
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> | |
|
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> | |
|
26 | 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> No newline at end of file | |
|
48 | <p><%= pagination_links_full @project_pages, :status => @status %> | |
|
49 | [ <%= @project_pages.current.first_item %> - <%= @project_pages.current.last_item %> / <%= @project_count %> ]</p> |
@@ -1,6 +1,6 | |||
|
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") %> |
@@ -1,6 +1,6 | |||
|
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") %> |
@@ -2,7 +2,7 | |||
|
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 %> |
@@ -23,7 +23,7 | |||
|
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 %> |
@@ -1,11 +1,11 | |||
|
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 %> |
@@ -49,7 +49,7 t_height = g_height + headers_height | |||
|
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 %> |
@@ -45,7 +45,7 | |||
|
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(", ") %> |
@@ -425,6 +425,8 button_rollback: Върни се към тази ревизия | |||
|
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: регистриран |
@@ -425,6 +425,8 button_rollback: Rollback to this version | |||
|
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 |
@@ -425,6 +425,8 button_rollback: Rollback to this version | |||
|
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 |
@@ -425,6 +425,8 button_rollback: Rollback to this version | |||
|
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 |
@@ -425,6 +425,8 button_rollback: Revenir à cette version | |||
|
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é |
@@ -425,6 +425,8 button_rollback: Ripristina questa versione | |||
|
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 |
@@ -426,6 +426,8 button_rollback: このバージョンにロールバック | |||
|
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: 登録 |
@@ -425,6 +425,8 button_rollback: Rollback naar deze versie | |||
|
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 |
@@ -425,6 +425,8 button_rollback: Voltar para esta versao | |||
|
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 |
@@ -425,6 +425,8 button_rollback: Voltar para esta versão | |||
|
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 |
@@ -428,6 +428,8 button_rollback: Rollback to this version | |||
|
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: 已注册 |
@@ -163,6 +163,8 vertical-align: middle; | |||
|
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); } |
@@ -1,5 +1,5 | |||
|
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,4 +125,19 class ProjectsControllerTest < Test::Unit::TestCase | |||
|
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 |
@@ -1,5 +1,5 | |||
|
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,6 +51,34 class ProjectTest < Test::Unit::TestCase | |||
|
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 !@ecookbook.active? | |
|
60 | assert !user.projects.include?(@ecookbook) | |
|
61 | # Subproject are also archived | |
|
62 | assert !@ecookbook.children.empty? | |
|
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) } |
General Comments 0
You need to be logged in to leave comments.
Login now