To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / app / controllers / projects_controller.rb @ 443:350acce374a2

History | View | Annotate | Download (10.7 KB)

1 0:513646585e45 Chris
# Redmine - project management software
2 441:cbce1fd3b1b7 Chris
# Copyright (C) 2006-2011  Jean-Philippe Lang
3 0:513646585e45 Chris
#
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 ProjectsController < ApplicationController
19
  menu_item :overview
20
  menu_item :roadmap, :only => :roadmap
21
  menu_item :settings, :only => :settings
22
23 22:40f7cfd4df19 chris
  before_filter :find_project, :except => [ :index, :list, :new, :create, :copy ]
24
  before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy]
25
  before_filter :authorize_global, :only => [:new, :create]
26 0:513646585e45 Chris
  before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
27 117:af80e5618e9b Chris
  accept_key_auth :index, :show, :create, :update, :destroy
28 22:40f7cfd4df19 chris
29
  after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller|
30 0:513646585e45 Chris
    if controller.request.post?
31
      controller.send :expire_action, :controller => 'welcome', :action => 'robots.txt'
32
    end
33
  end
34 22:40f7cfd4df19 chris
35 0:513646585e45 Chris
  helper :sort
36
  include SortHelper
37
  helper :custom_fields
38
  include CustomFieldsHelper
39
  helper :issues
40
  helper :queries
41
  include QueriesHelper
42
  helper :repositories
43
  include RepositoriesHelper
44
  include ProjectsHelper
45 131:513e61d1b4da chris
46 205:05f9a2a9c753 chris
  # Lists visible projects. Paginator is for top-level projects only
47
  # (subprojects belong to them)
48 0:513646585e45 Chris
  def index
49
    respond_to do |format|
50
      format.html {
51 205:05f9a2a9c753 chris
        sort_init 'name'
52
        sort_update %w(name lft created_on updated_on)
53 131:513e61d1b4da chris
        @limit = per_page_option
54 205:05f9a2a9c753 chris
        @project_count = Project.visible_roots.count
55 131:513e61d1b4da chris
        @project_pages = Paginator.new self, @project_count, @limit, params['page']
56
        @offset ||= @project_pages.current.offset
57 205:05f9a2a9c753 chris
        @projects = Project.visible_roots.all(:offset => @offset, :limit => @limit, :order => sort_clause)
58 131:513e61d1b4da chris
        if User.current.logged?
59 418:a9921f3e9088 chris
          # seems sort_by gives us case-sensitive ordering, which we don't want
60
#          @user_projects = User.current.projects.sort_by(&:name)
61
          @user_projects = User.current.projects.all(:order => :name)
62 131:513e61d1b4da chris
        end
63
        render :template => 'projects/index.rhtml', :layout => !request.xhr?
64 0:513646585e45 Chris
      }
65 117:af80e5618e9b Chris
      format.api  {
66
        @offset, @limit = api_offset_and_limit
67
        @project_count = Project.visible.count
68
        @projects = Project.visible.all(:offset => @offset, :limit => @limit, :order => 'lft')
69 0:513646585e45 Chris
      }
70
      format.atom {
71
        projects = Project.visible.find(:all, :order => 'created_on DESC',
72
                                              :limit => Setting.feeds_limit.to_i)
73
        render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
74
      }
75
    end
76
  end
77
78 22:40f7cfd4df19 chris
  def new
79 0:513646585e45 Chris
    @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
80
    @trackers = Tracker.all
81
    @project = Project.new(params[:project])
82 22:40f7cfd4df19 chris
  end
83
84 117:af80e5618e9b Chris
  verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
85 22:40f7cfd4df19 chris
  def create
86
    @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
87
    @trackers = Tracker.all
88 117:af80e5618e9b Chris
    @project = Project.new
89
    @project.safe_attributes = params[:project]
90 22:40f7cfd4df19 chris
91
    if validate_parent_id && @project.save
92
      @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
93
      # Add current user as a project member if he is not admin
94
      unless User.current.admin?
95
        r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first
96
        m = Member.new(:user => User.current, :roles => [r])
97
        @project.members << m
98
      end
99
      respond_to do |format|
100
        format.html {
101
          flash[:notice] = l(:notice_successful_create)
102
          redirect_to :controller => 'projects', :action => 'settings', :id => @project
103
        }
104 117:af80e5618e9b Chris
        format.api  { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
105 22:40f7cfd4df19 chris
      end
106 0:513646585e45 Chris
    else
107 22:40f7cfd4df19 chris
      respond_to do |format|
108
        format.html { render :action => 'new' }
109 117:af80e5618e9b Chris
        format.api  { render_validation_errors(@project) }
110 0:513646585e45 Chris
      end
111 22:40f7cfd4df19 chris
    end
112
113 0:513646585e45 Chris
  end
114
115
  def copy
116
    @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
117
    @trackers = Tracker.all
118
    @root_projects = Project.find(:all,
119
                                  :conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}",
120
                                  :order => 'name')
121
    @source_project = Project.find(params[:id])
122
    if request.get?
123
      @project = Project.copy_from(@source_project)
124
      if @project
125
        @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?
126
      else
127
        redirect_to :controller => 'admin', :action => 'projects'
128
      end
129
    else
130
      Mailer.with_deliveries(params[:notifications] == '1') do
131 117:af80e5618e9b Chris
        @project = Project.new
132
        @project.safe_attributes = params[:project]
133 0:513646585e45 Chris
        if validate_parent_id && @project.copy(@source_project, :only => params[:only])
134
          @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
135
          flash[:notice] = l(:notice_successful_create)
136 117:af80e5618e9b Chris
          redirect_to :controller => 'projects', :action => 'settings', :id => @project
137 0:513646585e45 Chris
        elsif !@project.new_record?
