##// END OF EJS Templates
Added the ability to archive projects:...
Jean-Philippe Lang -
r546:413247ee5b16
parent child
Show More
@@ -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 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
@@ -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, :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,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.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,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.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,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 &nbsp;
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 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>
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