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 @ 1541:2696466256ff

History | View | Annotate | Download (10.1 KB)

1
# Redmine - project management software
2
# Copyright (C) 2006-2014  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 ProjectsController < ApplicationController
19
  menu_item :overview
20
  menu_item :roadmap, :only => :roadmap
21
  menu_item :settings, :only => :settings
22

    
23
  before_filter :find_project, :except => [ :index, :list, :explore, :new, :create, :copy ]
24
  before_filter :authorize, :except => [ :index, :list, :explore, :new, :create, :copy, :archive, :unarchive, :destroy]
25
  before_filter :authorize_global, :only => [:new, :create]
26
  before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
27
  accept_rss_auth :index
28
  accept_api_auth :index, :show, :create, :update, :destroy
29

    
30
  after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller|
31
    if controller.request.post?
32
      controller.send :expire_action, :controller => 'welcome', :action => 'robots'
33
    end
34
  end
35

    
36
  helper :sort
37
  include SortHelper
38
  helper :custom_fields
39
  include CustomFieldsHelper
40
  helper :issues
41
  helper :queries
42
  include QueriesHelper
43
  helper :repositories
44
  include RepositoriesHelper
45
  include ProjectsHelper
46
  helper :members
47
  include ActivitiesHelper
48
  helper :activities
49

    
50
  # Lists visible projects. Paginator is for top-level projects only
51
  # (subprojects belong to them)
52
  def index
53
    respond_to do |format|
54
      format.html {
55
        sort_init 'name'
56
        sort_update %w(name lft created_on updated_on)
57
        @limit = per_page_option
58
        @project_count = Project.visible_roots.count
59
        @project_pages = Paginator.new self, @project_count, @limit, params['page']
60
        @offset ||= @project_pages.current.offset
61
        @projects = Project.visible_roots.all(:offset => @offset, :limit => @limit, :order => sort_clause)
62
        render :template => 'projects/index', :layout => !request.xhr?
63

    
64
## Redmine 2.2:
65
#        scope = Project
66
#        unless params[:closed]
67
#          scope = scope.active
68
#        end
69
#        @projects = scope.visible.order('lft').all
70
      }
71
      format.api  {
72
        @offset, @limit = api_offset_and_limit
73
        @project_count = Project.visible.count
74
        @projects = Project.visible.offset(@offset).limit(@limit).order('lft').all
75
      }
76
      format.atom {
77
        projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).all
78
        render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
79
      }
80
    end
81
  end
82

    
83
  # A different view of projects using explore boxes
84
  def explore
85
    respond_to do |format|
86
      format.html {
87
        @projects = Project.visible
88
        render :template => 'projects/explore', :layout => !request.xhr?
89
      }
90
    end
91
  end
92

    
93
  def new
94
    @issue_custom_fields = IssueCustomField.sorted.all
95
    @trackers = Tracker.sorted.all
96
    @project = Project.new
97
    @project.safe_attributes = params[:project]
98
  end
99

    
100
  def create
101
    @issue_custom_fields = IssueCustomField.sorted.all
102
    @trackers = Tracker.sorted.all
103
    @project = Project.new
104
    @project.safe_attributes = params[:project]
105

    
106
    if validate_is_public_key && validate_parent_id && @project.save
107
      @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
108
      # Add current user as a project member if current user is not admin
109
      unless User.current.admin?
110
        r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first
111
        m = Member.new(:user => User.current, :roles => [r])
112
        @project.members << m
113
      end
114
      respond_to do |format|
115
        format.html {
116
          flash[:notice] = l(:notice_successful_create)
117
          if params[:continue]
118
            attrs = {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}
119
            redirect_to new_project_path(attrs)
120
          else
121
            redirect_to settings_project_path(@project)
122
          end
123
        }
