"Fossies" - the Fresh Open Source Software Archive

Member "redmine-4.1.1/app/controllers/timelog_controller.rb" (6 Apr 2020, 9509 Bytes) of package /linux/www/redmine-4.1.1.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "timelog_controller.rb": 4.1.0_vs_4.1.1.

    1 # frozen_string_literal: true
    2 
    3 # Redmine - project management software
    4 # Copyright (C) 2006-2019  Jean-Philippe Lang
    5 #
    6 # This program is free software; you can redistribute it and/or
    7 # modify it under the terms of the GNU General Public License
    8 # as published by the Free Software Foundation; either version 2
    9 # of the License, or (at your option) any later version.
   10 #
   11 # This program is distributed in the hope that it will be useful,
   12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 # GNU General Public License for more details.
   15 #
   16 # You should have received a copy of the GNU General Public License
   17 # along with this program; if not, write to the Free Software
   18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   19 
   20 class TimelogController < ApplicationController
   21   menu_item :time_entries
   22 
   23   before_action :find_time_entry, :only => [:show, :edit, :update]
   24   before_action :check_editability, :only => [:edit, :update]
   25   before_action :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy]
   26   before_action :authorize, :only => [:show, :edit, :update, :bulk_edit, :bulk_update, :destroy]
   27 
   28   before_action :find_optional_issue, :only => [:new, :create]
   29   before_action :find_optional_project, :only => [:index, :report]
   30 
   31   accept_rss_auth :index
   32   accept_api_auth :index, :show, :create, :update, :destroy
   33 
   34   rescue_from Query::StatementInvalid, :with => :query_statement_invalid
   35 
   36   helper :issues
   37   include TimelogHelper
   38   helper :custom_fields
   39   include CustomFieldsHelper
   40   helper :queries
   41   include QueriesHelper
   42 
   43   def index
   44     retrieve_time_entry_query
   45     scope = time_entry_scope.
   46       preload(:issue => [:project, :tracker, :status, :assigned_to, :priority]).
   47       preload(:project, :user)
   48 
   49     respond_to do |format|
   50       format.html {
   51         @entry_count = scope.count
   52         @entry_pages = Paginator.new @entry_count, per_page_option, params['page']
   53         @entries = scope.offset(@entry_pages.offset).limit(@entry_pages.per_page).to_a
   54 
   55         render :layout => !request.xhr?
   56       }
   57       format.api  {
   58         @entry_count = scope.count
   59         @offset, @limit = api_offset_and_limit
   60         @entries = scope.offset(@offset).limit(@limit).preload(:custom_values => :custom_field).to_a
   61       }
   62       format.atom {
   63         entries = scope.limit(Setting.feeds_limit.to_i).reorder("#{TimeEntry.table_name}.created_on DESC").to_a
   64         render_feed(entries, :title => l(:label_spent_time))
   65       }
   66       format.csv {
   67         # Export all entries
   68         @entries = scope.to_a
   69         send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'timelog.csv')
   70       }
   71     end
   72   end
   73 
   74   def report
   75     retrieve_time_entry_query
   76     scope = time_entry_scope
   77 
   78     @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], scope)
   79 
   80     respond_to do |format|
   81       format.html { render :layout => !request.xhr? }
   82       format.csv  { send_data(report_to_csv(@report), :type => 'text/csv; header=present', :filename => 'timelog.csv') }
   83     end
   84   end
   85 
   86   def show
   87     respond_to do |format|
   88       # TODO: Implement html response
   89       format.html { head 406 }
   90       format.api
   91     end
   92   end
   93 
   94   def new
   95     @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :author => User.current, :spent_on => User.current.today)
   96     @time_entry.safe_attributes = params[:time_entry]
   97   end
   98 
   99   def create
  100     @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :author => User.current, :user => User.current, :spent_on => User.current.today)
  101     @time_entry.safe_attributes = params[:time_entry]
  102     if @time_entry.project && !User.current.allowed_to?(:log_time, @time_entry.project)
  103       render_403
  104       return
  105     end
  106 
  107     call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
  108 
  109     if @time_entry.save
  110       respond_to do |format|
  111         format.html {
  112           flash[:notice] = l(:notice_successful_create)
  113           if params[:continue]
  114             options = {
  115               :time_entry => {
  116                 :project_id => params[:time_entry][:project_id],
  117                 :issue_id => @time_entry.issue_id,
  118                 :spent_on => @time_entry.spent_on,
  119                 :activity_id => @time_entry.activity_id
  120               },
  121               :back_url => params[:back_url]
  122             }
  123             if params[:project_id] && @time_entry.project
  124               redirect_to new_project_time_entry_path(@time_entry.project, options)
  125             elsif params[:issue_id] && @time_entry.issue
  126               redirect_to new_issue_time_entry_path(@time_entry.issue, options)
  127             else
  128               redirect_to new_time_entry_path(options)
  129             end
  130           else
  131             redirect_back_or_default project_time_entries_path(@time_entry.project)
  132           end
  133         }
  134         format.api  { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) }
  135       end
  136     else
  137       respond_to do |format|
  138         format.html { render :action => 'new' }
  139         format.api  { render_validation_errors(@time_entry) }
  140       end
  141     end
  142   end
  143 
  144   def edit
  145     @time_entry.safe_attributes = params[:time_entry]
  146   end
  147 
  148   def update
  149     @time_entry.safe_attributes = params[:time_entry]
  150     call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
  151 
  152     if @time_entry.save
  153       respond_to do |format|
  154         format.html {
  155           flash[:notice] = l(:notice_successful_update)
  156           redirect_back_or_default project_time_entries_path(@time_entry.project)
  157         }
  158         format.api  { render_api_ok }
  159       end
  160     else
  161       respond_to do |format|
  162         format.html { render :action => 'edit' }
  163         format.api  { render_validation_errors(@time_entry) }
  164       end
  165     end
  166   end
  167 
  168   def bulk_edit
  169     @target_projects = Project.allowed_to(:log_time).to_a
  170     @custom_fields = TimeEntry.first.available_custom_fields.select {|field| field.format.bulk_edit_supported}
  171     if params[:time_entry]
  172       @target_project = @target_projects.detect {|p| p.id.to_s == params[:time_entry][:project_id].to_s}
  173     end
  174     if @target_project
  175       @available_activities = @target_project.activities
  176     else
  177       @available_activities = @projects.map(&:activities).reduce(:&)
  178     end
  179     @time_entry_params = params[:time_entry] || {}
  180     @time_entry_params[:custom_field_values] ||= {}
  181   end
  182 
  183   def bulk_update
  184     attributes = parse_params_for_bulk_update(params[:time_entry])
  185 
  186     unsaved_time_entries = []
  187     saved_time_entries = []
  188 
  189     @time_entries.each do |time_entry|
  190       time_entry.reload
  191       time_entry.safe_attributes = attributes
  192       call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry })
  193       if time_entry.save
  194         saved_time_entries << time_entry
  195       else
  196         unsaved_time_entries << time_entry
  197       end
  198     end
  199 
  200     if unsaved_time_entries.empty?
  201       flash[:notice] = l(:notice_successful_update) unless saved_time_entries.empty?
  202       redirect_back_or_default project_time_entries_path(@projects.first)
  203     else
  204       @saved_time_entries = @time_entries
  205       @unsaved_time_entries = unsaved_time_entries
  206       @time_entries = TimeEntry.where(:id => unsaved_time_entries.map(&:id)).
  207         preload(:project => :time_entry_activities).
  208         preload(:user).to_a
  209 
  210       bulk_edit
  211       render :action => 'bulk_edit'
  212     end
  213   end
  214 
  215   def destroy
  216     destroyed = TimeEntry.transaction do
  217       @time_entries.each do |t|
  218         unless t.destroy && t.destroyed?
  219           raise ActiveRecord::Rollback
  220         end
  221       end
  222     end
  223 
  224     respond_to do |format|
  225       format.html {
  226         if destroyed
  227           flash[:notice] = l(:notice_successful_delete)
  228         else
  229           flash[:error] = l(:notice_unable_delete_time_entry)
  230         end
  231         redirect_back_or_default project_time_entries_path(@projects.first), :referer => true
  232       }
  233       format.api  {
  234         if destroyed
  235           render_api_ok
  236         else
  237           render_validation_errors(@time_entries)
  238         end
  239       }
  240     end
  241   end
  242 
  243   private
  244 
  245   def find_time_entry
  246     @time_entry = TimeEntry.find(params[:id])
  247     @project = @time_entry.project
  248   rescue ActiveRecord::RecordNotFound
  249     render_404
  250   end
  251 
  252   def check_editability
  253     unless @time_entry.editable_by?(User.current)
  254       render_403
  255       return false
  256     end
  257   end
  258 
  259   def find_time_entries
  260     @time_entries = TimeEntry.where(:id => params[:id] || params[:ids]).
  261       preload(:project => :time_entry_activities).
  262       preload(:user).to_a
  263 
  264     raise ActiveRecord::RecordNotFound if @time_entries.empty?
  265     raise Unauthorized unless @time_entries.all? {|t| t.editable_by?(User.current)}
  266     @projects = @time_entries.collect(&:project).compact.uniq
  267     @project = @projects.first if @projects.size == 1
  268   rescue ActiveRecord::RecordNotFound
  269     render_404
  270   end
  271 
  272   def find_optional_issue
  273     if params[:issue_id].present?
  274       @issue = Issue.find(params[:issue_id])
  275       @project = @issue.project
  276       authorize
  277     else
  278       find_optional_project
  279     end
  280   end
  281 
  282   # Returns the TimeEntry scope for index and report actions
  283   def time_entry_scope(options={})
  284     @query.results_scope(options)
  285   end
  286 
  287   def retrieve_time_entry_query
  288     retrieve_query(TimeEntryQuery, false, :defaults => @default_columns_names)
  289   end
  290 end