controller_issues_bulk_edit_before_save => how to make as controller_issues_bulk_edit_after_save

Added by Stéphane CHÂTEAU 4 months ago

For a plugin, I create geometries to be able to georeference issues.
The goal of my problem is to be able to copy these geometries when creating issues. It's done by hooking controller_issues_new_after_save like this:

module xPointeHook
  module Hooks
    class GeometryIssueHook < Redmine::Hook::Listener
      def controller_issues_new_after_save_geometries(context = { })
        issue = context[:issue]

        if !issue.id.nil? && !issue.project_id.nil?
          if context[:params].key?(:copy_from) && !context[:params][:copy_from].nil?
            project = Project.find(issue.project_id)

            if !project.nil?
              #Rails.logger.info("project = " + project.id.to_s + " / name = " +  project.name)
              #Rails.logger.info("issue source = " + context[:params][:copy_from].to_s)
              if is_project_allow_pointe?(project)
                # Uniquement si le projet destination autorise les pointés
                Pointes.where(issue_id: context[:params][:copy_from]).all.each do |blc_pointe|
                  pointe = Pointes.new( { :issue_id => issue.id,
                                          :pointe => blc_pointe.pointe.nil? ? nil : blc_pointe.pointe.as_text(),
                                          :point_attendu => blc_pointe.point_attendu.nil? ? nil : blc_pointe.point_attendu.as_text(),
                                          :line_attendu => blc_pointe.line_attendu.nil? ? nil : blc_pointe.line_attendu.as_text(),
                                          :polygon_attendu => blc_pointe.polygon_attendu.nil? ? nil :  blc_pointe.polygon_attendu.as_text(),
                                          :state => blc_pointe.state,
                                          :comment => blc_pointe.comment
                                        }
                                      )
                  pointe.save
                end
              end
            end
          end
        end

        return ''
      end

      alias_method :controller_issues_new_after_save, :controller_issues_new_after_save_geometries
    end
  end
end

First I hook controller_issues_new_after_save and then, if the issue is a copy, and have geometries allowed on target project (is_project_allow_pointe?) then I copied Pointes'rows that match to source Issue to new one.
It's work perfectly !

The problem is ... for bulk copy. There are controller_issues_bulk_edit_before_save but no controller_issues_bulk_edit_after_save like asked by some developpers: https://www.redmine.org/issues/8757

I'm neebie on rails.
My question is: is it possible to hook controller_issues_bulk_edit_before_save and then hook on each issue 'after_save' callback with ActiveRecord?
The problem is, I cannot create Pointes.new if I have not the issue id and in controller_issues_bulk_edit_before_save the row is not already saved and the id is nil, so I must wait the issue really saved into database.