124
        format.api  { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
125
      end
126
    else
127
      respond_to do |format|
128
        format.html { render :action => 'new' }
129
        format.api  { render_validation_errors(@project) }
130
      end
131
    end
132
  end
133

    
134
  def copy
135
    @issue_custom_fields = IssueCustomField.sorted.all
136
    @trackers = Tracker.sorted.all
137
    @source_project = Project.find(params[:id])
138
    if request.get?
139
      @project = Project.copy_from(@source_project)
140
      @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?
141
    else
142
      Mailer.with_deliveries(params[:notifications] == '1') do
143
        @project = Project.new
144
        @project.safe_attributes = params[:project]
145
        if validate_parent_id && @project.copy(@source_project, :only => params[:only])
146
          @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
147
          flash[:notice] = l(:notice_successful_create)
148
          redirect_to settings_project_path(@project)
149
        elsif !@project.new_record?
150
          # Project was created
151
          # But some objects were not copied due to validation failures
152
          # (eg. issues from disabled trackers)
153
          # TODO: inform about that
154
          redirect_to settings_project_path(@project)
155
        end
156
      end
157
    end
158
  rescue ActiveRecord::RecordNotFound
159
    # source_project not found
160
    render_404
161
  end
162

    
163
  # Show @project
164
  def show
165
    # try to redirect to the requested menu item
166
    if params[:jump] && redirect_to_project_menu_item(@project, params[:jump])
167
      return
168
    end
169

    
170
    @users_by_role = @project.users_by_role
171
    @subprojects = @project.children.visible.all
172
    @news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").all
173
    @trackers = @project.rolled_up_trackers
174

    
175
    cond = @project.project_condition(Setting.display_subprojects_issues?)
176

    
177
    @open_issues_by_tracker = Issue.visible.open.where(cond).group(:tracker).count
178
    @total_issues_by_tracker = Issue.visible.where(cond).group(:tracker).count
179

    
180
    if User.current.allowed_to?(:view_time_entries, @project)
181
      @total_hours = TimeEntry.visible.where(cond).sum(:hours).to_f
182
    end
183

    
184
    @key = User.current.rss_key
185

    
186
    respond_to do |format|
187
      format.html
188
      format.api
189
    end
190
  end
191

    
192
  def settings
193
    @issue_custom_fields = IssueCustomField.sorted.all
194
    @issue_category ||= IssueCategory.new
195
    @member ||= @project.members.new
196
    @trackers = Tracker.sorted.all
197
    @repository ||= @project.repository
198
    @wiki ||= @project.wiki
199
  end
200

    
201
  def edit
202
  end
203

    
204
  def update
205
    @project.safe_attributes = params[:project]
206
    if validate_parent_id && @project.save
207
      @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
208
      respond_to do |format|
209
        format.html {
210
          flash[:notice] = l(:notice_successful_update)
211
          redirect_to settings_project_path(@project)
212
        }
213
        format.api  { render_api_ok }
214
      end
215
    else
216
      respond_to do |format|
217
        format.html {
218
          settings
219
          render :action => 'settings'
220
        }
221
        format.api  { render_validation_errors(@project) }
222
      end
223
    end
224
  end
225

    
226
  def overview
227
    @project.has_welcome_page = params[:has_welcome_page]
228
    if @project.save
229
      flash[:notice] = l(:notice_successful_update)
230
    end
231
    redirect_to :action => 'settings', :id => @project, :tab => 'overview'
232
  end
233

    
234
  def modules
235
    @project.enabled_module_names = params[:enabled_module_names]
236
    flash[:notice] = l(:notice_successful_update)
237
    redirect_to settings_project_path(@project, :tab => 'modules')
238
  end
239

    
240
  def archive
241
    if request.post?
242
      unless @project.archive
243
        flash[:error] = l(:error_can_not_archive_project)
244
      end
245
    end
246
    redirect_to admin_projects_path(:status => params[:status])
247
  end
248

    
249
  def unarchive
250
    @project.unarchive if request.post? && !@project.active?
251
    redirect_to admin_projects_path(:status => params[:status])
252
  end
253

    
254
  def close
255
    @project.close
256
    redirect_to project_path(@project)
257
  end
258

    
259
  def reopen
260
    @project.reopen
261
    redirect_to project_path(@project)
262
  end
263

    
264
  # Delete @project
265
  def destroy
266
    @project_to_destroy = @project
267
    if api_request? || params[:confirm]
268
      @project_to_destroy.destroy
269
      respond_to do |format|
270
        format.html { redirect_to admin_projects_path }
271
        format.api  { render_api_ok }
272
      end
273
    end
274
    # hide project in layout
275
    @project = nil
276
  end
277

    
278
  private
279

    
280
  def validate_is_public_key
281
    # Although is_public isn't mandatory in the project model (it gets
282
    # defaulted), it must be present in params -- it can be true or
283
    # false, but it must be there. This permits us to make forms in
284
    # which the user _has_ to select public or private (rather than
285
    # defaulting it) if we want to
286
    if params.nil? || params[:project].nil? || !params[:project].has_key?(:is_public)
287
      @project.errors.add :is_public, :public_or_private
288
      return false
289
    end
290
    true
291
  end
292

    
293
  # Validates parent_id param according to user's permissions
294
  # TODO: move it to Project model in a validation that depends on User.current
295
  def validate_parent_id
296
    return true if User.current.admin?
297
    parent_id = params[:project] && params[:project][:parent_id]
298
    if parent_id || @project.new_record?
299
      parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i)
300
      unless @project.allowed_parents.include?(parent)
301
        @project.errors.add :parent_id, :invalid
302
        return false
303
      end
304
    end
305
    true
306
  end
307
end