138
          # Project was created
139
          # But some objects were not copied due to validation failures
140
          # (eg. issues from disabled trackers)
141
          # TODO: inform about that
142 117:af80e5618e9b Chris
          redirect_to :controller => 'projects', :action => 'settings', :id => @project
143 0:513646585e45 Chris
        end
144
      end
145
    end
146
  rescue ActiveRecord::RecordNotFound
147
    redirect_to :controller => 'admin', :action => 'projects'
148
  end
149
150
  # Show @project
151
  def show
152
    if params[:jump]
153
      # try to redirect to the requested menu item
154
      redirect_to_project_menu_item(@project, params[:jump]) && return
155
    end
156
157
    @users_by_role = @project.users_by_role
158 441:cbce1fd3b1b7 Chris
    @subprojects = @project.children.visible.all
159 0:513646585e45 Chris
    @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
160
    @trackers = @project.rolled_up_trackers
161
162
    cond = @project.project_condition(Setting.display_subprojects_issues?)
163
164
    @open_issues_by_tracker = Issue.visible.count(:group => :tracker,
165
                                            :include => [:project, :status, :tracker],
166
                                            :conditions => ["(#{cond}) AND #{IssueStatus.table_name}.is_closed=?", false])
167
    @total_issues_by_tracker = Issue.visible.count(:group => :tracker,
168
                                            :include => [:project, :status, :tracker],
169
                                            :conditions => cond)
170
171 441:cbce1fd3b1b7 Chris
    if User.current.allowed_to?(:view_time_entries, @project)
172
      @total_hours = TimeEntry.visible.sum(:hours, :include => :project, :conditions => cond).to_f
173 0:513646585e45 Chris
    end
174 441:cbce1fd3b1b7 Chris
175 0:513646585e45 Chris
    @key = User.current.rss_key
176
177
    respond_to do |format|
178
      format.html
179 117:af80e5618e9b Chris
      format.api
180 0:513646585e45 Chris
    end
181
  end
182
183
  def settings
184
    @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
185
    @issue_category ||= IssueCategory.new
186
    @member ||= @project.members.new
187
    @trackers = Tracker.all
188
    @repository ||= @project.repository
189
    @wiki ||= @project.wiki
190
  end
191
192
  def edit
193 22:40f7cfd4df19 chris
  end
194
195 117:af80e5618e9b Chris
  # TODO: convert to PUT only
196
  verify :method => [:post, :put], :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
197 22:40f7cfd4df19 chris
  def update
198 117:af80e5618e9b Chris
    @project.safe_attributes = params[:project]
199 22:40f7cfd4df19 chris
    if validate_parent_id && @project.save
200
      @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
201
      respond_to do |format|
202
        format.html {
203
          flash[:notice] = l(:notice_successful_update)
204
          redirect_to :action => 'settings', :id => @project
205
        }
206 117:af80e5618e9b Chris
        format.api  { head :ok }
207 22:40f7cfd4df19 chris
      end
208 0:513646585e45 Chris
    else
209 22:40f7cfd4df19 chris
      respond_to do |format|
210
        format.html {
211
          settings
212
          render :action => 'settings'
213
        }
214 117:af80e5618e9b Chris
        format.api  { render_validation_errors(@project) }
215 0:513646585e45 Chris
      end
216
    end
217
  end
218 351:ebf53b46f3f3 chris
219 117:af80e5618e9b Chris
  verify :method => :post, :only => :modules, :render => {:nothing => true, :status => :method_not_allowed }
220 443:350acce374a2 Chris
221 351:ebf53b46f3f3 chris
  def overview
222
    @project.has_welcome_page = params[:has_welcome_page]
223
    if @project.save
224
      flash[:notice] = l(:notice_successful_update)
225
    end
226
    redirect_to :action => 'settings', :id => @project, :tab => 'overview'
227
  end
228
229 0:513646585e45 Chris
  def modules
230 117:af80e5618e9b Chris
    @project.enabled_module_names = params[:enabled_module_names]
231 0:513646585e45 Chris
    flash[:notice] = l(:notice_successful_update)
232
    redirect_to :action => 'settings', :id => @project, :tab => 'modules'
233
  end
234
235
  def archive
236
    if request.post?
237
      unless @project.archive
238
        flash[:error] = l(:error_can_not_archive_project)
239
      end
240
    end
241
    redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
242
  end
243
244
  def unarchive
245
    @project.unarchive if request.post? && !@project.active?
246
    redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
247
  end
248
249
  # Delete @project
250
  def destroy
251
    @project_to_destroy = @project
252
    if request.get?
253
      # display confirmation view
254
    else
255 117:af80e5618e9b Chris
      if api_request? || params[:confirm]
256 0:513646585e45 Chris
        @project_to_destroy.destroy
257
        respond_to do |format|
258
          format.html { redirect_to :controller => 'admin', :action => 'projects' }
259 117:af80e5618e9b Chris
          format.api  { head :ok }
260 0:513646585e45 Chris
        end
261
      end
262
    end
263
    # hide project in layout
264
    @project = nil
265
  end
266
267
private
268
  def find_optional_project
269
    return true unless params[:id]
270
    @project = Project.find(params[:id])
271
    authorize
272
  rescue ActiveRecord::RecordNotFound
273
    render_404
274
  end
275
276
  # Validates parent_id param according to user's permissions
277
  # TODO: move it to Project model in a validation that depends on User.current
278
  def validate_parent_id
279
    return true if User.current.admin?
280
    parent_id = params[:project] && params[:project][:parent_id]
281
    if parent_id || @project.new_record?
282
      parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i)
283
      unless @project.allowed_parents.include?(parent)
284
        @project.errors.add :parent_id, :invalid
285
        return false
286
      end
287
    end
288
    true
289
  end
290
end