diff --git a/app/models/dmsf_file_revision.rb b/app/models/dmsf_file_revision.rb index dcf659b9..edb90bc5 100644 --- a/app/models/dmsf_file_revision.rb +++ b/app/models/dmsf_file_revision.rb @@ -71,6 +71,10 @@ class DmsfFileRevision < ActiveRecord::Base def self.filename_to_title(filename) remove_extension(filename).gsub(/_+/, ' '); end + + def self.easy_activity_custom_project_scope(scope, options, event_type) + scope.where(:dmsf_files => { :project_id => options[:project_ids] }) + end def delete(commit = false, force = true) if self.dmsf_file.locked_for_user? diff --git a/lib/redmine_dmsf.rb b/lib/redmine_dmsf.rb index ba037f86..6d5a9d7a 100644 --- a/lib/redmine_dmsf.rb +++ b/lib/redmine_dmsf.rb @@ -35,6 +35,10 @@ require 'redmine_dmsf/patches/issue_patch' require 'redmine_dmsf/patches/application_helper_patch' require 'redmine_dmsf/patches/role_patch' +if defined?(EasyExtensions) + require 'redmine_dmsf/patches/easy_crm_case_patch' +end + # Load up classes that make up our WebDAV solution ontop of DAV4Rack require 'redmine_dmsf/webdav/base_resource' require 'redmine_dmsf/webdav/controller' @@ -65,5 +69,9 @@ require 'redmine_dmsf/hooks/views/search_view_hooks' require 'redmine_dmsf/hooks/helpers/issues_helper_hooks' require 'redmine_dmsf/hooks/helpers/search_helper_hooks' +if defined?(EasyExtensions) + require 'redmine_dmsf/hooks/controllers/easy_crm_cases_controller_hooks' +end + # Macros require 'redmine_dmsf/macros' diff --git a/lib/redmine_dmsf/hooks/controllers/easy_crm_cases_controller_hooks.rb b/lib/redmine_dmsf/hooks/controllers/easy_crm_cases_controller_hooks.rb new file mode 100644 index 00000000..048b0be6 --- /dev/null +++ b/lib/redmine_dmsf/hooks/controllers/easy_crm_cases_controller_hooks.rb @@ -0,0 +1,119 @@ +# encoding: utf-8 +# +# Redmine plugin for Document Management System "Features" +# +# Copyright (C) 2011-17 Karel Pičman +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module RedmineDmsf + module Hooks + include Redmine::Hook + + class ControllerEasyCrmCasesHook < RedmineDmsf::Hooks::Listener + + def controller_easy_crm_cases_before_save(context={}) + if context.is_a?(Hash) + easy_crm_case = context[:easy_crm_case] + params = context[:params] + easy_crm_case.save_dmsf_attachments(params[:dmsf_attachments]) + easy_crm_case.save_dmsf_links(params[:dmsf_links]) + easy_crm_case.save_dmsf_attachments_wfs(params[:dmsf_attachments_wfs], params[:dmsf_attachments]) + easy_crm_case.save_dmsf_links_wfs(params[:dmsf_links_wfs]) + end + end + + def controller_easy_crm_cases_after_save(context={}) + easy_crm_cases_after_save(context) + # Copy documents from the source issue + if context.is_a?(Hash) + easy_crm_case = context[:easy_crm_case] + params = context[:params] + copied_from = EasyCrmCase.find_by_id(params[:copy_from]) if params[:copy_from].present? + # Save documents + if copied_from + copied_from.dmsf_files.each do |dmsf_file| + dmsf_file.copy_to(easy_crm_case.project, easy_crm_cases.system_folder(true)) + end + end + end + end + + private + + def easy_crm_cases_after_save(context) + if context.is_a?(Hash) + easy_crm_case = context[:easy_crm_case] + params = context[:params] + # Attach DMS documents + uploaded_files = params[:dmsf_attachments] + if uploaded_files && uploaded_files.is_a?(Hash) + system_folder = easy_crm_case.system_folder(true) + uploaded_files.each do |key, uploaded_file| + upload = DmsfUpload.create_from_uploaded_attachment(easy_crm_case.project, system_folder, uploaded_file) + if upload + uploaded_file[:disk_filename] = upload.disk_filename + uploaded_file[:name] = upload.name + uploaded_file[:title] = upload.title + uploaded_file[:version] = 1 + uploaded_file[:size] = upload.size + uploaded_file[:mime_type] = upload.mime_type + uploaded_file[:tempfile_path] = upload.tempfile_path + if params[:dmsf_attachments_wfs].present? && params[:dmsf_attachments_wfs][key].present? + uploaded_file[:workflow_id] = params[:dmsf_attachments_wfs][key].to_i + end + end + end + DmsfUploadHelper.commit_files_internal uploaded_files, easy_crm_case.project, system_folder, + context[:controller] + end + # Attach DMS links + easy_crm_case.saved_dmsf_links.each do |l| + file = l.target_file + revision = file.last_revision + system_folder = easy_crm_case.system_folder(true) + if system_folder + l.project_id = system_folder.project_id + l.dmsf_folder_id = system_folder.id + if l.save + easy_crm_case.dmsf_file_added file + end + wf = easy_crm_case.saved_dmsf_links_wfs[l.id] + if wf + # Assign the workflow + revision.set_workflow(wf.id, 'assign') + revision.assign_workflow(wf.id) + # Start the workflow + revision.set_workflow(wf.id, 'start') + if revision.save + wf.notify_users(easy_crm_case.project, revision, context[:controller]) + begin + file.lock! + rescue DmsfLockError => e + Rails.logger.warn e.message + end + else + Rails.logger.error l(:error_workflow_assign) + end + end + end + end + end + end + + end + + end +end \ No newline at end of file diff --git a/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb b/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb index 13604b06..dce1df0f 100644 --- a/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb +++ b/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb @@ -25,6 +25,26 @@ module RedmineDmsf class DmsfViewListener < Redmine::Hook::ViewListener def view_issues_form_details_bottom(context={}) + return if defined?(EasyExtensions) + attach_documents_form(context) + end + + def view_issues_edit_notes_bottom(context={}) + attach_documents_form(context) + end + + def view_issues_show_description_bottom(context={}) + return if defined?(EasyExtensions) + show_attached_documents(context[:issue], context[:controller]) + end + + def view_issues_show_attachments_bottom(context={}) + show_attached_documents(context[:container], context[:controller]) + end + + private + + def attach_documents_form(context) if context.is_a?(Hash) && context[:issue] # Add Dmsf upload form issue = context[:issue] @@ -35,7 +55,7 @@ module RedmineDmsf html << '