May be it's a way to be able to add Pointes rows after issue bulk copy.
Actually I have this code: (same as previous but the specific hook controller_issues_bulk_edit_before_save.

module xPointeHook
  module Hooks
    class GeometryIssueHook < Redmine::Hook::Listener

      def controller_issues_bulk_edit_before_save_geometries(context = { })
        if context[:params][:copy].present?
          # Uniquement en cas de copie
          issue = context[:issue]
          Rails.logger.info("issue.id = " + (issue.id.nil? ? "nil" : issue.id.to_s))
          Rails.logger.info("issue.project_id = " + (issue.project_id.nil? ? "nil" : issue.project_id.to_s))

          context[:params].each do |key, value|
            Rails.logger.info("params[#{key}]  =  #{value}")
          end
        end
        Rails.logger.info(">>>>>>>> issue = #{context[:issue]}")
      end

      alias_method :controller_issues_bulk_edit_before_save, :controller_issues_bulk_edit_before_save_geometries
    end
  end
end

It's seems that in params[:ids] there is a list of source ids that allow me to retrieve source issue and then source Pointes rows.

Replies (1)

RE: controller_issues_bulk_edit_before_save => how to make as controller_issues_bulk_edit_after_save - Added by Stéphane CHÂTEAU 4 months ago

It's done by another way:
Controller:

module xPointeHook
  module Hooks
    class GeometryIssueHook < Redmine::Hook::Listener
      def controller_issues_new_before_save_geometries(context = { })
        issue = context[:issue]
        if !issue.project_id.nil?
          if context[:params].key?(:copy_from) && !context[:params][:copy_from].nil? && context[:params].key?(:copy_geometries) && context[:params][:copy_geometries] != "0" 
            project = Project.find(issue.project_id)
            if !project.nil? && is_project_allow_pointe?(project)
              # Uniquement si le projet destination autorise les pointés
              issue.set_create_pointe_on_save_issue_id_source(context[:params][:copy_from])
            end
          end
        end

        return ''
      end

      def controller_issues_bulk_edit_before_save_geometries(context = { })
        if context[:params][:copy].present? && context[:issue].copy? && context[:params].key?(:copy_geometries) && context[:params][:copy_geometries] != "0" 
          context[:issue].set_create_pointe_on_save_issue_id_source(context[:issue].copy_id)
        else
          if !check_pointes_states(context)
             context[:issue].set_not_allowed_to_be_saved
          end
        end
      end

      alias_method :controller_issues_new_before_save, :controller_issues_new_before_save_geometries
      alias_method :controller_issues_bulk_edit_before_save, :controller_issues_bulk_edit_before_save_geometries
    end
  end
end

Patch Issue:

module Geometry::Patches::Models
  module IssuePatch
    def self.included(base)
      base.send :include, InstanceMethods
    end

    module InstanceMethods
      def set_not_allowed_to_be_saved
        @can_save = false
      end

      def set_create_pointe_on_save_issue_id_source(id)
        @issue_id_ref = id
      end

      # Est appelé à chaque fois qu'une FT est sauvée
      def save
        bRet = false
        if @can_save.nil? || @can_save
          if !@issue_id_ref.nil?
            # Sauvegarde autorisée mais copie des pointés
            Issue.transaction do
              bRet = super
              if bRet
                bRet = create_pointe_copy_from
                if !bRet
                  # S'il faut copier les pointés et que ça a échoué
                  raise ActiveRecord::Rollback
                end
              end
            end
          else
            # Traitement par défaut de toutes les sauvegarde d'issue
            bRet = super
          end
        else
          # Sera remis à false à la prochaine tentative
          @can_save = nil
          @issue_id_ref = nil
          bRet = false
        end

        bRet
      end

      # Returns the issue copy id
      def copy_id
        return copy? ? @copied_from : nil
      end

    private
      # Est appelé à chaque fois qu'une FT est sauvée
      def create_pointe_copy_from
        bRet = true
        if !@issue_id_ref.nil?
          issueid = @issue_id_ref
          @issue_id_ref = nil

          Pointes.where(issue_id: issueid).all.each do |blc_pointe|
            pointe = Pointes.new( { :issue_id => self.id,
                                    :pointe => blc_pointe.pointe.nil? ? nil : blc_pointe.pointe.as_text(),
                                    :point_attendu => blc_pointe.point_attendu.nil? ? nil : blc_pointe.point_attendu.as_text(),
                                    :line_attendu => blc_pointe.line_attendu.nil? ? nil : blc_pointe.line_attendu.as_text(),
                                    :polygon_attendu => blc_pointe.polygon_attendu.nil? ? nil :  blc_pointe.polygon_attendu.as_text(),
                                    :state => blc_pointe.state,
                                    :comment => blc_pointe.comment
                                  }
                                )
            bRet = pointe.save && bRet
          end
        end
        bRet
      end

    end # Module InstanceMethods
  end # Module IssuePatch
end # Module Geometry

Init.rb: (simplified)

require 'redmine'

# It requires the file in lib/geometry/hooks/geometry_issue_hook.rb
require_dependency 'geometry/hooks/geometry_issue_hook'

Redmine::Plugin.register :geometry do
  name ''
  author ''
  description 'xxx'
  version '2.0.0'
  url ''

  # include file lib/geometry/patches/models/issue_patch.rb file
  unless Issue.included_modules.include?(Geometry::Patches::Models::IssuePatch)
    Issue.send(:include, Geometry::Patches::Models::IssuePatch)
  end
end

(1-1/1)