annotate app/controllers/timelog_controller.rb @ 1476:497ec7118440 biblio_alt_search_auth

Close obsolete branch biblio_alt_search_auth
author Chris Cannam
date Sat, 12 Oct 2013 13:49:02 +0100
parents 433d4f72a19b
children 622f24f53b42 261b3d9a4903
rev   line source
Chris@119 1 # Redmine - project management software
Chris@1115 2 # Copyright (C) 2006-2012 Jean-Philippe Lang
Chris@0 3 #
Chris@0 4 # This program is free software; you can redistribute it and/or
Chris@0 5 # modify it under the terms of the GNU General Public License
Chris@0 6 # as published by the Free Software Foundation; either version 2
Chris@0 7 # of the License, or (at your option) any later version.
Chris@909 8 #
Chris@0 9 # This program is distributed in the hope that it will be useful,
Chris@0 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 12 # GNU General Public License for more details.
Chris@909 13 #
Chris@0 14 # You should have received a copy of the GNU General Public License
Chris@0 15 # along with this program; if not, write to the Free Software
Chris@0 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Chris@0 17
Chris@0 18 class TimelogController < ApplicationController
Chris@0 19 menu_item :issues
Chris@1115 20
Chris@1115 21 before_filter :find_project_for_new_time_entry, :only => [:create]
Chris@441 22 before_filter :find_time_entry, :only => [:show, :edit, :update]
Chris@441 23 before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy]
Chris@1115 24 before_filter :authorize, :except => [:new, :index, :report]
Chris@1115 25
Chris@1115 26 before_filter :find_optional_project, :only => [:index, :report]
Chris@1115 27 before_filter :find_optional_project_for_new_time_entry, :only => [:new]
Chris@1115 28 before_filter :authorize_global, :only => [:new, :index, :report]
Chris@1115 29
Chris@507 30 accept_rss_auth :index
Chris@507 31 accept_api_auth :index, :show, :create, :update, :destroy
Chris@909 32
Chris@0 33 helper :sort
Chris@0 34 include SortHelper
Chris@0 35 helper :issues
Chris@0 36 include TimelogHelper
Chris@0 37 helper :custom_fields
Chris@0 38 include CustomFieldsHelper
Chris@909 39
chris@37 40 def index
Chris@0 41 sort_init 'spent_on', 'desc'
Chris@1115 42 sort_update 'spent_on' => ['spent_on', "#{TimeEntry.table_name}.created_on"],
Chris@0 43 'user' => 'user_id',
Chris@0 44 'activity' => 'activity_id',
Chris@0 45 'project' => "#{Project.table_name}.name",
Chris@0 46 'issue' => 'issue_id',
Chris@0 47 'hours' => 'hours'
Chris@909 48
Chris@1115 49 retrieve_date_range
Chris@1115 50
Chris@1115 51 scope = TimeEntry.visible.spent_between(@from, @to)
Chris@441 52 if @issue
Chris@1115 53 scope = scope.on_issue(@issue)
Chris@441 54 elsif @project
Chris@1115 55 scope = scope.on_project(@project, Setting.display_subprojects_issues?)
Chris@0 56 end
Chris@909 57
Chris@441 58 respond_to do |format|
Chris@441 59 format.html {
Chris@441 60 # Paginate results
Chris@1115 61 @entry_count = scope.count
Chris@441 62 @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
Chris@1115 63 @entries = scope.all(
Chris@1115 64 :include => [:project, :activity, :user, {:issue => :tracker}],
Chris@1115 65 :order => sort_clause,
Chris@1115 66 :limit => @entry_pages.items_per_page,
Chris@1115 67 :offset => @entry_pages.current.offset
Chris@1115 68 )
Chris@1115 69 @total_hours = scope.sum(:hours).to_f
Chris@0 70
Chris@441 71 render :layout => !request.xhr?
Chris@441 72 }
Chris@441 73 format.api {
Chris@1115 74 @entry_count = scope.count
Chris@441 75 @offset, @limit = api_offset_and_limit
Chris@1115 76 @entries = scope.all(
Chris@1115 77 :include => [:project, :activity, :user, {:issue => :tracker}],
Chris@1115 78 :order => sort_clause,
Chris@1115 79 :limit => @limit,
Chris@1115 80 :offset => @offset
Chris@1115 81 )
Chris@441 82 }
Chris@441 83 format.atom {
Chris@1115 84 entries = scope.all(
Chris@1115 85 :include => [:project, :activity, :user, {:issue => :tracker}],
Chris@1115 86 :order => "#{TimeEntry.table_name}.created_on DESC",
Chris@1115 87 :limit => Setting.feeds_limit.to_i
Chris@1115 88 )
Chris@441 89 render_feed(entries, :title => l(:label_spent_time))
Chris@441 90 }
Chris@441 91 format.csv {
Chris@441 92 # Export all entries
Chris@1115 93 @entries = scope.all(
Chris@1115 94 :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
Chris@1115 95 :order => sort_clause
Chris@1115 96 )
Chris@441 97 send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv')
Chris@441 98 }
Chris@0 99 end
Chris@0 100 end
Chris@909 101
Chris@1115 102 def report
Chris@1115 103 retrieve_date_range
Chris@1115 104 @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], @from, @to)
Chris@1115 105
Chris@1115 106 respond_to do |format|
Chris@1115 107 format.html { render :layout => !request.xhr? }
Chris@1115 108 format.csv { send_data(report_to_csv(@report), :type => 'text/csv; header=present', :filename => 'timelog.csv') }
Chris@1115 109 end
Chris@1115 110 end
Chris@1115 111
Chris@119 112 def show
Chris@119 113 respond_to do |format|
Chris@119 114 # TODO: Implement html response
Chris@119 115 format.html { render :nothing => true, :status => 406 }
Chris@119 116 format.api
Chris@119 117 end
Chris@119 118 end
chris@37 119
chris@37 120 def new
chris@37 121 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
Chris@929 122 @time_entry.safe_attributes = params[:time_entry]
chris@37 123 end
chris@37 124
chris@37 125 def create
Chris@0 126 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
Chris@929 127 @time_entry.safe_attributes = params[:time_entry]
Chris@909 128
Chris@0 129 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
Chris@909 130
chris@37 131 if @time_entry.save
Chris@119 132 respond_to do |format|
Chris@119 133 format.html {
Chris@1115 134 flash[:notice] = l(:notice_successful_create)
Chris@1115 135 if params[:continue]
Chris@1115 136 if params[:project_id]
Chris@1115 137 redirect_to :action => 'new', :project_id => @time_entry.project, :issue_id => @time_entry.issue,
Chris@1115 138 :time_entry => {:issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
Chris@1115 139 :back_url => params[:back_url]
Chris@1115 140 else
Chris@1115 141 redirect_to :action => 'new',
Chris@1115 142 :time_entry => {:project_id => @time_entry.project_id, :issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
Chris@1115 143 :back_url => params[:back_url]
Chris@1115 144 end
Chris@1115 145 else
Chris@1115 146 redirect_back_or_default :action => 'index', :project_id => @time_entry.project
Chris@1115 147 end
Chris@119 148 }
Chris@119 149 format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) }
Chris@119 150 end
chris@37 151 else
Chris@119 152 respond_to do |format|
Chris@1115 153 format.html { render :action => 'new' }
Chris@119 154 format.api { render_validation_errors(@time_entry) }
Chris@119 155 end
Chris@909 156 end
Chris@0 157 end
Chris@909 158
chris@37 159 def edit
Chris@929 160 @time_entry.safe_attributes = params[:time_entry]
chris@37 161 end
chris@37 162
chris@37 163 def update
Chris@929 164 @time_entry.safe_attributes = params[:time_entry]
Chris@909 165
chris@37 166 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
Chris@909 167
chris@37 168 if @time_entry.save
Chris@119 169 respond_to do |format|
Chris@119 170 format.html {
Chris@119 171 flash[:notice] = l(:notice_successful_update)
Chris@119 172 redirect_back_or_default :action => 'index', :project_id => @time_entry.project
Chris@119 173 }
Chris@1115 174 format.api { render_api_ok }
Chris@119 175 end
chris@37 176 else
Chris@119 177 respond_to do |format|
Chris@119 178 format.html { render :action => 'edit' }
Chris@119 179 format.api { render_validation_errors(@time_entry) }
Chris@119 180 end
Chris@909 181 end
chris@37 182 end
chris@37 183
Chris@441 184 def bulk_edit
Chris@441 185 @available_activities = TimeEntryActivity.shared.active
Chris@441 186 @custom_fields = TimeEntry.first.available_custom_fields
Chris@441 187 end
Chris@441 188
Chris@441 189 def bulk_update
Chris@441 190 attributes = parse_params_for_bulk_time_entry_attributes(params)
Chris@441 191
Chris@441 192 unsaved_time_entry_ids = []
Chris@441 193 @time_entries.each do |time_entry|
Chris@441 194 time_entry.reload
Chris@929 195 time_entry.safe_attributes = attributes
Chris@441 196 call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry })
Chris@441 197 unless time_entry.save
Chris@441 198 # Keep unsaved time_entry ids to display them in flash error
Chris@441 199 unsaved_time_entry_ids << time_entry.id
Chris@441 200 end
Chris@441 201 end
Chris@441 202 set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids)
Chris@441 203 redirect_back_or_default({:controller => 'timelog', :action => 'index', :project_id => @projects.first})
Chris@441 204 end
Chris@441 205
Chris@0 206 def destroy
Chris@1115 207 destroyed = TimeEntry.transaction do
Chris@1115 208 @time_entries.each do |t|
Chris@441 209 unless t.destroy && t.destroyed?
Chris@1115 210 raise ActiveRecord::Rollback
Chris@441 211 end
Chris@119 212 end
Chris@0 213 end
Chris@441 214
Chris@441 215 respond_to do |format|
Chris@441 216 format.html {
Chris@1115 217 if destroyed
Chris@1115 218 flash[:notice] = l(:notice_successful_delete)
Chris@1115 219 else
Chris@1115 220 flash[:error] = l(:notice_unable_delete_time_entry)
Chris@1115 221 end
Chris@441 222 redirect_back_or_default(:action => 'index', :project_id => @projects.first)
Chris@441 223 }
Chris@1115 224 format.api {
Chris@1115 225 if destroyed
Chris@1115 226 render_api_ok
Chris@1115 227 else
Chris@1115 228 render_validation_errors(@time_entries)
Chris@1115 229 end
Chris@1115 230 }
Chris@441 231 end
Chris@0 232 end
Chris@0 233
Chris@0 234 private
chris@37 235 def find_time_entry
chris@37 236 @time_entry = TimeEntry.find(params[:id])
chris@37 237 unless @time_entry.editable_by?(User.current)
chris@37 238 render_403
chris@37 239 return false
chris@37 240 end
chris@37 241 @project = @time_entry.project
chris@37 242 rescue ActiveRecord::RecordNotFound
chris@37 243 render_404
chris@37 244 end
chris@37 245
Chris@441 246 def find_time_entries
Chris@441 247 @time_entries = TimeEntry.find_all_by_id(params[:id] || params[:ids])
Chris@441 248 raise ActiveRecord::RecordNotFound if @time_entries.empty?
Chris@441 249 @projects = @time_entries.collect(&:project).compact.uniq
Chris@441 250 @project = @projects.first if @projects.size == 1
Chris@441 251 rescue ActiveRecord::RecordNotFound
Chris@441 252 render_404
Chris@441 253 end
Chris@441 254
Chris@441 255 def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids)
Chris@441 256 if unsaved_time_entry_ids.empty?
Chris@441 257 flash[:notice] = l(:notice_successful_update) unless time_entries.empty?
Chris@441 258 else
Chris@441 259 flash[:error] = l(:notice_failed_to_save_time_entries,
Chris@441 260 :count => unsaved_time_entry_ids.size,
Chris@441 261 :total => time_entries.size,
Chris@441 262 :ids => '#' + unsaved_time_entry_ids.join(', #'))
Chris@441 263 end
Chris@441 264 end
Chris@441 265
Chris@1115 266 def find_optional_project_for_new_time_entry
Chris@1115 267 if (project_id = (params[:project_id] || params[:time_entry] && params[:time_entry][:project_id])).present?
Chris@1115 268 @project = Project.find(project_id)
Chris@1115 269 end
Chris@119 270 if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present?
Chris@119 271 @issue = Issue.find(issue_id)
Chris@1115 272 @project ||= @issue.project
Chris@0 273 end
Chris@0 274 rescue ActiveRecord::RecordNotFound
Chris@0 275 render_404
Chris@0 276 end
Chris@909 277
Chris@1115 278 def find_project_for_new_time_entry
Chris@1115 279 find_optional_project_for_new_time_entry
Chris@1115 280 if @project.nil?
Chris@1115 281 render_404
Chris@1115 282 end
Chris@1115 283 end
Chris@1115 284
Chris@0 285 def find_optional_project
Chris@0 286 if !params[:issue_id].blank?
Chris@0 287 @issue = Issue.find(params[:issue_id])
Chris@0 288 @project = @issue.project
Chris@0 289 elsif !params[:project_id].blank?
Chris@0 290 @project = Project.find(params[:project_id])
Chris@0 291 end
Chris@0 292 end
Chris@909 293
Chris@0 294 # Retrieves the date range based on predefined ranges or specific from/to param dates
Chris@0 295 def retrieve_date_range
Chris@0 296 @free_period = false
Chris@0 297 @from, @to = nil, nil
Chris@0 298
Chris@0 299 if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?)
Chris@0 300 case params[:period].to_s
Chris@0 301 when 'today'
Chris@0 302 @from = @to = Date.today
Chris@0 303 when 'yesterday'
Chris@0 304 @from = @to = Date.today - 1
Chris@0 305 when 'current_week'
Chris@0 306 @from = Date.today - (Date.today.cwday - 1)%7
Chris@0 307 @to = @from + 6
Chris@0 308 when 'last_week'
Chris@0 309 @from = Date.today - 7 - (Date.today.cwday - 1)%7
Chris@0 310 @to = @from + 6
Chris@1115 311 when 'last_2_weeks'
Chris@1115 312 @from = Date.today - 14 - (Date.today.cwday - 1)%7
Chris@1115 313 @to = @from + 13
Chris@0 314 when '7_days'
Chris@0 315 @from = Date.today - 7
Chris@0 316 @to = Date.today
Chris@0 317 when 'current_month'
Chris@0 318 @from = Date.civil(Date.today.year, Date.today.month, 1)
Chris@0 319 @to = (@from >> 1) - 1
Chris@0 320 when 'last_month'
Chris@0 321 @from = Date.civil(Date.today.year, Date.today.month, 1) << 1
Chris@0 322 @to = (@from >> 1) - 1
Chris@0 323 when '30_days'
Chris@0 324 @from = Date.today - 30
Chris@0 325 @to = Date.today
Chris@0 326 when 'current_year'
Chris@0 327 @from = Date.civil(Date.today.year, 1, 1)
Chris@0 328 @to = Date.civil(Date.today.year, 12, 31)
Chris@0 329 end
Chris@0 330 elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?))
Chris@0 331 begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end
Chris@0 332 begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end
Chris@0 333 @free_period = true
Chris@0 334 else
Chris@0 335 # default
Chris@0 336 end
Chris@909 337
Chris@0 338 @from, @to = @to, @from if @from && @to && @from > @to
Chris@0 339 end
Chris@0 340
Chris@441 341 def parse_params_for_bulk_time_entry_attributes(params)
Chris@441 342 attributes = (params[:time_entry] || {}).reject {|k,v| v.blank?}
Chris@441 343 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
Chris@441 344 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
Chris@441 345 attributes
Chris@441 346 end
Chris@0 347 end