' html << "" html << context[:controller].send(:render_to_string, - {:partial => 'dmsf_upload/form', :locals => { :container => issue, :multiple => true }}) + { :partial => 'dmsf_upload/form', :locals => { :container => issue, :multiple => true }}) html << '

' html << '' html.html_safe @@ -43,33 +63,127 @@ module RedmineDmsf end end - def view_issues_show_description_bottom(context={}) - if context.is_a?(Hash) && context[:issue] - # Add list of attached documents - issue = context[:issue] - if User.current.allowed_to?(:view_dmsf_files, issue.project) && - Setting.plugin_redmine_dmsf['dmsf_act_as_attachable'] && - (issue.project.dmsf_act_as_attachable == Project::ATTACHABLE_DMS_AND_ATTACHMENTS) - links = [] - for dmsf_file in issue.dmsf_files - if dmsf_file.last_revision - links << [dmsf_file, nil, dmsf_file.created_at] - end + def show_attached_documents(container, controller) + # Add list of attached documents + if User.current.allowed_to?(:view_dmsf_files, container.project) && + Setting.plugin_redmine_dmsf['dmsf_act_as_attachable'] && + (container.project.dmsf_act_as_attachable == Project::ATTACHABLE_DMS_AND_ATTACHMENTS) + links = [] + for dmsf_file in container.dmsf_files + if dmsf_file.last_revision + links << [dmsf_file, nil, dmsf_file.created_at] end - for dmsf_link in issue.dmsf_links - dmsf_file = dmsf_link.target_file - if dmsf_file && dmsf_file.last_revision - links << [dmsf_file, dmsf_link, dmsf_link.created_at] - end + end + for dmsf_link in container.dmsf_links + dmsf_file = dmsf_link.target_file + if dmsf_file && dmsf_file.last_revision + links << [dmsf_file, dmsf_link, dmsf_link.created_at] end - # Sort by 'create_at' %> - links.sort!{ |x, y| x[2] <=> y[2] } - context[:controller].send(:render_to_string, {:partial => 'dmsf_files/links', + end + # Sort by 'create_at' + links.sort!{ |x, y| x[2] <=> y[2] } + unless defined?(EasyExtensions) + controller.send(:render_to_string, {:partial => 'dmsf_files/links', :locals => { :links => links, :thumbnails => Setting.thumbnails_enabled? }}) + else + attachment_rows(links, container, controller) end end end + private + + def attachment_rows(links, issue, controller) + html = '' + links.each do |dmsf_file, link, create_at| + html << attachment_row(dmsf_file, link, issue, controller) + end + html << '' + html.html_safe + end + + def attachment_row(dmsf_file, link, issue, controller) + if link + html = '' + else + html = '' + end + # Checkbox + show_checkboxes = true #options[:show_checkboxes].nil? ? true : options[:show_checkboxes] + if show_checkboxes + html << '' + end + file_view_url = url_for({:controller => :dmsf_files, :action => 'view', :id => dmsf_file}) + # Title, size + html << '' + html << link_to(h(dmsf_file.title),file_view_url, :target => '_blank', + :class => "icon icon-file #{DmsfHelper.filetype_css(dmsf_file.name)}", + :title => h(dmsf_file.last_revision.try(:tooltip)), + 'data-downloadurl' => "#{dmsf_file.last_revision.detect_content_type}:#{h(dmsf_file.name)}:#{file_view_url}") + html << "(#{number_to_human_size(dmsf_file.last_revision.size)})" + html << " - #{dmsf_file.description}" unless dmsf_file.description.blank? + html << '' + # Author, updated at + html << '' + html << "#{dmsf_file.last_revision.user}, #{format_time(dmsf_file.last_revision.updated_at)}" + html << '' + # Command icons + html << '' + html << '' + # Details + if User.current.allowed_to? :file_manipulation, dmsf_file.project + html << link_to('', dmsf_file_path(:id => dmsf_file), + :title => l(:link_details, :title => h(dmsf_file.last_revision.title)), + :class => 'icon icon-edit') + else + html << '' + end + # Email + html << link_to('', entries_operations_dmsf_path(:id => dmsf_file.project, + :email_entries => 'email', :files => [dmsf_file.id]), :method => :post, + :title => l(:heading_send_documents_by_email), :class => 'icon icon-email-disabled') + # Lock + if !dmsf_file.locked? + html << link_to('', lock_dmsf_files_path(:id => dmsf_file), + :title => l(:title_lock_file), :class => 'icon icon-lock') + elsif dmsf_file.unlockable? && (!dmsf_file.locked_for_user? || User.current.allowed_to?(:force_file_unlock, dmsf_file.project)) + html << link_to('', unlock_dmsf_files_path(:id => dmsf_file), + :title => dmsf_file.get_locked_title, :class => 'icon icon-unlock') + else + html << "" + end + unless dmsf_file.locked? + # Notifications + if dmsf_file.notification + html << link_to('',notify_deactivate_dmsf_files_path(:id => dmsf_file), + :title => l(:title_notifications_active_deactivate), :class => 'icon icon-email') + else + html << link_to('',notify_activate_dmsf_files_path(:id => dmsf_file), + :title => l(:title_notifications_not_active_activate), :class => 'icon icon-email-add') + end + # Delete + if issue.attributes_editable? && User.current.allowed_to?(:file_delete, dmsf_file.project) + html << link_to('', + link ? dmsf_link_path(link, :commit => 'yes') : dmsf_file_path(:id => dmsf_file, :commit => 'yes'), + :data => {:confirm => l(:text_are_you_sure)}, :method => :delete, :title => l(:title_delete), + :class => 'icon icon-del') + end + else + html << '' * 2 + end + # Approval workflow + wf = DmsfWorkflow.find_by_id(dmsf_file.last_revision.dmsf_workflow_id) if dmsf_file.last_revision.dmsf_workflow_id + html << controller.send(:render_to_string, {:partial => 'dmsf_files/approval_workflow_button', + :locals => {:file => dmsf_file, + :file_approval_allowed => User.current.allowed_to?(:file_approval, dmsf_file.project), + :workflows_available => DmsfWorkflow.where(['project_id = ? OR project_id IS NULL', dmsf_file.project.id]).exists?, + :project => dmsf_file.project, :wf => wf, :dmsf_link_id => nil }}) + html << '' + html << '' + html << '' + html + end + end end end diff --git a/lib/redmine_dmsf/patches/easy_crm_case_patch.rb b/lib/redmine_dmsf/patches/easy_crm_case_patch.rb new file mode 100644 index 00000000..1b979328 --- /dev/null +++ b/lib/redmine_dmsf/patches/easy_crm_case_patch.rb @@ -0,0 +1,186 @@ +# encoding: utf-8 +# +# Redmine plugin for Document Management System "Features" +# +# Copyright (C) 2011-17 Karel Pičman +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module RedmineDmsf + module Patches + module EasyCrmCasePatch + + def self.included(base) + base.send(:include, InstanceMethods) + base.class_eval do + unloadable + before_destroy :delete_system_folder + end + end + + module InstanceMethods + + def attributes_editable? + true + end + + def save_dmsf_attachments(dmsf_attachments) + @saved_dmsf_attachments = [] + if dmsf_attachments + dmsf_attachments = dmsf_attachments.map(&:last) + dmsf_attachments.each do |dmsf_attachment| + a = Attachment.find_by_token(dmsf_attachment[:token]) + @saved_dmsf_attachments << a if a + end + end + end + + def saved_dmsf_attachments + @saved_dmsf_attachments || [] + end + + def save_dmsf_links(dmsf_links) + @saved_dmsf_links = [] + if dmsf_links + ids = dmsf_links.map(&:last) + ids.each do |id| + l = DmsfLink.find_by_id(id) + @saved_dmsf_links << l if l + end + end + end + + def saved_dmsf_links + @saved_dmsf_links || [] + end + + def save_dmsf_attachments_wfs(dmsf_attachments_wfs, dmsf_attachments) + if dmsf_attachments_wfs + @dmsf_attachments_wfs = {} + dmsf_attachments_wfs.each do |attachment_id, approval_workflow_id| + attachment = dmsf_attachments[attachment_id] + if attachment + a = Attachment.find_by_token(attachment[:token]) + wf = DmsfWorkflow.find_by_id approval_workflow_id + @dmsf_attachments_wfs[a.id] = wf if wf && a + end + end + end + end + + def saved_dmsf_attachments_wfs + @dmsf_attachments_wfs || [] + end + + def save_dmsf_links_wfs(dmsf_links_wfs) + if dmsf_links_wfs + @saved_dmsf_links_wfs = {} + dmsf_links_wfs.each do |dmsf_link_id, approval_workflow_id| + wf = DmsfWorkflow.find_by_id approval_workflow_id + @saved_dmsf_links_wfs[dmsf_link_id.to_i] = wf if wf + end + end + end + + def saved_dmsf_links_wfs + @saved_dmsf_links_wfs || {} + end + + def system_folder(create = false) + parent = DmsfFolder.system.where(:project_id => self.project_id, :title => '.CRM cases').first + if create && !parent + parent = DmsfFolder.new + parent.project_id = self.project_id + parent.title = '.CRM cases' + parent.description = 'Documents assigned to CRM cases' + parent.user_id = User.anonymous.id + parent.system = true + parent.save + end + if parent + folder = DmsfFolder.system.where(['project_id = ? AND dmsf_folder_id = ? AND CAST(title AS DECIMAL) = ?', + self.project_id, parent.id, self.id]).first + if create && !folder + folder = DmsfFolder.new + folder.dmsf_folder_id = parent.id + folder.project_id = self.project_id + folder.title = "#{self.id} - #{self.name}" + folder.user_id = User.anonymous.id + folder.system = true + folder.save + end + end + folder + end + + def dmsf_files + files = [] + folder = self.system_folder + if folder + files = folder.dmsf_files.to_a + end + files + end + + def dmsf_links + links = [] + folder = self.system_folder + if folder + links = folder.dmsf_links + end + links + end + + def delete_system_folder + folder = self.system_folder + folder.destroy if folder + end + + def dmsf_file_added(dmsf_file) + unless dmsf_file.new_record? + self.journalize_dmsf_file(dmsf_file, :added) + end + end + + def dmsf_file_removed(dmsf_file) + unless dmsf_file.new_record? + self.journalize_dmsf_file(dmsf_file, :removed) + end + end + + # Adds a journal detail for an attachment that was added or removed + def journalize_dmsf_file(dmsf_file, added_or_removed) + init_journal(User.current) + key = (added_or_removed == :removed ? :old_value : :value) + current_journal.details << JournalDetail.new( + :property => 'dmsf_file', + :prop_key => dmsf_file.id, + key => dmsf_file.title + ) + current_journal.save + end + + end + + end + end +end + +# Apply patch +Rails.configuration.to_prepare do + unless EasyCrmCase.included_modules.include?(RedmineDmsf::Patches::EasyCrmCasePatch) + EasyCrmCase.send(:include, RedmineDmsf::Patches::EasyCrmCasePatch) + end +end