From dc0eb77cc61b5a4bec44bc597c0fd1e9e3590327 Mon Sep 17 00:00:00 2001 From: pavel Date: Tue, 11 Dec 2018 01:00:12 +0100 Subject: [PATCH 01/53] redmine 4.0.0 --- after_init.rb | 4 +- app/controllers/dmsf_controller.rb | 7 +- app/controllers/dmsf_files_controller.rb | 10 +- app/controllers/dmsf_upload_controller.rb | 10 +- app/controllers/dmsf_workflows_controller.rb | 34 +++---- app/helpers/dmsf_upload_helper.rb | 9 +- app/models/dmsf_file.rb | 2 +- app/models/dmsf_mailer.rb | 28 +++++- app/models/dmsf_workflow.rb | 8 +- db/migrate/01_create_hierarchy.rb | 2 +- db/migrate/02_dmsf_normalization.rb | 2 +- db/migrate/03_dmsf_0_8_0.rb | 2 +- db/migrate/04_dmsf_0_9_0.rb | 2 +- db/migrate/05_dmsf_0_9_0_1.rb | 2 +- db/migrate/06_dmsf_1_2_0.rb | 2 +- db/migrate/07_dmsf_1_4_4.rb | 2 +- .../20120822100401_create_dmsf_workflows.rb | 2 +- ...120822100402_create_dmsf_workflow_steps.rb | 2 +- ...3_create_dmsf_workflow_step_assignments.rb | 2 +- ...00404_create_dmsf_workflow_step_actions.rb | 2 +- db/migrate/20130819013955_update_projects.rb | 2 +- .../20131108141401_add_index_to_dmsf_files.rb | 2 +- ...0131108141402_add_index_to_dmsf_folders.rb | 2 +- ...3141401_add_index_to_dmsf_file_revision.rb | 2 +- .../20131113141402_add_index_to_dmsf_lock.rb | 2 +- .../20131113141403_create_dmsf_links.rb | 2 +- db/migrate/20140314132501_notifications_on.rb | 2 +- db/migrate/20140519133201_trash_bin.rb | 2 +- ...1013102501_remove_project_from_revision.rb | 2 +- ...41015132701_remove_folder_from_revision.rb | 2 +- ...0141205143001_remove_uniqueness_from_wf.rb | 2 +- .../20150120152101_notifications_nullable.rb | 2 +- db/migrate/20150130052716_add_external.rb | 2 +- .../20150202010301_add_user_to_links.rb | 2 +- db/migrate/20150910153701_title_not_null.rb | 2 +- db/migrate/20151020141801_large_files.rb | 2 +- db/migrate/20151209100001_title_format.rb | 2 +- ...20160215125801_approval_workflow_status.rb | 2 +- db/migrate/20160217133001_status_deleted.rb | 2 +- ...0222140401_approval_workflow_std_fields.rb | 2 +- .../20160421150501_add_digest_to_revision.rb | 2 +- .../20161223133200_create_dmsf_public_urls.rb | 2 +- ...64701_add_name_to_appoval_workflow_step.rb | 2 +- .../20170118142001_dmsf_file_container.rb | 2 +- ...0170204214753_add_revision_to_dmsf_lock.rb | 2 +- ...dmsf_file_last_revision_id_to_dmsf_lock.rb | 2 +- ...d_dmsf_not_inheritable_to_custom_fields.rb | 2 +- .../20170323131231_dmsf_description_limit.rb | 2 +- ...30131901_create_dmsf_folder_permissions.rb | 4 +- ...0421101901_dmsf_file_container_rollback.rb | 2 +- .../20170422104901_migrate_documents.rb | 2 +- db/migrate/20170526144701_dmsf_attachable.rb | 4 +- ...4101_change_revision_digest_limit_to_64.rb | 2 +- ...20171110155901_add_index_to_dmsf_folder.rb | 2 +- .../20180216152501_rename_title_format.rb | 2 +- db/migrate/20180903132101_fast_links.rb | 2 +- init.rb | 2 +- .../controllers/issues_controller_hooks.rb | 2 +- .../easy_crm_cases_controller_patch.rb | 2 +- lib/redmine_dmsf/webdav/dmsf_resource.rb | 10 +- lib/tasks/dmsf_alert_approvals.rake | 6 +- test/ci/redmine_install.sh | 2 +- .../dmsf_context_menus_controller_test.rb | 6 +- test/functional/dmsf_controller_test.rb | 76 +++++++------- test/functional/dmsf_files_controller_test.rb | 18 ++-- .../dmsf_files_copy_controller_test.rb | 42 ++++---- ...dmsf_folder_permissions_controller_test.rb | 6 +- .../dmsf_folders_copy_controller_test.rb | 46 ++++----- test/functional/dmsf_links_controller_test.rb | 98 +++++++++---------- .../dmsf_public_urls_controller_test.rb | 6 +- test/functional/dmsf_state_controller_test.rb | 16 +-- .../dmsf_workflow_controller_test.rb | 90 +++++++++-------- test/functional/issues_controller_test.rb | 4 +- test/functional/my_controller_test.rb | 2 +- .../rest_api/dmsf_file_api_test.rb | 12 +-- .../rest_api/dmsf_folder_api_test.rb | 12 +-- .../rest_api/dmsf_link_api_test.rb | 2 +- .../dmsf_webdav_custom_middleware_test.rb | 6 +- .../webdav/dmsf_webdav_delete_test.rb | 48 ++++----- .../webdav/dmsf_webdav_get_test.rb | 32 +++--- .../webdav/dmsf_webdav_head_test.rb | 24 ++--- .../webdav/dmsf_webdav_lock_test.rb | 39 ++++---- .../webdav/dmsf_webdav_mkcol_test.rb | 22 ++--- .../webdav/dmsf_webdav_move_test.rb | 76 +++++++------- .../webdav/dmsf_webdav_options_test.rb | 42 ++++---- .../webdav/dmsf_webdav_post_test.rb | 2 +- .../webdav/dmsf_webdav_propfind_test.rb | 26 ++--- .../webdav/dmsf_webdav_put_test.rb | 70 ++++++------- test/unit/dmsf_mailer_test.rb | 8 +- 89 files changed, 533 insertions(+), 532 deletions(-) diff --git a/after_init.rb b/after_init.rb index 6114569a..f5bbdcde 100644 --- a/after_init.rb +++ b/after_init.rb @@ -23,6 +23,8 @@ require_dependency 'zip' require_dependency File.dirname(__FILE__) + '/lib/redmine_dmsf.rb' +ActiveSupport::Dependencies.autoload_paths << File.join(File.dirname(__FILE__), 'app', 'validators') + def init # Administration menu extension Redmine::MenuManager.map :admin_menu do |menu| @@ -100,7 +102,7 @@ else init end -ActionDispatch::Reloader.to_prepare do +RedmineExtensions::Reloader.to_prepare do # Rubyzip configuration Zip.unicode_names = true diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index e545bbe9..1035ff09 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -178,7 +178,7 @@ class DmsfController < ApplicationController if params[:email][:to].strip.blank? flash[:error] = l(:error_email_to_must_be_entered) else - DmsfMailer.send_documents(@project, params[:email]).deliver + DmsfMailer.deliver_send_documents(@project, params[:email]) File.delete(params[:email][:zipped_content]) flash[:notice] = l(:notice_email_sent, params[:email][:to]) end @@ -527,10 +527,7 @@ class DmsfController < ApplicationController # Activities unless deleted_files.empty? begin - recipients = DmsfMailer.get_notify_users(@project, deleted_files) - recipients.each do |u| - DmsfMailer.files_deleted(u, @project, deleted_files).deliver - end + DmsfMailer.deliver_files_deleted(@project, deleted_files) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] unless recipients.empty? to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') diff --git a/app/controllers/dmsf_files_controller.rb b/app/controllers/dmsf_files_controller.rb index 61b19bfb..58576a5c 100644 --- a/app/controllers/dmsf_files_controller.rb +++ b/app/controllers/dmsf_files_controller.rb @@ -163,10 +163,7 @@ class DmsfFilesController < ApplicationController @file.set_last_revision revision flash[:notice] = (flash[:notice].nil? ? '' : flash[:notice]) + l(:notice_file_revision_created) begin - recipients = DmsfMailer.get_notify_users(@project, [@file]) - recipients.each do |u| - DmsfMailer.files_updated(u, @project, [@file]).deliver - end + DmsfMailer.deliver_files_updated(@project, [@file]) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] unless recipients.empty? to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') @@ -196,10 +193,7 @@ class DmsfFilesController < ApplicationController flash[:notice] = l(:notice_file_deleted) unless commit begin - recipients = DmsfMailer.get_notify_users(@project, [@file]) - recipients.each do |u| - DmsfMailer.files_deleted(u, @project, [@file]).deliver - end + DmsfMailer.deliver_files_deleted(@project, [@file]) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] unless recipients.empty? to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') diff --git a/app/controllers/dmsf_upload_controller.rb b/app/controllers/dmsf_upload_controller.rb index 5193b6b3..2cf7129f 100644 --- a/app/controllers/dmsf_upload_controller.rb +++ b/app/controllers/dmsf_upload_controller.rb @@ -42,16 +42,16 @@ class DmsfUploadController < ApplicationController def upload_files uploaded_files = params[:dmsf_attachments] @uploads = [] - if uploaded_files && uploaded_files.is_a?(Hash) + if uploaded_files # standard file input uploads - uploaded_files.each_value do |uploaded_file| + uploaded_files.each do |_, uploaded_file| upload = DmsfUpload.create_from_uploaded_attachment(@project, @folder, uploaded_file) @uploads.push(upload) if upload end else # plupload multi upload completed uploaded = params[:uploaded] - if uploaded && uploaded.is_a?(Hash) + if uploaded uploaded.each_value do |uploaded_file| @uploads.push(DmsfUpload.new(@project, @folder, uploaded_file)) end @@ -113,11 +113,11 @@ class DmsfUploadController < ApplicationController def commit @files = [] attachments = params[:attachments] - if attachments && attachments.is_a?(Hash) + if attachments @folder = DmsfFolder.visible.find_by(id: attachments[:folder_id]) if attachments[:folder_id].present? # standard file input uploads uploaded_files = attachments.select { |key, value| key == 'uploaded_file'} - uploaded_files.each_value do |uploaded_file| + uploaded_files.each do |_, uploaded_file| upload = DmsfUpload.create_from_uploaded_attachment(@project, @folder, uploaded_file) if upload uploaded_file[:disk_filename] = upload.disk_filename diff --git a/app/controllers/dmsf_workflows_controller.rb b/app/controllers/dmsf_workflows_controller.rb index 10605cdc..da49c30e 100644 --- a/app/controllers/dmsf_workflows_controller.rb +++ b/app/controllers/dmsf_workflows_controller.rb @@ -73,15 +73,13 @@ class DmsfWorkflowsController < ApplicationController if revision.workflow == DmsfWorkflow::STATE_APPROVED # Just approved recipients = DmsfMailer.get_notify_users(@project, [revision.dmsf_file], true) - recipients.each do |user| - DmsfMailer.workflow_notification( - user, + DmsfMailer.deliver_workflow_notification( + recipients, @dmsf_workflow, revision, :text_email_subject_approved, :text_email_finished_approved, - :text_email_to_see_history).deliver if user - end + :text_email_to_see_history) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] unless recipients.blank? to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') @@ -95,16 +93,14 @@ class DmsfWorkflowsController < ApplicationController recipients.push User.find_by(id: revision.dmsf_workflow_assigned_by) recipients.uniq! recipients = recipients & DmsfMailer.get_notify_users(@project, [revision.dmsf_file], true) - recipients.each do |user| - DmsfMailer.workflow_notification( - user, + DmsfMailer.deliver_workflow_notification( + recipients, @dmsf_workflow, revision, :text_email_subject_rejected, :text_email_finished_rejected, :text_email_to_see_history, - action.note).deliver - end + action.note) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] unless recipients.blank? to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') @@ -118,14 +114,14 @@ class DmsfWorkflowsController < ApplicationController # Delegation delegate = User.find_by(id: params[:step_action].to_i / 10) if DmsfMailer.get_notify_users(@project, [revision.dmsf_file], true).include?(delegate) - DmsfMailer.workflow_notification( - delegate, + DmsfMailer.deliver_workflow_notification( + [delegate], @dmsf_workflow, revision, :text_email_subject_delegated, :text_email_finished_delegated, :text_email_to_proceed, - action.note).deliver + action.note) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] flash[:warning] = l(:warning_email_notifications, :to => delegate.name) end @@ -138,24 +134,24 @@ class DmsfWorkflowsController < ApplicationController # Next step assignments.each do |assignment| if assignment.user && DmsfMailer.get_notify_users(@project, [revision.dmsf_file], true).include?(assignment.user) - DmsfMailer.workflow_notification( - assignment.user, + DmsfMailer.deliver_workflow_notification( + [assignment.user], @dmsf_workflow, revision, :text_email_subject_requires_approval, :text_email_finished_step, - :text_email_to_proceed).deliver + :text_email_to_proceed) end end to = User.find_by(id: revision.dmsf_workflow_assigned_by) if to && DmsfMailer.get_notify_users(@project, [revision.dmsf_file], true).include?(to) - DmsfMailer.workflow_notification( - to, + DmsfMailer.deliver_workflow_notification( + [to], @dmsf_workflow, revision, :text_email_subject_updated, :text_email_finished_step_short, - :text_email_to_see_status).deliver + :text_email_to_see_status) end if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] recipients = assignments.collect{ |a| a.user } diff --git a/app/helpers/dmsf_upload_helper.rb b/app/helpers/dmsf_upload_helper.rb index 4c148a7e..1b44374d 100644 --- a/app/helpers/dmsf_upload_helper.rb +++ b/app/helpers/dmsf_upload_helper.rb @@ -24,9 +24,9 @@ module DmsfUploadHelper def self.commit_files_internal(commited_files, project, folder, controller = nil) failed_uploads = [] files = [] - if commited_files && commited_files.is_a?(Hash) + if commited_files failed_uploads = [] - commited_files.each_value do |commited_file| + commited_files.each do |_, commited_file| name = commited_file[:name] new_revision = DmsfFileRevision.new file = DmsfFile.visible.find_file_by_name(project, folder, name) @@ -140,10 +140,7 @@ module DmsfUploadHelper # Notifications if (folder && folder.notification?) || (!folder && project.dmsf_notification?) begin - recipients = DmsfMailer.get_notify_users(project, files) - recipients.each do |u| - DmsfMailer.files_updated(u, project, files).deliver - end + DmsfMailer.deliver_files_updated(project, files) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] unless recipients.empty? to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') diff --git a/app/models/dmsf_file.rb b/app/models/dmsf_file.rb index 2917abd5..e286bec1 100644 --- a/app/models/dmsf_file.rb +++ b/app/models/dmsf_file.rb @@ -85,7 +85,7 @@ class DmsfFile < ActiveRecord::Base end end - def initialize + def initialize(*args) @project = nil super end diff --git a/app/models/dmsf_mailer.rb b/app/models/dmsf_mailer.rb index eee3ebdc..771a167f 100644 --- a/app/models/dmsf_mailer.rb +++ b/app/models/dmsf_mailer.rb @@ -24,6 +24,13 @@ require 'mailer' class DmsfMailer < Mailer layout 'mailer' + def self.deliver_files_updated(project, files) + users = get_notify_users(project, files) + users.each do |user| + files_updated(user, project, files).deliver_later + end + end + def files_updated(user, project, files) if user && project && files.count > 0 files = files.select { |file| file.notify? } @@ -37,6 +44,13 @@ class DmsfMailer < Mailer end end + def self.deliver_files_deleted(project, files) + users = get_notify_users(project, files) + users.each do |user| + files_deleted(user, project, files).deliver_later + end + end + def files_deleted(user, project, files) if user && files.count > 0 files = files.select { |file| file.notify? } @@ -50,7 +64,11 @@ class DmsfMailer < Mailer end end - def send_documents(project, email_params) + def self.deliver_send_documents(project, email_params) + send_documents(email_params[:to], project, email_params).deliver_later + end + + def send_documents(user, project, email_params) redmine_headers 'Project' => project.identifier if project @body = email_params[:body] @links_only = email_params[:links_only] == '1' @@ -63,10 +81,16 @@ class DmsfMailer < Mailer zipped_content_data = open(email_params[:zipped_content], 'rb') { |io| io.read } attachments['Documents.zip'] = { :content_type => 'application/zip', :content => zipped_content_data } end - mail :to => email_params[:to], :cc => email_params[:cc], + mail :to => user, :cc => email_params[:cc], :subject => email_params[:subject], 'From' => email_params[:from], 'Reply-To' => email_params[:reply_to] end + def self.deliver_workflow_notification(users, workflow, revision, subject_id, text1_id, text2_id, notice = nil) + users.each do |user| + workflow_notification(user, workflow, revision, subject_id.to_s, text1_id.to_s, text2_id.to_s, notice).deliver_later + end + end + def workflow_notification(user, workflow, revision, subject_id, text1_id, text2_id, notice = nil) if user && workflow && revision if revision.dmsf_file && revision.dmsf_file.project diff --git a/app/models/dmsf_workflow.rb b/app/models/dmsf_workflow.rb index 8195ea7a..85432d1b 100644 --- a/app/models/dmsf_workflow.rb +++ b/app/models/dmsf_workflow.rb @@ -195,15 +195,13 @@ class DmsfWorkflow < ActiveRecord::Base recipients = assignments.collect{ |a| a.user } recipients.uniq! recipients = recipients & DmsfMailer.get_notify_users(project, [revision.dmsf_file], true) - recipients.each do |user| - DmsfMailer.workflow_notification( - user, + DmsfMailer.deliver_workflow_notification( + recipients, self, revision, :text_email_subject_started, :text_email_started, - :text_email_to_proceed).deliver - end + :text_email_to_proceed) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] unless recipients.blank? to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') diff --git a/db/migrate/01_create_hierarchy.rb b/db/migrate/01_create_hierarchy.rb index a6317979..49ef8ae9 100644 --- a/db/migrate/01_create_hierarchy.rb +++ b/db/migrate/01_create_hierarchy.rb @@ -17,7 +17,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class CreateHierarchy < ActiveRecord::Migration +class CreateHierarchy < ActiveRecord::Migration[4.2] def change create_table :dmsf_folders do |t| diff --git a/db/migrate/02_dmsf_normalization.rb b/db/migrate/02_dmsf_normalization.rb index 0fe7ae59..f8023026 100644 --- a/db/migrate/02_dmsf_normalization.rb +++ b/db/migrate/02_dmsf_normalization.rb @@ -17,7 +17,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class DmsfNormalization < ActiveRecord::Migration +class DmsfNormalization < ActiveRecord::Migration[4.2] def up rename_column :dmsf_folders, :name, :title diff --git a/db/migrate/03_dmsf_0_8_0.rb b/db/migrate/03_dmsf_0_8_0.rb index f9f9dfe2..0f1387cb 100644 --- a/db/migrate/03_dmsf_0_8_0.rb +++ b/db/migrate/03_dmsf_0_8_0.rb @@ -17,7 +17,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class Dmsf080 < ActiveRecord::Migration +class Dmsf080 < ActiveRecord::Migration[4.2] def change add_column :projects, :dmsf_description, :text diff --git a/db/migrate/04_dmsf_0_9_0.rb b/db/migrate/04_dmsf_0_9_0.rb index 872b75ec..047c0634 100644 --- a/db/migrate/04_dmsf_0_9_0.rb +++ b/db/migrate/04_dmsf_0_9_0.rb @@ -17,7 +17,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class Dmsf090 < ActiveRecord::Migration +class Dmsf090 < ActiveRecord::Migration[4.2] def up add_column :members, :dmsf_mail_notification, :boolean diff --git a/db/migrate/05_dmsf_0_9_0_1.rb b/db/migrate/05_dmsf_0_9_0_1.rb index 1f9e5595..af35f0af 100644 --- a/db/migrate/05_dmsf_0_9_0_1.rb +++ b/db/migrate/05_dmsf_0_9_0_1.rb @@ -17,7 +17,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class Dmsf0901 < ActiveRecord::Migration +class Dmsf0901 < ActiveRecord::Migration[4.2] def change create_table :dmsf_file_revision_accesses do |t| diff --git a/db/migrate/06_dmsf_1_2_0.rb b/db/migrate/06_dmsf_1_2_0.rb index bd7b8afe..33424599 100644 --- a/db/migrate/06_dmsf_1_2_0.rb +++ b/db/migrate/06_dmsf_1_2_0.rb @@ -19,7 +19,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class Dmsf120 < ActiveRecord::Migration +class Dmsf120 < ActiveRecord::Migration[4.2] def up add_column :dmsf_file_revisions, :project_id, :integer, null: true diff --git a/db/migrate/07_dmsf_1_4_4.rb b/db/migrate/07_dmsf_1_4_4.rb index 6c5ad4b0..48fd0af7 100644 --- a/db/migrate/07_dmsf_1_4_4.rb +++ b/db/migrate/07_dmsf_1_4_4.rb @@ -20,7 +20,7 @@ require 'fileutils' require 'uuidtools' -class Dmsf144 < ActiveRecord::Migration +class Dmsf144 < ActiveRecord::Migration[4.2] class DmsfFileLock < ActiveRecord::Base belongs_to :file, class_name: 'DmsfFile', foreign_key: 'dmsf_file_id' diff --git a/db/migrate/20120822100401_create_dmsf_workflows.rb b/db/migrate/20120822100401_create_dmsf_workflows.rb index 8fe30932..3661c38f 100644 --- a/db/migrate/20120822100401_create_dmsf_workflows.rb +++ b/db/migrate/20120822100401_create_dmsf_workflows.rb @@ -19,7 +19,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class CreateDmsfWorkflows < ActiveRecord::Migration +class CreateDmsfWorkflows < ActiveRecord::Migration[4.2] def up create_table :dmsf_workflows do |t| diff --git a/db/migrate/20120822100402_create_dmsf_workflow_steps.rb b/db/migrate/20120822100402_create_dmsf_workflow_steps.rb index b72236fd..2dd9e0fa 100644 --- a/db/migrate/20120822100402_create_dmsf_workflow_steps.rb +++ b/db/migrate/20120822100402_create_dmsf_workflow_steps.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class CreateDmsfWorkflowSteps < ActiveRecord::Migration +class CreateDmsfWorkflowSteps < ActiveRecord::Migration[4.2] def change create_table :dmsf_workflow_steps do |t| diff --git a/db/migrate/20120822100403_create_dmsf_workflow_step_assignments.rb b/db/migrate/20120822100403_create_dmsf_workflow_step_assignments.rb index 435b8a5c..42523cf6 100644 --- a/db/migrate/20120822100403_create_dmsf_workflow_step_assignments.rb +++ b/db/migrate/20120822100403_create_dmsf_workflow_step_assignments.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class CreateDmsfWorkflowStepAssignments < ActiveRecord::Migration +class CreateDmsfWorkflowStepAssignments < ActiveRecord::Migration[4.2] def change create_table :dmsf_workflow_step_assignments do |t| diff --git a/db/migrate/20120822100404_create_dmsf_workflow_step_actions.rb b/db/migrate/20120822100404_create_dmsf_workflow_step_actions.rb index 69b6b510..7433e272 100644 --- a/db/migrate/20120822100404_create_dmsf_workflow_step_actions.rb +++ b/db/migrate/20120822100404_create_dmsf_workflow_step_actions.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class CreateDmsfWorkflowStepActions < ActiveRecord::Migration +class CreateDmsfWorkflowStepActions < ActiveRecord::Migration[4.2] def change create_table :dmsf_workflow_step_actions do |t| diff --git a/db/migrate/20130819013955_update_projects.rb b/db/migrate/20130819013955_update_projects.rb index f93f3fc1..a3f07ab5 100644 --- a/db/migrate/20130819013955_update_projects.rb +++ b/db/migrate/20130819013955_update_projects.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class UpdateProjects < ActiveRecord::Migration +class UpdateProjects < ActiveRecord::Migration[4.2] def change # DMSF - project's root folder notification diff --git a/db/migrate/20131108141401_add_index_to_dmsf_files.rb b/db/migrate/20131108141401_add_index_to_dmsf_files.rb index 917b7c2c..a4ccf91c 100644 --- a/db/migrate/20131108141401_add_index_to_dmsf_files.rb +++ b/db/migrate/20131108141401_add_index_to_dmsf_files.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddIndexToDmsfFiles < ActiveRecord::Migration +class AddIndexToDmsfFiles < ActiveRecord::Migration[4.2] def change add_index :dmsf_files, :project_id diff --git a/db/migrate/20131108141402_add_index_to_dmsf_folders.rb b/db/migrate/20131108141402_add_index_to_dmsf_folders.rb index 8df3c40a..be1c3e29 100644 --- a/db/migrate/20131108141402_add_index_to_dmsf_folders.rb +++ b/db/migrate/20131108141402_add_index_to_dmsf_folders.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddIndexToDmsfFolders < ActiveRecord::Migration +class AddIndexToDmsfFolders < ActiveRecord::Migration[4.2] def change add_index :dmsf_folders, :project_id diff --git a/db/migrate/20131113141401_add_index_to_dmsf_file_revision.rb b/db/migrate/20131113141401_add_index_to_dmsf_file_revision.rb index e250fe69..61dfc6f5 100644 --- a/db/migrate/20131113141401_add_index_to_dmsf_file_revision.rb +++ b/db/migrate/20131113141401_add_index_to_dmsf_file_revision.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddIndexToDmsfFileRevision < ActiveRecord::Migration +class AddIndexToDmsfFileRevision < ActiveRecord::Migration[4.2] def change add_index :dmsf_file_revisions, :dmsf_file_id diff --git a/db/migrate/20131113141402_add_index_to_dmsf_lock.rb b/db/migrate/20131113141402_add_index_to_dmsf_lock.rb index 2184eb1b..ba51c200 100644 --- a/db/migrate/20131113141402_add_index_to_dmsf_lock.rb +++ b/db/migrate/20131113141402_add_index_to_dmsf_lock.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddIndexToDmsfLock < ActiveRecord::Migration +class AddIndexToDmsfLock < ActiveRecord::Migration[4.2] def change add_index :dmsf_locks, :entity_id diff --git a/db/migrate/20131113141403_create_dmsf_links.rb b/db/migrate/20131113141403_create_dmsf_links.rb index 70686ba6..45d6cd56 100644 --- a/db/migrate/20131113141403_create_dmsf_links.rb +++ b/db/migrate/20131113141403_create_dmsf_links.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class CreateDmsfLinks < ActiveRecord::Migration +class CreateDmsfLinks < ActiveRecord::Migration[4.2] def change create_table :dmsf_links do |t| diff --git a/db/migrate/20140314132501_notifications_on.rb b/db/migrate/20140314132501_notifications_on.rb index 91973556..8f190207 100644 --- a/db/migrate/20140314132501_notifications_on.rb +++ b/db/migrate/20140314132501_notifications_on.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class NotificationsOn < ActiveRecord::Migration +class NotificationsOn < ActiveRecord::Migration[4.2] def up # Switch on the default notifications for new projects and folders diff --git a/db/migrate/20140519133201_trash_bin.rb b/db/migrate/20140519133201_trash_bin.rb index 0ceb8ea2..e9ce27f2 100644 --- a/db/migrate/20140519133201_trash_bin.rb +++ b/db/migrate/20140519133201_trash_bin.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class TrashBin < ActiveRecord::Migration +class TrashBin < ActiveRecord::Migration[4.2] def up # DMSF - project's root folder notification diff --git a/db/migrate/20141013102501_remove_project_from_revision.rb b/db/migrate/20141013102501_remove_project_from_revision.rb index 7a154bf9..c5fdd785 100644 --- a/db/migrate/20141013102501_remove_project_from_revision.rb +++ b/db/migrate/20141013102501_remove_project_from_revision.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class RemoveProjectFromRevision < ActiveRecord::Migration +class RemoveProjectFromRevision < ActiveRecord::Migration[4.2] def up remove_column :dmsf_file_revisions, :project_id diff --git a/db/migrate/20141015132701_remove_folder_from_revision.rb b/db/migrate/20141015132701_remove_folder_from_revision.rb index 17d1df67..ef30cbc4 100644 --- a/db/migrate/20141015132701_remove_folder_from_revision.rb +++ b/db/migrate/20141015132701_remove_folder_from_revision.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class RemoveFolderFromRevision < ActiveRecord::Migration +class RemoveFolderFromRevision < ActiveRecord::Migration[4.2] def up remove_column :dmsf_file_revisions, :dmsf_folder_id diff --git a/db/migrate/20141205143001_remove_uniqueness_from_wf.rb b/db/migrate/20141205143001_remove_uniqueness_from_wf.rb index 878d5c22..18fce0be 100644 --- a/db/migrate/20141205143001_remove_uniqueness_from_wf.rb +++ b/db/migrate/20141205143001_remove_uniqueness_from_wf.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class RemoveUniquenessFromWf < ActiveRecord::Migration +class RemoveUniquenessFromWf < ActiveRecord::Migration[4.2] def up remove_index(:dmsf_workflows, :name) if index_exists?(:dmsf_workflows, :name) diff --git a/db/migrate/20150120152101_notifications_nullable.rb b/db/migrate/20150120152101_notifications_nullable.rb index c58efbe7..e0e27b81 100644 --- a/db/migrate/20150120152101_notifications_nullable.rb +++ b/db/migrate/20150120152101_notifications_nullable.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class NotificationsNullable < ActiveRecord::Migration +class NotificationsNullable < ActiveRecord::Migration[4.2] def up change_column :projects, :dmsf_notification, :boolean, default: false, null: true diff --git a/db/migrate/20150130052716_add_external.rb b/db/migrate/20150130052716_add_external.rb index c736f0a3..2fe116b6 100644 --- a/db/migrate/20150130052716_add_external.rb +++ b/db/migrate/20150130052716_add_external.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddExternal < ActiveRecord::Migration +class AddExternal < ActiveRecord::Migration[4.2] def up change_column :dmsf_links, :target_id, :integer, null: true diff --git a/db/migrate/20150202010301_add_user_to_links.rb b/db/migrate/20150202010301_add_user_to_links.rb index ed1dc111..13fc4333 100644 --- a/db/migrate/20150202010301_add_user_to_links.rb +++ b/db/migrate/20150202010301_add_user_to_links.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddUserToLinks < ActiveRecord::Migration +class AddUserToLinks < ActiveRecord::Migration[4.2] def change add_column :dmsf_links, :user_id, :integer diff --git a/db/migrate/20150910153701_title_not_null.rb b/db/migrate/20150910153701_title_not_null.rb index 80577366..14be804a 100644 --- a/db/migrate/20150910153701_title_not_null.rb +++ b/db/migrate/20150910153701_title_not_null.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class TitleNotNull < ActiveRecord::Migration +class TitleNotNull < ActiveRecord::Migration[4.2] def up change_column :dmsf_file_revisions, :title, :string, null: false diff --git a/db/migrate/20151020141801_large_files.rb b/db/migrate/20151020141801_large_files.rb index fd4b0203..fe4442bc 100644 --- a/db/migrate/20151020141801_large_files.rb +++ b/db/migrate/20151020141801_large_files.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class LargeFiles < ActiveRecord::Migration +class LargeFiles < ActiveRecord::Migration[4.2] def up change_column :dmsf_file_revisions, :size, :bigint, null: true diff --git a/db/migrate/20151209100001_title_format.rb b/db/migrate/20151209100001_title_format.rb index 6fd80d30..8cd48d09 100644 --- a/db/migrate/20151209100001_title_format.rb +++ b/db/migrate/20151209100001_title_format.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class TitleFormat < ActiveRecord::Migration +class TitleFormat < ActiveRecord::Migration[4.2] def change add_column :members, :title_format, :text, null: true, limit: 100 diff --git a/db/migrate/20160215125801_approval_workflow_status.rb b/db/migrate/20160215125801_approval_workflow_status.rb index 37877d4d..08c7b71d 100644 --- a/db/migrate/20160215125801_approval_workflow_status.rb +++ b/db/migrate/20160215125801_approval_workflow_status.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class ApprovalWorkflowStatus < ActiveRecord::Migration +class ApprovalWorkflowStatus < ActiveRecord::Migration[4.2] def up add_column :dmsf_workflows, :status, :integer, null: false, diff --git a/db/migrate/20160217133001_status_deleted.rb b/db/migrate/20160217133001_status_deleted.rb index 34cda511..2e539fb5 100644 --- a/db/migrate/20160217133001_status_deleted.rb +++ b/db/migrate/20160217133001_status_deleted.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class StatusDeleted < ActiveRecord::Migration +class StatusDeleted < ActiveRecord::Migration[4.2] def up case ActiveRecord::Base.connection.adapter_name.downcase diff --git a/db/migrate/20160222140401_approval_workflow_std_fields.rb b/db/migrate/20160222140401_approval_workflow_std_fields.rb index ffdea6dc..fa3fdc00 100644 --- a/db/migrate/20160222140401_approval_workflow_std_fields.rb +++ b/db/migrate/20160222140401_approval_workflow_std_fields.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class ApprovalWorkflowStdFields < ActiveRecord::Migration +class ApprovalWorkflowStdFields < ActiveRecord::Migration[4.2] def up add_column :dmsf_workflows, :updated_on, :timestamp diff --git a/db/migrate/20160421150501_add_digest_to_revision.rb b/db/migrate/20160421150501_add_digest_to_revision.rb index 6500f8be..b103c951 100644 --- a/db/migrate/20160421150501_add_digest_to_revision.rb +++ b/db/migrate/20160421150501_add_digest_to_revision.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddDigestToRevision < ActiveRecord::Migration +class AddDigestToRevision < ActiveRecord::Migration[4.2] def up add_column :dmsf_file_revisions, :digest, :string, limit: 40, default: '', null: false diff --git a/db/migrate/20161223133200_create_dmsf_public_urls.rb b/db/migrate/20161223133200_create_dmsf_public_urls.rb index 8575be95..cd5447c7 100644 --- a/db/migrate/20161223133200_create_dmsf_public_urls.rb +++ b/db/migrate/20161223133200_create_dmsf_public_urls.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class CreateDmsfPublicUrls < ActiveRecord::Migration +class CreateDmsfPublicUrls < ActiveRecord::Migration[4.2] def change create_table :dmsf_public_urls do |t| diff --git a/db/migrate/20170103164701_add_name_to_appoval_workflow_step.rb b/db/migrate/20170103164701_add_name_to_appoval_workflow_step.rb index ece8afdf..c39e4a8d 100644 --- a/db/migrate/20170103164701_add_name_to_appoval_workflow_step.rb +++ b/db/migrate/20170103164701_add_name_to_appoval_workflow_step.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddNameToAppovalWorkflowStep < ActiveRecord::Migration +class AddNameToAppovalWorkflowStep < ActiveRecord::Migration[4.2] def change add_column :dmsf_workflow_steps, :name, :string, limit: 30, null: true diff --git a/db/migrate/20170118142001_dmsf_file_container.rb b/db/migrate/20170118142001_dmsf_file_container.rb index 66c95096..4528b643 100644 --- a/db/migrate/20170118142001_dmsf_file_container.rb +++ b/db/migrate/20170118142001_dmsf_file_container.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class DmsfFileContainer < ActiveRecord::Migration +class DmsfFileContainer < ActiveRecord::Migration[4.2] def up remove_index :dmsf_files, :project_id diff --git a/db/migrate/20170204214753_add_revision_to_dmsf_lock.rb b/db/migrate/20170204214753_add_revision_to_dmsf_lock.rb index 58a2ce2e..faa44ae7 100644 --- a/db/migrate/20170204214753_add_revision_to_dmsf_lock.rb +++ b/db/migrate/20170204214753_add_revision_to_dmsf_lock.rb @@ -19,7 +19,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddRevisionToDmsfLock < ActiveRecord::Migration +class AddRevisionToDmsfLock < ActiveRecord::Migration[4.2] def change add_column :dmsf_locks, :revision, :integer, null: true diff --git a/db/migrate/20170214153223_add_dmsf_file_last_revision_id_to_dmsf_lock.rb b/db/migrate/20170214153223_add_dmsf_file_last_revision_id_to_dmsf_lock.rb index 1e962b73..19f64be1 100644 --- a/db/migrate/20170214153223_add_dmsf_file_last_revision_id_to_dmsf_lock.rb +++ b/db/migrate/20170214153223_add_dmsf_file_last_revision_id_to_dmsf_lock.rb @@ -19,7 +19,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddDmsfFileLastRevisionIdToDmsfLock < ActiveRecord::Migration +class AddDmsfFileLastRevisionIdToDmsfLock < ActiveRecord::Migration[4.2] def up rename_column :dmsf_locks, :revision, :dmsf_file_last_revision_id diff --git a/db/migrate/20170217141601_add_dmsf_not_inheritable_to_custom_fields.rb b/db/migrate/20170217141601_add_dmsf_not_inheritable_to_custom_fields.rb index d40ff6a9..08a8a052 100644 --- a/db/migrate/20170217141601_add_dmsf_not_inheritable_to_custom_fields.rb +++ b/db/migrate/20170217141601_add_dmsf_not_inheritable_to_custom_fields.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddDmsfNotInheritableToCustomFields < ActiveRecord::Migration +class AddDmsfNotInheritableToCustomFields < ActiveRecord::Migration[4.2] def change add_column :custom_fields, :dmsf_not_inheritable, :boolean, null: true diff --git a/db/migrate/20170323131231_dmsf_description_limit.rb b/db/migrate/20170323131231_dmsf_description_limit.rb index a6e2ffc9..9e720736 100644 --- a/db/migrate/20170323131231_dmsf_description_limit.rb +++ b/db/migrate/20170323131231_dmsf_description_limit.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class DmsfDescriptionLimit < ActiveRecord::Migration +class DmsfDescriptionLimit < ActiveRecord::Migration[4.2] def up change_column :projects, :dmsf_description, :text, null: true, limit: 65535 diff --git a/db/migrate/20170330131901_create_dmsf_folder_permissions.rb b/db/migrate/20170330131901_create_dmsf_folder_permissions.rb index e1c5445d..4429bbb0 100644 --- a/db/migrate/20170330131901_create_dmsf_folder_permissions.rb +++ b/db/migrate/20170330131901_create_dmsf_folder_permissions.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class CreateDmsfFolderPermissions < ActiveRecord::Migration +class CreateDmsfFolderPermissions < ActiveRecord::Migration[4.2] def change create_table :dmsf_folder_permissions do |t| @@ -29,4 +29,4 @@ class CreateDmsfFolderPermissions < ActiveRecord::Migration add_index :dmsf_folder_permissions, :dmsf_folder_id end -end \ No newline at end of file +end diff --git a/db/migrate/20170421101901_dmsf_file_container_rollback.rb b/db/migrate/20170421101901_dmsf_file_container_rollback.rb index f6ed7f94..4480cac5 100644 --- a/db/migrate/20170421101901_dmsf_file_container_rollback.rb +++ b/db/migrate/20170421101901_dmsf_file_container_rollback.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class DmsfFileContainerRollback < ActiveRecord::Migration +class DmsfFileContainerRollback < ActiveRecord::Migration[4.2] def up # Add system folder_flag to dmsf_folders diff --git a/db/migrate/20170422104901_migrate_documents.rb b/db/migrate/20170422104901_migrate_documents.rb index 027a32c6..baec86be 100644 --- a/db/migrate/20170422104901_migrate_documents.rb +++ b/db/migrate/20170422104901_migrate_documents.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class MigrateDocuments < ActiveRecord::Migration +class MigrateDocuments < ActiveRecord::Migration[4.2] def up # Migrate all documents from dmsf/p_{project identifier} to dmsf/{year}/{month} diff --git a/db/migrate/20170526144701_dmsf_attachable.rb b/db/migrate/20170526144701_dmsf_attachable.rb index f1b390d1..fd33aa7d 100644 --- a/db/migrate/20170526144701_dmsf_attachable.rb +++ b/db/migrate/20170526144701_dmsf_attachable.rb @@ -18,14 +18,14 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class DmsfAttachable < ActiveRecord::Migration +class DmsfAttachable < ActiveRecord::Migration[4.2] def up # DMSF - project's root folder notification add_column :projects, :dmsf_act_as_attachable, :integer, default: 1, null: false Project.update_all dmsf_act_as_attachable: 1 end - + def down remove_column :projects, :dmsf_act_as_attachable end diff --git a/db/migrate/20171027124101_change_revision_digest_limit_to_64.rb b/db/migrate/20171027124101_change_revision_digest_limit_to_64.rb index ca94c18c..a4cb84f3 100644 --- a/db/migrate/20171027124101_change_revision_digest_limit_to_64.rb +++ b/db/migrate/20171027124101_change_revision_digest_limit_to_64.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class ChangeRevisionDigestLimitTo64 < ActiveRecord::Migration +class ChangeRevisionDigestLimitTo64 < ActiveRecord::Migration[4.2] def up change_column :dmsf_file_revisions, :digest, :string, limit: 64 diff --git a/db/migrate/20171110155901_add_index_to_dmsf_folder.rb b/db/migrate/20171110155901_add_index_to_dmsf_folder.rb index 07ba83b6..55dac6ce 100644 --- a/db/migrate/20171110155901_add_index_to_dmsf_folder.rb +++ b/db/migrate/20171110155901_add_index_to_dmsf_folder.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AddIndexToDmsfFolder < ActiveRecord::Migration +class AddIndexToDmsfFolder < ActiveRecord::Migration[4.2] def change add_index :dmsf_folders, :dmsf_folder_id diff --git a/db/migrate/20180216152501_rename_title_format.rb b/db/migrate/20180216152501_rename_title_format.rb index 458b7337..aa337cdd 100644 --- a/db/migrate/20180216152501_rename_title_format.rb +++ b/db/migrate/20180216152501_rename_title_format.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class RenameTitleFormat < ActiveRecord::Migration +class RenameTitleFormat < ActiveRecord::Migration[4.2] def up rename_column :members, :title_format, :dmsf_title_format diff --git a/db/migrate/20180903132101_fast_links.rb b/db/migrate/20180903132101_fast_links.rb index 81c3467c..f0627023 100644 --- a/db/migrate/20180903132101_fast_links.rb +++ b/db/migrate/20180903132101_fast_links.rb @@ -18,7 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class FastLinks < ActiveRecord::Migration +class FastLinks < ActiveRecord::Migration[4.2] def change add_column :members, :dmsf_fast_links, :boolean, default: false, null: false diff --git a/init.rb b/init.rb index fc069e5d..c54e3288 100644 --- a/init.rb +++ b/init.rb @@ -34,7 +34,7 @@ Redmine::Plugin.register :redmine_dmsf do description 'Document Management System Features' version '1.6.2' - requires_redmine version_or_higher: '3.4.0' + requires_redmine version_or_higher: '4.0.0' settings partial: 'settings/dmsf_settings', default: { diff --git a/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb b/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb index 78ae7081..e9a25705 100644 --- a/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb +++ b/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb @@ -116,7 +116,7 @@ module RedmineDmsf end # Attach DMS documents uploaded_files = params[:dmsf_attachments] - if uploaded_files && uploaded_files.is_a?(Hash) + if uploaded_files system_folder = issue.system_folder(true) uploaded_files.each do |key, uploaded_file| upload = DmsfUpload.create_from_uploaded_attachment(issue.project, system_folder, uploaded_file) diff --git a/lib/redmine_dmsf/patches/easy_crm_cases_controller_patch.rb b/lib/redmine_dmsf/patches/easy_crm_cases_controller_patch.rb index 19669d58..86439d98 100644 --- a/lib/redmine_dmsf/patches/easy_crm_cases_controller_patch.rb +++ b/lib/redmine_dmsf/patches/easy_crm_cases_controller_patch.rb @@ -32,7 +32,7 @@ module RedmineDmsf easy_crm_cases.each do |easy_crm_case| # Attach DMS documents uploaded_files = params[:dmsf_attachments] - if uploaded_files && uploaded_files.is_a?(Hash) + if uploaded_files 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) diff --git a/lib/redmine_dmsf/webdav/dmsf_resource.rb b/lib/redmine_dmsf/webdav/dmsf_resource.rb index ba38136d..6b456c8d 100644 --- a/lib/redmine_dmsf/webdav/dmsf_resource.rb +++ b/lib/redmine_dmsf/webdav/dmsf_resource.rb @@ -199,10 +199,7 @@ module RedmineDmsf destroy = false end if file.delete(destroy) - recipients = DmsfMailer.get_notify_users(project, [file]) - recipients.each do |u| - DmsfMailer.files_deleted(u, project, [file]).deliver - end + DmsfMailer.deliver_files_deleted(project, [file]) NoContent else Conflict @@ -599,10 +596,7 @@ module RedmineDmsf new_revision.create_digest new_revision.save # Notifications - recipients = DmsfMailer.get_notify_users(project, [f]) - recipients.each do |u| - DmsfMailer.files_updated(u, project, [f]).deliver - end + DmsfMailer.deliver_files_updated(project, [f]) else raise InternalServerError end diff --git a/lib/tasks/dmsf_alert_approvals.rake b/lib/tasks/dmsf_alert_approvals.rake index d6a80874..489f4f34 100644 --- a/lib/tasks/dmsf_alert_approvals.rake +++ b/lib/tasks/dmsf_alert_approvals.rake @@ -49,13 +49,13 @@ class DmsfAlertApprovals if dry_run puts "#{assignment.user.name} <#{assignment.user.mail}>" else - DmsfMailer.workflow_notification( - assignment.user, + DmsfMailer.deliver_workflow_notification( + [assignment.user], workflow, revision, :text_email_subject_requires_approval, :text_email_finished_step, - :text_email_to_proceed).deliver + :text_email_to_proceed) end end end diff --git a/test/ci/redmine_install.sh b/test/ci/redmine_install.sh index 5f6104c3..4d772be0 100644 --- a/test/ci/redmine_install.sh +++ b/test/ci/redmine_install.sh @@ -21,7 +21,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. export REDMINE_GIT_REPO=git://github.com/redmine/redmine.git -export REDMINE_GIT_TAG=3.4-stable +export REDMINE_GIT_TAG=4.0-stable clone() { diff --git a/test/functional/dmsf_context_menus_controller_test.rb b/test/functional/dmsf_context_menus_controller_test.rb index f6791c21..d41e8e50 100644 --- a/test/functional/dmsf_context_menus_controller_test.rb +++ b/test/functional/dmsf_context_menus_controller_test.rb @@ -44,7 +44,7 @@ class DmsfContextMenusControllerTest < RedmineDmsf::Test::TestCase end def test_dmsf - get :dmsf, :id => @project1.id, :ids => ["file-#{@file1.id}"] + get :dmsf, :params => {:id => @project1.id, :ids => ["file-#{@file1.id}"]} assert_response :success assert_select 'a.icon-edit', :text => l(:button_edit) assert_select 'a.icon-del', :text => l(:button_delete) @@ -53,7 +53,7 @@ class DmsfContextMenusControllerTest < RedmineDmsf::Test::TestCase end def test_dmsf_no_edit - get :dmsf, :id => @project1.id, :ids => ["folder-#{@folder1.id}"] + get :dmsf, :params => {:id => @project1.id, :ids => ["folder-#{@folder1.id}"]} assert_response :success assert_select 'a.icon-edit', :text => l(:button_edit), :count => 0 assert_select 'a.icon-del', :text => l(:button_delete) @@ -62,7 +62,7 @@ class DmsfContextMenusControllerTest < RedmineDmsf::Test::TestCase end def test_trash - get :trash, :id => @project1.id, :ids => ["file-#{@file1.id}"] + get :trash, :params => {:id => @project1.id, :ids => ["file-#{@file1.id}"]} assert_response :success assert_select 'a.icon-cancel', :text => l(:title_restore) assert_select 'a.icon-del', :text => l(:button_delete) diff --git a/test/functional/dmsf_controller_test.rb b/test/functional/dmsf_controller_test.rb index 54660699..32e32eef 100644 --- a/test/functional/dmsf_controller_test.rb +++ b/test/functional/dmsf_controller_test.rb @@ -74,7 +74,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase def test_edit_folder_forbidden # Missing permissions - get :edit, :id => @project, :folder_id => @folder1 + get :edit, :params => {:id => @project, :folder_id => @folder1} assert_response :forbidden end @@ -82,7 +82,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase # Permissions OK @role.add_permission! :view_dmsf_folders @role.add_permission! :folder_manipulation - get :edit, :id => @project, :folder_id => @folder1 + get :edit, :params => {:id => @project, :folder_id => @folder1} assert_response :success assert_select 'label', { :text => @custom_field.name } assert_select 'option', { :value => @custom_value.value } @@ -90,28 +90,28 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase def test_trash_forbidden # Missing permissions - get :trash, :id => @project + get :trash, :params => {:id => @project} assert_response :forbidden end def test_trash_allowed # Permissions OK @role.add_permission! :file_delete - get :trash, :id => @project + get :trash, :params => {:id => @project} assert_response :success assert_select 'h2', { :text => l(:link_trash_bin) } end def test_delete_forbidden # Missing permissions - get :delete, :id => @project, :folder_id => @folder1.id, :commit => false + get :delete, :params => {:id => @project, :folder_id => @folder1.id, :commit => false} assert_response :forbidden end def test_delete_not_empty # Permissions OK but the folder is not empty @role.add_permission! :folder_manipulation - get :delete, :id => @project, :folder_id => @folder1.id, :commit => false + get :delete, :params => {:id => @project, :folder_id => @folder1.id, :commit => false} assert_response :redirect assert_include l(:error_folder_is_not_empty), flash[:error] end @@ -119,7 +119,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase def test_delete_locked # Permissions OK but the folder is locked @role.add_permission! :folder_manipulation - get :delete, :id => @project, :folder_id => @folder2.id, :commit => false + get :delete, :params => {:id => @project, :folder_id => @folder2.id, :commit => false} assert_response :redirect assert_include l(:error_folder_is_locked), flash[:error] end @@ -127,7 +127,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase def test_delete_ok # Empty and not locked folder @role.add_permission! :folder_manipulation - get :delete, :id => @project, :folder_id => @folder4.id, :commit => false + get :delete, :params => {:id => @project, :folder_id => @folder4.id, :commit => false} assert_response :redirect end @@ -135,7 +135,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase # Missing permissions @folder4.deleted = 1 @folder4.save - get :restore, :id => @project, :folder_id => @folder4.id + get :restore, :params => {:id => @project, :folder_id => @folder4.id} assert_response :forbidden end @@ -145,14 +145,14 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase @role.add_permission! :folder_manipulation @folder4.deleted = 1 @folder4.save - get :restore, :id => @project, :folder_id => @folder4.id + get :restore, :params => {:id => @project, :folder_id => @folder4.id} assert_response :redirect end def test_delete_restore_entries_forbidden # Missing permissions - get :entries_operation, :id => @project, :delete_entries => 'Delete', - :ids => ["folder-#{@folder1.id}", "file-#{@file1.id}", "folder-link-#{@folder_link1.id}", "file-link-#{@file_link2.id}"] + get :entries_operation, :params => {:id => @project, :delete_entries => 'Delete', + :ids => ["folder-#{@folder1.id}", "file-#{@file1.id}", "folder-link-#{@folder_link1.id}", "file-link-#{@file_link2.id}"]} assert_response :forbidden end @@ -160,8 +160,8 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase # Permissions OK but the folder is not empty @request.env['HTTP_REFERER'] = dmsf_folder_path(:id => @project.id) @role.add_permission! :view_dmsf_files - get :entries_operation, :id => @project, :delete_entries => 'Delete', - :ids => ["folder-#{@folder1.id}", "file-#{@file1.id}", "folder-link-#{@folder_link1.id}", "file-link-#{@file_link2.id}"] + get :entries_operation, :params => {:id => @project, :delete_entries => 'Delete', + :ids => ["folder-#{@folder1.id}", "file-#{@file1.id}", "folder-link-#{@folder_link1.id}", "file-link-#{@file_link2.id}"]} assert_response :redirect assert_equal flash[:error].to_s, l(:error_folder_is_not_empty) end @@ -171,8 +171,8 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase @request.env['HTTP_REFERER'] = dmsf_folder_path(:id => @project.id) @role.add_permission! :view_dmsf_files flash[:error] = nil - get :entries_operation, :id => @project, :delete_entries => 'Delete', - :ids => ["file-#{@file1.id}", "file-link-#{@file_link2.id}"] + get :entries_operation, :params => {:id => @project, :delete_entries => 'Delete', + :ids => ["file-#{@file1.id}", "file-link-#{@file_link2.id}"]} assert_response :redirect assert_nil flash[:error] end @@ -181,8 +181,8 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase # Restore @role.add_permission! :view_dmsf_files @request.env['HTTP_REFERER'] = trash_dmsf_path(:id => @project.id) - get :entries_operation, :id => @project, :restore_entries => 'Restore', - :ids => ["file-#{@file1.id}", "file-link-#{@file_link2.id}"] + get :entries_operation, :params => {:id => @project, :restore_entries => 'Restore', + :ids => ["file-#{@file1.id}", "file-link-#{@file_link2.id}"]} assert_response :redirect assert_nil flash[:error] end @@ -190,7 +190,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase def test_show @role.add_permission! :view_dmsf_files @role.add_permission! :view_dmsf_folders - get :show, :id => @project.id + get :show, :params => {:id => @project.id} assert_response :success assert_select 'tr.dmsf_tree', :count => 0 end @@ -198,7 +198,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase def test_show_tag @role.add_permission! :view_dmsf_files @role.add_permission! :view_dmsf_folders - get :show, :id => @project.id, :custom_field_id => 21, :custom_value => 'Technical documentation' + get :show, :params => {:id => @project.id, :custom_field_id => 21, :custom_value => 'Technical documentation'} assert_response :success assert_select 'tr.dmsf_tree', :count => 0 end @@ -208,7 +208,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase @role.add_permission! :view_dmsf_folders @manager.pref[:dmsf_tree_view] = '1' @manager.preference.save - get :show, :id => @project.id + get :show, :params => {:id => @project.id} assert_response :success assert_select 'tr.dmsf_tree' end @@ -216,27 +216,27 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase def test_show_csv @role.add_permission! :view_dmsf_files @role.add_permission! :view_dmsf_folders - get :show, id: @project.id, format: 'csv', :settings => { dmsf_columns: %w(id title) } + get :show, :params => {id: @project.id, format: 'csv', :settings => { dmsf_columns: %w(id title) }} assert_response :success assert_equal 'text/csv; header=present', @response.content_type end def test_new_forbidden @role.remove_permission! :folder_manipulation - get :new, :id => @project, :parent_id => nil + get :new, :params => {:id => @project, :parent_id => nil} assert_response :forbidden end def test_new @role.add_permission! :folder_manipulation - get :new, :id => @project, :parent_id => nil + get :new, :params => {:id => @project, :parent_id => nil} assert_response :success end def test_email_entries_email_from Setting.plugin_redmine_dmsf['dmsf_documents_email_from'] = 'karel.picman@kontron.com' @role.add_permission! :view_dmsf_files - get :entries_operation, :id => @project, :email_entries => 'Email', :ids => ["file-#{@file1.id}"] + get :entries_operation, :params => {:id => @project, :email_entries => 'Email', :ids => ["file-#{@file1.id}"]} assert_response :success assert_select "input:match('value', ?)", Setting.plugin_redmine_dmsf['dmsf_documents_email_from'] end @@ -244,49 +244,49 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase def test_email_entries_reply_to Setting.plugin_redmine_dmsf['dmsf_documents_email_reply_to'] = 'karel.picman@kontron.com' @role.add_permission! :view_dmsf_files - get :entries_operation, :id => @project, :email_entries => 'Email', :ids => ["file-#{@file1.id}"] + get :entries_operation, :params => {:id => @project, :email_entries => 'Email', :ids => ["file-#{@file1.id}"]} assert_response :success assert_select "input:match('value', ?)", Setting.plugin_redmine_dmsf['dmsf_documents_email_reply_to'] end def test_email_entries_links_only - Setting.plugin_redmine_dmsf['dmsf_documents_email_links_only'] = true + Setting.plugin_redmine_dmsf['dmsf_documents_email_links_only'] = '1' @role.add_permission! :view_dmsf_files - get :entries_operation, :id => @project, :email_entries => 'Email', :ids => ["file-#{@file1.id}"] + get :entries_operation, :params => {:id => @project, :email_entries => 'Email', :ids => ["file-#{@file1.id}"]} assert_response :success assert_select "input:match('value', ?)", Setting.plugin_redmine_dmsf['dmsf_documents_email_links_only'] end def test_add_email_forbidden - xhr :get, :add_email, id: @project.id + get :add_email, :params => {id: @project.id}, :xhr => true assert_response :forbidden end def test_add_email @role.add_permission! :view_dmsf_files - xhr :get, :add_email, id: @project.id + get :add_email, :params => {id: @project.id}, :xhr => true assert_response :success end def test_append_email_forbidden - post :append_email, :id => @project, :user_ids => @project.members.collect{ |m| m.user.id }, :format => 'js' + post :append_email, :params => {:id => @project, :user_ids => @project.members.collect{ |m| m.user.id }, :format => 'js'} assert_response :forbidden end def test_append_email @role.add_permission! :view_dmsf_files - post :append_email, :id => @project, :user_ids => @project.members.collect{ |m| m.user.id }, :format => 'js' + post :append_email, :params => {:id => @project, :user_ids => @project.members.collect{ |m| m.user.id }, :format => 'js'} assert_response :success end def test_autocomplete_for_user_forbidden - xhr :get, :autocomplete_for_user, id: @project.id + get :autocomplete_for_user, :params => {id: @project.id}, :xhr => true assert_response :forbidden end def test_autocomplete_for_user @role.add_permission! :view_dmsf_files - xhr :get, :autocomplete_for_user, id: @project + get :autocomplete_for_user, :params => {id: @project}, :xhr => true assert_response :success end @@ -294,10 +294,10 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase @role.add_permission! :folder_manipulation @role.add_permission! :view_dmsf_folders assert_difference 'DmsfFolder.count', +1 do - post :create, :id => @project.id, :dmsf_folder => { + post :create, :params => {:id => @project.id, :dmsf_folder => { :title => 'New folder', :description => 'Unit tests' - } + }} end assert_redirected_to dmsf_folder_path(:id => @project, :folder_id => nil) end @@ -306,10 +306,10 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase @role.add_permission! :folder_manipulation @role.add_permission! :view_dmsf_folders assert_difference 'DmsfFolder.count', +1 do - post :create, :id => @project.id, :parent_id => @folder1.id, :dmsf_folder => { + post :create, :params => {:id => @project.id, :parent_id => @folder1.id, :dmsf_folder => { :title => 'New folder', :description => 'Unit tests' - } + }} end assert_redirected_to dmsf_folder_path(:id => @project, :folder_id => @folder1) end diff --git a/test/functional/dmsf_files_controller_test.rb b/test/functional/dmsf_files_controller_test.rb index 84f20bcf..cd4b96f9 100644 --- a/test/functional/dmsf_files_controller_test.rb +++ b/test/functional/dmsf_files_controller_test.rb @@ -57,39 +57,39 @@ class DmsfFilesControllerTest < RedmineDmsf::Test::TestCase def test_show_file_ok # Permissions OK @role.add_permission! :view_dmsf_files - get :show, :id => @file.id + get :show, :params => {:id => @file.id} assert_response :success end def test_show_file_forbidden # Missing permissions - get :show, :id => @file.id + get :show, :params => {:id => @file.id} assert_response :forbidden end def test_view_file_ok # Permissions OK @role.add_permission! :view_dmsf_files - get :view, :id => @file.id + get :view, :params => {:id => @file.id} assert_response :success end def test_view_file_forbidden # Missing permissions - get :view, :id => @file.id + get :view, :params => {:id => @file.id} assert_response :forbidden end def delete_forbidden # Missing permissions - delete @file, :commit => false + delete @file, :params => {:commit => false} assert_response :forbidden end def delete_locked # Permissions OK but the file is locked @role.add_permission! :file_delete - delete @file, :commit => false + delete @file, :params => {:commit => false} assert_response :redirect assert_include l(:error_file_is_locked), flash[:error] end @@ -98,19 +98,19 @@ class DmsfFilesControllerTest < RedmineDmsf::Test::TestCase # Permissions OK and not locked flash[:error].clear @file.unlock! - delete @file, :commit => false + delete @file, :params => {:commit => false} assert_response :redirect assert_equal 0, flash[:error].size end def test_obsolete_revision_ok @role.add_permission! :file_manipulation - get :obsolete_revision, :id => @file.last_revision.id + get :obsolete_revision, :params => {:id => @file.last_revision.id} assert_redirected_to :action => 'show', :id => @file end def test_obsolete_revision_missing_permissions - get :obsolete_revision, :id => @file.last_revision.id + get :obsolete_revision, :params => {:id => @file.last_revision.id} assert :forbiden end diff --git a/test/functional/dmsf_files_copy_controller_test.rb b/test/functional/dmsf_files_copy_controller_test.rb index c01619e4..091bd84d 100644 --- a/test/functional/dmsf_files_copy_controller_test.rb +++ b/test/functional/dmsf_files_copy_controller_test.rb @@ -72,127 +72,127 @@ class DmsfFilesCopyControllerTest < RedmineDmsf::Test::TestCase def test_authorize_admin @request.session[:user_id] = @user_admin.id - get :new, :id => @file1.id + get :new, :params => {:id => @file1.id} assert_response :success assert_template 'new' end def test_authorize_non_member @request.session[:user_id] = @user_non_member.id - get :new, :id => @file1.id + get :new, :params => {:id => @file1.id} assert_response :forbidden end def test_authorize_member_no_module @project1.disable_module!(:dmsf) - get :new, :id => @file1.id + get :new, :params => {:id => @file1.id} assert_response :forbidden end def test_authorize_forbidden @role_manager.remove_permission! :file_manipulation - get :new, :id => @file1.id + get :new, :params => {:id => @file1.id} assert_response :forbidden end def test_target_folder - get :new, :id => @file1.id, :target_folder_id => @folder1.id + get :new, :params => {:id => @file1.id, :target_folder_id => @folder1.id} assert_response :success assert_template 'new' end def test_target_folder_forbidden @role_manager.remove_permission! :view_dmsf_folders - get :new, :id => @file1.id, :target_folder_id => @folder1.id + get :new, :params => {:id => @file1.id, :target_folder_id => @folder1.id} assert_response :not_found end def test_target_project - get :new, :id => @file1.id, :target_project_id => @project1.id + get :new, :params => {:id => @file1.id, :target_project_id => @project1.id} assert_response :success assert_template 'new' end def test_new - get :new, :id => @file1.id + get :new, :params => {:id => @file1.id} assert_response :success assert_template 'new' end def test_copy - post :copy, :id => @file1.id, :target_project_id => @project1.id, :target_folder_id => @folder1.id + post :copy, :params => {:id => @file1.id, :target_project_id => @project1.id, :target_folder_id => @folder1.id} assert_response :redirect assert_nil flash[:error] end def test_copy_the_same_target - post :copy, :id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @file1.dmsf_folder + post :copy, :params => {:id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @file1.dmsf_folder} assert_equal flash[:error], l(:error_target_folder_same) assert_redirected_to :action => 'new', :target_project_id => @file1.project.id, :target_folder_id => @file1.dmsf_folder end def test_copy_to_locked_folder @folder1.lock! - post :copy, :id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @folder1.id + post :copy, :params => {:id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @folder1.id} assert_response :forbidden end def test_copy_to_dmsf_not_enabled - post :copy, :id => @file1.id, :target_project_id => @project5.id, :target_folder_id => nil + post :copy, :params => {:id => @file1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :forbidden end def test_copy_to_dmsf_enabled @project5.enable_module!(:dmsf) - post :copy, :id => @file1.id, :target_project_id => @project5.id, :target_folder_id => nil + post :copy, :params => {:id => @file1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :redirect assert_nil flash[:error] end def test_copy_to_as_non_member - post :copy, :id => @file1.id, :target_project_id => @project2.id, :target_folder_id => nil + post :copy, :params => {:id => @file1.id, :target_project_id => @project2.id, :target_folder_id => nil} assert_response :forbidden end def test_move - post :move, :id => @file1.id, :target_project_id => @project1.id, :target_folder_id => @folder1.id + post :move, :params => {:id => @file1.id, :target_project_id => @project1.id, :target_folder_id => @folder1.id} assert_response :redirect assert_nil flash[:error] end def test_move_the_same_target - post :move, :id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @file1.dmsf_folder + post :move, :params => {:id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @file1.dmsf_folder} assert_equal flash[:error], l(:error_target_folder_same) assert_redirected_to :action => 'new', :target_project_id => @file1.project.id, :target_folder_id => @file1.dmsf_folder end def test_move_to_locked @file1.lock! - post :move, :id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @folder1.id + post :move, :params => {:id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @folder1.id} assert_response :redirect assert_equal l(:error_file_is_locked), flash[:error] end def test_move_to_locked_folder @folder1.lock! - post :move, :id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @folder1.id + post :move, :params => {:id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @folder1.id} assert_response :forbidden end def test_move_to_dmsf_not_enabled - post :move, :id => @file1.id, :target_project_id => @project5.id, :target_folder_id => nil + post :move, :params => {:id => @file1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :forbidden end def test_move_to_dmsf_enabled @project5.enable_module!(:dmsf) - post :move, :id => @file1.id, :target_project_id => @project5.id, :target_folder_id => nil + post :move, :params => {:id => @file1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :redirect assert_nil flash[:error] end def test_move_to_as_non_member - post :move, :id => @file1.id, :target_project_id => @project2.id, :target_folder_id => nil + post :move, :params => {:id => @file1.id, :target_project_id => @project2.id, :target_folder_id => nil} assert_response :forbidden end diff --git a/test/functional/dmsf_folder_permissions_controller_test.rb b/test/functional/dmsf_folder_permissions_controller_test.rb index 46eba14a..6cd8a8d1 100644 --- a/test/functional/dmsf_folder_permissions_controller_test.rb +++ b/test/functional/dmsf_folder_permissions_controller_test.rb @@ -46,20 +46,20 @@ class DmsfFolderPermissionsControllerTest < RedmineDmsf::Test::TestCase end def test_new - xhr :get, :new, :project_id => @project1, :format => 'js' + get :new, :params => {:project_id => @project1, :format => 'js'}, :xhr => true assert_response :success assert_template 'new' assert_equal 'text/javascript', response.content_type end def test_autocomplete_for_user - xhr :get, :autocomplete_for_user, :project_id => @project1, :q => 'smi', :format => 'js' + get :autocomplete_for_user, :params => {:project_id => @project1, :q => 'smi', :format => 'js'}, :xhr => true assert_response :success assert_include 'John Smith', response.body end def test_append - xhr :get, :new, :project_id => @project1, :user_ids => [@manager.id], :format => 'js' + get :new, :params => {:project_id => @project1, :user_ids => [@manager.id], :format => 'js'}, :xhr => true assert_response :success assert_template 'new' assert_equal 'text/javascript', response.content_type diff --git a/test/functional/dmsf_folders_copy_controller_test.rb b/test/functional/dmsf_folders_copy_controller_test.rb index 25eb6c0c..adb9e998 100644 --- a/test/functional/dmsf_folders_copy_controller_test.rb +++ b/test/functional/dmsf_folders_copy_controller_test.rb @@ -73,55 +73,55 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase def test_authorize_admin @request.session[:user_id] = @user_admin.id - get :new, :id => @folder1.id + get :new, :params => {:id => @folder1.id} assert_response :success assert_template 'new' end def test_authorize_non_member @request.session[:user_id] = @user_non_member.id - get :new, :id => @folder1.id + get :new, :params => {:id => @folder1.id} assert_response :forbidden end def test_authorize_member_no_module @project1.disable_module!(:dmsf) - get :new, :id => @folder1.id + get :new, :params => {:id => @folder1.id} assert_response :forbidden end def test_authorize_forbidden @role_manager.remove_permission! :folder_manipulation - get :new, :id => @folder1.id + get :new, :params => {:id => @folder1.id} assert_response :forbidden end def test_target_folder - get :new, :id => @folder1.id, :target_folder_id => @folder2.id + get :new, :params => {:id => @folder1.id, :target_folder_id => @folder2.id} assert_response :success assert_template 'new' end def test_target_folder_forbidden @role_manager.remove_permission! :view_dmsf_folders - get :new, :id => @folder1.id, :target_folder_id => @folder2.id + get :new, :params => {:id => @folder1.id, :target_folder_id => @folder2.id} assert_response :forbidden end def test_target_project - get :new, :id => @folder1.id, :target_project_id => @project1.id + get :new, :params => {:id => @folder1.id, :target_project_id => @project1.id} assert_response :success assert_template 'new' end def test_new - get :new, :id => @folder1.id + get :new, :params => {:id => @folder1.id} assert_response :success assert_template 'new' end def test_copy - post :copy, :id => @folder1.id, :target_project_id => @project1.id, :target_folder_id => @folder6.id + post :copy, :params => {:id => @folder1.id, :target_project_id => @project1.id, :target_folder_id => @folder6.id} assert_response :redirect assert_nil flash[:error] end @@ -130,7 +130,7 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase @request.session[:user_id] = @user_admin.id @project2.enable_module!(:dmsf) assert_equal @project1.id, @folder1.project_id - post :copy, :id => @folder1.id, :target_project_id => @project2.id + post :copy, :params => {:id => @folder1.id, :target_project_id => @project2.id} assert_response :redirect assert_nil flash[:error] # Check all childs' project ID @@ -141,71 +141,71 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase end def test_copy_the_same_target - post :copy, :id => @folder1.id, :target_project_id => @folder1.project.id, :target_folder_id => @folder1.dmsf_folder + post :copy, :params => {:id => @folder1.id, :target_project_id => @folder1.project.id, :target_folder_id => @folder1.dmsf_folder} assert_equal flash[:error], l(:error_target_folder_same) assert_redirected_to :action => 'new', :target_project_id => @folder1.project.id, :target_folder_id => @folder1.dmsf_folder end def test_copy_to_locked_folder - post :copy, :id => @folder1.id, :target_project_id => @folder1.project.id, :target_folder_id => @folder2.id + post :copy, :params => {:id => @folder1.id, :target_project_id => @folder1.project.id, :target_folder_id => @folder2.id} assert_response :forbidden end def test_copy_to_dmsf_not_enabled - post :copy, :id => @folder1.id, :target_project_id => @project5.id, :target_folder_id => nil + post :copy, :params => {:id => @folder1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :forbidden end def test_copy_to_dmsf_enabled @project5.enable_module!(:dmsf) - post :copy, :id => @folder1.id, :target_project_id => @project5.id, :target_folder_id => nil + post :copy, :params => {:id => @folder1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :redirect assert_nil flash[:error] end def test_copy_to_as_non_member - post :copy, :id => @folder1.id, :target_project_id => @project2.id, :target_folder_id => nil + post :copy, :params => {:id => @folder1.id, :target_project_id => @project2.id, :target_folder_id => nil} assert_response :forbidden end def test_move - post :move, :id => @folder1.id, :target_project_id => @project1.id, :target_folder_id => @folder6.id + post :move, :params => {:id => @folder1.id, :target_project_id => @project1.id, :target_folder_id => @folder6.id} assert_response :redirect assert_nil flash[:error] end def test_move_the_same_target - post :move, :id => @folder1.id, :target_project_id => @folder1.project.id, :target_folder_id => @folder1.dmsf_folder + post :move, :params => {:id => @folder1.id, :target_project_id => @folder1.project.id, :target_folder_id => @folder1.dmsf_folder} assert_equal flash[:error], l(:error_target_folder_same) assert_redirected_to :action => 'new', :target_project_id => @folder1.project.id, :target_folder_id => @folder1.dmsf_folder end def test_move_to_locked @folder1.lock! - post :move, :id => @folder1.id, :target_project_id => @folder1.project.id, :target_folder_id => @folder2.id + post :move, :params => {:id => @folder1.id, :target_project_id => @folder1.project.id, :target_folder_id => @folder2.id} assert_response :forbidden end def test_move_to_locked_folder - post :move, :id => @folder1.id, :target_project_id => @folder2.project.id, :target_folder_id => @folder2.id + post :move, :params => {:id => @folder1.id, :target_project_id => @folder2.project.id, :target_folder_id => @folder2.id} assert_response :forbidden end def test_move_to_dmsf_not_enabled - post :move, :id => @folder1.id, :target_project_id => @project5.id, :target_folder_id => nil + post :move, :params => {:id => @folder1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :forbidden end def test_move_to_dmsf_enabled @project5.enable_module!(:dmsf) - post :move, :id => @folder1.id, :target_project_id => @project5.id, :target_folder_id => nil + post :move, :params => {:id => @folder1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :redirect assert_nil flash[:error] end def test_move_to_as_non_member - post :move, :id => @folder1.id, :target_project_id => @project2.id, :target_folder_id => nil + post :move, :params => {:id => @folder1.id, :target_project_id => @project2.id, :target_folder_id => nil} assert_response :forbidden end @@ -213,7 +213,7 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase @request.session[:user_id] = @user_admin.id @project2.enable_module!(:dmsf) assert_equal @project1.id, @folder1.project_id - post :move, :id => @folder1.id, :target_project_id => @project2.id + post :move, :params => {:id => @folder1.id, :target_project_id => @project2.id} assert_response :redirect assert_nil flash[:error] # Check all childs' project ID diff --git a/test/functional/dmsf_links_controller_test.rb b/test/functional/dmsf_links_controller_test.rb index 648408b7..019cc286 100644 --- a/test/functional/dmsf_links_controller_test.rb +++ b/test/functional/dmsf_links_controller_test.rb @@ -73,27 +73,27 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase def test_authorize_admin @request.session[:user_id] = @user_admin.id - get :new, :project_id => @project1.id + get :new, :params => {:project_id => @project1.id} assert_response :success assert_template 'new' end def test_authorize_non_member @request.session[:user_id] = @user_non_member.id - get :new, :project_id => @project2.id + get :new, :params => {:project_id => @project2.id} assert_response :forbidden end def test_authorize_member_ok @request.session[:user_id] = @user_member.id - get :new, :project_id => @project1.id + get :new, :params => {:project_id => @project1.id} assert_response :success end def test_authorize_member_no_module # Without the module @project1.disable_module!(:dmsf) - get :new, :project_id => @project1.id + get :new, :params => {:project_id => @project1.id} assert_response :forbidden end @@ -101,12 +101,12 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase # Without permissions @project1.enable_module!(:dmsf) @role_manager.remove_permission! :file_manipulation - get :new, :project_id => @project1.id + get :new, :params => {:project_id => @project1.id} assert_response :forbidden end def test_new - get :new, :project_id => @project1.id, :type => 'link_to' + get :new, :params => {:project_id => @project1.id, :type => 'link_to'} assert_response :success assert_select 'label', { :text => l(:label_target_project) } end @@ -115,7 +115,7 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase member = Member.where(:user_id => @user_member.id, :project_id => @project1.id).first assert member member.update_attribute :dmsf_fast_links, true - get :new, :project_id => @project1.id, :type => 'link_to' + get :new, :params => {:project_id => @project1.id, :type => 'link_to'} assert_response :success assert_select 'label', { :count => 0, :text => l(:label_target_project) } end @@ -123,7 +123,7 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase def test_create_file_link_from_f1 # 1. File link in a folder from another folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :target_project_id => @project2.id, :dmsf_folder_id => @folder1.id, @@ -131,7 +131,7 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase :target_folder_id => @folder3.id, :name => 'file_link', :type => 'link_from' - } + }} end assert_redirected_to dmsf_folder_path(:id => @project1.id, :folder_id => @folder1.id) end @@ -139,7 +139,7 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase def test_create_file_link_from_f2 # 2. File link in a folder from another root folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :dmsf_folder_id => @folder1.id, :target_project_id => @project2.id, @@ -147,7 +147,7 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase :target_folder_id => 'Documents', :name => 'file_link', :type => 'link_from' - } + }} end assert_redirected_to dmsf_folder_path(:id => @project1.id, :folder_id => @folder1.id) end @@ -155,14 +155,14 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase def test_create_file_link_from_f3 # 3. File link in a root folder from another folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :target_project_id => @project2.id, :target_file_id => @file6.id, :target_folder_id => @folder3.id, :name => 'file_link', :type => 'link_from' - } + }} end assert_redirected_to dmsf_folder_path(:id => @project1.id) end @@ -170,28 +170,28 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase def test_create_file_link_from_f4 # 4. File link in a root folder from another root folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :target_project_id => @project2.id, :target_file_id => @file2.id, :name => 'file_link', :type => 'link_from' - } - end + }} + end assert_redirected_to dmsf_folder_path(:id => @project1.id) end def test_create_folder_link_from_d1 # 1. Folder link in a folder from another folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :dmsf_folder_id => @folder1.id, :target_project_id => @project2.id, :target_folder_id => @folder3.id, :name => 'folder_link', :type => 'link_from' - } + }} end assert_redirected_to dmsf_folder_path(:id => @project1.id, :folder_id => @folder1.id) end @@ -199,13 +199,13 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase def test_create_folder_link_from_d2 # 2. Folder link in a folder from another root folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :dmsf_folder_id => @folder1.id, :target_project_id => @project2.id, :name => 'folder_link', :type => 'link_from' - } + }} end assert_redirected_to dmsf_folder_path(:id => @project1.id, :folder_id => @folder1.id) end @@ -213,13 +213,13 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase def test_create_folder_link_from_d3 # 3. Folder link in a root folder from another folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :target_project_id => @project2.id, :target_folder_id => @folder3.id, :name => 'folder_link', :type => 'link_from' - } + }} end assert_redirected_to dmsf_folder_path(:id => @project1.id) end @@ -227,35 +227,35 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase def test_create_folder_link_from_d4 # 4. Folder link in a root folder from another root folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :target_project_id => @project2.id, :name => 'folder_link', :type => 'link_from' - } - end + }} + end assert_redirected_to dmsf_folder_path(:id => @project1.id) end def test_create_file_link_to_f1 # 1. File link to a root folder from another folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :dmsf_file_id => @file1.id, :target_project_id => @project2.id, :target_folder_id => @folder3.id, :name => 'file_link', :type => 'link_to' - } - end + }} + end assert_redirected_to dmsf_file_path(@file1) end def test_create_file_link_to_f2 # 2. File link to a folder from another folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project2.id, :dmsf_folder_id => @folder3.id, :target_project_id => @project1.id, @@ -263,85 +263,85 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase :dmsf_file_id => @file6.id, :name => 'file_link', :type => 'link_to' - } - end + }} + end assert_redirected_to dmsf_file_path(@file6) end def test_create_file_link_to_f3 # 3. File link to a root folder from another root folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project2.id, :target_project_id => @project1.id, :dmsf_file_id => @file6.id, :name => 'file_link', :type => 'link_to' - } - end + }} + end assert_redirected_to dmsf_file_path(@file6) end def test_create_file_link_to_f4 # 4. File link to a folder from another root folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project2.id, :dmsf_folder_id => @folder3.id, :target_project_id => @project1.id, :dmsf_file_id => @file6.id, :name => 'file_link', :type => 'link_to' - } - end + }} + end assert_redirected_to dmsf_file_path(@file6) end def test_create_external_link_from assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :target_project_id => @project1.id, :name => 'file_link', :external_link => 'true', :type => 'link_from' - } - end + }} + end assert_redirected_to dmsf_folder_path(:id => @project1.id) end def test_create_folder_link_to_f1 # 1. Folder link to a root folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :dmsf_folder_id => @folder1.id, :target_project_id => @project2.id, :name => 'folder_link', :type => 'link_to' - } - end + }} + end assert_redirected_to edit_dmsf_path(:id => @project1.id, :folder_id => @folder1.id) end def test_create_folder_link_to_f2 # 2. Folder link to a folder assert_difference 'DmsfLink.count', +1 do - post :create, :dmsf_link => { + post :create, :params => {:dmsf_link => { :project_id => @project1.id, :dmsf_folder_id => @folder1.id, :target_project_id => @project2.id, :target_folder_id => @folder3.id, :name => 'folder_link', :type => 'link_to' - } - end + }} + end assert_redirected_to edit_dmsf_path(:id => @project1.id, :folder_id => @folder1.id) end def test_destroy assert_difference 'DmsfLink.visible.count', -1 do - delete :destroy, :project_id => @project1.id, :id => @file_link.id + delete :destroy, :params => {:project_id => @project1.id, :id => @file_link.id} end assert_redirected_to dmsf_folder_path(:id => @project1.id, :folder_id => @folder1.id) end @@ -350,7 +350,7 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase # Missing permissions @request.env['HTTP_REFERER'] = trash_dmsf_path(:id => @project1.id) @role_manager.remove_permission! :file_manipulation - get :restore, :project_id => @project1.id, :id => @file_link.id + get :restore, :params => {:project_id => @project1.id, :id => @file_link.id} assert_response :forbidden end @@ -358,7 +358,7 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase # Permissions OK @request.env['HTTP_REFERER'] = trash_dmsf_path(:id => @project1.id) @role_manager.add_permission! :file_manipulation - get :restore, :project_id => @project1.id, :id => @file_link.id + get :restore, :params => {:project_id => @project1.id, :id => @file_link.id} assert_response :redirect end diff --git a/test/functional/dmsf_public_urls_controller_test.rb b/test/functional/dmsf_public_urls_controller_test.rb index 831265a4..da4845a7 100644 --- a/test/functional/dmsf_public_urls_controller_test.rb +++ b/test/functional/dmsf_public_urls_controller_test.rb @@ -35,17 +35,17 @@ class DmsfPublicUrlsControllerTest < RedmineDmsf::Test::TestCase end def test_show_valid_url - get :show, :token => 'd8d33e21914a433b280fdc94450ee212' + get :show, :params => {:token => 'd8d33e21914a433b280fdc94450ee212'} assert_response :success end def test_show_url_width_invalid_token - get :show, :token => 'f8d33e21914a433b280fdc94450ee212' + get :show, :params => {:token => 'f8d33e21914a433b280fdc94450ee212'} assert_response :not_found end def test_show_url_that_has_expired - get :show, :token => 'e8d33e21914a433b280fdc94450ee212' + get :show, :params => {:token => 'e8d33e21914a433b280fdc94450ee212'} assert_response :not_found end diff --git a/test/functional/dmsf_state_controller_test.rb b/test/functional/dmsf_state_controller_test.rb index 021aeaab..1cab016e 100644 --- a/test/functional/dmsf_state_controller_test.rb +++ b/test/functional/dmsf_state_controller_test.rb @@ -47,8 +47,8 @@ class DmsfStateControllerTest < RedmineDmsf::Test::TestCase # Member @request.session[:user_id] = @user_member.id @role_manager.add_permission! :user_preferences - post :user_pref_save, :id => @project.id, :email_notify => 1, - :title_format => '%t_%v' + post :user_pref_save, :params => {:id => @project.id, :email_notify => 1, + :title_format => '%t_%v'} assert_redirected_to settings_project_path(@project, :tab => 'dmsf') assert_not_nil flash[:notice] assert_equal flash[:notice], l(:notice_your_preferences_were_saved) @@ -57,8 +57,8 @@ class DmsfStateControllerTest < RedmineDmsf::Test::TestCase def test_user_pref_save_member_forbidden # Member @request.session[:user_id] = @user_member.id - post :user_pref_save, :id => @project.id, :email_notify => 1, - :title_format => '%t_%v' + post :user_pref_save, :params => {:id => @project.id, :email_notify => 1, + :title_format => '%t_%v'} assert_response :forbidden end @@ -66,8 +66,8 @@ class DmsfStateControllerTest < RedmineDmsf::Test::TestCase # Non Member @request.session[:user_id] = @user_non_member.id @role_manager.add_permission! :user_preferences - post :user_pref_save, :id => @project.id, :email_notify => 1, - :title_format => '%t_%v' + post :user_pref_save, :params => {:id => @project.id, :email_notify => 1, + :title_format => '%t_%v'} assert_response :forbidden end @@ -75,8 +75,8 @@ class DmsfStateControllerTest < RedmineDmsf::Test::TestCase # Admin - non member @request.session[:user_id] = @user_admin.id @role_manager.add_permission! :user_preferences - post :user_pref_save, :id => @project.id, :email_notify => 1, - :title_format => '%t_%v' + post :user_pref_save, :params => {:id => @project.id, :email_notify => 1, + :title_format => '%t_%v'} assert_redirected_to settings_project_path(@project, :tab => 'dmsf') assert_not_nil flash[:warning] assert_equal flash[:warning], l(:user_is_not_project_member) diff --git a/test/functional/dmsf_workflow_controller_test.rb b/test/functional/dmsf_workflow_controller_test.rb index 88bec7d0..a879ca40 100644 --- a/test/functional/dmsf_workflow_controller_test.rb +++ b/test/functional/dmsf_workflow_controller_test.rb @@ -85,7 +85,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase def test_authorize_member # Non member @request.session[:user_id] = @user_non_member.id - get :index, :project_id => @project1.id + get :index, :params => {:project_id => @project1.id} assert_response :forbidden end @@ -97,7 +97,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase def test_authorize_projects # Project - get :index, :project_id => @project1.id + get :index, :params => {:project_id => @project1.id} assert_response :success assert_template 'index' end @@ -105,23 +105,23 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase def test_authorize_manage_workflows_forbidden # Without permissions @role_manager.remove_permission! :manage_workflows - get :index, :project_id => @project1.id + get :index, :params => {:project_id => @project1.id} assert_response :forbidden end def test_authorization_file_approval_ok @role_manager.add_permission! :file_approval @revision2.dmsf_workflow_id = @wf1.id - get :start, :id => @revision2.dmsf_workflow_id, - :dmsf_file_revision_id => @revision2.id + get :start, :params => {:id => @revision2.dmsf_workflow_id, + :dmsf_file_revision_id => @revision2.id} assert_response :redirect end def test_authorization_file_approval_forbidden @role_manager.remove_permission! :file_approval @revision2.dmsf_workflow_id = @wf1.id - get :start, :id => @revision2.dmsf_workflow_id, - :dmsf_file_revision_id => @revision2.id + get :start, :params => {:id => @revision2.dmsf_workflow_id, + :dmsf_file_revision_id => @revision2.id} assert_response :forbidden end @@ -129,7 +129,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase # Without the module @role_manager.add_permission! :file_manipulation @project1.disable_module!(:dmsf) - get :index, :project_id => @project1.id + get :index, :params => {:project_id => @project1.id} assert_response :forbidden end @@ -141,52 +141,52 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase end def test_index_project - get :index, :project_id => @project1.id + get :index, :params => {:project_id => @project1.id} assert_response :success assert_template 'index' end def test_new - get :new, :project_id => @project1.id + get :new, :params => {:project_id => @project1.id} assert_response :success assert_template 'new' end def test_lock - put :update, :id => @wf1.id, :dmsf_workflow => { :status => DmsfWorkflow::STATUS_LOCKED } + put :update, :params => {:id => @wf1.id, :dmsf_workflow => { :status => DmsfWorkflow::STATUS_LOCKED }} @wf1.reload assert @wf1.locked?, "#{@wf1.name} status is #{@wf1.status}" end def test_unlock @request.session[:user_id] = @user_admin.id - put :update, :id => @wf3.id, :dmsf_workflow => { :status => DmsfWorkflow::STATUS_ACTIVE } + put :update, :params => {:id => @wf3.id, :dmsf_workflow => { :status => DmsfWorkflow::STATUS_ACTIVE }} @wf3.reload assert @wf3.active?, "#{@wf3.name} status is #{@wf3.status}" end def test_show - get :show, :id => @wf1.id + get :show, :params => {:id => @wf1.id} assert_response :success assert_template 'show' end def test_create assert_difference 'DmsfWorkflow.count', +1 do - post :create, :dmsf_workflow => {:name => 'wf4', :project_id => @project1.id} + post :create, :params => {:dmsf_workflow => {:name => 'wf4', :project_id => @project1.id}} end assert_redirected_to settings_project_path(@project1, :tab => 'dmsf_workflow') end def test_update - put :update, :id => @wf1.id, :dmsf_workflow => {:name => 'wf1a'} + put :update, :params => {:id => @wf1.id, :dmsf_workflow => {:name => 'wf1a'}} @wf1.reload assert_equal 'wf1a', @wf1.name end def test_destroy assert_difference 'DmsfWorkflow.count', -1 do - delete :destroy, :id => @wf1.id + delete :destroy, :params => {:id => @wf1.id} end assert_redirected_to settings_project_path(@project1, :tab => 'dmsf_workflow') assert_equal 0, DmsfWorkflowStep.where(:dmsf_workflow_id => @wf1.id).all.count @@ -194,8 +194,8 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase def test_add_step assert_difference 'DmsfWorkflowStep.count', +1 do - post :add_step, :commit => l(:dmsf_or), :step => 1, :name => '1st step', :id => @wf1.id, - :user_ids => [@user_non_member.id] + post :add_step, :params => {:commit => l(:dmsf_or), :step => 1, :name => '1st step', :id => @wf1.id, + :user_ids => [@user_non_member.id]} end assert_response :success ws = DmsfWorkflowStep.order(id: :desc).first @@ -209,7 +209,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase def test_remove_step n = DmsfWorkflowStep.where(:dmsf_workflow_id => @wf1.id, :step => 1).count assert_difference 'DmsfWorkflowStep.count', -n do - delete :remove_step, :step => @wfs1.id, :id => @wf1.id + delete :remove_step, :params => {:step => @wfs1.id, :id => @wf1.id} end assert_response :redirect ws = DmsfWorkflowStep.where(:dmsf_workflow_id => @wf1.id).order(:id =>:asc).first @@ -217,7 +217,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase end def test_reorder_steps_to_lower - put :reorder_steps, :step => 1, :id => @wf1.id, :dmsf_workflow => {:position => 2} + put :reorder_steps, :params => {:step => 1, :id => @wf1.id, :dmsf_workflow => {:position => 2}} assert_response :success @wfs1.reload @wfs2.reload @@ -232,7 +232,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase end def test_reorder_steps_to_lowest - put :reorder_steps, :step => 1, :id => @wf1.id, :dmsf_workflow => {:position => 3} + put :reorder_steps, :params => {:step => 1, :id => @wf1.id, :dmsf_workflow => {:position => 3}} assert_response :success @wfs1.reload @wfs2.reload @@ -247,7 +247,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase end def test_reorder_steps_to_higher - put :reorder_steps, :step => 3, :id => @wf1.id, :dmsf_workflow => {:position => 2} + put :reorder_steps, :params => {:step => 3, :id => @wf1.id, :dmsf_workflow => {:position => 2}} assert_response :success @wfs1.reload @wfs2.reload @@ -262,7 +262,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase end def test_reorder_steps_to_highest - put :reorder_steps, :step => 3, :id => @wf1.id, :dmsf_workflow => {:position => '1'} + put :reorder_steps, :params => {:step => 3, :id => @wf1.id, :dmsf_workflow => {:position => '1'}} assert_response :success @wfs1.reload @wfs2.reload @@ -278,14 +278,14 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase def test_action_approve post( - :new_action, + :new_action, :params => { :commit => l(:button_submit), :id => @wf1.id, :dmsf_workflow_step_assignment_id => @wfsa2.id, :dmsf_file_revision_id => @revision1.id, :step_action => DmsfWorkflowStepAction::ACTION_APPROVE, :user_id => nil, - :note => '') + :note => ''}) assert_redirected_to dmsf_folder_path(:id => @project1.id) assert DmsfWorkflowStepAction.where( :dmsf_workflow_step_assignment_id => @wfsa2.id, @@ -294,13 +294,13 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase def test_action_reject post( - :new_action, + :new_action, :params => { :commit => l(:button_submit), :id => @wf1.id, :dmsf_workflow_step_assignment_id => @wfsa2.id, :dmsf_file_revision_id => @revision2.id, :step_action => DmsfWorkflowStepAction::ACTION_REJECT, - :note => 'Rejected because...') + :note => 'Rejected because...'}) assert_response :redirect assert DmsfWorkflowStepAction.where( :dmsf_workflow_step_assignment_id => @wfsa2.id, @@ -308,14 +308,13 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase end def test_action - xhr( - :get, - :action, + get( + :action, :xhr => true, :params => { :project_id => @project1.id, :id => @wf1.id, :dmsf_workflow_step_assignment_id => @wfsa2.id, :dmsf_file_revision_id => @revision2.id, - :title => l(:title_waiting_for_approval)) + :title => l(:title_waiting_for_approval)}) assert_response :success assert_match(/ajax-modal/, response.body) assert_template 'action' @@ -323,13 +322,13 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase def test_new_action_delegate post( - :new_action, + :new_action, :params => { :commit => l(:button_submit), :id => @wf1.id, :dmsf_workflow_step_assignment_id => @wfsa2.id, :dmsf_file_revision_id => @revision2.id, :step_action => @user_admin.id * 10, - :note => 'Delegated because...') + :note => 'Delegated because...'}) assert_redirected_to dmsf_folder_path(:id => @project1.id) assert DmsfWorkflowStepAction.where( :dmsf_workflow_step_assignment_id => @wfsa2.id, @@ -339,13 +338,12 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase end def test_assign - xhr( - :get, - :assign, + get( + :assign, :xhr => true, :params => { :project_id => @project1.id, :id => @wf1.id, :dmsf_file_revision_id => @revision1.id, - :title => l(:label_dmsf_wokflow_action_assign)) + :title => l(:label_dmsf_wokflow_action_assign)}) assert_response :success assert_match(/ajax-modal/, response.body) assert_template 'assign' @@ -353,24 +351,24 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase def test_start @revision2.dmsf_workflow_id = @wf1.id - get :start, :id => @revision2.dmsf_workflow_id, :dmsf_file_revision_id => @revision2.id + get :start, :params => {:id => @revision2.dmsf_workflow_id, :dmsf_file_revision_id => @revision2.id} assert_redirected_to dmsf_folder_path(:id => @project1.id) end def test_assignment post( - :assignment, + :assignment, :params => { :commit => l(:button_submit), :id => @wf1.id, :dmsf_workflow_id => @wf1.id, :dmsf_file_revision_id => @revision2.id, :action => 'assignment', - :project_id => @project1.id) + :project_id => @project1.id}) assert_response :redirect end def test_update_step_name - put :update_step, id: @wf1.id, step: @wfs2.step, dmsf_workflow: { step_name: 'new_name'} + put :update_step, :params => {id: @wf1.id, step: @wfs2.step, dmsf_workflow: { step_name: 'new_name'}} assert_response :redirect # All steps in the same step must be renamed @wfs2.reload @@ -383,22 +381,22 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase end def test_update_step_operators - put :update_step, + put :update_step, :params => { :id => @wf1, :step => '1', :operator_step => { @wfs1.id.to_s => DmsfWorkflowStep::OPERATOR_OR.to_s }, - :assignee => { @wfs1.id.to_s => @wfs1.user_id.to_s } + :assignee => { @wfs1.id.to_s => @wfs1.user_id.to_s }} assert_response :redirect @wfs1.reload assert_equal @wfs1.operator, DmsfWorkflowStep::OPERATOR_OR end def test_update_step_assignee - put :update_step, + put :update_step, :params => { :id => @wf1, :step => '1', :operator_step => { @wfs1.id.to_s => DmsfWorkflowStep::OPERATOR_OR.to_s }, - :assignee => { @wfs1.id.to_s => @user_non_member.id.to_s } + :assignee => { @wfs1.id.to_s => @user_non_member.id.to_s }} assert_response :redirect @wfs1.reload assert_equal @user_non_member.id, @wfs1.user_id @@ -407,7 +405,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase def test_delete_step name = @wfs2.name assert_difference 'DmsfWorkflowStep.count', -1 do - delete :delete_step, :id => @wf1, :step => @wfs2.id + delete :delete_step, :params => {:id => @wf1, :step => @wfs2.id} end @wfs3.reload assert_equal @wfs3.name, name diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index ca7cf5e2..aa84cc4e 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -67,8 +67,8 @@ class IssuesControllerTest < RedmineDmsf::Test::TestCase main_system_folder = @issue1.main_system_folder assert main_system_folder assert_equal @project1.id, main_system_folder.project_id - put :update, id: @issue1.id, issue: { project_id: @project2.id, tracker_id: '1', priority_id: '6', - category_id: '3' } + put :update, :params => {id: @issue1.id, issue: { project_id: @project2.id, tracker_id: '1', priority_id: '6', + category_id: '3' }} assert_redirected_to action: 'show', id: @issue1.id @issue1.reload assert_equal @project2.id, @issue1.project.id diff --git a/test/functional/my_controller_test.rb b/test/functional/my_controller_test.rb index a627e191..4abaecf9 100644 --- a/test/functional/my_controller_test.rb +++ b/test/functional/my_controller_test.rb @@ -38,7 +38,7 @@ class MyControllerTest < RedmineDmsf::Test::TestCase end def test_page_with_open_approvals_one_approval - DmsfFileRevision.delete_all(id: 5) + DmsfFileRevision.where(id: 5).delete_all @user_member.pref[:my_page_layout] = { 'top' => ['open_approvals'] } @user_member.pref.save! get :page diff --git a/test/integration/rest_api/dmsf_file_api_test.rb b/test/integration/rest_api/dmsf_file_api_test.rb index 19c13290..6ee39187 100644 --- a/test/integration/rest_api/dmsf_file_api_test.rb +++ b/test/integration/rest_api/dmsf_file_api_test.rb @@ -95,7 +95,7 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest def test_upload_document @role.add_permission! :file_manipulation #curl --data-binary "@cat.gif" -H "Content-Type: application/octet-stream" -X POST -u ${1}:${2} http://localhost:3000/projects/12/dmsf/upload.xml?filename=cat.gif - post "/projects/#{@project1.id}/dmsf/upload.xml?filename=test.txt&key=#{@token.value}", 'File content', {"CONTENT_TYPE" => 'application/octet-stream'} + post "/projects/#{@project1.id}/dmsf/upload.xml?filename=test.txt&key=#{@token.value}", :params => 'File content', :headers => {"CONTENT_TYPE" => 'application/octet-stream'} assert_response :created assert_equal 'application/xml', response.content_type # @@ -120,7 +120,7 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest } assert_difference 'DmsfFileRevision.count', +1 do - post "/projects/#{@project1.id}/dmsf/commit.xml?key=#{@token.value}", payload, {"CONTENT_TYPE" => 'application/xml'} + post "/projects/#{@project1.id}/dmsf/commit.xml?key=#{@token.value}", :params => payload, :headers => {"CONTENT_TYPE" => 'application/xml'} end # # @@ -138,7 +138,7 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest def test_delete_file @role.add_permission! :file_delete # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml - delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", {'CONTENT_TYPE' => 'application/xml'} + delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} assert_response :success @file1.reload assert_equal DmsfFile::STATUS_DELETED, @file1.deleted @@ -148,14 +148,14 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest def test_delete_file_no_permissions token = Token.create!(:user => @jsmith, :action => 'api') # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml - delete "/dmsf/files/#{@file1.id}.xml?key=#{token.value}", {'CONTENT_TYPE' => 'application/xml'} + delete "/dmsf/files/#{@file1.id}.xml?key=#{token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} assert_response :forbidden end def test_delete_folder_commit_yes @role.add_permission! :file_delete # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml&commit=yes - delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}&commit=yes", {'CONTENT_TYPE' => 'application/xml'} + delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}&commit=yes", :headers => {'CONTENT_TYPE' => 'application/xml'} assert_response :success assert_nil DmsfFile.find_by(id: @file1.id) end @@ -166,7 +166,7 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest @file1.lock! User.current = @jsmith # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml - delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", {'CONTENT_TYPE' => 'application/xml'} + delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} assert_response 422 # # diff --git a/test/integration/rest_api/dmsf_folder_api_test.rb b/test/integration/rest_api/dmsf_folder_api_test.rb index d0adda7a..077b5b08 100644 --- a/test/integration/rest_api/dmsf_folder_api_test.rb +++ b/test/integration/rest_api/dmsf_folder_api_test.rb @@ -151,7 +151,7 @@ class DmsfFolderApiTest < RedmineDmsf::Test::IntegrationTest A folder created via REST API } - post "/projects/#{@project1.id}/dmsf/create.xml?key=#{token.value}", payload, {'CONTENT_TYPE' => 'application/xml'} + post "/projects/#{@project1.id}/dmsf/create.xml?key=#{token.value}", :params => payload, :headers => {'CONTENT_TYPE' => 'application/xml'} assert_response :success # # @@ -242,7 +242,7 @@ class DmsfFolderApiTest < RedmineDmsf::Test::IntegrationTest rest_api A folder updated via REST API } - post "/projects/#{@project1.id}/dmsf/save.xml?folder_id=1&key=#{token.value}", payload, {'CONTENT_TYPE' => 'application/xml'} + post "/projects/#{@project1.id}/dmsf/save.xml?folder_id=1&key=#{token.value}", :params => payload, :headers => {'CONTENT_TYPE' => 'application/xml'} assert_response :success # # @@ -258,7 +258,7 @@ class DmsfFolderApiTest < RedmineDmsf::Test::IntegrationTest token = Token.create!(:user => @jsmith, :action => 'api') # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/projects/1/dmsf/delete.xml?folder_id=3 delete "/projects/#{@project1.id}/dmsf/delete.xml?key=#{token.value}&folder_id=#{@folder1.id}", - {'CONTENT_TYPE' => 'application/xml'} + :headers => {'CONTENT_TYPE' => 'application/xml'} assert_response :success @folder1.reload assert_equal DmsfFolder::STATUS_DELETED, @folder1.deleted @@ -269,7 +269,7 @@ class DmsfFolderApiTest < RedmineDmsf::Test::IntegrationTest token = Token.create!(:user => @jsmith, :action => 'api') # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/projects/1/dmsf/delete.xml?folder_id=3 delete "/projects/#{@project1.id}/dmsf/delete.xml?key=#{token.value}&folder_id=#{@folder1.id}", - {'CONTENT_TYPE' => 'application/xml'} + :headers => {'CONTENT_TYPE' => 'application/xml'} assert_response :forbidden end @@ -278,7 +278,7 @@ class DmsfFolderApiTest < RedmineDmsf::Test::IntegrationTest token = Token.create!(:user => @jsmith, :action => 'api') # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/projects/1/dmsf/delete.xml?folder_id=3 delete "/projects/#{@project1.id}/dmsf/delete.xml?key=#{token.value}&folder_id=#{@folder1.id}&commit=yes", - {'CONTENT_TYPE' => 'application/xml'} + :headers => {'CONTENT_TYPE' => 'application/xml'} assert_response :success assert_nil DmsfFolder.find_by(id: @folder1.id) end @@ -291,7 +291,7 @@ class DmsfFolderApiTest < RedmineDmsf::Test::IntegrationTest token = Token.create!(:user => @jsmith, :action => 'api') # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/projects/1/dmsf/delete.xml?folder_id=3 delete "/projects/#{@project1.id}/dmsf/delete.xml?key=#{token.value}&folder_id=#{@folder1.id}", - {'CONTENT_TYPE' => 'application/xml'} + :headers => {'CONTENT_TYPE' => 'application/xml'} assert_response 422 # # diff --git a/test/integration/rest_api/dmsf_link_api_test.rb b/test/integration/rest_api/dmsf_link_api_test.rb index 21e4e499..7c08d88f 100644 --- a/test/integration/rest_api/dmsf_link_api_test.rb +++ b/test/integration/rest_api/dmsf_link_api_test.rb @@ -59,7 +59,7 @@ class DmsfLinkApiTest < RedmineDmsf::Test::IntegrationTest #{name} } - post "/dmsf_links.xml?key=#{token.value}", payload, {'CONTENT_TYPE' => 'application/xml'} + post "/dmsf_links.xml?key=#{token.value}", :params => payload, :headers => {'CONTENT_TYPE' => 'application/xml'} assert_response :success # # diff --git a/test/integration/webdav/dmsf_webdav_custom_middleware_test.rb b/test/integration/webdav/dmsf_webdav_custom_middleware_test.rb index b7ba05d5..25f36f35 100644 --- a/test/integration/webdav/dmsf_webdav_custom_middleware_test.rb +++ b/test/integration/webdav/dmsf_webdav_custom_middleware_test.rb @@ -32,18 +32,18 @@ class DmsfWebdavCustomMiddlewareTest < RedmineDmsf::Test::IntegrationTest end def test_options_for_root_path - xml_http_request :options, '/' + process :options, '/' assert_response defined?(EasyExtensions) ? :method_not_allowed : :not_found end def test_options_for_dmsf_root_path - xml_http_request :options, '/dmsf' + process :options, '/dmsf' assert_response :success end def test_webdav_not_enabled Setting.plugin_redmine_dmsf['dmsf_webdav'] = nil - xml_http_request :options, '/dmsf/webdav' + process :options, '/dmsf/webdav' assert_response :not_found end diff --git a/test/integration/webdav/dmsf_webdav_delete_test.rb b/test/integration/webdav/dmsf_webdav_delete_test.rb index f2d13972..73da5af9 100644 --- a/test/integration/webdav/dmsf_webdav_delete_test.rb +++ b/test/integration/webdav/dmsf_webdav_delete_test.rb @@ -83,51 +83,51 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest end def test_failed_authentication_global - delete '/dmsf/webdav', nil, credentials('admin', 'badpassword') + delete '/dmsf/webdav', :params => nil, :headers => credentials('admin', 'badpassword') assert_response :unauthorized end def test_failed_authentication - delete "/dmsf/webdav/#{@project1.identifier}", nil, credentials('admin', 'badpassword') + delete "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => credentials('admin', 'badpassword') assert_response :unauthorized end def test_root_folder - delete '/dmsf/webdav', nil, @admin + delete '/dmsf/webdav', :params => nil, :headers => @admin assert_response :not_implemented end def test_delete_not_empty_folder - put "/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}", nil, @admin + put "/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}", :params => nil, :headers => @admin assert_response :forbidden end def test_not_existed_project - delete '/dmsf/webdav/not_a_project/file.txt', nil, @admin + delete '/dmsf/webdav/not_a_project/file.txt', :params => nil, :headers => @admin assert_response :not_found end def test_dmsf_not_enabled @project1.disable_module! :dmsf - delete "/dmsf/webdav/#{@project1.identifier}/test.txt", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => nil, :headers => @jsmith assert_response :not_found # Item does not exist, as project is not enabled. end def test_delete_when_ro Setting.plugin_redmine_dmsf['dmsf_webdav_strategy'] = 'WEBDAV_READ_ONLY' - delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, @admin + delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, :headers => @admin assert_response :bad_gateway # Item does not exist, as project is not enabled. end def test_unlocked_file - delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, @admin + delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, :headers => @admin assert_response :no_content @file1.reload assert @file1.deleted?, "File #{@file1.name} hasn't been deleted" end def test_unathorized_user - delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, :headers => @jsmith assert_response :not_found # Without folder_view permission, he will not even be aware of its existence. @file1.reload assert !@file1.deleted?, "File #{@file1.name} is expected to exist" @@ -135,7 +135,7 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest def test_unathorized_user_forbidden @role.add_permission! :view_dmsf_folders - delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, :headers => @jsmith assert_response :forbidden # Now jsmith's role has view_folder rights, however they do not hold file manipulation rights. @file1.reload assert !@file1.deleted?, "File #{@file1.name} is expected to exist" @@ -143,7 +143,7 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest def test_view_folder_not_allowed @role.add_permission! :file_manipulation - delete "/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}", :params => nil, :headers => @jsmith assert_response :not_found # Without folder_view permission, he will not even be aware of its existence. @folder1.reload assert !@folder1.deleted?, "Folder #{@folder1.title} is expected to exist" @@ -151,14 +151,14 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest def test_folder_manipulation_not_allowed @role.add_permission! :view_dmsf_folders - delete "/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}", :params => nil, :headers => @jsmith assert_response :forbidden # Without manipulation permission, action is forbidden. @folder1.reload assert !@folder1.deleted?, "Foler #{@folder1.title} is expected to exist" end def test_folder_delete_by_admin - delete "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}", nil, @admin + delete "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}", :params => nil, :headers => @admin assert_response :success @folder6.reload assert @folder6.deleted?, "Folder #{@folder1.title} is not expected to exist" @@ -167,7 +167,7 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest def test_folder_delete_by_user @role.add_permission! :view_dmsf_folders @role.add_permission! :folder_manipulation - delete "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}", :params => nil, :headers => @jsmith assert_response :success @folder6.reload assert @folder6.deleted?, "Folder #{@folder1.title} is not expected to exist" @@ -177,17 +177,17 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true @role.add_permission! :view_dmsf_folders @role.add_permission! :folder_manipulation - delete "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}", :params => nil, :headers => @jsmith assert_response :not_found p1name_uri = Addressable::URI.escape(RedmineDmsf::Webdav::ProjectResource.create_project_name(@project1)) - delete "/dmsf/webdav/#{p1name_uri}/#{@folder6.title}", nil, @jsmith + delete "/dmsf/webdav/#{p1name_uri}/#{@folder6.title}", :params => nil, :headers => @jsmith assert_response :success @folder6.reload assert @folder6.deleted?, "Folder #{@folder1.title} is not expected to exist" end def test_file_delete_by_administrator - delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, @admin + delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, :headers => @admin assert_response :success @file1.reload assert @file1.deleted?, "File #{@file1.name} is not expected to exist" @@ -196,7 +196,7 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest def test_file_delete_by_user @role.add_permission! :view_dmsf_folders @role.add_permission! :file_delete - delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, :headers => @jsmith assert_response :success @file1.reload assert @file1.deleted?, "File #{@file1.name} is not expected to exist" @@ -206,10 +206,10 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true @role.add_permission! :view_dmsf_folders @role.add_permission! :file_delete - delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, :headers => @jsmith assert_response :not_found p1name_uri = Addressable::URI.escape(RedmineDmsf::Webdav::ProjectResource.create_project_name(@project1)) - delete "/dmsf/webdav/#{p1name_uri}/#{@file1.name}", nil, @jsmith + delete "/dmsf/webdav/#{p1name_uri}/#{@file1.name}", :params => nil, :headers => @jsmith assert_response :success @file1.reload assert @file1.deleted?, "File #{@file1.name} is not expected to exist" @@ -218,7 +218,7 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest def test_folder_delete_fragments @role.add_permission! :view_dmsf_folders @role.add_permission! :folder_manipulation - delete "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}/#frament=HTTP/1.1", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}/#frament=HTTP/1.1", :params => nil, :headers => @jsmith assert_response :bad_request end @@ -226,7 +226,7 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest @role.add_permission! :view_dmsf_folders @role.add_permission! :folder_manipulation @folder6.lock! - delete "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}", :params => nil, :headers => @jsmith assert_response :locked @folder6.reload assert !@folder6.deleted?, "Folder #{@folder6.title} is expected to exist" @@ -236,7 +236,7 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest @role.add_permission! :view_dmsf_folders @role.add_permission! :file_delete @file1.lock! - delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, :headers => @jsmith assert_response :locked @file1.reload assert !@file1.deleted?, "File #{@file1.name} is expected to exist" @@ -245,7 +245,7 @@ class DmsfWebdavDeleteTest < RedmineDmsf::Test::IntegrationTest def test_non_versioned_file @role.add_permission! :view_dmsf_folders @role.add_permission! :file_delete - delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, @jsmith + delete "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, :headers => @jsmith assert_response :success # The file should be destroyed assert_nil DmsfFile.visible.find_by(id: @file1.id) diff --git a/test/integration/webdav/dmsf_webdav_get_test.rb b/test/integration/webdav/dmsf_webdav_get_test.rb index 701894e0..d2738b5d 100644 --- a/test/integration/webdav/dmsf_webdav_get_test.rb +++ b/test/integration/webdav/dmsf_webdav_get_test.rb @@ -69,57 +69,57 @@ class DmsfWebdavGetTest < RedmineDmsf::Test::IntegrationTest end def test_should_deny_failed_authentication - get '/dmsf/webdav', nil, credentials('admin', 'badpassword') + get '/dmsf/webdav', :params => nil, :headers => credentials('admin', 'badpassword') assert_response :unauthorized end def test_should_permit_authenticated_user - get '/dmsf/webdav', nil, @admin + get '/dmsf/webdav', :params => nil, :headers => @admin assert_response :success end def test_should_list_dmsf_enabled_project - get '/dmsf/webdav', nil, @admin + get '/dmsf/webdav', :params => nil, :headers => @admin assert_response :success assert !response.body.match(@project1.identifier).nil?, "Expected to find project #{@project1.identifier} in return data" Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true project1_uri = RedmineDmsf::Webdav::ProjectResource.create_project_name(@project1) - get '/dmsf/webdav', nil, @admin + get '/dmsf/webdav', :params => nil, :headers => @admin assert_response :success assert_no_match @project1.identifier, response.body assert_match project1_uri, response.body end def test_should_not_list_non_dmsf_enabled_project - get '/dmsf/webdav', nil, @jsmith + get '/dmsf/webdav', :params => nil, :headers => @jsmith assert_response :success assert response.body.match(@project2.identifier).nil?, "Unexpected find of project #{@project2.identifier} in return data" end def test_should_return_status_404_when_project_does_not_exist @project1.enable_module! :dmsf # Flag module enabled - get '/dmsf/webdav/project_does_not_exist', nil, @jsmith + get '/dmsf/webdav/project_does_not_exist', :params => nil, :headers => @jsmith assert_response :not_found end def test_should_return_status_404_when_dmsf_not_enabled - get "/dmsf/webdav/#{@project2.identifier}", nil, @jsmith + get "/dmsf/webdav/#{@project2.identifier}", :params => nil, :headers => @jsmith assert_response :not_found end def test_download_file_from_dmsf_enabled_project - get "/dmsf/webdav/#{@project1.identifier}/test.txt", nil, @admin + get "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => nil, :headers => @admin assert_response :success Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true project1_uri = Addressable::URI.escape(RedmineDmsf::Webdav::ProjectResource.create_project_name(@project1)) - get "/dmsf/webdav/#{@project1.identifier}/test.txt", nil, @admin + get "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => nil, :headers => @admin assert_response :not_found - get "/dmsf/webdav/#{project1_uri}/test.txt", nil, @admin + get "/dmsf/webdav/#{project1_uri}/test.txt", :params => nil, :headers => @admin assert_response :success end def test_should_list_dmsf_contents_within_project - get "/dmsf/webdav/#{@project1.identifier}", nil, @admin + get "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @admin assert_response :success folder = DmsfFolder.find_by(id: 1) assert_not_nil folder @@ -132,13 +132,13 @@ class DmsfWebdavGetTest < RedmineDmsf::Test::IntegrationTest end def test_user_assigned_to_project_dmsf_module_not_enabled - get "/dmsf/webdav/#{@project1.identifier}", nil, @jsmith + get "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @jsmith assert_response :not_found end def test_user_assigned_to_project_folder_forbidden @project2.enable_module! :dmsf # Flag module enabled - get "/dmsf/webdav/#{@project2.identifier}", nil, @jsmith + get "/dmsf/webdav/#{@project2.identifier}", :params => nil, :headers => @jsmith assert_response :not_found end @@ -146,14 +146,14 @@ class DmsfWebdavGetTest < RedmineDmsf::Test::IntegrationTest @project1.enable_module! :dmsf # Flag module enabled @role.add_permission! :view_dmsf_folders @role.add_permission! :view_dmsf_files - get "/dmsf/webdav/#{@project1.identifier}", nil, @jsmith + get "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @jsmith assert_response :success end def test_user_assigned_to_project_file_forbidden @project1.enable_module! :dmsf # Flag module enabled @role.add_permission! :view_dmsf_folders - get "/dmsf/webdav/#{@project1.identifier}/test.txt", nil, @jsmith + get "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => nil, :headers => @jsmith assert_response :forbidden end @@ -161,7 +161,7 @@ class DmsfWebdavGetTest < RedmineDmsf::Test::IntegrationTest @project1.enable_module! :dmsf # Flag module enabled @role.add_permission! :view_dmsf_folders @role.add_permission! :view_dmsf_files - get "/dmsf/webdav/#{@project1.identifier}/test.txt", nil, @jsmith + get "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => nil, :headers => @jsmith assert_response :success end diff --git a/test/integration/webdav/dmsf_webdav_head_test.rb b/test/integration/webdav/dmsf_webdav_head_test.rb index 962188bb..d14d1b26 100644 --- a/test/integration/webdav/dmsf_webdav_head_test.rb +++ b/test/integration/webdav/dmsf_webdav_head_test.rb @@ -71,13 +71,13 @@ class DmsfWebdavHeadTest < RedmineDmsf::Test::IntegrationTest end def test_head_responds_with_authentication - head "/dmsf/webdav/#{@project1.identifier}", nil, @admin + head "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @admin assert_response :success check_headers_exist Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true - head "/dmsf/webdav/#{@project1.identifier}", nil, @admin + head "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @admin assert_response :not_found - head "/dmsf/webdav/#{@project1_uri}", nil, @admin + head "/dmsf/webdav/#{@project1_uri}", :params => nil, :headers => @admin assert_response :success end @@ -87,48 +87,48 @@ class DmsfWebdavHeadTest < RedmineDmsf::Test::IntegrationTest # (but may include an etag, so there is an allowance for a 1 in 2 failure rate on (optionally) required # headers) def test_head_responds_to_file - head "/dmsf/webdav/#{@project1.identifier}/test.txt", nil, @admin + head "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => nil, :headers => @admin assert_response :success check_headers_exist # Note it'll allow 1 out of the 3 expected to fail Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true - head "/dmsf/webdav/#{@project1.identifier}/test.txt", nil, @admin + head "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => nil, :headers => @admin assert_response :not_found - head "/dmsf/webdav/#{@project1_uri}/test.txt", nil, @admin + head "/dmsf/webdav/#{@project1_uri}/test.txt", :params => nil, :headers => @admin assert_response :success end def test_head_responds_to_file_anonymous_other_user_agent - head "/dmsf/webdav/#{@project1.identifier}/test.txt", nil, {:HTTP_USER_AGENT => 'Other'} + head "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => nil, :headers => {:HTTP_USER_AGENT => 'Other'} assert_response :unauthorized check_headers_dont_exist end def test_head_fails_when_file_not_found - head "/dmsf/webdav/#{@project1.identifier}/not_here.txt", nil, @admin + head "/dmsf/webdav/#{@project1.identifier}/not_here.txt", :params => nil, :headers => @admin assert_response :not_found check_headers_dont_exist end def test_head_fails_when_file_not_found_anonymous_other_user_agent - head "/dmsf/webdav/#{@project1.identifier}/not_here.txt", nil, {:HTTP_USER_AGENT => 'Other'} + head "/dmsf/webdav/#{@project1.identifier}/not_here.txt", :params => nil, :headers => {:HTTP_USER_AGENT => 'Other'} assert_response :unauthorized check_headers_dont_exist end def test_head_fails_when_folder_not_found - head '/dmsf/webdav/folder_not_here', nil, @admin + head '/dmsf/webdav/folder_not_here', :params => nil, :headers => @admin assert_response :not_found check_headers_dont_exist end def test_head_fails_when_folder_not_found_anonymous_other_user_agent - head '/dmsf/webdav/folder_not_here', nil, {:HTTP_USER_AGENT => 'Other'} + head '/dmsf/webdav/folder_not_here', :params => nil, :headers => {:HTTP_USER_AGENT => 'Other'} assert_response :unauthorized check_headers_dont_exist end def test_head_fails_when_project_is_not_enabled_for_dmsf - head "/dmsf/webdav/#{@project2.identifier}/test.txt", nil, @jsmith + head "/dmsf/webdav/#{@project2.identifier}/test.txt", :params => nil, :headers => @jsmith assert_response :not_found check_headers_dont_exist end diff --git a/test/integration/webdav/dmsf_webdav_lock_test.rb b/test/integration/webdav/dmsf_webdav_lock_test.rb index 946dd130..bda56018 100644 --- a/test/integration/webdav/dmsf_webdav_lock_test.rb +++ b/test/integration/webdav/dmsf_webdav_lock_test.rb @@ -57,20 +57,21 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest log_user 'admin', 'admin' # login as admin assert !User.current.anonymous?, 'Current user is anonymous' assert @file1.lock!, "File failed to be locked by #{User.current.name}" - xml_http_request :lock, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", + process :lock, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => %{ jsmith }, - @jsmith.merge!({ HTTP_DEPTH: 'infinity', HTTP_TIMEOUT: 'Infinite' }) + :headers => @jsmith.merge!({ HTTP_DEPTH: 'infinity', HTTP_TIMEOUT: 'Infinite' }) assert_response :locked end def test_lock_file create_time = Time.utc(2000, 1, 2, 3, 4, 5) refresh_time = Time.utc(2000, 1, 2, 6, 7, 8) + locktoken = nil # Time travel, will make the usec part of the time 0 travel_to create_time do @@ -81,8 +82,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest jsmith } - xml_http_request :lock, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", xml, - @jsmith.merge!({ HTTP_DEPTH: 'infinity', HTTP_TIMEOUT: 'Infinite' }) + process :lock, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => xml, + :headers => @jsmith.merge!({ HTTP_DEPTH: 'infinity', HTTP_TIMEOUT: 'Infinite' }) assert_response :success # Verify the response # @@ -113,22 +114,22 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest assert_equal create_time, l.created_at assert_equal create_time, l.updated_at assert_equal (create_time + 1.week), l.expires_at + end - travel_to refresh_time do - # Refresh lock - xml_http_request :lock, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", - nil, - @jsmith.merge!({ HTTP_DEPTH: 'infinity', HTTP_TIMEOUT: 'Infinite', HTTP_IF: locktoken }) - assert_response :success - # 1.week = 7*24*3600=604800 seconds - assert_match 'Second-604800', response.body - # Verify the lock in the db - @file1.reload - l = @file1.lock.first - assert_equal create_time, l.created_at - assert_equal refresh_time, l.updated_at - assert_equal (refresh_time + 1.week), l.expires_at - end + travel_to refresh_time do + # Refresh lock + process :lock, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", + :params => nil, + :headers => @jsmith.merge!({ HTTP_DEPTH: 'infinity', HTTP_TIMEOUT: 'Infinite', HTTP_IF: locktoken }) + assert_response :success + # 1.week = 7*24*3600=604800 seconds + assert_match 'Second-604800', response.body + # Verify the lock in the db + @file1.reload + l = @file1.lock.first + assert_equal create_time, l.created_at + assert_equal refresh_time, l.updated_at + assert_equal (refresh_time + 1.week), l.expires_at end end diff --git a/test/integration/webdav/dmsf_webdav_mkcol_test.rb b/test/integration/webdav/dmsf_webdav_mkcol_test.rb index b23357f1..d4a298b9 100644 --- a/test/integration/webdav/dmsf_webdav_mkcol_test.rb +++ b/test/integration/webdav/dmsf_webdav_mkcol_test.rb @@ -66,28 +66,28 @@ class DmsfWebdavMkcolTest < RedmineDmsf::Test::IntegrationTest end def test_mkcol_requires_authentication - xml_http_request :mkcol, '/dmsf/webdav/test1' + process :mkcol, '/dmsf/webdav/test1' assert_response :unauthorized end def test_mkcol_fails_to_create_folder_at_root_level - xml_http_request :mkcol, '/dmsf/webdav/test1', nil, @admin + process :mkcol, '/dmsf/webdav/test1', :params => nil, :headers => @admin assert_response :method_not_allowed end def test_should_not_succeed_on_a_non_existant_project - xml_http_request :mkcol, '/dmsf/webdav/project_doesnt_exist/test1', nil, @admin + process :mkcol, '/dmsf/webdav/project_doesnt_exist/test1', :params => nil, :headers => @admin assert_response :not_found end def test_should_not_succed_on_a_non_dmsf_enabled_project - xml_http_request :mkcol, "/dmsf/webdav/#{@project1.identifier}/folder", nil, @jsmith + process :mkcol, "/dmsf/webdav/#{@project1.identifier}/folder", :params => nil, :headers => @jsmith assert_response :forbidden end def test_should_not_create_folder_without_permissions @project1.enable_module! :dmsf # Flag module enabled - xml_http_request :mkcol, "/dmsf/webdav/#{@project1.identifier}/folder", nil, @jsmith + process :mkcol, "/dmsf/webdav/#{@project1.identifier}/folder", :params => nil, :headers => @jsmith assert_response :forbidden end @@ -95,27 +95,27 @@ class DmsfWebdavMkcolTest < RedmineDmsf::Test::IntegrationTest @project1.enable_module! :dmsf # Flag module enabled @role.add_permission! :folder_manipulation @role.add_permission! :view_dmsf_folders - xml_http_request :mkcol, - "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}", nil, @jsmith + process :mkcol, + "/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}", :params => nil, :headers => @jsmith assert_response :method_not_allowed end def test_should_fail_to_create_folder_for_user_without_rights @project1.enable_module! :dmsf # Flag module enabled - xml_http_request :mkcol, "/dmsf/webdav/#{@project1.identifier}/test1", nil, @jsmith + process :mkcol, "/dmsf/webdav/#{@project1.identifier}/test1", :params => nil, :headers => @jsmith assert_response :forbidden end def test_should_create_folder_for_non_admin_user_with_rights @project1.enable_module! :dmsf @role.add_permission! :folder_manipulation - xml_http_request :mkcol, "/dmsf/webdav/#{@project1.identifier}/test1", nil, @jsmith + process :mkcol, "/dmsf/webdav/#{@project1.identifier}/test1", :params => nil, :headers => @jsmith assert_response :success # Created Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true project1_uri = Addressable::URI.escape(RedmineDmsf::Webdav::ProjectResource.create_project_name(@project1)) - xml_http_request :mkcol, "/dmsf/webdav/#{@project1.identifier}/test2", nil, @jsmith + process :mkcol, "/dmsf/webdav/#{@project1.identifier}/test2", :params => nil, :headers => @jsmith assert_response :not_found - xml_http_request :mkcol, "/dmsf/webdav/#{project1_uri}/test3", nil, @jsmith + process :mkcol, "/dmsf/webdav/#{project1_uri}/test3", :params => nil, :headers => @jsmith assert_response :success # Created end diff --git a/test/integration/webdav/dmsf_webdav_move_test.rb b/test/integration/webdav/dmsf_webdav_move_test.rb index e904c440..4060e5d5 100644 --- a/test/integration/webdav/dmsf_webdav_move_test.rb +++ b/test/integration/webdav/dmsf_webdav_move_test.rb @@ -75,8 +75,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest def test_move_denied_for_anonymous new_name = "#{@file1.name}.moved" assert_no_difference '@file1.dmsf_file_revisions.count' do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, - {:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"} + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, + :headers => {:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"} assert_response :unauthorized end end @@ -85,8 +85,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest @role.remove_permission! :folder_manipulation new_name = "#{@file1.name}.moved" assert_no_difference '@file1.dmsf_file_revisions.count' do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) assert_response :forbidden end end @@ -95,8 +95,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest @role.remove_permission! :folder_manipulation new_name = "#{@file1.name}.moved" assert_difference '@file1.dmsf_file_revisions.count', +1 do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, - @admin.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, + :headers => @admin.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) assert_response :created f = DmsfFile.find_file_by_name @project1, nil, "#{new_name}" assert f, "Moved file '#{new_name}' not found in project." @@ -104,16 +104,16 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest end def test_move_non_existent_file - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/not_a_file.txt", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/moved_file.txt"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/not_a_file.txt", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/moved_file.txt"}) assert_response :not_found # NotFound end def test_move_to_new_filename new_name = "#{@file1.name}.moved" assert_difference '@file1.dmsf_file_revisions.count', +1 do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) assert_response :created f = DmsfFile.find_file_by_name @project1, nil, "#{new_name}" assert f, "Moved file '#{new_name}' not found in project." @@ -125,8 +125,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest project1_uri = Addressable::URI.escape(RedmineDmsf::Webdav::ProjectResource.create_project_name(@project1)) new_name = "#{@file1.name}.moved" assert_difference '@file1.dmsf_file_revisions.count', +1 do - xml_http_request :move, "/dmsf/webdav/#{project1_uri}/#{@file1.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{project1_uri}/#{new_name}"}) + process :move, "/dmsf/webdav/#{project1_uri}/#{@file1.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{project1_uri}/#{new_name}"}) assert_response :created f = DmsfFile.find_file_by_name @project1, nil, "#{new_name}" assert f, "Moved file '#{new_name}' not found in project." @@ -136,8 +136,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest def test_move_zero_sized_to_new_filename new_name = "#{@file10.name}.moved" assert_no_difference '@file10.dmsf_file_revisions.count' do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file10.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file10.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) assert_response :created f = DmsfFile.find_file_by_name @project1, nil, "#{new_name}" assert f, "Moved file '#{new_name}' not found in project." @@ -146,8 +146,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest def test_move_to_new_folder assert_difference '@file1.dmsf_file_revisions.count', +1 do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}/#{@file1.name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}/#{@file1.name}"}) assert_response :created @file1.reload assert_equal @folder1.id, @file1.dmsf_folder_id @@ -158,8 +158,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true project1_uri = Addressable::URI.escape(RedmineDmsf::Webdav::ProjectResource.create_project_name(@project1)) assert_difference '@file1.dmsf_file_revisions.count', +1 do - xml_http_request :move, "/dmsf/webdav/#{project1_uri}/#{@file1.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{project1_uri}/#{@folder1.title}/#{@file1.name}"}) + process :move, "/dmsf/webdav/#{project1_uri}/#{@file1.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{project1_uri}/#{@folder1.title}/#{@file1.name}"}) assert_response :created @file1.reload assert_equal @folder1.id, @file1.dmsf_folder_id @@ -168,8 +168,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest def test_move_zero_sized_to_new_folder assert_no_difference '@file10.dmsf_file_revisions.count' do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file10.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}/#{@file10.name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file10.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}/#{@file10.name}"}) assert_response :created @file10.reload assert_equal @folder1.id, @file10.dmsf_folder_id @@ -182,8 +182,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest new_name = "#{file9.name}" assert_no_difference 'file9.dmsf_file_revisions.count' do assert_no_difference '@file1.dmsf_file_revisions.count' do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) assert_response :not_implemented # NotImplemented end end @@ -195,8 +195,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest assert @file1.lock!, "File failed to be locked by #{User.current.name}" new_name = "#{@file1.name}.moved" assert_no_difference '@file1.dmsf_file_revisions.count' do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) assert_response :locked end end @@ -208,8 +208,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest new_name = "#{@file1.name}.moved" assert_no_difference '@file1.dmsf_file_revisions.count' do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, - @admin.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, + :headers => @admin.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) assert_response :locked end end @@ -222,15 +222,15 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest # Move once new_name = "#{@file1.name}.m1" assert_difference '@file1.dmsf_file_revisions.count', +1 do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}"}) assert_response :success # Created end # Move twice, make sure that the MsOffice store sequence is not disrupting normal move new_name2 = "#{new_name}.m2" assert_difference '@file1.dmsf_file_revisions.count', +1 do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{new_name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name2}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{new_name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name2}"}) assert_response :success # Created end end @@ -255,8 +255,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest # Move the original file to AAAAAAAA.tmp. The original file should not changed but a new file should be created. assert_no_difference '@file1.dmsf_file_revisions.count' do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{temp_file_name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{temp_file_name}"}) assert_response :success # Created end @@ -268,8 +268,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest # Move a temporary file (use AAAAAAAA.tmp) to the original file. assert_difference '@file1.dmsf_file_revisions.count', +1 do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{temp_file_name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{@file1.name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{temp_file_name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{@file1.name}"}) assert_response :success # Created end @@ -282,8 +282,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest # Move the original file to BBBBBBBB.tmp. The original file should not change but a new file should be created. assert_no_difference '@file1.dmsf_file_revisions.count' do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{temp_file_name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{temp_file_name}"}) assert_response :success # Created end @@ -295,8 +295,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest # Move a temporary file (use BBBBBBBB.tmp) to the original file. assert_no_difference '@file1.dmsf_file_revisions.count' do - xml_http_request :move, "/dmsf/webdav/#{@project1.identifier}/#{temp_file_name}", nil, - @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{@file1.name}"}) + process :move, "/dmsf/webdav/#{@project1.identifier}/#{temp_file_name}", :params => nil, + :headers => @jsmith.merge!({:destination => "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{@file1.name}"}) assert_response :success # Created end end diff --git a/test/integration/webdav/dmsf_webdav_options_test.rb b/test/integration/webdav/dmsf_webdav_options_test.rb index dcaea560..38e77d62 100644 --- a/test/integration/webdav/dmsf_webdav_options_test.rb +++ b/test/integration/webdav/dmsf_webdav_options_test.rb @@ -51,13 +51,13 @@ class DmsfWebdavOptionsTest < RedmineDmsf::Test::IntegrationTest end def test_options_requires_no_authentication_for_root_level - xml_http_request :options, '/dmsf/webdav' + process :options, '/dmsf/webdav' assert_response :success end def test_options_returns_expected_allow_header_for_ro Setting.plugin_redmine_dmsf['dmsf_webdav_strategy'] = 'WEBDAV_READ_ONLY' - xml_http_request :options, '/dmsf/webdav' + process :options, '/dmsf/webdav' assert_response :success assert !(response.headers.nil? || response.headers.empty?), 'Response headers are empty' assert response.headers['Allow'] , 'Allow header is empty or does not exist' @@ -65,7 +65,7 @@ class DmsfWebdavOptionsTest < RedmineDmsf::Test::IntegrationTest end def test_options_returns_expected_allow_header_for_rw - xml_http_request :options, '/dmsf/webdav' + process :options, '/dmsf/webdav' assert_response :success assert !(response.headers.nil? || response.headers.empty?), 'Response headers are empty' assert response.headers['Allow'] , 'Allow header is empty or does not exist' @@ -74,14 +74,14 @@ class DmsfWebdavOptionsTest < RedmineDmsf::Test::IntegrationTest end def test_options_returns_expected_dav_header - xml_http_request :options, '/dmsf/webdav' + process :options, '/dmsf/webdav' assert_response :success assert !(response.headers.nil? || response.headers.empty?), 'Response headers are empty' assert response.headers['Dav'] , 'Dav header is empty or does not exist' end def test_options_returns_expected_ms_auth_via_header - xml_http_request :options, '/dmsf/webdav' + process :options, '/dmsf/webdav' assert_response :success assert !(response.headers.nil? || response.headers.empty?), 'Response headers are empty' assert response.headers['Ms-Author-Via'] , 'Ms-Author-Via header is empty or does not exist' @@ -89,33 +89,33 @@ class DmsfWebdavOptionsTest < RedmineDmsf::Test::IntegrationTest end def test_options_requires_authentication_for_non_root_request - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}" + process :options, "/dmsf/webdav/#{@project1.identifier}" assert_response :unauthorized end def test_un_authenticated_options_returns_expected_allow_header - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}" + process :options, "/dmsf/webdav/#{@project1.identifier}" assert_response :unauthorized assert !(response.headers.nil? || response.headers.empty?), 'Response headers are empty' assert_nil response.headers['Allow'] , 'Allow header should not exist' end def test_un_authenticated_options_returns_expected_dav_header - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}" + process :options, "/dmsf/webdav/#{@project1.identifier}" assert_response :unauthorized assert !(response.headers.nil? || response.headers.empty?), 'Response headers are empty' assert_nil response.headers['Dav'] , 'Dav header should not exist' end def test_un_authenticated_options_returns_expected_ms_auth_via_header - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}" + process :options, "/dmsf/webdav/#{@project1.identifier}" assert_response :unauthorized assert !(response.headers.nil? || response.headers.empty?), 'Response headers are empty' assert_nil response.headers['Ms-Author-Via'] , 'Ms-Author-Via header should not exist' end def test_authenticated_options_returns_expected_allow_header - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}", nil, @jsmith + process :options, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @jsmith assert_response :success assert !(response.headers.nil? || response.headers.empty?), 'Response headers are empty' assert response.headers['Allow'], 'Allow header is empty or does not exist' @@ -124,14 +124,14 @@ class DmsfWebdavOptionsTest < RedmineDmsf::Test::IntegrationTest end def test_authenticated_options_returns_expected_dav_header - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}", nil, @jsmith + process :options, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @jsmith assert_response :success assert !(response.headers.nil? || response.headers.empty?), 'Response headers are empty' assert response.headers['Dav'], 'Dav header is empty or does not exist' end def test_authenticated_options_returns_expected_ms_auth_via_header - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}", nil, @jsmith + process :options, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @jsmith assert_response :success assert !(response.headers.nil? || response.headers.empty?), 'Response headers are empty' assert response.headers['Ms-Author-Via'], 'Ms-Author-Via header is empty or does not exist' @@ -139,40 +139,40 @@ class DmsfWebdavOptionsTest < RedmineDmsf::Test::IntegrationTest end def test_un_authenticated_options_for_msoffice_user_agent - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}", nil, {:HTTP_USER_AGENT => 'Microsoft Office Word 2014'} + process :options, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => {:HTTP_USER_AGENT => 'Microsoft Office Word 2014'} assert_response :unauthorized end def test_authenticated_options_for_msoffice_user_agent - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}", nil, - @admin.merge!({:HTTP_USER_AGENT => 'Microsoft Office Word 2014'}) + process :options, "/dmsf/webdav/#{@project1.identifier}", :params => nil, + :headers => @admin.merge!({:HTTP_USER_AGENT => 'Microsoft Office Word 2014'}) assert_response :success end def test_un_authenticated_options_for_other_user_agent - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}", nil, {:HTTP_USER_AGENT => 'Other'} + process :options, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => {:HTTP_USER_AGENT => 'Other'} assert_response :unauthorized end def test_authenticated_options_for_other_user_agent - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}", nil, @admin.merge!({:HTTP_USER_AGENT => 'Other'}) + process :options, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @admin.merge!({:HTTP_USER_AGENT => 'Other'}) assert_response :success Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true project1_uri = Addressable::URI.escape(RedmineDmsf::Webdav::ProjectResource.create_project_name(@project1)) - xml_http_request :options, "/dmsf/webdav/#{@project1.identifier}", nil, @admin.merge!({:HTTP_USER_AGENT => 'Other'}) + process :options, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @admin.merge!({:HTTP_USER_AGENT => 'Other'}) assert_response :not_found - xml_http_request :options, "/dmsf/webdav/#{project1_uri}", nil, @admin.merge!({:HTTP_USER_AGENT => 'Other'}) + process :options, "/dmsf/webdav/#{project1_uri}", :params => nil, :headers => @admin.merge!({:HTTP_USER_AGENT => 'Other'}) assert_response :success end def test_authenticated_options_returns_404_for_non_dmsf_enabled_items @project2.disable_module! :dmsf - xml_http_request :options, "/dmsf/webdav/#{@project2.identifier}", nil, @jsmith + process :options, "/dmsf/webdav/#{@project2.identifier}", :params => nil, :headers => @jsmith assert_response :not_found end def test_authenticated_options_returns_404_for_not_found - xml_http_request :options, '/dmsf/webdav/does-not-exist', nil, @jsmith + process :options, '/dmsf/webdav/does-not-exist', :params => nil, :headers => @jsmith assert_response :not_found end diff --git a/test/integration/webdav/dmsf_webdav_post_test.rb b/test/integration/webdav/dmsf_webdav_post_test.rb index 72ff6160..b7ec4fa8 100644 --- a/test/integration/webdav/dmsf_webdav_post_test.rb +++ b/test/integration/webdav/dmsf_webdav_post_test.rb @@ -43,7 +43,7 @@ class DmsfWebdavPostTest < RedmineDmsf::Test::IntegrationTest # Test post is not implemented def test_post_not_implemented - post '/dmsf/webdav/', nil, @admin + post '/dmsf/webdav/', :params => nil, :headers => @admin assert_response :not_implemented end diff --git a/test/integration/webdav/dmsf_webdav_propfind_test.rb b/test/integration/webdav/dmsf_webdav_propfind_test.rb index 8b0bcb82..348bd355 100644 --- a/test/integration/webdav/dmsf_webdav_propfind_test.rb +++ b/test/integration/webdav/dmsf_webdav_propfind_test.rb @@ -63,26 +63,26 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest end def test_propfind_denied_for_anonymous - xml_http_request :propfind, '/dmsf/webdav/', nil, {:HTTP_DEPTH => '0'} + process :propfind, '/dmsf/webdav/', :params => nil, :headers => {:HTTP_DEPTH => '0'} assert_response :unauthorized end def test_propfind_depth0_on_root_for_non_member - xml_http_request :propfind, '/dmsf/webdav/', nil, @jsmith.merge!({:HTTP_DEPTH => '0'}) + process :propfind, '/dmsf/webdav/', :params => nil, :headers => @jsmith.merge!({:HTTP_DEPTH => '0'}) assert_response :multi_status assert response.body.include?('http://www.example.com:80/dmsf/webdav/') assert response.body.include?('/') end def test_propfind_depth1_on_root_for_non_member - xml_http_request :propfind, '/dmsf/webdav/', nil, @jsmith.merge!({:HTTP_DEPTH => '1'}) + process :propfind, '/dmsf/webdav/', :params => nil, :headers => @jsmith.merge!({:HTTP_DEPTH => '1'}) assert_response :multi_status assert response.body.include?('http://www.example.com:80/dmsf/webdav/') assert response.body.include?( '/') end def test_propfind_depth0_on_root_for_admin - xml_http_request :propfind, '/dmsf/webdav/', nil, @admin.merge!({:HTTP_DEPTH => '0'}) + process :propfind, '/dmsf/webdav/', :params => nil, :headers => @admin.merge!({:HTTP_DEPTH => '0'}) assert_response :multi_status assert response.body.include?('http://www.example.com:80/dmsf/webdav/') assert response.body.include?('/') @@ -90,7 +90,7 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest def test_propfind_depth1_on_root_for_admin_with_project_names Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true - xml_http_request :propfind, '/dmsf/webdav/', nil, @admin.merge!({:HTTP_DEPTH => '1'}) + process :propfind, '/dmsf/webdav/', :params => nil, :headers => @admin.merge!({:HTTP_DEPTH => '1'}) assert_response :multi_status assert response.body.include?('http://www.example.com:80/dmsf/webdav/') assert response.body.include?('/') @@ -103,12 +103,12 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest end def test_propfind_depth0_on_project1_for_non_member - xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, @jsmith.merge!({:HTTP_DEPTH => '0'}) + process :propfind, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @jsmith.merge!({:HTTP_DEPTH => '0'}) assert_response :not_found end def test_propfind_depth0_on_project1_for_admin - xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, @admin.merge!({:HTTP_DEPTH => '0'}) + process :propfind, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @admin.merge!({:HTTP_DEPTH => '0'}) assert_response :multi_status assert response.body.include?("http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/") assert response.body.include?("#{@project1.identifier}") @@ -116,16 +116,16 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest def test_propfind_depth0_on_project1_for_admin_with_project_names Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true - xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, @admin.merge!({:HTTP_DEPTH => '0'}) + process :propfind, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @admin.merge!({:HTTP_DEPTH => '0'}) assert_response :not_found - xml_http_request :propfind, "/dmsf/webdav/#{@project1_uri}", nil, @admin.merge!({:HTTP_DEPTH => '0'}) + process :propfind, "/dmsf/webdav/#{@project1_uri}", :params => nil, :headers => @admin.merge!({:HTTP_DEPTH => '0'}) assert_response :multi_status assert response.body.include?("http://www.example.com:80/dmsf/webdav/#{@project1_uri}/") assert response.body.include?("#{@project1_name}") end def test_propfind_depth1_on_project1_for_admin - xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, @admin.merge!({:HTTP_DEPTH => '1'}) + process :propfind, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @admin.merge!({:HTTP_DEPTH => '1'}) assert_response :multi_status # Project assert response.body.include?("http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/") @@ -146,9 +146,9 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest def test_propfind_depth1_on_project1_for_admin_with_project_names Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true - xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, @admin.merge!({:HTTP_DEPTH => '1'}) + process :propfind, "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => @admin.merge!({:HTTP_DEPTH => '1'}) assert_response :not_found - xml_http_request :propfind, "/dmsf/webdav/#{@project1_uri}", nil, @admin.merge!({:HTTP_DEPTH => '1'}) + process :propfind, "/dmsf/webdav/#{@project1_uri}", :params => nil, :headers => @admin.merge!({:HTTP_DEPTH => '1'}) assert_response :multi_status # Project assert response.body.include?("http://www.example.com:80/dmsf/webdav/#{@project1_uri}/") @@ -171,7 +171,7 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest @project1.save! project1_new_name = RedmineDmsf::Webdav::ProjectResource.create_project_name(@project1) project1_new_uri = Addressable::URI.escape(project1_new_name) - xml_http_request :propfind, "/dmsf/webdav/#{project1_new_uri}", nil, @admin.merge!({:HTTP_DEPTH => '1'}) + process :propfind, "/dmsf/webdav/#{project1_new_uri}", :params => nil, :headers => @admin.merge!({:HTTP_DEPTH => '1'}) assert_response :multi_status assert response.body.include?("http://www.example.com:80/dmsf/webdav/#{project1_new_uri}/") assert response.body.include?("#{project1_new_name}") diff --git a/test/integration/webdav/dmsf_webdav_put_test.rb b/test/integration/webdav/dmsf_webdav_put_test.rb index f85a0584..e57ae4fe 100644 --- a/test/integration/webdav/dmsf_webdav_put_test.rb +++ b/test/integration/webdav/dmsf_webdav_put_test.rb @@ -74,46 +74,46 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest end def test_put_denied_with_failed_authentication_root - put '/dmsf/webdav', nil, credentials('admin', 'badpassword') + put '/dmsf/webdav', :params => nil, :headers => credentials('admin', 'badpassword') assert_response :unauthorized end def test_put_denied_with_failed_authentication - put "/dmsf/webdav/#{@project1.identifier}", nil, credentials('admin', 'badpassword') + put "/dmsf/webdav/#{@project1.identifier}", :params => nil, :headers => credentials('admin', 'badpassword') assert_response :unauthorized end def test_put_denied_at_root_level - put '/dmsf/webdav/test.txt', '1234', @admin.merge!({:content_type => :text}) + put '/dmsf/webdav/test.txt', :params => '1234', :headers => @admin.merge!({:content_type => :text}) assert_response :not_implemented end def test_put_denied_on_folder - put "/dmsf/webdav/#{@project1.identifier}", '1234', @admin.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}", :params => '1234', :headers => @admin.merge!({:content_type => :text}) assert_response :forbidden end def test_put_failed_on_non_existant_project - put '/dmsf/webdav/not_a_project/file.txt', '1234', @admin.merge!({:content_type => :text}) + put '/dmsf/webdav/not_a_project/file.txt', :params => '1234', :headers => @admin.merge!({:content_type => :text}) assert_response :conflict # not_a_project does not exist - file.txt cannot be created end def test_put_as_admin_granted_on_dmsf_enabled_project - put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", '1234', @admin.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", :params => '1234', :headers => @admin.merge!({:content_type => :text}) assert_response :created # Lets check for our file file = DmsfFile.find_file_by_name @project1, nil, 'test-1234.txt' assert file, 'Check for files existance' Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true project1_uri = Addressable::URI.escape(RedmineDmsf::Webdav::ProjectResource.create_project_name(@project1)) - put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", '1234', @admin.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", :params => '1234', :headers => @admin.merge!({:content_type => :text}) assert_response :conflict - put "/dmsf/webdav/#{project1_uri}/test-1234.txt", '1234', @admin.merge!({:content_type => :text}) + put "/dmsf/webdav/#{project1_uri}/test-1234.txt", :params => '1234', :headers => @admin.merge!({:content_type => :text}) assert_response :created end def test_put_failed_as_jsmith_on_non_dmsf_enabled_project - put "/dmsf/webdav/#{@project2.identifier}/test-1234.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project2.identifier}/test-1234.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :conflict # Should report conflict, as project 2 technically doesn't exist if not enabled # Lets check for our file file = DmsfFile.find_file_by_name @project2, nil, 'test-1234.txt' @@ -122,14 +122,14 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest def test_put_failed_when_no_permission @project2.enable_module! :dmsf # Flag module enabled - put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :conflict # We don't hold the permission view_dmsf_folders, and thus project 2 doesn't exist to us. end def test_put_failed_when_no_file_manipulation_permission @project1.enable_module! :dmsf # Flag module enabled @role.add_permission! :view_dmsf_folders - put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :forbidden # We don't hold the permission file_manipulation - so we're unable to do anything with files end @@ -137,7 +137,7 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest @project1.enable_module! :dmsf # Flag module enabled @role.add_permission! :file_manipulation # Check we don't have write access even if we do have the file_manipulation permission - put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :conflict # We don't hold the permission view_dmsf_folders, and thus project 2 doesn't exist to us. # Lets check for our file file = DmsfFile.find_file_by_name @project1, nil, 'test-1234.txt' @@ -148,7 +148,7 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest @project1.enable_module! :dmsf # Flag module enabled @role.add_permission! :view_dmsf_folders @role.add_permission! :file_manipulation - put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :created # Now we have permissions # Lets check for our file file = DmsfFile.find_file_by_name @project1, nil, 'test-1234.txt' @@ -157,9 +157,9 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest assert_equal file.last_revision.digest_type, 'SHA256' Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = true project1_uri = Addressable::URI.escape(RedmineDmsf::Webdav::ProjectResource.create_project_name(@project1)) - put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test-1234.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :conflict - put "/dmsf/webdav/#{project1_uri}/test-1234.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{project1_uri}/test-1234.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :created # Now we have permissions end @@ -170,7 +170,7 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest file = DmsfFile.find_file_by_name @project1, nil, 'test.txt' assert_not_nil file, 'test.txt file not found' assert_difference 'file.dmsf_file_revisions.count', +1 do - put "/dmsf/webdav/#{@project1.identifier}/test.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :created end end @@ -184,7 +184,7 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest file = DmsfFile.find_file_by_name @project1, nil, 'test.txt' assert file.lock!, "File failed to be locked by #{User.current.name}" assert_no_difference 'file.dmsf_file_revisions.count' do - put "/dmsf/webdav/#{@project1.identifier}/test.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :locked end end @@ -198,7 +198,7 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest file = DmsfFile.find_file_by_name @project1, nil, 'test.txt' assert file.lock!, "File failed to be locked by #{User.current.name}" assert_no_difference 'file.dmsf_file_revisions.count' do - put "/dmsf/webdav/#{@project1.identifier}/test.txt", '1234', @admin.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => '1234', :headers => @admin.merge!({:content_type => :text}) assert_response :locked end end @@ -216,12 +216,12 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest # First PUT should always create new revision. assert_difference 'file.dmsf_file_revisions.count', +1 do - put "/dmsf/webdav/#{@project1.identifier}/test.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :created end # Second PUT on a locked file should only update the revision that were created on the first PUT assert_no_difference 'file.dmsf_file_revisions.count' do - put "/dmsf/webdav/#{@project1.identifier}/test.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :created end # Unlock @@ -237,12 +237,12 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest # First PUT should always create new revision. assert_difference 'file.dmsf_file_revisions.count', +1 do - put "/dmsf/webdav/#{@project1.identifier}/test.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :created end # Second PUT on a locked file should only update the revision that were created on the first PUT assert_no_difference 'file.dmsf_file_revisions.count' do - put "/dmsf/webdav/#{@project1.identifier}/test.txt", '1234', @jsmith.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test.txt", :params => '1234', :headers => @jsmith.merge!({:content_type => :text}) assert_response :created end end @@ -252,15 +252,15 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest @project1.enable_module! :dmsf @role.add_permission! :view_dmsf_folders @role.add_permission! :file_manipulation - put "/dmsf/webdav/#{@project1.identifier}/._test.txt", '1234', @admin.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/._test.txt", :params => '1234', :headers => @admin.merge!({:content_type => :text}) assert_response :no_content - put "/dmsf/webdav/#{@project1.identifier}/.DS_Store", '1234', @admin.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/.DS_Store", :params => '1234', :headers => @admin.merge!({:content_type => :text}) assert_response :no_content - put "/dmsf/webdav/#{@project1.identifier}/Thumbs.db", '1234', @admin.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/Thumbs.db", :params => '1234', :headers => @admin.merge!({:content_type => :text}) assert_response :no_content original = Setting.plugin_redmine_dmsf['dmsf_webdav_ignore'] Setting.plugin_redmine_dmsf['dmsf_webdav_ignore'] = '.dump$' - put "/dmsf/webdav/#{@project1.identifier}/test.dump", '1234', @admin.merge!({:content_type => :text}) + put "/dmsf/webdav/#{@project1.identifier}/test.dump", :params => '1234', :headers => @admin.merge!({:content_type => :text}) assert_response :no_content Setting.plugin_redmine_dmsf['dmsf_webdav_ignore'] = original end @@ -271,44 +271,44 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest @role.add_permission! :file_manipulation credentials = @admin.merge!({ content_type: :text }) - put "/dmsf/webdav/#{@project1.identifier}/file1.tmp", '1234', credentials + put "/dmsf/webdav/#{@project1.identifier}/file1.tmp", :params => '1234', :headers => credentials assert_response :success file1 = DmsfFile.find_by(project_id: @project1.id, dmsf_folder: nil, name: 'file1.tmp') assert file1 assert_difference 'file1.dmsf_file_revisions.count', 0 do - put "/dmsf/webdav/#{@project1.identifier}/file1.tmp", '5678', credentials + put "/dmsf/webdav/#{@project1.identifier}/file1.tmp", :params => '5678', :headers => credentials assert_response :created end assert_difference 'file1.dmsf_file_revisions.count', 0 do - put "/dmsf/webdav/#{@project1.identifier}/file1.tmp", '9ABC', credentials + put "/dmsf/webdav/#{@project1.identifier}/file1.tmp", :params => '9ABC', :headers => credentials assert_response :created end - put "/dmsf/webdav/#{@project1.identifier}/~$file2.txt", '1234', credentials + put "/dmsf/webdav/#{@project1.identifier}/~$file2.txt", :params => '1234', :headers => credentials assert_response :success file2 = DmsfFile.find_by(project_id: @project1.id, dmsf_folder_id: nil, name: '~$file2.txt') assert file2 assert_difference 'file2.dmsf_file_revisions.count', 0 do - put "/dmsf/webdav/#{@project1.identifier}/~$file2.txt", '5678', credentials + put "/dmsf/webdav/#{@project1.identifier}/~$file2.txt", :params => '5678', :headers => credentials assert_response :created end assert_difference 'file2.dmsf_file_revisions.count', 0 do - put "/dmsf/webdav/#{@project1.identifier}/~$file2.txt", '9ABC', credentials + put "/dmsf/webdav/#{@project1.identifier}/~$file2.txt", :params => '9ABC', :headers => credentials assert_response :created end original = Setting.plugin_redmine_dmsf['dmsf_webdav_disable_versioning'] Setting.plugin_redmine_dmsf['dmsf_webdav_disable_versioning'] = '.dump$' - put "/dmsf/webdav/#{@project1.identifier}/file3.dump", '1234', credentials + put "/dmsf/webdav/#{@project1.identifier}/file3.dump", :params => '1234', :headers => credentials assert_response :success file3 = DmsfFile.find_by(project_id: @project1.id, dmsf_folder_id: nil, name: 'file3.dump') assert file3 assert_difference 'file3.dmsf_file_revisions.count', 0 do - put "/dmsf/webdav/#{@project1.identifier}/file3.dump", '5678', credentials + put "/dmsf/webdav/#{@project1.identifier}/file3.dump", :params => '5678', :headers => credentials assert_response :created end assert_difference 'file3.dmsf_file_revisions.count', 0 do - put "/dmsf/webdav/#{@project1.identifier}/file3.dump", '9ABC', credentials + put "/dmsf/webdav/#{@project1.identifier}/file3.dump", :params => '9ABC', :headers => credentials assert_response :created end Setting.plugin_redmine_dmsf['dmsf_webdav_disable_versioning'] = original diff --git a/test/unit/dmsf_mailer_test.rb b/test/unit/dmsf_mailer_test.rb index fb97f19a..3319a904 100644 --- a/test/unit/dmsf_mailer_test.rb +++ b/test/unit/dmsf_mailer_test.rb @@ -42,14 +42,14 @@ class DmsfMailerTest < RedmineDmsf::Test::UnitTest end def test_files_updated - email = DmsfMailer.files_updated(@user2, @file1.project, [@file1]).deliver + email = DmsfMailer.files_updated(@user2, @file1.project, [@file1]).deliver_now assert email assert text_part(email).body.include? @file1.project.name assert html_part(email).body.include? @file1.project.name end def test_files_deleted - email = DmsfMailer.files_deleted(@user2, @file1.project, [@file1]).deliver + email = DmsfMailer.files_deleted(@user2, @file1.project, [@file1]).deliver_now assert email assert text_part(email).body.include? @file1.project.name assert html_part(email).body.include? @file1.project.name @@ -64,7 +64,7 @@ class DmsfMailerTest < RedmineDmsf::Test::UnitTest email_params[:expired_at] = Date.today email_params[:folders] = nil email_params[:files] = "[\"#{@file1.id}\"]" - email = DmsfMailer.send_documents(@file1.project, email_params).deliver + email = DmsfMailer.send_documents(@user2, @file1.project, email_params) assert email assert text_part(email).body.include? body assert html_part(email).body.include? body @@ -72,7 +72,7 @@ class DmsfMailerTest < RedmineDmsf::Test::UnitTest def test_workflow_notification email = DmsfMailer.workflow_notification(@user2, @wf1, @rev2, :text_email_subject_started, :text_email_started, - :text_email_to_proceed) + :text_email_to_proceed).deliver_now assert email assert text_part(email).body.include? l(:text_email_subject_started) assert html_part(email).body.include? l(:text_email_subject_started) From 6e64842e1ac82c77fdcc5996f67dcff82ed3516c Mon Sep 17 00:00:00 2001 From: pavel Date: Tue, 11 Dec 2018 01:22:33 +0100 Subject: [PATCH 02/53] gem --- Gemfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Gemfile b/Gemfile index d9294841..87cb0d19 100644 --- a/Gemfile +++ b/Gemfile @@ -35,3 +35,7 @@ end # Dav4Rack gem 'ox' + +group :test do + gem 'rails-controller-testing' +end \ No newline at end of file From bdb3d2df48d555421df6f31c505900c9c57bed15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 20 Dec 2018 14:39:11 +0100 Subject: [PATCH 03/53] Rails 5 --- Gemfile | 2 +- app/controllers/dmsf_controller.rb | 24 ++-- app/controllers/dmsf_files_controller.rb | 20 +-- app/controllers/dmsf_files_copy_controller.rb | 6 +- .../dmsf_folders_copy_controller.rb | 6 +- app/controllers/dmsf_links_controller.rb | 6 +- app/controllers/dmsf_state_controller.rb | 2 +- app/controllers/dmsf_workflows_controller.rb | 26 ++-- app/helpers/dmsf_upload_helper.rb | 2 +- app/models/dmsf_folder.rb | 8 +- app/models/dmsf_mailer.rb | 126 +++++++++--------- .../easy_dms/epm_dmsf_locked_documents.rb | 28 ++-- .../easy_dms/epm_dmsf_open_approvals.rb | 22 +-- assets/images/bullet_arrow_down.png | Bin 220 -> 0 bytes assets/stylesheets/redmine_dmsf.css | 4 +- init.rb | 2 +- lib/redmine_dmsf.rb | 2 +- .../controllers/issues_controller_hooks.rb | 8 +- .../patches/easy_crm_case_patch.rb | 4 +- lib/redmine_dmsf/patches/issue_patch.rb | 4 +- lib/redmine_dmsf/test/test_case.rb | 12 +- lib/redmine_dmsf/test/unit_test.rb | 6 - test/functional/dmsf_controller_test.rb | 12 +- test/functional/dmsf_files_controller_test.rb | 6 +- .../dmsf_files_copy_controller_test.rb | 14 +- .../dmsf_folders_copy_controller_test.rb | 16 +-- 26 files changed, 191 insertions(+), 177 deletions(-) delete mode 100644 assets/images/bullet_arrow_down.png diff --git a/Gemfile b/Gemfile index 87cb0d19..6b00846f 100644 --- a/Gemfile +++ b/Gemfile @@ -22,7 +22,7 @@ source 'https://rubygems.org' -gem 'rubyzip', '>= 1.0.0' +gem 'rubyzip', '>= 1.1.3' gem 'zip-zip' gem 'simple_enum' gem 'uuidtools' diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index 1035ff09..73182275 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -93,7 +93,7 @@ class DmsfController < ApplicationController :type => 'application/zip', :disposition => 'attachment') rescue Exception => e - flash[:error] = e.message + flash[:errors] = e.message end def entries_operation @@ -156,7 +156,7 @@ class DmsfController < ApplicationController rescue DmsfAccessError render_403 # and return rescue StandardError => e - flash[:error] = e.message + flash[:errors] = e.message Rails.logger.error e.message end end @@ -176,7 +176,7 @@ class DmsfController < ApplicationController def entries_email if params[:email][:to].strip.blank? - flash[:error] = l(:error_email_to_must_be_entered) + flash[:errors] = l(:error_email_to_must_be_entered) else DmsfMailer.deliver_send_documents(@project, params[:email]) File.delete(params[:email][:zipped_content]) @@ -253,7 +253,7 @@ class DmsfController < ApplicationController if result flash[:notice] = l(:notice_folder_deleted) else - flash[:error] = @folder.errors.full_messages.to_sentence + flash[:errors] = @folder.errors.full_messages.to_sentence end respond_to do |format| format.html do @@ -271,7 +271,7 @@ class DmsfController < ApplicationController if @folder.restore flash[:notice] = l(:notice_dmsf_folder_restored) else - flash[:error] = @folder.errors.full_messages.to_sentence + flash[:errors] = @folder.errors.full_messages.to_sentence end redirect_to :back end @@ -285,7 +285,7 @@ class DmsfController < ApplicationController if @project.save flash[:notice] = l(:notice_folder_details_were_saved) else - flash[:error] = @project.errors.full_messages.to_sentence + flash[:errors] = @project.errors.full_messages.to_sentence end end redirect_to dmsf_folder_path(:id => @project) @@ -343,7 +343,7 @@ class DmsfController < ApplicationController @folder.unlock! flash[:notice] = l(:notice_folder_unlocked) else - flash[:error] = l(:error_only_user_that_locked_folder_can_unlock_it) + flash[:errors] = l(:error_only_user_that_locked_folder_can_unlock_it) end end redirect_to :back @@ -466,7 +466,7 @@ class DmsfController < ApplicationController folder = DmsfFolder.find_by(id: id) if folder unless folder.restore - flash[:error] = folder.errors.full_messages.to_sentence + flash[:errors] = folder.errors.full_messages.to_sentence end else raise FileNotFound @@ -477,7 +477,7 @@ class DmsfController < ApplicationController file = DmsfFile.find_by(id: id) if file unless file.restore - flash[:error] = file.errors.full_messages.to_sentence + flash[:errors] = file.errors.full_messages.to_sentence end else raise FileNotFound @@ -488,7 +488,7 @@ class DmsfController < ApplicationController link = DmsfLink.find_by(id: id) if link unless link.restore - flash[:error] = link.errors.full_messages.to_sentence + flash[:errors] = link.errors.full_messages.to_sentence end else raise FileNotFound @@ -502,7 +502,7 @@ class DmsfController < ApplicationController folder = DmsfFolder.find_by(id: id) if folder unless folder.delete commit - flash[:error] = folder.errors.full_messages.to_sentence + flash[:errors] = folder.errors.full_messages.to_sentence return end elsif !commit @@ -547,7 +547,7 @@ class DmsfController < ApplicationController link = DmsfLink.find_by(id: id) link.delete commit if link end - if flash[:error].blank? && flash[:warning].blank? + if flash[:errors].blank? && flash[:warning].blank? flash[:notice] = l(:notice_entries_deleted) end end diff --git a/app/controllers/dmsf_files_controller.rb b/app/controllers/dmsf_files_controller.rb index 58576a5c..050cb7c6 100644 --- a/app/controllers/dmsf_files_controller.rb +++ b/app/controllers/dmsf_files_controller.rb @@ -95,7 +95,7 @@ class DmsfFilesController < ApplicationController def create_revision if params[:dmsf_file_revision] if @file.locked_for_user? - flash[:error] = l(:error_file_is_locked) + flash[:errors] = l(:error_file_is_locked) else revision = DmsfFileRevision.new revision.title = params[:dmsf_file_revision][:title] @@ -175,10 +175,10 @@ class DmsfFilesController < ApplicationController logger.error "Could not send email notifications: #{e.message}" end else - flash[:error] = @file.errors.full_messages.join(', ') + flash[:errors] = @file.errors.full_messages.join(', ') end else - flash[:error] = revision.errors.full_messages.join(', ') + flash[:errors] = revision.errors.full_messages.join(', ') end end end @@ -207,7 +207,7 @@ class DmsfFilesController < ApplicationController end else msg = @file.errors.full_messages.join(', ') - flash[:error] = msg + flash[:errors] = msg Rails.logger.error msg end end @@ -232,7 +232,7 @@ class DmsfFilesController < ApplicationController end flash[:notice] = l(:notice_revision_deleted) else - flash[:error] = @revision.errors.full_messages.join(', ') + flash[:errors] = @revision.errors.full_messages.join(', ') end end redirect_to :action => 'show', :id => @file @@ -243,7 +243,7 @@ class DmsfFilesController < ApplicationController if @revision.obsolete flash[:notice] = l(:notice_revision_obsoleted) else - flash[:error] = @revision.errors.full_messages.join(', ') + flash[:errors] = @revision.errors.full_messages.join(', ') end end redirect_to :action => 'show', :id => @file @@ -257,7 +257,7 @@ class DmsfFilesController < ApplicationController @file.lock! flash[:notice] = l(:notice_file_locked) rescue Exception => e - flash[:error] = e.message + flash[:errors] = e.message end end redirect_to :back @@ -272,10 +272,10 @@ class DmsfFilesController < ApplicationController @file.unlock! flash[:notice] = l(:notice_file_unlocked) rescue Exception => e - flash[:error] = e.message + flash[:errors] = e.message end else - flash[:error] = l(:error_only_user_that_locked_file_can_unlock_it) + flash[:errors] = l(:error_only_user_that_locked_file_can_unlock_it) end end redirect_to :back @@ -305,7 +305,7 @@ class DmsfFilesController < ApplicationController if @file.restore flash[:notice] = l(:notice_dmsf_file_restored) else - flash[:error] = @file.errors.full_messages.to_sentence + flash[:errors] = @file.errors.full_messages.to_sentence end redirect_to :back end diff --git a/app/controllers/dmsf_files_copy_controller.rb b/app/controllers/dmsf_files_copy_controller.rb index 60f085ce..356bfa48 100644 --- a/app/controllers/dmsf_files_copy_controller.rb +++ b/app/controllers/dmsf_files_copy_controller.rb @@ -36,7 +36,7 @@ class DmsfFilesCopyController < ApplicationController def copy new_file = @file.copy_to(@target_project, @target_folder) unless new_file.errors.empty? - flash[:error] = new_file.errors.full_messages.join(', ') + flash[:errors] = new_file.errors.full_messages.join(', ') redirect_to :action => 'new', :id => @file, :target_project_id => @target_project, :target_folder_id => @target_folder return @@ -47,7 +47,7 @@ class DmsfFilesCopyController < ApplicationController def move unless @file.move_to(@target_project, @target_folder) - flash[:error] = @file.errors.full_messages.join(', ') + flash[:errors] = @file.errors.full_messages.join(', ') redirect_to :action => 'new', :id => @file, :target_project_id => @target_project, :target_folder_id => @target_folder return @@ -89,7 +89,7 @@ private def check_target_folder if (@target_folder && @target_folder == @file.dmsf_folder) || (@target_folder.nil? && @file.dmsf_folder.nil? && @target_project == @file.project) - flash[:error] = l(:error_target_folder_same) + flash[:errors] = l(:error_target_folder_same) redirect_to :action => :new, :id => @file, :target_project_id => @target_project.id, :target_folder_id => @target_folder return diff --git a/app/controllers/dmsf_folders_copy_controller.rb b/app/controllers/dmsf_folders_copy_controller.rb index acc5f1e4..f702e81f 100644 --- a/app/controllers/dmsf_folders_copy_controller.rb +++ b/app/controllers/dmsf_folders_copy_controller.rb @@ -36,7 +36,7 @@ class DmsfFoldersCopyController < ApplicationController def copy new_folder = @folder.copy_to(@target_project, @target_folder) unless new_folder.errors.empty? - flash[:error] = new_folder.errors.full_messages.join(', ') + flash[:errors] = new_folder.errors.full_messages.join(', ') redirect_to :action => 'new', :id => @folder, :target_project_id => @target_project, :target_folder_id => @target_folder return @@ -52,7 +52,7 @@ class DmsfFoldersCopyController < ApplicationController flash[:notice] = l(:notice_successful_update) redirect_to dmsf_folder_path(:id => @target_project, :folder_id => @folder) else - flash[:error] = @folder.errors.full_messages.join(', ') + flash[:errors] = @folder.errors.full_messages.join(', ') redirect_to :action => 'new', :id => @folder, :target_project_id => @target_project, :target_folder_id => @target_folder end @@ -91,7 +91,7 @@ class DmsfFoldersCopyController < ApplicationController def check_target_folder if (@target_folder && @target_folder == @folder.dmsf_folder) || (@target_folder.nil? && @folder.dmsf_folder.nil? && @target_project == @folder.project) - flash[:error] = l(:error_target_folder_same) + flash[:errors] = l(:error_target_folder_same) redirect_to :action => :new, :id => @folder, :target_project_id => @target_project.id, :target_folder_id => @target_folder return diff --git a/app/controllers/dmsf_links_controller.rb b/app/controllers/dmsf_links_controller.rb index 4e7e4304..8c86aa7f 100644 --- a/app/controllers/dmsf_links_controller.rb +++ b/app/controllers/dmsf_links_controller.rb @@ -112,7 +112,7 @@ class DmsfLinksController < ApplicationController if result flash[:notice] = l(:notice_successful_create) else - flash[:error] = @dmsf_link.errors.full_messages.to_sentence + flash[:errors] = @dmsf_link.errors.full_messages.to_sentence end else # Link to @@ -141,7 +141,7 @@ class DmsfLinksController < ApplicationController if result flash[:notice] = l(:notice_successful_create) else - flash[:error] = @dmsf_link.errors.full_messages.to_sentence + flash[:errors] = @dmsf_link.errors.full_messages.to_sentence end end respond_to do |format| @@ -169,7 +169,7 @@ class DmsfLinksController < ApplicationController flash[:notice] = l(:notice_successful_delete) else @dmsf_link.errors.each do |e, msg| - flash[:error] = msg + flash[:errors] = msg end end end diff --git a/app/controllers/dmsf_state_controller.rb b/app/controllers/dmsf_state_controller.rb index d5c42cd6..e3551e56 100644 --- a/app/controllers/dmsf_state_controller.rb +++ b/app/controllers/dmsf_state_controller.rb @@ -35,7 +35,7 @@ class DmsfStateController < ApplicationController if format_valid?(member.dmsf_title_format) && member.save flash[:notice] = l(:notice_your_preferences_were_saved) else - flash[:error] = l(:notice_your_preferences_were_not_saved) + flash[:errors] = l(:notice_your_preferences_were_not_saved) end else flash[:warning] = l(:user_is_not_project_member) diff --git a/app/controllers/dmsf_workflows_controller.rb b/app/controllers/dmsf_workflows_controller.rb index da49c30e..57001ed3 100644 --- a/app/controllers/dmsf_workflows_controller.rb +++ b/app/controllers/dmsf_workflows_controller.rb @@ -171,7 +171,7 @@ class DmsfWorkflowsController < ApplicationController end flash[:notice] = l(:notice_successful_update) elsif action.action != DmsfWorkflowStepAction::ACTION_APPROVE && action.note.blank? - flash[:error] = l(:error_empty_note) + flash[:errors] = l(:error_empty_note) end end end @@ -203,12 +203,12 @@ class DmsfWorkflowsController < ApplicationController flash[:notice] = l(:notice_successful_update) end else - flash[:error] = l(:error_workflow_assign) + flash[:errors] = l(:error_workflow_assign) end end end rescue StandardError => e - flash[:error] = e.message + flash[:errors] = e.message end redirect_to :back return @@ -293,7 +293,7 @@ class DmsfWorkflowsController < ApplicationController redirect_to dmsf_workflows_path end else - flash[:error] = @dmsf_workflow.errors.full_messages.to_sentence + flash[:errors] = @dmsf_workflow.errors.full_messages.to_sentence redirect_to dmsf_workflow_path(@dmsf_workflow) end else @@ -306,7 +306,7 @@ class DmsfWorkflowsController < ApplicationController @dmsf_workflow.destroy flash[:notice] = l(:notice_successful_delete) rescue - flash[:error] = l(:error_unable_delete_dmsf_workflow) + flash[:errors] = l(:error_unable_delete_dmsf_workflow) end if @project redirect_to settings_project_path(@project, :tab => 'dmsf_workflow') @@ -350,11 +350,11 @@ class DmsfWorkflowsController < ApplicationController if ws.save @dmsf_workflow.dmsf_workflow_steps << ws else - flash[:error] = ws.errors.full_messages.to_sentence + flash[:errors] = ws.errors.full_messages.to_sentence end end else - flash[:error] = l(:error_workflow_assign) + flash[:errors] = l(:error_workflow_assign) end end respond_to do |format| @@ -372,7 +372,7 @@ class DmsfWorkflowsController < ApplicationController if n > params[:step].to_i ws.step = n - 1 unless ws.save - flash[:error] = l(:notice_cannot_renumber_steps) + flash[:errors] = l(:notice_cannot_renumber_steps) end end end @@ -383,7 +383,7 @@ class DmsfWorkflowsController < ApplicationController def reorder_steps if request.put? unless @dmsf_workflow.reorder_steps(params[:step].to_i, params[:dmsf_workflow][:position].to_i) - flash[:error] = l(:notice_cannot_renumber_steps) + flash[:errors] = l(:notice_cannot_renumber_steps) end end respond_to do |format| @@ -402,7 +402,7 @@ class DmsfWorkflowsController < ApplicationController @dmsf_workflow.notify_users(@project, revision, self) flash[:notice] = l(:notice_workflow_started) else - flash[:error] = l(:notice_cannot_start_workflow) + flash[:errors] = l(:notice_cannot_start_workflow) end end redirect_to :back @@ -418,11 +418,11 @@ class DmsfWorkflowsController < ApplicationController @dmsf_workflow.dmsf_workflow_steps.where(step: step.step).find_each do |s| s.name = step.name unless s.save - flash[:error] = s.errors.full_messages.to_sentence + flash[:errors] = s.errors.full_messages.to_sentence end end else - flash[:error] = step.errors.full_messages.to_sentence + flash[:errors] = step.errors.full_messages.to_sentence end end # Operators/Assignees @@ -433,7 +433,7 @@ class DmsfWorkflowsController < ApplicationController step.operator = operator.to_i step.user_id = params[:assignee][id] unless step.save - flash[:error] = step.errors.full_messages.to_sentence + flash[:errors] = step.errors.full_messages.to_sentence Rails.logger.error step.errors.full_messages.to_sentence end end diff --git a/app/helpers/dmsf_upload_helper.rb b/app/helpers/dmsf_upload_helper.rb index 1b44374d..b6958c75 100644 --- a/app/helpers/dmsf_upload_helper.rb +++ b/app/helpers/dmsf_upload_helper.rb @@ -109,7 +109,7 @@ module DmsfUploadHelper end rescue Exception => e Rails.logger.error e.message - controller.flash[:error] = e.message if controller + controller.flash[:errors] = e.message if controller failed_uploads.push(file) end else diff --git a/app/models/dmsf_folder.rb b/app/models/dmsf_folder.rb index bcaec122..fe4d5a0c 100644 --- a/app/models/dmsf_folder.rb +++ b/app/models/dmsf_folder.rb @@ -73,7 +73,7 @@ class DmsfFolder < ActiveRecord::Base "LEFT JOIN #{DmsfFolderPermission.table_name} ON #{DmsfFolder.table_name}.id = #{DmsfFolderPermission.table_name}.dmsf_folder_id").where( deleted: STATUS_DELETED).where(DmsfFolder.visible_condition).distinct } - scope :system, -> { where(system: true) } + scope :issystem, -> { where(system: true) } scope :notsystem, -> { where(system: false) } acts_as_customizable @@ -506,8 +506,10 @@ class DmsfFolder < ActiveRecord::Base self.dmsf_folder_id = params[:parent_id] # Custom fields if params[:dmsf_folder][:custom_field_values].present? - params[:dmsf_folder][:custom_field_values].each_with_index do |v, i| - custom_field_values[i].value = v[1] + i = 0 + params[:dmsf_folder][:custom_field_values].each do |param| + custom_field_values[i].value = param[1] + i += 1 end end # Permissions diff --git a/app/models/dmsf_mailer.rb b/app/models/dmsf_mailer.rb index 771a167f..d08c721a 100644 --- a/app/models/dmsf_mailer.rb +++ b/app/models/dmsf_mailer.rb @@ -31,19 +31,6 @@ class DmsfMailer < Mailer end end - def files_updated(user, project, files) - if user && project && files.count > 0 - files = files.select { |file| file.notify? } - redmine_headers 'Project' => project.identifier if project - @files = files - @project = project - message_id project - set_language_if_valid user.language - mail :to => user.mail, - :subject => "[#{@project.name} - #{l(:menu_dmsf)}] #{l(:text_email_doc_updated_subject)}" - end - end - def self.deliver_files_deleted(project, files) users = get_notify_users(project, files) users.each do |user| @@ -51,65 +38,16 @@ class DmsfMailer < Mailer end end - def files_deleted(user, project, files) - if user && files.count > 0 - files = files.select { |file| file.notify? } - redmine_headers 'Project' => project.identifier if project - @files = files - @project = project - message_id project - set_language_if_valid user.language - mail :to => user.mail, - :subject => "[#{@project.name} - #{l(:menu_dmsf)}] #{l(:text_email_doc_deleted_subject)}" - end - end - def self.deliver_send_documents(project, email_params) send_documents(email_params[:to], project, email_params).deliver_later end - def send_documents(user, project, email_params) - redmine_headers 'Project' => project.identifier if project - @body = email_params[:body] - @links_only = email_params[:links_only] == '1' - @public_urls = email_params[:public_urls] == '1' - @expired_at = email_params[:expired_at] - @folders = email_params[:folders] - @files = email_params[:files] - - unless @links_only - zipped_content_data = open(email_params[:zipped_content], 'rb') { |io| io.read } - attachments['Documents.zip'] = { :content_type => 'application/zip', :content => zipped_content_data } - end - mail :to => user, :cc => email_params[:cc], - :subject => email_params[:subject], 'From' => email_params[:from], 'Reply-To' => email_params[:reply_to] - end - def self.deliver_workflow_notification(users, workflow, revision, subject_id, text1_id, text2_id, notice = nil) users.each do |user| workflow_notification(user, workflow, revision, subject_id.to_s, text1_id.to_s, text2_id.to_s, notice).deliver_later end end - def workflow_notification(user, workflow, revision, subject_id, text1_id, text2_id, notice = nil) - if user && workflow && revision - if revision.dmsf_file && revision.dmsf_file.project - @project = revision.dmsf_file.project - redmine_headers 'Project' => @project.identifier - end - set_language_if_valid user.language - @user = user - message_id workflow - @workflow = workflow - @revision = revision - @text1 = l(text1_id, :name => workflow.name, :filename => revision.dmsf_file.name, :notice => notice) - @text2 = l(text2_id) - @notice = notice - mail :to => user.mail, - :subject => "[#{@project.name} - #{l(:field_label_dmsf_workflow)}] #{@workflow.name} #{l(subject_id)}" - end - end - def self.get_notify_users(project, files = [], force_notification = false) return [] unless project.active? if !force_notification && files.present? @@ -166,4 +104,68 @@ class DmsfMailer < Mailer notify_members.collect { |m| m.user }.uniq end + private + + def workflow_notification(user, workflow, revision, subject_id, text1_id, text2_id, notice = nil) + if user && workflow && revision + if revision.dmsf_file && revision.dmsf_file.project + @project = revision.dmsf_file.project + redmine_headers 'Project' => @project.identifier + end + set_language_if_valid user.language + @user = user + message_id workflow + @workflow = workflow + @revision = revision + @text1 = l(text1_id, :name => workflow.name, :filename => revision.dmsf_file.name, :notice => notice) + @text2 = l(text2_id) + @notice = notice + mail :to => user.mail, + :subject => "[#{@project.name} - #{l(:field_label_dmsf_workflow)}] #{@workflow.name} #{l(subject_id)}" + end + end + + def send_documents(user, project, email_params) + redmine_headers 'Project' => project.identifier if project + @body = email_params[:body] + @links_only = email_params[:links_only] == '1' + @public_urls = email_params[:public_urls] == '1' + @expired_at = email_params[:expired_at] + @folders = email_params[:folders] + @files = email_params[:files] + + unless @links_only + zipped_content_data = open(email_params[:zipped_content], 'rb') { |io| io.read } + attachments['Documents.zip'] = { :content_type => 'application/zip', :content => zipped_content_data } + end + mail :to => user, :cc => email_params[:cc], + :subject => email_params[:subject], 'From' => email_params[:from], 'Reply-To' => email_params[:reply_to] + end + + def files_deleted(user, project, files) + if user && files.count > 0 + files = files.select { |file| file.notify? } + redmine_headers 'Project' => project.identifier if project + @files = files + @project = project + message_id project + set_language_if_valid user.language + mail :to => user.mail, + :subject => "[#{@project.name} - #{l(:menu_dmsf)}] #{l(:text_email_doc_deleted_subject)}" + end + end + + def files_updated(user, project, files) + if user && project && files.count > 0 + files = files.select { |file| file.notify? } + redmine_headers 'Project' => project.identifier if project + @files = files + @project = project + message_id project + set_language_if_valid user.language + mail :to => user.mail, + :subject => "[#{@project.name} - #{l(:menu_dmsf)}] #{l(:text_email_doc_updated_subject)}" + end + end + end diff --git a/app/models/easy_page_modules/easy_dms/epm_dmsf_locked_documents.rb b/app/models/easy_page_modules/easy_dms/epm_dmsf_locked_documents.rb index 4390af5f..20e30b8a 100644 --- a/app/models/easy_page_modules/easy_dms/epm_dmsf_locked_documents.rb +++ b/app/models/easy_page_modules/easy_dms/epm_dmsf_locked_documents.rb @@ -18,22 +18,26 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class EpmDmsfLockedDocuments < EasyPageModule +if defined?(EasyExtensions) - def category_name - @category_name ||= 'easy_dms' - end + class EpmDmsfLockedDocuments < EasyPageModule - def get_show_data(settings, user, page_context = {}) - {} - end + def category_name + @category_name ||= 'easy_dms' + end - def get_edit_data(settings, user, page_context = {}) - {} - end + def get_show_data(settings, user, page_context = {}) + {} + end + + def get_edit_data(settings, user, page_context = {}) + {} + end + + def registered_in_plugin + 'redmine_dmsf' + end - def registered_in_plugin - 'redmine_dmsf' end end \ No newline at end of file diff --git a/app/models/easy_page_modules/easy_dms/epm_dmsf_open_approvals.rb b/app/models/easy_page_modules/easy_dms/epm_dmsf_open_approvals.rb index abaf2715..a65e5330 100644 --- a/app/models/easy_page_modules/easy_dms/epm_dmsf_open_approvals.rb +++ b/app/models/easy_page_modules/easy_dms/epm_dmsf_open_approvals.rb @@ -18,18 +18,22 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class EpmDmsfOpenApprovals < EasyPageModule +if defined?(EasyExtensions) - def category_name - @category_name ||= 'easy_dms' - end + class EpmDmsfOpenApprovals < EasyPageModule - def get_show_data(settings, user, page_context = {}) - {} - end + def category_name + @category_name ||= 'easy_dms' + end + + def get_show_data(settings, user, page_context = {}) + {} + end + + def registered_in_plugin + 'redmine_dmsf' + end - def registered_in_plugin - 'redmine_dmsf' end end \ No newline at end of file diff --git a/assets/images/bullet_arrow_down.png b/assets/images/bullet_arrow_down.png deleted file mode 100644 index cb819a7d15b8ebb6f2c96b67d92315e2bb723fed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6n3BBRT^Rni_n+Ah4nJ za0`PlBg3pY5H=O_6ID&+^S}73tV}CLb;wUjv*T7lmDD=kT)>oVPw@YICk*= zeu+AxKM6n1edv97`@54K59|H?hQ%KZHW(Hd{7L#zA>7RwKV|>@#K+H4Dh_`5@cX+$ z3zM6RgYU#2W%Fl0zWDvU)MUBD&;thobU*(6#Q!+6e}e2u3y~%%2I(!TEH8u9LGEYp MboFyt=akR{0DDwV761SM diff --git a/assets/stylesheets/redmine_dmsf.css b/assets/stylesheets/redmine_dmsf.css index dee60b89..0c4f9203 100644 --- a/assets/stylesheets/redmine_dmsf.css +++ b/assets/stylesheets/redmine_dmsf.css @@ -285,12 +285,12 @@ div.dmsf_revision_inner_box .attribute .label { .dmsf_hidden { display:none; } .dmsf_tree span.dmsf_expander { cursor: pointer; } .dmsf_tree.dmsf_expanded td.dmsf_title span { - background: url(../images/bullet_arrow_down.png) no-repeat 0 50%; + background: url(../../../images/arrow_down.png) no-repeat 0 50%; padding-left: 16px; } .dmsf_tree.dmsf_child .dmsf_title span { padding-left: 16px; } .dmsf_tree.dmsf_collapsed .dmsf_title span { - background: url(../../../images/bullet_arrow_right.png) no-repeat 0 50%; + background: url(../../../images/arrow_right.png) no-repeat 0 50%; padding-left: 16px; } .dmsf_tree.idnt-1 .dmsf_title {padding-left: 1.5em;} diff --git a/init.rb b/init.rb index c54e3288..cf49015b 100644 --- a/init.rb +++ b/init.rb @@ -32,7 +32,7 @@ Redmine::Plugin.register :redmine_dmsf do end author 'Vít Jonáš / Daniel Munn / Karel Pičman' description 'Document Management System Features' - version '1.6.2' + version '2.0.0 devel' requires_redmine version_or_higher: '4.0.0' diff --git a/lib/redmine_dmsf.rb b/lib/redmine_dmsf.rb index 65890cc6..8ac7bfc5 100644 --- a/lib/redmine_dmsf.rb +++ b/lib/redmine_dmsf.rb @@ -52,7 +52,7 @@ require 'redmine_dmsf/webdav/index_resource' require 'redmine_dmsf/webdav/project_resource' require 'redmine_dmsf/webdav/resource_proxy' -# Exceptions +# Errors require 'redmine_dmsf/errors/dmsf_access_error' require 'redmine_dmsf/errors/dmsf_content_error' require 'redmine_dmsf/errors/dmsf_email_max_file_error' diff --git a/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb b/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb index e9a25705..7aacb8b1 100644 --- a/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb +++ b/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb @@ -81,7 +81,7 @@ module RedmineDmsf if old_system_folder old_system_folder.title = "#{issue.id} - #{DmsfFolder::get_valid_title(issue.subject)}" unless old_system_folder.save - controller.flash[:error] = old_system_folder.errors.full_messages.to_sentence + controller.flash[:errors] = old_system_folder.errors.full_messages.to_sentence Rails.logger.error old_system_folder.errors.full_messages.to_sentence end end @@ -93,20 +93,20 @@ module RedmineDmsf old_system_folder.dmsf_folder_id = new_main_system_folder.id old_system_folder.project_id = project_id unless old_system_folder.save - controller.flash[:error] = old_system_folder.errors.full_messages.to_sentence + controller.flash[:errors] = old_system_folder.errors.full_messages.to_sentence Rails.logger.error old_system_folder.errors.full_messages.to_sentence end issue.dmsf_files.each do |dmsf_file| dmsf_file.project_id = project_id unless dmsf_file.save - controller.flash[:error] = dmsf_file.errors.full_messages.to_sentence + controller.flash[:errors] = dmsf_file.errors.full_messages.to_sentence Rails.logger.error dmsf_file.errors.full_messages.to_sentence end end issue.dmsf_links.each do | dmsf_link| dmsf_link.project_id = project_id unless dmsf_link.save - controller.flash[:error] = dmsf_link.errors.full_messages.to_sentence + controller.flash[:errors] = dmsf_link.errors.full_messages.to_sentence Rails.logger.error dmsf_link.errors.full_messages.to_sentence end end diff --git a/lib/redmine_dmsf/patches/easy_crm_case_patch.rb b/lib/redmine_dmsf/patches/easy_crm_case_patch.rb index bd269b18..4d4884f1 100644 --- a/lib/redmine_dmsf/patches/easy_crm_case_patch.rb +++ b/lib/redmine_dmsf/patches/easy_crm_case_patch.rb @@ -98,7 +98,7 @@ module RedmineDmsf end def system_folder(create = false) - parent = DmsfFolder.system.where(project_id: self.project_id, title: '.CRM cases').first + parent = DmsfFolder.issystem.find_by(project_id: self.project_id, title: '.CRM cases') if create && !parent parent = DmsfFolder.new parent.project_id = self.project_id @@ -109,7 +109,7 @@ module RedmineDmsf parent.save end if parent - folder = DmsfFolder.system.where(['project_id = ? AND dmsf_folder_id = ? AND CAST(title AS DECIMAL) = ?', + folder = DmsfFolder.issystem.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 diff --git a/lib/redmine_dmsf/patches/issue_patch.rb b/lib/redmine_dmsf/patches/issue_patch.rb index 72ebfb82..e2776ae0 100644 --- a/lib/redmine_dmsf/patches/issue_patch.rb +++ b/lib/redmine_dmsf/patches/issue_patch.rb @@ -93,7 +93,7 @@ module RedmineDmsf def main_system_folder(create = false, prj_id = nil) prj_id ||= self.project_id - parent = DmsfFolder.system.find_by(project_id: prj_id, title: '.Issues') + parent = DmsfFolder.issystem.find_by(project_id: prj_id, title: '.Issues') if create && !parent parent = DmsfFolder.new parent.project_id = prj_id @@ -110,7 +110,7 @@ module RedmineDmsf prj_id ||= self.project_id parent = main_system_folder(create, prj_id) if parent - folder = DmsfFolder.system.where(["project_id = ? AND dmsf_folder_id = ? AND title LIKE '? - %'", + folder = DmsfFolder.issystem.where(["project_id = ? AND dmsf_folder_id = ? AND title LIKE '? - %'", prj_id, parent.id, self.id]).first if create && !folder folder = DmsfFolder.new diff --git a/lib/redmine_dmsf/test/test_case.rb b/lib/redmine_dmsf/test/test_case.rb index e07ea1aa..85b1cd56 100644 --- a/lib/redmine_dmsf/test/test_case.rb +++ b/lib/redmine_dmsf/test/test_case.rb @@ -34,9 +34,17 @@ module RedmineDmsf end super(table_names) end - + def setup - @request = ActionController::TestRequest.new + if ::Rails::VERSION::MAJOR >= 5 + if ::Rails::VERSION::MINOR >= 1 + @request = ActionController::TestRequest.create(self.class.controller_class) + else + @request = ActionController::TestRequest.create + end + else + @request = ActionController::TestRequest.new + end @response = ActionController::TestResponse.new end diff --git a/lib/redmine_dmsf/test/unit_test.rb b/lib/redmine_dmsf/test/unit_test.rb index ae7a2739..4fc84545 100644 --- a/lib/redmine_dmsf/test/unit_test.rb +++ b/lib/redmine_dmsf/test/unit_test.rb @@ -20,12 +20,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# Load the normal Rails helper -#require File.expand_path("#{Rails.root}/test/test_helper") - -# Use fixtures from redmine -#ActiveSupport::TestCase.fixture_path = "#{Rails.root}/test/fixtures" - module RedmineDmsf module Test class UnitTest < ActiveSupport::TestCase diff --git a/test/functional/dmsf_controller_test.rb b/test/functional/dmsf_controller_test.rb index 32e32eef..bad83326 100644 --- a/test/functional/dmsf_controller_test.rb +++ b/test/functional/dmsf_controller_test.rb @@ -113,7 +113,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase @role.add_permission! :folder_manipulation get :delete, :params => {:id => @project, :folder_id => @folder1.id, :commit => false} assert_response :redirect - assert_include l(:error_folder_is_not_empty), flash[:error] + assert_include l(:error_folder_is_not_empty), flash[:errors] end def test_delete_locked @@ -121,7 +121,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase @role.add_permission! :folder_manipulation get :delete, :params => {:id => @project, :folder_id => @folder2.id, :commit => false} assert_response :redirect - assert_include l(:error_folder_is_locked), flash[:error] + assert_include l(:error_folder_is_locked), flash[:errors] end def test_delete_ok @@ -163,18 +163,18 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase get :entries_operation, :params => {:id => @project, :delete_entries => 'Delete', :ids => ["folder-#{@folder1.id}", "file-#{@file1.id}", "folder-link-#{@folder_link1.id}", "file-link-#{@file_link2.id}"]} assert_response :redirect - assert_equal flash[:error].to_s, l(:error_folder_is_not_empty) + assert_equal flash[:errors].to_s, l(:error_folder_is_not_empty) end def test_delete_restore_entries_ok # Permissions OK @request.env['HTTP_REFERER'] = dmsf_folder_path(:id => @project.id) @role.add_permission! :view_dmsf_files - flash[:error] = nil + flash[:errors] = nil get :entries_operation, :params => {:id => @project, :delete_entries => 'Delete', :ids => ["file-#{@file1.id}", "file-link-#{@file_link2.id}"]} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] end def test_restore_entries @@ -184,7 +184,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase get :entries_operation, :params => {:id => @project, :restore_entries => 'Restore', :ids => ["file-#{@file1.id}", "file-link-#{@file_link2.id}"]} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] end def test_show diff --git a/test/functional/dmsf_files_controller_test.rb b/test/functional/dmsf_files_controller_test.rb index cd4b96f9..9b1ae46a 100644 --- a/test/functional/dmsf_files_controller_test.rb +++ b/test/functional/dmsf_files_controller_test.rb @@ -91,16 +91,16 @@ class DmsfFilesControllerTest < RedmineDmsf::Test::TestCase @role.add_permission! :file_delete delete @file, :params => {:commit => false} assert_response :redirect - assert_include l(:error_file_is_locked), flash[:error] + assert_include l(:error_file_is_locked), flash[:errors] end def delete_ok # Permissions OK and not locked - flash[:error].clear + flash[:errors].clear @file.unlock! delete @file, :params => {:commit => false} assert_response :redirect - assert_equal 0, flash[:error].size + assert_equal 0, flash[:errors].size end def test_obsolete_revision_ok diff --git a/test/functional/dmsf_files_copy_controller_test.rb b/test/functional/dmsf_files_copy_controller_test.rb index 091bd84d..701639ad 100644 --- a/test/functional/dmsf_files_copy_controller_test.rb +++ b/test/functional/dmsf_files_copy_controller_test.rb @@ -122,12 +122,12 @@ class DmsfFilesCopyControllerTest < RedmineDmsf::Test::TestCase def test_copy post :copy, :params => {:id => @file1.id, :target_project_id => @project1.id, :target_folder_id => @folder1.id} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] end def test_copy_the_same_target post :copy, :params => {:id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @file1.dmsf_folder} - assert_equal flash[:error], l(:error_target_folder_same) + assert_equal flash[:errors], l(:error_target_folder_same) assert_redirected_to :action => 'new', :target_project_id => @file1.project.id, :target_folder_id => @file1.dmsf_folder end @@ -146,7 +146,7 @@ class DmsfFilesCopyControllerTest < RedmineDmsf::Test::TestCase @project5.enable_module!(:dmsf) post :copy, :params => {:id => @file1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] end def test_copy_to_as_non_member @@ -157,12 +157,12 @@ class DmsfFilesCopyControllerTest < RedmineDmsf::Test::TestCase def test_move post :move, :params => {:id => @file1.id, :target_project_id => @project1.id, :target_folder_id => @folder1.id} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] end def test_move_the_same_target post :move, :params => {:id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @file1.dmsf_folder} - assert_equal flash[:error], l(:error_target_folder_same) + assert_equal flash[:errors], l(:error_target_folder_same) assert_redirected_to :action => 'new', :target_project_id => @file1.project.id, :target_folder_id => @file1.dmsf_folder end @@ -170,7 +170,7 @@ class DmsfFilesCopyControllerTest < RedmineDmsf::Test::TestCase @file1.lock! post :move, :params => {:id => @file1.id, :target_project_id => @file1.project.id, :target_folder_id => @folder1.id} assert_response :redirect - assert_equal l(:error_file_is_locked), flash[:error] + assert_equal l(:error_file_is_locked), flash[:errors] end def test_move_to_locked_folder @@ -188,7 +188,7 @@ class DmsfFilesCopyControllerTest < RedmineDmsf::Test::TestCase @project5.enable_module!(:dmsf) post :move, :params => {:id => @file1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] end def test_move_to_as_non_member diff --git a/test/functional/dmsf_folders_copy_controller_test.rb b/test/functional/dmsf_folders_copy_controller_test.rb index adb9e998..4da4c611 100644 --- a/test/functional/dmsf_folders_copy_controller_test.rb +++ b/test/functional/dmsf_folders_copy_controller_test.rb @@ -123,7 +123,7 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase def test_copy post :copy, :params => {:id => @folder1.id, :target_project_id => @project1.id, :target_folder_id => @folder6.id} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] end def test_copy_to_another_project @@ -132,7 +132,7 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase assert_equal @project1.id, @folder1.project_id post :copy, :params => {:id => @folder1.id, :target_project_id => @project2.id} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] # Check all childs' project ID tree = DmsfHelper::all_children_sorted(@project2, 0, 0) tree.each do |f, pos| @@ -142,7 +142,7 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase def test_copy_the_same_target post :copy, :params => {:id => @folder1.id, :target_project_id => @folder1.project.id, :target_folder_id => @folder1.dmsf_folder} - assert_equal flash[:error], l(:error_target_folder_same) + assert_equal flash[:errors], l(:error_target_folder_same) assert_redirected_to :action => 'new', :target_project_id => @folder1.project.id, :target_folder_id => @folder1.dmsf_folder end @@ -161,7 +161,7 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase @project5.enable_module!(:dmsf) post :copy, :params => {:id => @folder1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] end def test_copy_to_as_non_member @@ -172,12 +172,12 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase def test_move post :move, :params => {:id => @folder1.id, :target_project_id => @project1.id, :target_folder_id => @folder6.id} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] end def test_move_the_same_target post :move, :params => {:id => @folder1.id, :target_project_id => @folder1.project.id, :target_folder_id => @folder1.dmsf_folder} - assert_equal flash[:error], l(:error_target_folder_same) + assert_equal flash[:errors], l(:error_target_folder_same) assert_redirected_to :action => 'new', :target_project_id => @folder1.project.id, :target_folder_id => @folder1.dmsf_folder end @@ -201,7 +201,7 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase @project5.enable_module!(:dmsf) post :move, :params => {:id => @folder1.id, :target_project_id => @project5.id, :target_folder_id => nil} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] end def test_move_to_as_non_member @@ -215,7 +215,7 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase assert_equal @project1.id, @folder1.project_id post :move, :params => {:id => @folder1.id, :target_project_id => @project2.id} assert_response :redirect - assert_nil flash[:error] + assert_nil flash[:errors] # Check all childs' project ID tree = DmsfHelper::all_children_sorted(@project2, 0, 0) tree.each do |f, pos| From 468b2ac8aaafdb34a31ecde196b7f6099e92fb4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Fri, 21 Dec 2018 12:27:25 +0100 Subject: [PATCH 04/53] Rails 5 --- .travis.yml | 4 +- app/models/dmsf_mailer.rb | 127 +++++++++++++++++----------------- test/unit/dmsf_mailer_test.rb | 41 +++++++---- 3 files changed, 91 insertions(+), 81 deletions(-) diff --git a/.travis.yml b/.travis.yml index e91e4676..c9f92a17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,10 +23,10 @@ language: ruby sudo: true -dist: trusty +dist: xenial rvm: - - 2.4 + - 2.5 before_install: - mysql -e 'CREATE DATABASE IF NOT EXISTS test CHARACTER SET utf8mb4;' diff --git a/app/models/dmsf_mailer.rb b/app/models/dmsf_mailer.rb index d08c721a..cfec0697 100644 --- a/app/models/dmsf_mailer.rb +++ b/app/models/dmsf_mailer.rb @@ -25,21 +25,63 @@ class DmsfMailer < Mailer layout 'mailer' def self.deliver_files_updated(project, files) + files = files.select { |file| file.notify? } users = get_notify_users(project, files) users.each do |user| files_updated(user, project, files).deliver_later end end + def files_updated(user, project, files) + if user && project && files.size > 0 + redmine_headers 'Project' => project.identifier if project + @files = files + @project = project + message_id project + set_language_if_valid user.language + mail :to => user.mail, subject: "[#{@project.name} - #{l(:menu_dmsf)}] #{l(:text_email_doc_updated_subject)}" + end + end + def self.deliver_files_deleted(project, files) + files = files.select { |file| file.notify? } users = get_notify_users(project, files) users.each do |user| files_deleted(user, project, files).deliver_later end end + def files_deleted(user, project, files) + if user && files.count > 0 + redmine_headers 'Project' => project.identifier if project + @files = files + @project = project + message_id project + set_language_if_valid user.language + mail :to => user.mail, + :subject => "[#{@project.name} - #{l(:menu_dmsf)}] #{l(:text_email_doc_deleted_subject)}" + end + end + def self.deliver_send_documents(project, email_params) - send_documents(email_params[:to], project, email_params).deliver_later + send_documents(User.current, project, email_params).deliver_later + end + + def send_documents(_, project, email_params) + redmine_headers 'Project' => project.identifier if project + @body = email_params[:body] + @links_only = email_params[:links_only] == '1' + @public_urls = email_params[:public_urls] == '1' + @expired_at = email_params[:expired_at] + @folders = email_params[:folders] + @files = email_params[:files] + + unless @links_only + zipped_content_data = open(email_params[:zipped_content], 'rb') { |io| io.read } + attachments['Documents.zip'] = { :content_type => 'application/zip', :content => zipped_content_data } + end + mail to: email_params[:to], cc: email_params[:cc], subject: email_params[:subject], 'From' => email_params[:from], + 'Reply-To' => email_params[:reply_to] end def self.deliver_workflow_notification(users, workflow, revision, subject_id, text1_id, text2_id, notice = nil) @@ -48,6 +90,25 @@ class DmsfMailer < Mailer end end + def workflow_notification(user, workflow, revision, subject_id, text1_id, text2_id, notice = nil) + if user && workflow && revision + if revision.dmsf_file && revision.dmsf_file.project + @project = revision.dmsf_file.project + redmine_headers 'Project' => @project.identifier + end + set_language_if_valid user.language + @user = user + message_id workflow + @workflow = workflow + @revision = revision + @text1 = l(text1_id, :name => workflow.name, :filename => revision.dmsf_file.name, :notice => notice) + @text2 = l(text2_id) + @notice = notice + mail :to => user.mail, + :subject => "[#{@project.name} - #{l(:field_label_dmsf_workflow)}] #{@workflow.name} #{l(subject_id)}" + end + end + def self.get_notify_users(project, files = [], force_notification = false) return [] unless project.active? if !force_notification && files.present? @@ -104,68 +165,4 @@ class DmsfMailer < Mailer notify_members.collect { |m| m.user }.uniq end - private - - def workflow_notification(user, workflow, revision, subject_id, text1_id, text2_id, notice = nil) - if user && workflow && revision - if revision.dmsf_file && revision.dmsf_file.project - @project = revision.dmsf_file.project - redmine_headers 'Project' => @project.identifier - end - set_language_if_valid user.language - @user = user - message_id workflow - @workflow = workflow - @revision = revision - @text1 = l(text1_id, :name => workflow.name, :filename => revision.dmsf_file.name, :notice => notice) - @text2 = l(text2_id) - @notice = notice - mail :to => user.mail, - :subject => "[#{@project.name} - #{l(:field_label_dmsf_workflow)}] #{@workflow.name} #{l(subject_id)}" - end - end - - def send_documents(user, project, email_params) - redmine_headers 'Project' => project.identifier if project - @body = email_params[:body] - @links_only = email_params[:links_only] == '1' - @public_urls = email_params[:public_urls] == '1' - @expired_at = email_params[:expired_at] - @folders = email_params[:folders] - @files = email_params[:files] - - unless @links_only - zipped_content_data = open(email_params[:zipped_content], 'rb') { |io| io.read } - attachments['Documents.zip'] = { :content_type => 'application/zip', :content => zipped_content_data } - end - mail :to => user, :cc => email_params[:cc], - :subject => email_params[:subject], 'From' => email_params[:from], 'Reply-To' => email_params[:reply_to] - end - - def files_deleted(user, project, files) - if user && files.count > 0 - files = files.select { |file| file.notify? } - redmine_headers 'Project' => project.identifier if project - @files = files - @project = project - message_id project - set_language_if_valid user.language - mail :to => user.mail, - :subject => "[#{@project.name} - #{l(:menu_dmsf)}] #{l(:text_email_doc_deleted_subject)}" - end - end - - def files_updated(user, project, files) - if user && project && files.count > 0 - files = files.select { |file| file.notify? } - redmine_headers 'Project' => project.identifier if project - @files = files - @project = project - message_id project - set_language_if_valid user.language - mail :to => user.mail, - :subject => "[#{@project.name} - #{l(:menu_dmsf)}] #{l(:text_email_doc_updated_subject)}" - end - end - end diff --git a/test/unit/dmsf_mailer_test.rb b/test/unit/dmsf_mailer_test.rb index 3319a904..d90d55f5 100644 --- a/test/unit/dmsf_mailer_test.rb +++ b/test/unit/dmsf_mailer_test.rb @@ -23,14 +23,21 @@ require File.expand_path('../../test_helper', __FILE__) class DmsfMailerTest < RedmineDmsf::Test::UnitTest include Redmine::I18n - fixtures :users, :projects, :dmsf_files, :dmsf_workflows, :dmsf_file_revisions, :members + fixtures :users, :projects, :dmsf_files, :dmsf_workflows, :dmsf_file_revisions, :members, :email_addresses, + :roles, :member_roles def setup @user2 = User.find 2 @file1 = DmsfFile.find 1 + @file1.notify_activate @wf1 = DmsfWorkflow.find 1 @rev2 = DmsfFileRevision.find 2 @project1 = Project.find 1 + # Mailer settings + ActionMailer::Base.deliveries.clear + Setting.plain_text_mail = '0' + Setting.default_language = 'en' + User.current = nil end def test_truth @@ -42,15 +49,15 @@ class DmsfMailerTest < RedmineDmsf::Test::UnitTest end def test_files_updated - email = DmsfMailer.files_updated(@user2, @file1.project, [@file1]).deliver_now - assert email + DmsfMailer.deliver_files_updated(@file1.project, [@file1]) + email = last_email assert text_part(email).body.include? @file1.project.name assert html_part(email).body.include? @file1.project.name end def test_files_deleted - email = DmsfMailer.files_deleted(@user2, @file1.project, [@file1]).deliver_now - assert email + DmsfMailer.deliver_files_deleted(@file1.project, [@file1]) + email = last_email assert text_part(email).body.include? @file1.project.name assert html_part(email).body.include? @file1.project.name end @@ -58,40 +65,40 @@ class DmsfMailerTest < RedmineDmsf::Test::UnitTest def test_send_documents email_params = Hash.new body = 'Test' + email_params[:to] = @user2.mail + email_params[:from] = @user2.mail email_params[:body] = body email_params[:links_only] = '1' email_params[:public_urls] == '0' - email_params[:expired_at] = Date.today + email_params[:expired_at] = DateTime.current.to_s email_params[:folders] = nil email_params[:files] = "[\"#{@file1.id}\"]" - email = DmsfMailer.send_documents(@user2, @file1.project, email_params) - assert email + DmsfMailer.deliver_send_documents(@file1.project, email_params) + email = last_email assert text_part(email).body.include? body assert html_part(email).body.include? body end def test_workflow_notification - email = DmsfMailer.workflow_notification(@user2, @wf1, @rev2, :text_email_subject_started, :text_email_started, - :text_email_to_proceed).deliver_now - assert email + DmsfMailer.deliver_workflow_notification([@user2], @wf1, @rev2, :text_email_subject_started, + :text_email_started, :text_email_to_proceed) + email = last_email assert text_part(email).body.include? l(:text_email_subject_started) assert html_part(email).body.include? l(:text_email_subject_started) end def test_get_notify_users - @file1.notification = true users = DmsfMailer.get_notify_users(@project1, [@file1]) assert users.present? end def test_get_notify_users_notification_switched_off - @file1.notification = false + @file1.notify_deactivate users = DmsfMailer.get_notify_users(@project1, [@file1]) assert users.blank? end def test_get_notify_users_on_inactive_projects - @file1.notification = true @project1.status = Project::STATUS_CLOSED users = DmsfMailer.get_notify_users(@project1, [@file1]) assert users.blank? @@ -99,6 +106,12 @@ class DmsfMailerTest < RedmineDmsf::Test::UnitTest private + def last_email + mail = ActionMailer::Base.deliveries.last + assert_not_nil mail + mail + end + def text_part(email) email.parts.detect {|part| part.content_type.include?('text/plain')} end From 56781260d2cc057fcabc028fb2af7295ac76849f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Tue, 25 Dec 2018 07:37:15 +0100 Subject: [PATCH 05/53] #935 Upload failure --- app/controllers/dmsf_upload_controller.rb | 2 +- app/helpers/dmsf_upload_helper.rb | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/controllers/dmsf_upload_controller.rb b/app/controllers/dmsf_upload_controller.rb index 2cf7129f..8090e3f3 100644 --- a/app/controllers/dmsf_upload_controller.rb +++ b/app/controllers/dmsf_upload_controller.rb @@ -52,7 +52,7 @@ class DmsfUploadController < ApplicationController # plupload multi upload completed uploaded = params[:uploaded] if uploaded - uploaded.each_value do |uploaded_file| + uploaded.each do |_, uploaded_file| @uploads.push(DmsfUpload.new(@project, @folder, uploaded_file)) end end diff --git a/app/helpers/dmsf_upload_helper.rb b/app/helpers/dmsf_upload_helper.rb index b6958c75..f5860daa 100644 --- a/app/helpers/dmsf_upload_helper.rb +++ b/app/helpers/dmsf_upload_helper.rb @@ -82,8 +82,10 @@ module DmsfUploadHelper new_revision.digest = DmsfFileRevision.create_digest commited_file[:tempfile_path] if commited_file[:custom_field_values].present? - commited_file[:custom_field_values].each_with_index do |v, i| - new_revision.custom_field_values[i].value = v[1] + i = 0 + commited_file[:custom_field_values].each do |_, v| + new_revision.custom_field_values[i].value = v + i = i + 1 end end From 2183ac71f1ed9419d3c2eb6238f81ce476eca62f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Tue, 25 Dec 2018 07:40:03 +0100 Subject: [PATCH 06/53] #933 Changes in xapian_indexer --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b45d05de..6bd7ae25 100644 --- a/README.md +++ b/README.md @@ -279,13 +279,13 @@ It is necessary to index DMSF files with omindex before searching attempts to re 1. Change the configuration part of redmine_dmsf/extra/xapian_indexer.rb file according to your environment. (The path to the index database set in xapian_indexer.rb must corresponds to the path set in the plugin's settings.) - 2. Run `ruby redmine_dmsf/extra/xapian_indexer.rb -vf` + 2. Run `ruby redmine_dmsf/extra/xapian_indexer.rb -v` This command should be run on regular basis (e.g. from cron) Example of cron job (once per hour at 8th minute): - 8 * * * * root /usr/bin/ruby redmine_dmsf/extra/xapian_indexer.rb -f + 8 * * * * root /usr/bin/ruby redmine_dmsf/extra/xapian_indexer.rb See redmine_dmsf/extra/xapian_indexer.rb for help. From 4a2f512186bb59fed37442013235dc81418d7715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Wed, 2 Jan 2019 14:09:19 +0100 Subject: [PATCH 07/53] #936 Then go to configuration an internal error 500 appear --- app/views/settings/_dmsf_settings.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/settings/_dmsf_settings.html.erb b/app/views/settings/_dmsf_settings.html.erb index 7b12f713..887ac689 100644 --- a/app/views/settings/_dmsf_settings.html.erb +++ b/app/views/settings/_dmsf_settings.html.erb @@ -83,12 +83,12 @@ <% rescue %>

<%= l(:error_file_can_not_be_created) %>

<% ensure %> - <% File.delete(testfilename) if File.exist?(testfilename) %> + <% FileUtils.rm_rf(testfilename) %> <% end %> <% end %>

- <%= content_tag(:label, l(:label_tmpdir)) %> + <%= content_tag(:label, l(:label_tmpdir)) %> <% tmpdir = @settings['dmsf_tmpdir'].strip if @settings['dmsf_tmpdir'].present? tmpdir = Dir.tmpdir if tmpdir.blank? From 07d272daa4b4953472b1300498f57e20c71e6049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Wed, 2 Jan 2019 14:42:47 +0100 Subject: [PATCH 08/53] Documents upload if disk is full #937 --- app/controllers/dmsf_files_controller.rb | 20 +++++++++++++++----- app/models/dmsf_file_revision.rb | 2 +- app/views/settings/_dmsf_settings.html.erb | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/app/controllers/dmsf_files_controller.rb b/app/controllers/dmsf_files_controller.rb index 050cb7c6..b4785365 100644 --- a/app/controllers/dmsf_files_controller.rb +++ b/app/controllers/dmsf_files_controller.rb @@ -139,8 +139,10 @@ class DmsfFilesController < ApplicationController # Custom fields if params[:dmsf_file_revision][:custom_field_values].present? - params[:dmsf_file_revision][:custom_field_values].each_with_index do |v, i| - revision.custom_field_values[i].value = v[1] + i = 0 + params[:dmsf_file_revision][:custom_field_values].each do |_, v| + revision.custom_field_values[i].value = v + i = i + 1 end end @@ -149,14 +151,22 @@ class DmsfFilesController < ApplicationController if revision.save revision.assign_workflow(params[:dmsf_workflow_id]) if upload - FileUtils.mv(upload.tempfile_path, revision.disk_file(false)) + begin + FileUtils.mv(upload.tempfile_path, revision.disk_file(false)) + rescue StandardError => e + Rails.logger.error e.message + flash[:error] = e.message + revision.destroy + redirect_to :back + return + end end if @file.locked? && !@file.locks.empty? begin @file.unlock! flash[:notice] = "#{l(:notice_file_unlocked)}, " rescue Exception => e - logger.error "Cannot unlock the file: #{e.message}" + Rails.logger.error "Cannot unlock the file: #{e.message}" end end if @file.save @@ -172,7 +182,7 @@ class DmsfFilesController < ApplicationController end end rescue Exception => e - logger.error "Could not send email notifications: #{e.message}" + Rails.logger.error "Could not send email notifications: #{e.message}" end else flash[:errors] = @file.errors.full_messages.join(', ') diff --git a/app/models/dmsf_file_revision.rb b/app/models/dmsf_file_revision.rb index 596d4e7d..a43554ed 100644 --- a/app/models/dmsf_file_revision.rb +++ b/app/models/dmsf_file_revision.rb @@ -133,7 +133,7 @@ class DmsfFileRevision < ActiveRecord::Base end if Setting.plugin_redmine_dmsf['dmsf_really_delete_files'] dependencies = DmsfFileRevision.where(disk_filename: disk_filename).all.size - File.delete(disk_file) if dependencies <= 1 && File.exist?(disk_file) + FileUtils.rm_f(disk_file) if dependencies <= 1 end super end diff --git a/app/views/settings/_dmsf_settings.html.erb b/app/views/settings/_dmsf_settings.html.erb index 887ac689..2e5aaa5c 100644 --- a/app/views/settings/_dmsf_settings.html.erb +++ b/app/views/settings/_dmsf_settings.html.erb @@ -83,7 +83,7 @@ <% rescue %>

<%= l(:error_file_can_not_be_created) %>

<% ensure %> - <% FileUtils.rm_rf(testfilename) %> + <% FileUtils.rm_f(testfilename) %> <% end %> <% end %> From 729c3d78b3f54a11641a52b63a624c336914b8cd Mon Sep 17 00:00:00 2001 From: pavel Date: Wed, 2 Jan 2019 23:03:36 +0100 Subject: [PATCH 09/53] file descriptor leaks --- app/controllers/dmsf_controller.rb | 7 ++++--- app/views/settings/_dmsf_settings.html.erb | 14 +++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index 73182275..bf7c59f0 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -378,9 +378,10 @@ class DmsfController < ApplicationController zipped_content = DmsfHelper.temp_dir.join(DmsfHelper.temp_filename('dmsf_email_sent_documents.zip')) File.open(zipped_content, 'wb') do |f| - zip_file = File.open(zip.finish, 'rb') - while (buffer = zip_file.read(8192)) - f.write(buffer) + File.open(zip.finish, 'rb') do |zip_file| + while (buffer = zip_file.read(8192)) + f.write(buffer) + end end end diff --git a/app/views/settings/_dmsf_settings.html.erb b/app/views/settings/_dmsf_settings.html.erb index 2e5aaa5c..501c8750 100644 --- a/app/views/settings/_dmsf_settings.html.erb +++ b/app/views/settings/_dmsf_settings.html.erb @@ -78,11 +78,11 @@ <% end %> <% testfilename = DmsfFile.storage_path.join('test.test') %> <% if File.exist?(storage_dir) %> - <% begin %> - <% File.open(testfilename, 'wb') %> + <% begin %> + <% File.open(testfilename, 'wb') {} %> <% rescue %>

<%= l(:error_file_can_not_be_created) %>

- <% ensure %> + <% ensure %> <% FileUtils.rm_f(testfilename) %> <% end %> <% end %> @@ -108,12 +108,12 @@ <% path = Pathname.new(tmpdir) %> <% testfilename = path.join('test.test') %> <% if File.exist?(tmpdir) %> - <% begin %> - <% File.open(testfilename, 'wb') %> + <% begin %> + <% File.open(testfilename, 'wb') {} %> <% rescue %>

<%= l(:error_tmpfile_can_not_be_created) %>

- <% ensure %> - <% File.delete(testfilename) if File.exist?(testfilename) %> + <% ensure %> + <% FileUtils.rm_f(testfilename) %> <% end %> <% end %> From ead480f720432cbc5d9c92b86df0d5229601d83b Mon Sep 17 00:00:00 2001 From: pavel Date: Wed, 2 Jan 2019 23:32:42 +0100 Subject: [PATCH 10/53] dav4rack 1.1.0 --- lib/dav4rack/controller.rb | 17 +++++++----- lib/dav4rack/destination_header.rb | 25 +++++------------- lib/dav4rack/request.rb | 10 ++++++- lib/dav4rack/resource.rb | 6 ++++- lib/dav4rack/uri.rb | 42 ++++++++++++++++++++++++++++++ lib/dav4rack/version.rb | 2 +- 6 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 lib/dav4rack/uri.rb diff --git a/lib/dav4rack/controller.rb b/lib/dav4rack/controller.rb index f75086dd..da77a260 100644 --- a/lib/dav4rack/controller.rb +++ b/lib/dav4rack/controller.rb @@ -102,12 +102,14 @@ module DAV4Rack # Return response to HEAD def head if(resource.exist?) - response['Etag'] = resource.etag - response['Content-Type'] = resource.content_type - response['Content-Length'] = resource.content_length.to_s - response['Last-Modified'] = resource.last_modified.httpdate - resource.head(request, response) - OK + res = resource.head(request, response) + if(res == OK) + response['Etag'] ||= resource.etag + response['Content-Type'] ||= resource.content_type + response['Content-Length'] ||= resource.content_length.to_s + response['Last-Modified'] ||= resource.last_modified.httpdate + end + res else NotFound end @@ -197,7 +199,8 @@ module DAV4Rack return BadRequest unless request.depth == :infinity return BadRequest unless dest = request.destination - if status = dest.validate + if status = dest.validate(host: request.host, + resource_path: resource.path) return status end diff --git a/lib/dav4rack/destination_header.rb b/lib/dav4rack/destination_header.rb index fe43e7e1..bdaae6ec 100644 --- a/lib/dav4rack/destination_header.rb +++ b/lib/dav4rack/destination_header.rb @@ -5,24 +5,13 @@ module DAV4Rack attr_reader :host, :path, :path_info - def initialize(value, script_name: nil) - @script_name = script_name.to_s - @value = value.to_s.strip - parse - end - - def parse - uri = Addressable::URI.parse @value - + # uri is expected to be a DAV4Rack::Uri instance + def initialize(uri) @host = uri.host - @path = Addressable::URI.unencode uri.path - - if @script_name - if @path =~ /\A(?#{Regexp.escape @script_name}(?\/.*))\z/ - @path_info = $~[:path_info] - else - raise ArgumentError, 'invalid destination header value' - end + @path = uri.path + unless @path_info = uri.path_info + # nil path info means path is outside the realm of script_name + raise ArgumentError, "invalid destination header value: #{uri.to_s}" end end @@ -30,7 +19,7 @@ module DAV4Rack def validate(host: nil, resource_path: nil) if host and self.host and self.host != host DAV4Rack::HTTPStatus::BadGateway - elsif self.path == resource_path + elsif resource_path and self.path_info == resource_path DAV4Rack::HTTPStatus::Forbidden end end diff --git a/lib/dav4rack/request.rb b/lib/dav4rack/request.rb index 7851988b..3a867db7 100644 --- a/lib/dav4rack/request.rb +++ b/lib/dav4rack/request.rb @@ -3,6 +3,7 @@ require 'uri' require 'addressable/uri' require 'dav4rack/logger' +require 'dav4rack/uri' module DAV4Rack class Request < Rack::Request @@ -84,7 +85,7 @@ module DAV4Rack # Destination header def destination @destination ||= if h = get_header('HTTP_DESTINATION') - DestinationHeader.new h, script_name: script_name + DestinationHeader.new DAV4Rack::Uri.new(h, script_name: script_name) end end @@ -123,6 +124,13 @@ module DAV4Rack "#{script_name}#{expand_path path}" end + # returns the given path, but with the leading script_name removed. Will + # return nil if the path does not begin with the script_name + def path_info_for(full_path, script_name: self.script_name) + uri = DAV4Rack::Uri.new full_path, script_name: script_name + return uri.path_info + end + # expands '/foo/../bar' to '/bar' def expand_path(path) path.squeeze! '/' diff --git a/lib/dav4rack/resource.rb b/lib/dav4rack/resource.rb index 2981e852..6eb62d3e 100644 --- a/lib/dav4rack/resource.rb +++ b/lib/dav4rack/resource.rb @@ -208,8 +208,12 @@ module DAV4Rack NotImplemented end + # HTTP HEAD request. + # + # Like GET, but without content. Override if you set custom headers in GET + # to set them here as well. def head(request, response) - #no-op, but called by the controller + OK end # HTTP PUT request. diff --git a/lib/dav4rack/uri.rb b/lib/dav4rack/uri.rb new file mode 100644 index 00000000..20a5dbcf --- /dev/null +++ b/lib/dav4rack/uri.rb @@ -0,0 +1,42 @@ +require 'addressable/uri' + +module DAV4Rack + + # adds a bit of parsing logic around a header URI or path value + class Uri + + attr_reader :host, :path, :path_info, :script_name + + def initialize(uri_or_path, script_name: nil) + # more than one leading slash confuses Addressable::URI, resulting e.g. + # with //remote.php/dav/files in a path of /dav/files with a host + # remote.php. + @uri_or_path = uri_or_path.to_s.strip.sub %r{\A/+}, '/' + + @script_name = script_name + parse + end + + def to_s + @uri_or_path + end + + private + + def parse + uri = Addressable::URI.parse @uri_or_path + + @host = uri.host + @path = Addressable::URI.unencode uri.path + + if @script_name + if @path =~ /\A(?#{Regexp.escape @script_name}(?\/.*))\z/ + @path_info = $~[:path_info] + end + else + @path_info = @path + end + end + + end +end diff --git a/lib/dav4rack/version.rb b/lib/dav4rack/version.rb index 221a3e9a..d386f6c5 100644 --- a/lib/dav4rack/version.rb +++ b/lib/dav4rack/version.rb @@ -13,5 +13,5 @@ module DAV4Rack end end - VERSION = Version.new('1.0.0') + VERSION = Version.new('1.1.0') end From dc6d9ec9e056478474d9c290ecc247a55d7262a0 Mon Sep 17 00:00:00 2001 From: pavel Date: Thu, 3 Jan 2019 01:46:38 +0100 Subject: [PATCH 11/53] optimize regex matchers --- app/controllers/dmsf_state_controller.rb | 2 +- app/helpers/dmsf_helper.rb | 10 ++++++---- app/validators/dmsf_file_name_validator.rb | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/controllers/dmsf_state_controller.rb b/app/controllers/dmsf_state_controller.rb index e3551e56..4f2efecd 100644 --- a/app/controllers/dmsf_state_controller.rb +++ b/app/controllers/dmsf_state_controller.rb @@ -49,7 +49,7 @@ class DmsfStateController < ApplicationController private def format_valid?(format) - format.blank? || ((format =~ /%(t|d|v|i|r)/) && format.length < 256) + format.blank? || ((/%(t|d|v|i|r)/.match?(format)) && format.length < 256) end end \ No newline at end of file diff --git a/app/helpers/dmsf_helper.rb b/app/helpers/dmsf_helper.rb index 0f7ec4e3..a3af0d0c 100644 --- a/app/helpers/dmsf_helper.rb +++ b/app/helpers/dmsf_helper.rb @@ -48,11 +48,13 @@ module DmsfHelper # get only the filename, not the whole path just_filename = File.basename(filename.gsub('\\\\', '/')) # replace all non alphanumeric, hyphens or periods with underscore - just_filename = just_filename.gsub(/[^\w\.\-]/,'_') - unless just_filename =~ %r{^[a-zA-Z0-9_\.\-]*$} + just_filename.gsub!(/[^\w\.\-]/, '_') + unless %r{^[a-zA-Z0-9_\.\-]*$}.match?(just_filename) # keep the extension if any - extension = $1 if just_filename =~ %r{(\.[a-zA-Z0-9]+)$} - just_filename = Digest::SHA256.hexdigest(just_filename) << extension + if just_filename =~ %r{(\.[a-zA-Z0-9]+)$} + extension = $1 + just_filename = Digest::SHA256.hexdigest(just_filename) << extension + end end just_filename end diff --git a/app/validators/dmsf_file_name_validator.rb b/app/validators/dmsf_file_name_validator.rb index 5996dbc7..7e9b0411 100644 --- a/app/validators/dmsf_file_name_validator.rb +++ b/app/validators/dmsf_file_name_validator.rb @@ -22,7 +22,7 @@ class DmsfFileNameValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) - unless value =~ /\A[^#{DmsfFolder::INVALID_CHARACTERS}]*\z/ + unless /\A[^#{DmsfFolder::INVALID_CHARACTERS}]*\z/.match?(value) record.errors.add attribute, :error_contains_invalid_character end end From 9569b367a64f48c610ebb81e71483634d25370fe Mon Sep 17 00:00:00 2001 From: pavel Date: Thu, 3 Jan 2019 02:20:49 +0100 Subject: [PATCH 12/53] find_by, any?, presence --- app/controllers/dmsf_controller.rb | 8 ++++---- app/controllers/dmsf_files_controller.rb | 2 +- app/controllers/dmsf_state_controller.rb | 2 +- app/controllers/dmsf_workflows_controller.rb | 2 +- app/helpers/dmsf_workflows_helper.rb | 2 +- app/models/dmsf_file.rb | 4 ++-- app/models/dmsf_folder.rb | 4 ++-- app/models/dmsf_mailer.rb | 2 +- app/views/dmsf/_dmsf_rows.erb | 2 +- test/unit/dmsf_workflow_step_test.rb | 10 +++++----- 10 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index 73182275..e95e4e87 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -402,8 +402,8 @@ class DmsfController < ApplicationController :folders => selected_folders, :files => selected_files, :subject => "#{@project.name} #{l(:label_dmsf_file_plural).downcase}", - :from => Setting.plugin_redmine_dmsf['dmsf_documents_email_from'].blank? ? - "#{User.current.name} <#{User.current.mail}>" : Setting.plugin_redmine_dmsf['dmsf_documents_email_from'], + :from => Setting.plugin_redmine_dmsf['dmsf_documents_email_from'].presence || + "#{User.current.name} <#{User.current.mail}>", :reply_to => Setting.plugin_redmine_dmsf['dmsf_documents_email_reply_to'] } render :action => 'email_entries' @@ -434,7 +434,7 @@ class DmsfController < ApplicationController end def zip_entries(zip, selected_folders, selected_files) - member = Member.where(user_id: User.current.id, project_id: @project.id).first + member = Member.find_by(user_id: User.current.id, project_id: @project.id) selected_folders.each do |selected_folder_id| folder = DmsfFolder.visible.find_by(id: selected_folder_id) if folder @@ -684,7 +684,7 @@ class DmsfController < ApplicationController @subfolders = DmsfHelper.visible_folders(@subfolders, @project) end - @ajax_upload_size = Setting.plugin_redmine_dmsf['dmsf_max_ajax_upload_filesize'].present? ? Setting.plugin_redmine_dmsf['dmsf_max_ajax_upload_filesize'] : 100 + @ajax_upload_size = Setting.plugin_redmine_dmsf['dmsf_max_ajax_upload_filesize'].presence || 100 # Trash @trash_visible = @folder_manipulation_allowed && @file_manipulation_allowed && diff --git a/app/controllers/dmsf_files_controller.rb b/app/controllers/dmsf_files_controller.rb index b4785365..689eb0ba 100644 --- a/app/controllers/dmsf_files_controller.rb +++ b/app/controllers/dmsf_files_controller.rb @@ -57,7 +57,7 @@ class DmsfFilesController < ApplicationController access.dmsf_file_revision = @revision access.action = DmsfFileRevisionAccess::DownloadAction access.save! - member = Member.where(user_id: User.current.id, project_id: @file.project.id).first + member = Member.find_by(user_id: User.current.id, project_id: @file.project.id) if member && !member.dmsf_title_format.nil? && !member.dmsf_title_format.empty? title_format = member.dmsf_title_format else diff --git a/app/controllers/dmsf_state_controller.rb b/app/controllers/dmsf_state_controller.rb index e3551e56..d3f7107b 100644 --- a/app/controllers/dmsf_state_controller.rb +++ b/app/controllers/dmsf_state_controller.rb @@ -27,7 +27,7 @@ class DmsfStateController < ApplicationController before_action :authorize def user_pref_save - member = @project.members.where(user_id: User.current.id).first + member = @project.members.find_by(user_id: User.current.id) if member member.dmsf_mail_notification = params[:email_notify] member.dmsf_title_format = params[:title_format] diff --git a/app/controllers/dmsf_workflows_controller.rb b/app/controllers/dmsf_workflows_controller.rb index 57001ed3..ad37ab06 100644 --- a/app/controllers/dmsf_workflows_controller.rb +++ b/app/controllers/dmsf_workflows_controller.rb @@ -339,7 +339,7 @@ class DmsfWorkflowsController < ApplicationController end operator = (params[:commit] == l(:dmsf_and)) ? DmsfWorkflowStep::OPERATOR_AND : DmsfWorkflowStep::OPERATOR_OR user_ids = User.where(id: params[:user_ids]).ids - if user_ids.count > 0 + if user_ids.any? user_ids.each do |user_id| ws = DmsfWorkflowStep.new ws.dmsf_workflow_id = @dmsf_workflow.id diff --git a/app/helpers/dmsf_workflows_helper.rb b/app/helpers/dmsf_workflows_helper.rb index 01509f6c..62ba5fbc 100644 --- a/app/helpers/dmsf_workflows_helper.rb +++ b/app/helpers/dmsf_workflows_helper.rb @@ -51,7 +51,7 @@ module DmsfWorkflowsHelper options = Array.new options << [l(:dmsf_new_step), 0] steps.each do |step| - options << [step.name.present? ? step.name : step.step.to_s, step.step] + options << [step.name.presence || step.step.to_s, step.step] end options_for_select(options, 0) end diff --git a/app/models/dmsf_file.rb b/app/models/dmsf_file.rb index e286bec1..eb0cbee0 100644 --- a/app/models/dmsf_file.rb +++ b/app/models/dmsf_file.rb @@ -391,7 +391,7 @@ class DmsfFile < ActiveRecord::Base next if dmsf_attrs.length == 0 || id_attribute == 0 next unless results.select{|f| f.id.to_s == id_attribute}.empty? - dmsf_file = DmsfFile.visible.where(limit_options).where(id: id_attribute).first + dmsf_file = DmsfFile.visible.where(limit_options).find_by(id: id_attribute) if dmsf_file && DmsfFolder.permissions?(dmsf_file.dmsf_folder) if user.allowed_to?(:view_dmsf_files, dmsf_file.project) && @@ -417,7 +417,7 @@ class DmsfFile < ActiveRecord::Base end def display_name - member = Member.where(user_id: User.current.id, project_id: project_id).first + member = Member.find_by(user_id: User.current.id, project_id: project_id) if member && !member.dmsf_title_format.nil? && !member.dmsf_title_format.empty? title_format = member.dmsf_title_format else diff --git a/app/models/dmsf_folder.rb b/app/models/dmsf_folder.rb index fe4d5a0c..8d217888 100644 --- a/app/models/dmsf_folder.rb +++ b/app/models/dmsf_folder.rb @@ -130,9 +130,9 @@ class DmsfFolder < ActiveRecord::Base def self.find_by_title(project, folder, title) if folder - visible.where(project_id: project.id, dmsf_folder_id: nil, title: title).first + visible.find_by(project_id: project.id, dmsf_folder_id: nil, title: title) else - visible.where(project_id: project.id, dmsf_folder_id: folder.id, title: title).first + visible.find_by(project_id: project.id, dmsf_folder_id: folder.id, title: title) end end diff --git a/app/models/dmsf_mailer.rb b/app/models/dmsf_mailer.rb index cfec0697..33adc322 100644 --- a/app/models/dmsf_mailer.rb +++ b/app/models/dmsf_mailer.rb @@ -52,7 +52,7 @@ class DmsfMailer < Mailer end def files_deleted(user, project, files) - if user && files.count > 0 + if user && files.any? redmine_headers 'Project' => project.identifier if project @files = files @project = project diff --git a/app/views/dmsf/_dmsf_rows.erb b/app/views/dmsf/_dmsf_rows.erb index 45540ab1..bdfd2420 100644 --- a/app/views/dmsf/_dmsf_rows.erb +++ b/app/views/dmsf/_dmsf_rows.erb @@ -23,7 +23,7 @@ <% parent = @folder ? @folder : @project %> <% DmsfHelper.all_children_sorted(parent, @pos, @idnt).each do |obj, position| %> <% classes = "dmsf_tree idnt-#{@idnt} hascontextmenu" %> - <% if obj.is_a?(DmsfFolder) && ((obj.dmsf_folders.visible.count > 0) || (obj.dmsf_files.visible.count > 0) || (obj.dmsf_links.visible.count > 0)) %> + <% if obj.is_a?(DmsfFolder) && ((obj.dmsf_folders.visible.any?) || (obj.dmsf_files.visible.any?) || (obj.dmsf_links.visible.any?)) %> <% classes += ' idnt dmsf_collapsed dmsf-not-loaded' %> <% id = "id='#{obj.id}span'".html_safe %> <% onclick = "onclick=\"dmsfToggle('#{obj.id}','#{obj.id}span','#{escape_javascript(expand_folder_dmsf_path)}')\"" %> diff --git a/test/unit/dmsf_workflow_step_test.rb b/test/unit/dmsf_workflow_step_test.rb index 77b2b55a..cd0b5e36 100644 --- a/test/unit/dmsf_workflow_step_test.rb +++ b/test/unit/dmsf_workflow_step_test.rb @@ -72,25 +72,25 @@ class DmsfWorkflowStepTest < RedmineDmsf::Test::UnitTest def test_validate_workflow_id_presence @wfs1.dmsf_workflow_id = nil assert !@wfs1.save - assert@wfs1.errors.count > 0 + assert @wfs1.errors.any? end def test_validate_step_presence @wfs1.step = nil assert !@wfs1.save - assert @wfs1.errors.count > 0 + assert @wfs1.errors.any? end def test_validate_user_id_presence @wfs1.user_id = nil assert !@wfs1.save - assert@wfs1.errors.count > 0 + assert @wfs1.errors.any? end def test_validate_operator_presence @wfs1.operator = nil assert !@wfs1.save - assert @wfs1.errors.count > 0 + assert @wfs1.errors.any? end def test_validate_user_id_uniqueness @@ -98,7 +98,7 @@ class DmsfWorkflowStepTest < RedmineDmsf::Test::UnitTest @wfs2.dmsf_workflow_id = @wfs1.dmsf_workflow_id @wfs2.step = @wfs1.step assert !@wfs2.save - assert @wfs2.errors.count > 0 + assert @wfs2.errors.any? end def test_validate_name_length From dcc5341caef6e48aabc4eebc21084187150afccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 3 Jan 2019 10:12:45 +0100 Subject: [PATCH 13/53] dav4rack license #940 --- lib/dav4rack/LICENSE | 42 ++++ lib/dav4rack/README.md | 467 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 509 insertions(+) create mode 100644 lib/dav4rack/LICENSE create mode 100644 lib/dav4rack/README.md diff --git a/lib/dav4rack/LICENSE b/lib/dav4rack/LICENSE new file mode 100644 index 00000000..7d0bc974 --- /dev/null +++ b/lib/dav4rack/LICENSE @@ -0,0 +1,42 @@ +Current DAV4Rack license: + +Copyright (c) 2010 Chris Roberts + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +Original rack_dav source license: + +Copyright (c) 2009 Matthias Georgi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/dav4rack/README.md b/lib/dav4rack/README.md new file mode 100644 index 00000000..35577ee4 --- /dev/null +++ b/lib/dav4rack/README.md @@ -0,0 +1,467 @@ +# DAV4Rack - Web Authoring for Rack[![Build Status](https://travis-ci.org/planio-gmbh/dav4rack.svg?branch=master)](https://travis-ci.org/planio-gmbh/dav4rack) + +DAV4Rack is a framework for providing WebDAV via Rack allowing content +authoring over HTTP. It is based off the [original RackDAV +framework](http://github.com/georgi/rack_dav) adding some useful new features: + +- Better resource support for building fully virtualized resource structures +- Generic locking as well as Resource level specific locking +- Interceptor middleware to provide virtual mapping to resources +- Mapped resource paths +- Authentication support +- Resource callbacks +- Remote file proxying (including sendfile support for remote files) +- Nokogiri based document parsing +- Ox based XML document building (for performance reasons) + +If you find issues, please create a new issue on github. If you have fixes, +please fork the repo and send me a pull request with your modifications. If you +are just here to use the library, enjoy! + + +## About this fork + +This is the [Planio](https://plan.io/redmine-hosting) fork of DAV4Rack. The +master branch includes improvements and fixes done by @djgraham and +@tim-vandecasteele in their respective forks on Github. + +It also incorporates various fixes that were made as part of the redmine\_dmsf +plugin, as well as improvements done by ourselves during development of an +upcoming redmine document management plugin. + +Several core APIs were changed in the process so it will not be a straight +upgrade for applications that were developed with DAV4Rack 0.3 (the last +released Gem version). + +## Install + +### Bundler + +To use this fork, include in your Gemfile: + + gem 'dav4rack', git: 'https://github.com/planio-gmbh/dav4rack.git', branch: 'master' + + +### Via RubyGems + + gem install dav4rack + +This will give you the last officially released version, which is *very* old. + + +## Documentation + +- [DAV4Rack documentation](http://chrisroberts.github.com/dav4rack) + +## Quickstart + +If you just want to share a folder over WebDAV, you can just start a +simple server with: + + dav4rack + +This will start a Unicorn, Mongrel or WEBrick server on port 3000, which you +can connect to without authentication. Unicorn and Mongrel will be much more +responsive than WEBrick, so if you are having slowness issues, install one of +them and restart the dav4rack process. The simple file resource allows very +basic authentication which is used for an example. To enable it: + + dav4rack --username=user --password=pass + + +## Rack Handler + +Using DAV4Rack within a rack application is pretty simple. A very slim +rackup script would look something like this: + + +```ruby + require 'rubygems' + require 'dav4rack' + + use Rack::CommonLogger + run DAV4Rack::Handler.new(root: '/path/to/public/fileshare') +``` + +This will use the included FileResource and set the share path. However, +DAV4Rack has some nifty little extras that can be enabled in the rackup script. +First, an example of how to use a custom resource: + +```ruby + run DAV4Rack::Handler.new(resource_class: CustomResource, + custom: 'options', + passed: 'to resource') +``` + +Next, lets venture into mapping a path for our WebDAV access. In this example, +we will use default FileResource like in the first example, but instead of the +WebDAV content being available at the root directory, we will map it to a +specific directory: `/webdav/share/` + +```ruby + require 'rubygems' + require 'dav4rack' + + use Rack::CommonLogger + + app = Rack::Builder.new{ + map '/webdav/share/' do + run DAV4Rack::Handler.new(root: '/path/to/public/fileshare') + end + }.to_app + run app +``` + +Aside from the `Builder#map` block, notice the new option passed to the Handler's +initialization, `:root_uri_path`. When DAV4Rack receives a request, it will +automatically convert the request to the proper path and pass it to the +resource. + +Another tool available when building the rackup script is the Interceptor. The +Interceptor's job is to simply intercept WebDAV requests received up the path +hierarchy where no resources are currently mapped. For example, lets continue +with the last example but this time include the interceptor: + + +```ruby + require 'rubygems' + require 'dav4rack' + + use Rack::CommonLogger + app = Rack::Builder.new{ + map '/webdav/share/' do + run DAV4Rack::Handler.new(root: '/path/to/public/fileshare') + end + map '/webdav/share2/' do + run DAV4Rack::Handler.new(resource_class: CustomResource) + end + map '/' do + use DAV4Rack::Interceptor, mappings: { + '/webdav/share/' => {resource_class: FileResource, custom: 'option'}, + '/webdav/share2/' => {resource_class: CustomResource} + } + use Rails::Rack::Static + run ActionController::Dispatcher.new + end + }.to_app + run app +``` + +In this example we have two WebDAV resources restricted by path. This means +those resources will handle requests to `/webdav/share/* and /webdav/share2/*` +but nothing above that. To allow webdav to respond, we provide the Interceptor. +The Interceptor does not provide any authentication support. It simply creates +a virtual file system view to the provided mapped paths. Once the actual +resources have been reached, authentication will be enforced based on the +requirements defined by the individual resource. Also note in the root map you +can see we are running a Rails application. This is how you can easily enable +DAV4Rack with your Rails application. + + +## Custom Middleware + +This is an alternative way to integrate one or more webdav handlers into a +Rails app. It uses a custom middleware dispatching to any number of mounted +Dav4Rack handlers, handles OPTIONS requests outside the webdav namespaces for +interoperability with microsoft windows and lastly dispatches any remaining +requests to the main (Rails) application. + +```ruby + +class CustomMiddleware + + def initialize(app) + @rails_app = app + + @dav_app = Rack::Builder.new{ + map '/dav/' do + run DAV4Rack::Handler.new(resource_class: CustomResource) + end + + map '/other/dav' do + run CustomDavHandler.new + end + }.to_app + end + + def call(env) + status, headers, body = @dav_app.call env + + # If the URL map generated by Rack::Builder did not find a matching path, + # it will return a 404 along with the X-Cascade header set to 'pass'. + if status == 404 and headers['X-Cascade'] == 'pass' + + # The MS web redirector webdav client likes to go up a level and try + # OPTIONS there. We catch that here and respond telling it that just + # plain HTTP is going on. + if 'OPTIONS'.casecmp(env['REQUEST_METHOD'].to_s) == 0 + [ '200', { 'Allow' => 'OPTIONS,HEAD,GET,PUT,POST,DELETE' }, [''] ] + else + # let Rails handle the request + @rails_app.call env + end + + else + [status, headers, body] + end + end + +end +``` + +You can add this middleware to your Rails app using + +```ruby +Rails.configuration.middleware.insert_before ActionDispatch::Cookies, CustomMiddleware +``` + +## Logging + +DAV4Rack provides some simple logging in a Rails style format (simply for +consistency) so the output should look somewhat familiar. + + DAV4Rack::Handler.new(resource_class: CustomResource, log_to: '/my/log/file') + +You can even specify the level of logging: + + DAV4Rack::Handler.new(resource_class: CustomResource, log_to: ['/my/log/file', Logger::DEBUG]) + +In order to use the Rails logger, just specify `log_to: Rails.logger`. + +## Custom Resources + +Creating your own resource is easy. Simply inherit the DAV4Rack::Resource +class, and start redefining all the methods you want to customize. The +DAV4Rack::Resource class only has implementations for methods that can be +provided extremely generically. This means that most things will require at +least some sort of implementation. However, because the Resource is defined so +generically, and the Controller simply passes the request on to the Resource, +it is easy to create fully virtualized resources. + +## Helpers + +There are some helpers worth mentioning that make things a little easier. + +First of all, take note that the `request` object will be an instance of `DAV4Rack::Request`, which extends `Rack::Request` with some useful helpers. + +### Redirects and sending remote files + +If `request.client_allows_redirect?` is true, the currently connected client +will accept and properly use a 302 redirect for a GET request. Most clients do +not properly support this, which can be a real pain when working with +virtualized files that may be located some where else, like S3. To deal with +those clients that don't support redirects, a helper has been provided so +resources don't have to deal with proxying themselves. The DAV4Rack::RemoteFile +is a modified Rack::File that can do some interesting things. First, lets look +at its most basic use: + + class MyResource < DAV4Rack::Resource + def setup + @item = method_to_fill_this_properly + end + + def get + if(request.client_allows_redirect?) + response.redirect item[:url] + else + response.body = DAV4Rack::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type) + OK + end + end + end + +This is a simple proxy. When Rack receives the RemoteFile, it will pull a chunk of data from object, which in turn pulls it from the socket, and +sends it to the user over and over again until the EOF is reached. This much the same method that Rack::File uses but instead we are pulling +from a socket rather than an actual file. Now, instead of proxying these files from a remote server every time, lets cache them: + + response.body = DAV4Rack::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type, :cache_directory => '/tmp') + +Providing the `:cache_directory` will let RemoteFile cache the items locally, +and then search for them on subsequent requests before heading out to the +network. The cached file name is based off the SHA1 hash of the file path, size +and last modified time. It is important to note that for services like S3, the +path will often change, making this cache pretty worthless. To combat this, we +can provide a reference to use instead: + + response.body = DAV4Rack::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type, :cache_directory => '/tmp', :cache_ref => item[:static_url]) + +These methods will work just fine, but it would be really nice to just let +someone else deal with the proxying and let the process get back to dealing +with actual requests. RemoteFile will happily do that as long as the frontend +server is setup correctly. Using the sendfile approach will tell the RemoteFile +to simply pass the headers on and let the server deal with doing the actual +proxying. First, lets look at an implementation using all the features, and +then degrade that down to the bare minimum. These examples are NGINX specific, +but are based off the Rack::Sendfile implementation and as such should be +applicable to other servers. First, a simplified NGINX server block: + + server { + listen 80; + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_set_header X-Sendfile-Type X-Accel-Redirect; + proxy_set_header X-Accel-Remote-Mapping webdav_redirect + proxy_pass http://my_app_server; + } + + location ~* /webdav_redirect { + internal; + resolver 127.0.0.1; + set $r_host $upstream_http_redirect_host; + set $r_url $upstream_http_redirect_url; + proxy_set_header Authorization ''; + proxy_set_header Host $r_host; + proxy_max_temp_file_size 0; + proxy_pass $r_url; + } + } + +With this in place, the parameters for the RemoteFile change slightly: + + response.body = DAV4Rack::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type, :sendfile => true) + +The RemoteFile will automatically take care of building out the correct path and sending the proper headers. If the X-Accel-Remote-Mapping header +is not available, you can simply pass the value: + + response.body = DAV4Rack::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type, :sendfile => true, :sendfile_prefix => 'webdav_redirect') + +And if you don't have the X-Sendfile-Type header set, you can fix that by changing the value of :sendfile: + + response.body = DAV4Rack::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type, :sendfile => 'X-Accel-Redirect', :sendfile_prefix => 'webdav_redirect') + +And if you have none of the above because your server hasn't been configured for sendfile support, you're out of luck until it's configured. + +## Authentication + +Authentication is performed on a per Resource basis. The Controller object will +call `#authenticate` on any Resources it handles requests for. Basic +Authentication information from the request will be passed to the method. +Depending on the result, the Controller will either continue on with the +request, or send a 401 Unauthorized response. + +Override `Resource#authentication_realm` and `Resource#authentication_error_msg` to customize the realm name and response content for authentication failures. + +Authentication can also be implemented using callbacks, as discussed below. + +## Callbacks + +*Deprecated*. This feature will most probably be removed in the future. + +If you want to implement general before/after logic for every request, use a +custom controller class and override `#process`. + + +Resources can make use of callbacks to easily apply permissions, authentication or any other action that needs to be performed before or after any or all +actions. Callbacks are applied to all publicly available methods. This is important for methods used internally within the resource. Methods not meant +to be called by the Controller, or anyone else, should be scoped protected or private to reduce the interaction with callbacks. + +Callbacks can be called before or after a method call. For example: + + class MyResource < DAV4Rack::Resource + before do |resource, method_name| + resource.send(:my_authentication_method) + end + + after do |resource, method_name| + puts "#{Time.now} -> Completed: #{resource}##{method_name}" + end + + private + + def my_authentication_method + true + end + end + +In this example MyResource#my_authentication_method will be called before any public method is called. After any method has been called a status +line will be printed to STDOUT. Running callbacks before/after every method call is a bit much in most cases, so callbacks can be applied to specific +methods: + + class MyResource < DAV4Rack::Resource + before_get do |resource| + puts "#{Time.now} -> Received GET request from resource: #{resource}" + end + end + +In this example, a simple status line will be printed to STDOUT before the MyResource#get method is called. The current resource object is always +provided to callbacks. The method name is only provided to the generic before/after callbacks. + +Something very handy for dealing with the mess of files OS X leaves on the system: + + class MyResource < DAV4Rack::Resource + after_unlock do |resource| + resource.delete if resource.name[0,1] == '.' + end + end + +Because OS X implements locking correctly, we can wait until it releases the lock on the file, and remove it if it's a hidden file. + +Callbacks are called in the order they are defined, so you can easily build callbacks off each other. Like this example: + + class MyResource < DAV4Rack::Resource + before do |resource, method_name| + resource.DAV_authenticate unless resource.user.is_a?(User) + raise Unauthorized unless resource.user.is_a?(User) + end + before do |resource, method_name| + resource.user.allowed?(method_name) + end + end + +In this example, the second block checking User#allowed? can count on Resource#user being defined because the blocks are called in +order, and if the Resource#user is not a User type, an exception is raised. + +### Avoiding callbacks + +Something special to notice in the last example is the DAV_ prefix on authenticate. Providing the DAV_ prefix will prevent +any callbacks being applied to the given method. This allows us to provide a public method that the callback can access on the resource +without getting stuck in a loop. + +## Software using DAV4Rack! + +* {meishi}[https://github.com/inferiorhumanorgans/meishi] - Lightweight CardDAV implementation in Rails +* {dav4rack_ext}[https://github.com/schmurfy/dav4rack_ext] - CardDAV extension. (CalDAV planned) + +## Issues/Bugs/Questions + +### Known Issues + +- OS X Finder PUT fails when using NGINX (this is due to NGINX's lack of + chunked transfer encoding in earlier versions). Use a recent version of + NGINX. +- Windows WebDAV mini-redirector - this client is very broken. Windows from + version 7 onwards however should work fine with the `OPTIONS` handling + addition demonstrated above. +- Lots of unimplemented parts of the webdav spec (patches always welcome). Run + `test/litmus_all.sh` to see what works and what doesnt. + + +### Unknown Issues + +Please report issues at github: http://github.com/planio-gmbh/dav4rack/issues +Include as much information about the environment as possible (especially client OS / software). + +## Contributors + +A big thanks to everyone contributing to help make this project better. + +* [clyfe](http://github.com/clyfe) +* [antiloopgmbh](http://github.com/antiloopgmbh) +* [krug](http://github.com/krug) +* [teefax](http://github.com/teefax) +* [buffym](https://github.com/buffym) +* [jbangert](https://github.com/jbangert) +* [doxavore](https://github.com/doxavore) +* [spicyj](https://github.com/spicyj) +* [TurchenkoAlex](https://github.com/TurchenkoAlex) +* [exabugs](https://github.com/exabugs) +* [inferiorhumanorgans](https://github.com/inferiorhumanorgans) +* [schmurfy](https://github.com/schmurfy) +* [pifleo](https://github.com/pifleo) +* [mlmorg](https://github.com/mlmorg) + +## License + +Just like RackDAV before it, this software is distributed under the MIT license. From bbf2b083306ba139c37e03f0f7692fec50c8824d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 3 Jan 2019 11:00:19 +0100 Subject: [PATCH 14/53] bundle: command not found --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index c9f92a17..6c18bc98 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,7 @@ rvm: - 2.5 before_install: + - gem install bundler - mysql -e 'CREATE DATABASE IF NOT EXISTS test CHARACTER SET utf8mb4;' - psql -c 'create database test;' -U postgres - export WORKSPACE=`pwd`/workspace From c6f711ff7d9b62ca1193c933e8f84b1c74f611c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 3 Jan 2019 11:40:27 +0100 Subject: [PATCH 15/53] reverted: bundle: command not found --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6c18bc98..c9f92a17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,6 @@ rvm: - 2.5 before_install: - - gem install bundler - mysql -e 'CREATE DATABASE IF NOT EXISTS test CHARACTER SET utf8mb4;' - psql -c 'create database test;' -U postgres - export WORKSPACE=`pwd`/workspace From 958abb6714a959874f92a6f947d2f503dad224fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Fri, 4 Jan 2019 10:56:23 +0100 Subject: [PATCH 16/53] Displaying folder permissions from parent folders --- app/controllers/dmsf_controller.rb | 1 - .../dmsf_folder_permissions_controller.rb | 7 ++-- app/helpers/dmsf_folder_permissions_helper.rb | 36 ++++++++++++++----- app/models/dmsf_folder.rb | 33 +++++++++++++++++ app/views/dmsf/edit.html.erb | 10 ++++-- .../dmsf_folder_permissions/_new.html.erb | 12 +++---- ...dmsf_folder_permissions_controller_test.rb | 8 +++-- test/unit/dmsf_folder_test.rb | 21 +++++++++-- 8 files changed, 101 insertions(+), 27 deletions(-) diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index c1a39b61..985333c5 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -195,7 +195,6 @@ class DmsfController < ApplicationController @parent = @folder.dmsf_folder @pathfolder = copy_folder(@folder) @force_file_unlock_allowed = User.current.allowed_to?(:force_file_unlock, @project) - @users = Principal.active.where(id: @folder.dmsf_folder_permissions.users.map{ |p| p.object_id }) end def create diff --git a/app/controllers/dmsf_folder_permissions_controller.rb b/app/controllers/dmsf_folder_permissions_controller.rb index 8d58d61f..47c5f1ea 100644 --- a/app/controllers/dmsf_folder_permissions_controller.rb +++ b/app/controllers/dmsf_folder_permissions_controller.rb @@ -20,7 +20,7 @@ class DmsfFolderPermissionsController < ApplicationController - before_action :find_folder, :only => [:destroy] + before_action :find_folder, only: [:destroy, :new, :autocomplete_for_user] before_action :find_project before_action :authorize before_action :permissions @@ -49,7 +49,10 @@ class DmsfFolderPermissionsController < ApplicationController private def users_for_new_users - Principal.active.visible.member_of(@project).like(params[:q]).order(:type, :lastname).to_a + users = @dmsf_folder.permissions_users + ids = users.collect{ |u| u[0].id } + Principal.active.visible.member_of(@project).like(params[:q]).where(['id NOT IN (?)', ids.join(',')]).order( + :type, :lastname).to_a end def find_project diff --git a/app/helpers/dmsf_folder_permissions_helper.rb b/app/helpers/dmsf_folder_permissions_helper.rb index 8ada6ed6..597bd39c 100644 --- a/app/helpers/dmsf_folder_permissions_helper.rb +++ b/app/helpers/dmsf_folder_permissions_helper.rb @@ -1,15 +1,35 @@ +# encoding: utf-8 +# +# Redmine plugin for Document Management System "Features" +# +# Copyright © 2011 Vít Jonáš +# Copyright © 2011-18 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 DmsfFolderPermissionsHelper def users_checkboxes(users) s = '' - if users - users.each do |user| - content = check_box_tag('permissions[user_ids][]', user.id, true, :id => nil) + user.name - s << content_tag(:label, content, :id => "user_permission_ids_#{user.id}", :class => 'inline') - end - end - s.html_safe - end + users.each do |user| + user = [user, false] unless user.is_a?(Array) + content = check_box_tag('permissions[user_ids][]', user[0].id, true, disabled: user[1], id: nil) + user[0].name + s << content_tag(:label, content, id: "user_permission_ids_#{user[0].id}", class: 'inline') + end + s.html_safe + end def render_principals_for_new_folder_permissions(users) principals_check_box_tags 'user_ids[]', users diff --git a/app/models/dmsf_folder.rb b/app/models/dmsf_folder.rb index 8d217888..196fc73d 100644 --- a/app/models/dmsf_folder.rb +++ b/app/models/dmsf_folder.rb @@ -543,8 +543,41 @@ class DmsfFolder < ActiveRecord::Base title.gsub(/[#{INVALID_CHARACTERS}]/, '.').gsub(/\.{2,}/, '.').chomp('.') end + def permission_for_role(role) + options = Hash.new + options[:checked] = false + options[:disabled] = false + permission_for_role_recursive(self, role, options) + options[:disabled] = false unless options[:checked] + options.values + end + + def permissions_users + users = Array.new + permissions_users_recursive(self, users, false) + users + end + private + def permission_for_role_recursive(folder, role, options) + options[:checked] = folder.dmsf_folder_permissions.roles.exists?(object_id: role.id) + if !options[:checked] && folder.dmsf_folder && !folder.dmsf_folder.deleted? + options[:disabled] = true + permission_for_role_recursive(folder.dmsf_folder, role, options) + end + end + + def permissions_users_recursive(folder, users, disabled) + if folder + usrs = Principal.active.where(id: folder.dmsf_folder_permissions.users.map{ |p| p.object_id }) + usrs.each do |u| + users << [u, disabled] + end + permissions_users_recursive(folder.dmsf_folder, users, true) + end + end + def self.directory_subtree(tree, folder, level, current_folder) folders = DmsfFolder.where(project_id: folder.project_id, dmsf_folder_id: folder.id).notsystem.visible(false).to_a folders.delete(current_folder) diff --git a/app/views/dmsf/edit.html.erb b/app/views/dmsf/edit.html.erb index 023b8e58..7e69ff70 100644 --- a/app/views/dmsf/edit.html.erb +++ b/app/views/dmsf/edit.html.erb @@ -77,12 +77,16 @@

<%= label_tag '', l(:label_permissions) %> <% User.current.managed_roles(@project).each do |role| %> - <% checked = @folder.dmsf_folder_permissions.roles.exists?(object_id: role.id) %> - + <% checked, disabled = @folder.permission_for_role(role) %> + <% end %>
- <% checkboxes = users_checkboxes(@users) %> + <% users = @folder.permissions_users %> + <% checkboxes = users_checkboxes(users) %> <%= checkboxes %>
<% if checkboxes.present? %> diff --git a/app/views/dmsf_folder_permissions/_new.html.erb b/app/views/dmsf_folder_permissions/_new.html.erb index dc639fc7..c0388254 100644 --- a/app/views/dmsf_folder_permissions/_new.html.erb +++ b/app/views/dmsf_folder_permissions/_new.html.erb @@ -22,22 +22,20 @@

<%= l(:label_user_search) %>

-<%= form_tag(append_dmsf_folder_permissions_path, - :remote => true, - :method => :post, - :id => 'new-user-form') do %> +<%= form_tag(append_dmsf_folder_permissions_path, remote: true, method: :post, id: 'new-user-form') do %> <%= hidden_field_tag :project_id, @project.id %>

<%= label_tag 'user_search', l(:label_user_search) %><%= text_field_tag 'user_search', nil %>

<%= late_javascript_tag "observeSearchfield('user_search', 'users_for_users', '#{ escape_javascript url_for( - :controller => 'dmsf_folder_permissions', :action => 'autocomplete_for_user', :project_id => @project) }')" %> + controller: 'dmsf_folder_permissions', action: 'autocomplete_for_user', project_id: @project, + dmsf_folder_id: @dmsf_folder) }')" %>
<%= render_principals_for_new_folder_permissions(@principals) %>

- <%= submit_tag l(:button_add), :name => nil, :onclick => "hideModal(this);" %> - <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %> + <%= submit_tag l(:button_add), name: nil, onclick: 'hideModal(this);' %> + <%= submit_tag l(:button_cancel), name: nil, onclick: 'hideModal(this);', type: 'button' %>

<% end %> diff --git a/test/functional/dmsf_folder_permissions_controller_test.rb b/test/functional/dmsf_folder_permissions_controller_test.rb index 6cd8a8d1..b53ef286 100644 --- a/test/functional/dmsf_folder_permissions_controller_test.rb +++ b/test/functional/dmsf_folder_permissions_controller_test.rb @@ -46,20 +46,22 @@ class DmsfFolderPermissionsControllerTest < RedmineDmsf::Test::TestCase end def test_new - get :new, :params => {:project_id => @project1, :format => 'js'}, :xhr => true + get :new, params: { project_id: @project1, dmsf_folder_id: @folder7, format: 'js'}, xhr: true assert_response :success assert_template 'new' assert_equal 'text/javascript', response.content_type end def test_autocomplete_for_user - get :autocomplete_for_user, :params => {:project_id => @project1, :q => 'smi', :format => 'js'}, :xhr => true + get :autocomplete_for_user, params: { project_id: @project1, dmsf_folder_id: @folder7, q: 'smi', format: 'js'}, + xhr: true assert_response :success assert_include 'John Smith', response.body end def test_append - get :new, :params => {:project_id => @project1, :user_ids => [@manager.id], :format => 'js'}, :xhr => true + get :new, params: { project_id: @project1, dmsf_folder_id: @folder7, user_ids: [@manager.id], format: 'js'}, + xhr: true assert_response :success assert_template 'new' assert_equal 'text/javascript', response.content_type diff --git a/test/unit/dmsf_folder_test.rb b/test/unit/dmsf_folder_test.rb index 0f363612..0765c06d 100644 --- a/test/unit/dmsf_folder_test.rb +++ b/test/unit/dmsf_folder_test.rb @@ -22,7 +22,8 @@ require File.expand_path('../../test_helper', __FILE__) class DmsfFolderTest < RedmineDmsf::Test::UnitTest - fixtures :projects, :users, :email_addresses, :dmsf_folders, :roles, :members, :member_roles, :dmsf_folder_permissions + fixtures :projects, :users, :email_addresses, :dmsf_folders, :roles, :members, :member_roles, + :dmsf_folder_permissions def setup @project = Project.find 1 @@ -35,8 +36,8 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest @folder7 = DmsfFolder.find 7 @manager = User.find 2 @developer = User.find 3 - manager_role = Role.find 1 - manager_role.add_permission! :view_dmsf_folders + @manager_role = Role.find 1 + @manager_role.add_permission! :view_dmsf_folders developer_role = Role.find 2 developer_role.add_permission! :view_dmsf_folders User.current = @manager @@ -52,6 +53,7 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest assert_kind_of Project, @project assert_kind_of User, @manager assert_kind_of User, @developer + assert_kind_of Role, @manager_role end def test_visiblity @@ -188,4 +190,17 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest assert_equal 'test', DmsfFolder::get_valid_title("test#{DmsfFolder::INVALID_CHARACTERS}") end + def test_permission_for_role + checked, disabled = @folder7.permission_for_role(@manager_role) + assert checked + assert !disabled + end + + def test_permissions_users + users = @folder7.permissions_users + assert users.any? + assert users[0] + assert !users[1] + end + end \ No newline at end of file From 87c555b1d06f0fccf37664cb8fa49db3160dd6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Fri, 4 Jan 2019 12:42:50 +0100 Subject: [PATCH 17/53] Copyright 2018 -> 2019 --- .travis.yml | 2 +- Gemfile | 2 +- after_init.rb | 2 +- app/controllers/dmsf_context_menus_controller.rb | 2 +- app/controllers/dmsf_controller.rb | 2 +- app/controllers/dmsf_files_controller.rb | 2 +- app/controllers/dmsf_files_copy_controller.rb | 2 +- app/controllers/dmsf_folder_permissions_controller.rb | 2 +- app/controllers/dmsf_folders_copy_controller.rb | 2 +- app/controllers/dmsf_links_controller.rb | 2 +- app/controllers/dmsf_public_urls_controller.rb | 2 +- app/controllers/dmsf_state_controller.rb | 2 +- app/controllers/dmsf_upload_controller.rb | 2 +- app/controllers/dmsf_workflows_controller.rb | 2 +- app/helpers/dmsf_folder_permissions_helper.rb | 2 +- app/helpers/dmsf_helper.rb | 2 +- app/helpers/dmsf_links_helper.rb | 2 +- app/helpers/dmsf_upload_helper.rb | 2 +- app/helpers/dmsf_workflows_helper.rb | 2 +- app/models/dmsf_file.rb | 2 +- app/models/dmsf_file_revision.rb | 2 +- app/models/dmsf_file_revision_access.rb | 2 +- app/models/dmsf_file_revision_custom_field.rb | 2 +- app/models/dmsf_folder.rb | 2 +- app/models/dmsf_folder_permission.rb | 2 +- app/models/dmsf_link.rb | 2 +- app/models/dmsf_lock.rb | 2 +- app/models/dmsf_mailer.rb | 2 +- app/models/dmsf_public_url.rb | 2 +- app/models/dmsf_upload.rb | 2 +- app/models/dmsf_workflow.rb | 2 +- app/models/dmsf_workflow_step.rb | 2 +- app/models/dmsf_workflow_step_action.rb | 2 +- app/models/dmsf_workflow_step_assignment.rb | 2 +- .../easy_page_modules/easy_dms/epm_dmsf_locked_documents.rb | 2 +- .../easy_page_modules/easy_dms/epm_dmsf_open_approvals.rb | 2 +- app/validators/dmsf_file_name_validator.rb | 2 +- app/validators/dmsf_url_validator.rb | 2 +- app/validators/dmsf_workflow_name_validator.rb | 2 +- app/views/dmsf/_add_email.html.erb | 2 +- app/views/dmsf/_custom_fields.html.erb | 2 +- app/views/dmsf/_dir.html.erb | 2 +- app/views/dmsf/_dir_trash.html.erb | 2 +- app/views/dmsf/_dmsf_rows.erb | 2 +- app/views/dmsf/_file.html.erb | 2 +- app/views/dmsf/_file_trash.html.erb | 2 +- app/views/dmsf/_list_view.erb | 2 +- app/views/dmsf/_path.html.erb | 2 +- app/views/dmsf/_tree_view.erb | 2 +- app/views/dmsf/_url.html.erb | 2 +- app/views/dmsf/_url_trash.html.erb | 2 +- app/views/dmsf/add_email.js.erb | 2 +- app/views/dmsf/append_email.js.erb | 2 +- app/views/dmsf/autocomplete_for_user.js.erb | 2 +- app/views/dmsf/edit.html.erb | 2 +- app/views/dmsf/edit_root.html.erb | 2 +- app/views/dmsf/email_entries.html.erb | 2 +- app/views/dmsf/show.html.erb | 2 +- app/views/dmsf/trash.html.erb | 2 +- app/views/dmsf_context_menus/dmsf.html.erb | 2 +- app/views/dmsf_context_menus/trash.html.erb | 2 +- app/views/dmsf_files/_file_new_revision.html.erb | 2 +- app/views/dmsf_files/_link.html.erb | 2 +- app/views/dmsf_files/_links.html.erb | 2 +- app/views/dmsf_files/_revision_access.html.erb | 2 +- app/views/dmsf_files/_thumbnails.html.erb | 2 +- app/views/dmsf_files/show.html.erb | 2 +- app/views/dmsf_files_copy/new.html.erb | 2 +- app/views/dmsf_folder_permissions/_new.html.erb | 2 +- app/views/dmsf_folder_permissions/append.js.erb | 2 +- .../dmsf_folder_permissions/autocomplete_for_user.js.erb | 2 +- app/views/dmsf_folder_permissions/new.js.erb | 2 +- app/views/dmsf_folders_copy/_form.html.erb | 2 +- app/views/dmsf_folders_copy/new.html.erb | 2 +- app/views/dmsf_links/_form.html.erb | 2 +- app/views/dmsf_links/autocomplete_for_project.js.erb | 2 +- app/views/dmsf_links/create.js.erb | 2 +- app/views/dmsf_links/new.html.erb | 2 +- app/views/dmsf_links/new.js.erb | 2 +- app/views/dmsf_mailer/files_deleted.html.erb | 2 +- app/views/dmsf_mailer/files_deleted.text.erb | 2 +- app/views/dmsf_mailer/files_updated.html.erb | 2 +- app/views/dmsf_mailer/send_documents.html.erb | 2 +- app/views/dmsf_mailer/send_documents.text.erb | 2 +- app/views/dmsf_mailer/workflow_notification.html.erb | 2 +- app/views/dmsf_mailer/workflow_notification.text.erb | 2 +- app/views/dmsf_public_urls/_new.html.erb | 2 +- app/views/dmsf_state/_user_pref.html.erb | 2 +- app/views/dmsf_upload/_form.html.erb | 2 +- app/views/dmsf_upload/_multi_upload.html.erb | 2 +- app/views/dmsf_upload/_upload_file.html.erb | 2 +- app/views/dmsf_upload/_upload_file_locked.html.erb | 2 +- app/views/dmsf_upload/upload.js.erb | 2 +- app/views/dmsf_upload/upload_file.html.erb | 2 +- app/views/dmsf_upload/upload_files.html.erb | 2 +- app/views/dmsf_workflows/_action.html.erb | 2 +- app/views/dmsf_workflows/_approval_workflow_button.html.erb | 2 +- app/views/dmsf_workflows/_assign.html.erb | 2 +- app/views/dmsf_workflows/_log.html.erb | 2 +- app/views/dmsf_workflows/_main.html.erb | 2 +- app/views/dmsf_workflows/_new_step_form.html.erb | 2 +- app/views/dmsf_workflows/_new_step_modal.html.erb | 2 +- app/views/dmsf_workflows/_steps.html.erb | 2 +- app/views/dmsf_workflows/action.js.erb | 2 +- app/views/dmsf_workflows/add_step.html.erb | 2 +- app/views/dmsf_workflows/assign.js.erb | 2 +- app/views/dmsf_workflows/assignment.js.erb | 2 +- app/views/dmsf_workflows/index.html.erb | 2 +- app/views/dmsf_workflows/log.html.erb | 2 +- app/views/dmsf_workflows/log.js.erb | 2 +- app/views/dmsf_workflows/new.html.erb | 2 +- app/views/dmsf_workflows/new_step.js.erb | 2 +- app/views/dmsf_workflows/remove_step.html.erb | 2 +- app/views/dmsf_workflows/reorder_steps.html.erb | 2 +- app/views/dmsf_workflows/show.html.erb | 2 +- .../easy_dms/_dmsf_locked_documents_edit.html.erb | 2 +- .../easy_dms/_dmsf_locked_documents_show.html.erb | 2 +- .../easy_dms/_dmsf_open_approvals_edit.html.erb | 2 +- .../easy_dms/_dmsf_open_approvals_show.html.erb | 2 +- app/views/hooks/redmine_dmsf/_view_my_account.html.erb | 2 +- app/views/hooks/redmine_dmsf/_view_projects_form.html.erb | 2 +- app/views/hooks/redmine_dmsf/_view_users_bulk_edit.html.erb | 2 +- app/views/my/blocks/_locked_documents.html.erb | 2 +- app/views/my/blocks/_open_approvals.html.erb | 2 +- app/views/search/_container.html.erb | 2 +- app/views/settings/_dmsf_columns.html.erb | 2 +- app/views/settings/_dmsf_settings.html.erb | 2 +- assets/javascripts/attachments_dmsf.js | 2 +- assets/javascripts/redmine_dmsf.js | 2 +- assets/stylesheets/redmine_dmsf.css | 2 +- config/locales/cs.yml | 2 +- config/locales/de.yml | 2 +- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- config/locales/fr.yml | 2 +- config/locales/hu.yml | 2 +- config/locales/it.yml | 2 +- config/locales/ja.yml | 2 +- config/locales/ko.yml | 2 +- config/locales/nl.yml | 2 +- config/locales/pl.yml | 2 +- config/locales/pt-BR.yml | 2 +- config/locales/ru.yml | 2 +- config/locales/sl.yml | 2 +- config/locales/zh-TW.yml | 2 +- config/locales/zh.yml | 2 +- config/routes.rb | 2 +- db/migrate/01_create_hierarchy.rb | 2 +- db/migrate/02_dmsf_normalization.rb | 2 +- db/migrate/03_dmsf_0_8_0.rb | 2 +- db/migrate/04_dmsf_0_9_0.rb | 2 +- db/migrate/05_dmsf_0_9_0_1.rb | 2 +- db/migrate/06_dmsf_1_2_0.rb | 2 +- db/migrate/07_dmsf_1_4_4.rb | 2 +- db/migrate/20120822100401_create_dmsf_workflows.rb | 4 ++-- db/migrate/20120822100402_create_dmsf_workflow_steps.rb | 2 +- .../20120822100403_create_dmsf_workflow_step_assignments.rb | 2 +- .../20120822100404_create_dmsf_workflow_step_actions.rb | 2 +- db/migrate/20130819013955_update_projects.rb | 2 +- db/migrate/20131108141401_add_index_to_dmsf_files.rb | 2 +- db/migrate/20131108141402_add_index_to_dmsf_folders.rb | 2 +- db/migrate/20131113141401_add_index_to_dmsf_file_revision.rb | 2 +- db/migrate/20131113141402_add_index_to_dmsf_lock.rb | 2 +- db/migrate/20131113141403_create_dmsf_links.rb | 2 +- db/migrate/20140314132501_notifications_on.rb | 2 +- db/migrate/20140519133201_trash_bin.rb | 2 +- db/migrate/20141013102501_remove_project_from_revision.rb | 2 +- db/migrate/20141015132701_remove_folder_from_revision.rb | 2 +- db/migrate/20141205143001_remove_uniqueness_from_wf.rb | 2 +- db/migrate/20150120152101_notifications_nullable.rb | 2 +- db/migrate/20150130052716_add_external.rb | 2 +- db/migrate/20150202010301_add_user_to_links.rb | 2 +- db/migrate/20150910153701_title_not_null.rb | 2 +- db/migrate/20151020141801_large_files.rb | 2 +- db/migrate/20151209100001_title_format.rb | 2 +- db/migrate/20160215125801_approval_workflow_status.rb | 2 +- db/migrate/20160217133001_status_deleted.rb | 2 +- db/migrate/20160222140401_approval_workflow_std_fields.rb | 2 +- db/migrate/20160421150501_add_digest_to_revision.rb | 2 +- db/migrate/20161223133200_create_dmsf_public_urls.rb | 2 +- .../20170103164701_add_name_to_appoval_workflow_step.rb | 2 +- db/migrate/20170118142001_dmsf_file_container.rb | 2 +- db/migrate/20170204214753_add_revision_to_dmsf_lock.rb | 2 +- ...70214153223_add_dmsf_file_last_revision_id_to_dmsf_lock.rb | 2 +- ...0170217141601_add_dmsf_not_inheritable_to_custom_fields.rb | 2 +- db/migrate/20170323131231_dmsf_description_limit.rb | 2 +- db/migrate/20170330131901_create_dmsf_folder_permissions.rb | 2 +- db/migrate/20170421101901_dmsf_file_container_rollback.rb | 2 +- db/migrate/20170422104901_migrate_documents.rb | 2 +- db/migrate/20170526144701_dmsf_attachable.rb | 2 +- .../20171027124101_change_revision_digest_limit_to_64.rb | 2 +- db/migrate/20171110155901_add_index_to_dmsf_folder.rb | 2 +- db/migrate/20180216152501_rename_title_format.rb | 2 +- db/migrate/20180903132101_fast_links.rb | 2 +- extra/api/api_client.rb | 2 +- extra/api/api_client.sh | 2 +- extra/xapian_indexer.rb | 2 +- init.rb | 2 +- lib/dmsf_zip.rb | 2 +- lib/redmine_dmsf.rb | 2 +- lib/redmine_dmsf/errors/dmsf_access_error.rb | 2 +- lib/redmine_dmsf/errors/dmsf_content_error.rb | 2 +- lib/redmine_dmsf/errors/dmsf_email_max_file_error.rb | 2 +- lib/redmine_dmsf/errors/dmsf_file_not_found_error.rb | 2 +- lib/redmine_dmsf/errors/dmsf_lock_error.rb | 2 +- lib/redmine_dmsf/errors/dmsf_zip_max_file_error.rb | 2 +- lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb | 2 +- lib/redmine_dmsf/hooks/controllers/search_controller_hooks.rb | 2 +- lib/redmine_dmsf/hooks/helpers/issues_helper_hooks.rb | 2 +- lib/redmine_dmsf/hooks/helpers/search_helper_hooks.rb | 2 +- lib/redmine_dmsf/hooks/views/base_view_hooks.rb | 2 +- lib/redmine_dmsf/hooks/views/custom_field_view_hooks.rb | 2 +- lib/redmine_dmsf/hooks/views/issue_view_hooks.rb | 2 +- lib/redmine_dmsf/hooks/views/my_account_view_hooks.rb | 2 +- lib/redmine_dmsf/hooks/views/search_view_hooks.rb | 2 +- lib/redmine_dmsf/hooks/views/view_projects_form_hook.rb | 2 +- lib/redmine_dmsf/lockable.rb | 2 +- lib/redmine_dmsf/macros.rb | 2 +- lib/redmine_dmsf/patches/attachable_patch.rb | 2 +- lib/redmine_dmsf/patches/easy_crm_case_patch.rb | 2 +- lib/redmine_dmsf/patches/easy_crm_cases_controller_patch.rb | 2 +- lib/redmine_dmsf/patches/issue_patch.rb | 2 +- lib/redmine_dmsf/patches/project_patch.rb | 2 +- lib/redmine_dmsf/patches/projects_helper_patch.rb | 2 +- lib/redmine_dmsf/patches/role_patch.rb | 2 +- lib/redmine_dmsf/patches/user_patch.rb | 2 +- lib/redmine_dmsf/patches/user_preference_patch.rb | 2 +- lib/redmine_dmsf/test/integration_test.rb | 2 +- lib/redmine_dmsf/test/unit_test.rb | 2 +- lib/redmine_dmsf/webdav/base_resource.rb | 2 +- lib/redmine_dmsf/webdav/custom_middleware.rb | 2 +- lib/redmine_dmsf/webdav/dmsf_resource.rb | 2 +- lib/redmine_dmsf/webdav/index_resource.rb | 2 +- lib/redmine_dmsf/webdav/project_resource.rb | 2 +- lib/redmine_dmsf/webdav/resource_proxy.rb | 2 +- lib/tasks/dmsf_alert_approvals.rake | 2 +- lib/tasks/dmsf_convert_documents.rake | 2 +- lib/tasks/dmsf_create_digests.rake | 2 +- lib/tasks/dmsf_maintenance.rake | 2 +- test/ci/redmine_install.sh | 2 +- test/fixtures/custom_fields.yml | 2 +- test/fixtures/custom_values.yml | 2 +- test/functional/dmsf_context_menus_controller_test.rb | 2 +- test/functional/dmsf_controller_test.rb | 2 +- test/functional/dmsf_files_controller_test.rb | 2 +- test/functional/dmsf_files_copy_controller_test.rb | 2 +- test/functional/dmsf_folder_permissions_controller_test.rb | 2 +- test/functional/dmsf_folders_copy_controller_test.rb | 2 +- test/functional/dmsf_links_controller_test.rb | 2 +- test/functional/dmsf_public_urls_controller_test.rb | 2 +- test/functional/dmsf_state_controller_test.rb | 2 +- test/functional/dmsf_workflow_controller_test.rb | 2 +- test/functional/issues_controller_test.rb | 2 +- test/functional/my_controller_test.rb | 2 +- test/integration/rest_api/dmsf_file_api_test.rb | 2 +- test/integration/rest_api/dmsf_folder_api_test.rb | 2 +- test/integration/rest_api/dmsf_link_api_test.rb | 2 +- test/integration/webdav/dmsf_webdav_custom_middleware_test.rb | 2 +- test/integration/webdav/dmsf_webdav_delete_test.rb | 2 +- test/integration/webdav/dmsf_webdav_get_test.rb | 2 +- test/integration/webdav/dmsf_webdav_head_test.rb | 2 +- test/integration/webdav/dmsf_webdav_lock_test.rb | 2 +- test/integration/webdav/dmsf_webdav_mkcol_test.rb | 2 +- test/integration/webdav/dmsf_webdav_move_test.rb | 2 +- test/integration/webdav/dmsf_webdav_options_test.rb | 2 +- test/integration/webdav/dmsf_webdav_post_test.rb | 2 +- test/integration/webdav/dmsf_webdav_propfind_test.rb | 2 +- test/integration/webdav/dmsf_webdav_put_test.rb | 2 +- test/test_helper.rb | 2 +- test/unit/attachable_patch_test.rb | 2 +- test/unit/dmsf_file_revision_test.rb | 2 +- test/unit/dmsf_file_test.rb | 2 +- test/unit/dmsf_folder_permission_test.rb | 2 +- test/unit/dmsf_folder_test.rb | 2 +- test/unit/dmsf_link_test.rb | 2 +- test/unit/dmsf_lock_test.rb | 2 +- test/unit/dmsf_mailer_test.rb | 2 +- test/unit/dmsf_public_url_test.rb | 2 +- test/unit/dmsf_workflow_step_action_test.rb | 2 +- test/unit/dmsf_workflow_step_assignment_test.rb | 2 +- test/unit/dmsf_workflow_step_test.rb | 2 +- test/unit/dmsf_workflow_test.rb | 2 +- test/unit/issue_patch_test.rb | 2 +- test/unit/project_patch_test.rb | 2 +- test/unit/user_patch_test.rb | 2 +- 285 files changed, 286 insertions(+), 286 deletions(-) diff --git a/.travis.yml b/.travis.yml index c9f92a17..cb117264 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/Gemfile b/Gemfile index 6b00846f..e6511368 100644 --- a/Gemfile +++ b/Gemfile @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/after_init.rb b/after_init.rb index f5bbdcde..84ce3d8d 100644 --- a/after_init.rb +++ b/after_init.rb @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/controllers/dmsf_context_menus_controller.rb b/app/controllers/dmsf_context_menus_controller.rb index b4b29788..20547503 100644 --- a/app/controllers/dmsf_context_menus_controller.rb +++ b/app/controllers/dmsf_context_menus_controller.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index 985333c5..13fed7be 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/controllers/dmsf_files_controller.rb b/app/controllers/dmsf_files_controller.rb index 689eb0ba..da8f4ead 100644 --- a/app/controllers/dmsf_files_controller.rb +++ b/app/controllers/dmsf_files_controller.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/controllers/dmsf_files_copy_controller.rb b/app/controllers/dmsf_files_copy_controller.rb index 356bfa48..03f710ad 100644 --- a/app/controllers/dmsf_files_copy_controller.rb +++ b/app/controllers/dmsf_files_copy_controller.rb @@ -1,7 +1,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/controllers/dmsf_folder_permissions_controller.rb b/app/controllers/dmsf_folder_permissions_controller.rb index 47c5f1ea..cae91564 100644 --- a/app/controllers/dmsf_folder_permissions_controller.rb +++ b/app/controllers/dmsf_folder_permissions_controller.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/controllers/dmsf_folders_copy_controller.rb b/app/controllers/dmsf_folders_copy_controller.rb index f702e81f..bca88feb 100644 --- a/app/controllers/dmsf_folders_copy_controller.rb +++ b/app/controllers/dmsf_folders_copy_controller.rb @@ -1,7 +1,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/controllers/dmsf_links_controller.rb b/app/controllers/dmsf_links_controller.rb index 8c86aa7f..707d6e54 100644 --- a/app/controllers/dmsf_links_controller.rb +++ b/app/controllers/dmsf_links_controller.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/controllers/dmsf_public_urls_controller.rb b/app/controllers/dmsf_public_urls_controller.rb index 7b76fa2e..e26e1db8 100644 --- a/app/controllers/dmsf_public_urls_controller.rb +++ b/app/controllers/dmsf_public_urls_controller.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/controllers/dmsf_state_controller.rb b/app/controllers/dmsf_state_controller.rb index 9af7e476..60c7f5b6 100644 --- a/app/controllers/dmsf_state_controller.rb +++ b/app/controllers/dmsf_state_controller.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/controllers/dmsf_upload_controller.rb b/app/controllers/dmsf_upload_controller.rb index 8090e3f3..b6403e0e 100644 --- a/app/controllers/dmsf_upload_controller.rb +++ b/app/controllers/dmsf_upload_controller.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/controllers/dmsf_workflows_controller.rb b/app/controllers/dmsf_workflows_controller.rb index ad37ab06..d0f3540b 100644 --- a/app/controllers/dmsf_workflows_controller.rb +++ b/app/controllers/dmsf_workflows_controller.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/helpers/dmsf_folder_permissions_helper.rb b/app/helpers/dmsf_folder_permissions_helper.rb index 597bd39c..46a3f420 100644 --- a/app/helpers/dmsf_folder_permissions_helper.rb +++ b/app/helpers/dmsf_folder_permissions_helper.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/helpers/dmsf_helper.rb b/app/helpers/dmsf_helper.rb index a3af0d0c..9d698cdc 100644 --- a/app/helpers/dmsf_helper.rb +++ b/app/helpers/dmsf_helper.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/helpers/dmsf_links_helper.rb b/app/helpers/dmsf_links_helper.rb index d4e4a9bf..2942dc17 100644 --- a/app/helpers/dmsf_links_helper.rb +++ b/app/helpers/dmsf_links_helper.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/helpers/dmsf_upload_helper.rb b/app/helpers/dmsf_upload_helper.rb index f5860daa..b6ed1803 100644 --- a/app/helpers/dmsf_upload_helper.rb +++ b/app/helpers/dmsf_upload_helper.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/helpers/dmsf_workflows_helper.rb b/app/helpers/dmsf_workflows_helper.rb index 62ba5fbc..859052bf 100644 --- a/app/helpers/dmsf_workflows_helper.rb +++ b/app/helpers/dmsf_workflows_helper.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_file.rb b/app/models/dmsf_file.rb index eb0cbee0..801649dd 100644 --- a/app/models/dmsf_file.rb +++ b/app/models/dmsf_file.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_file_revision.rb b/app/models/dmsf_file_revision.rb index a43554ed..e385f1dc 100644 --- a/app/models/dmsf_file_revision.rb +++ b/app/models/dmsf_file_revision.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_file_revision_access.rb b/app/models/dmsf_file_revision_access.rb index eca301b8..c3c9240f 100644 --- a/app/models/dmsf_file_revision_access.rb +++ b/app/models/dmsf_file_revision_access.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_file_revision_custom_field.rb b/app/models/dmsf_file_revision_custom_field.rb index f25f0873..7572ecea 100644 --- a/app/models/dmsf_file_revision_custom_field.rb +++ b/app/models/dmsf_file_revision_custom_field.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_folder.rb b/app/models/dmsf_folder.rb index 196fc73d..e1fbbe28 100644 --- a/app/models/dmsf_folder.rb +++ b/app/models/dmsf_folder.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_folder_permission.rb b/app/models/dmsf_folder_permission.rb index 84475d75..be29d43b 100644 --- a/app/models/dmsf_folder_permission.rb +++ b/app/models/dmsf_folder_permission.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_link.rb b/app/models/dmsf_link.rb index 3e4331df..d961e831 100644 --- a/app/models/dmsf_link.rb +++ b/app/models/dmsf_link.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_lock.rb b/app/models/dmsf_lock.rb index 04c29cb7..386bb4d5 100644 --- a/app/models/dmsf_lock.rb +++ b/app/models/dmsf_lock.rb @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_mailer.rb b/app/models/dmsf_mailer.rb index 33adc322..e83e3353 100644 --- a/app/models/dmsf_mailer.rb +++ b/app/models/dmsf_mailer.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_public_url.rb b/app/models/dmsf_public_url.rb index dd12562f..6a1b39c4 100644 --- a/app/models/dmsf_public_url.rb +++ b/app/models/dmsf_public_url.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_upload.rb b/app/models/dmsf_upload.rb index 5fe6a233..5fcdbdec 100644 --- a/app/models/dmsf_upload.rb +++ b/app/models/dmsf_upload.rb @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_workflow.rb b/app/models/dmsf_workflow.rb index 85432d1b..22bf02d2 100644 --- a/app/models/dmsf_workflow.rb +++ b/app/models/dmsf_workflow.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_workflow_step.rb b/app/models/dmsf_workflow_step.rb index 86ebf8a1..621f204a 100644 --- a/app/models/dmsf_workflow_step.rb +++ b/app/models/dmsf_workflow_step.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_workflow_step_action.rb b/app/models/dmsf_workflow_step_action.rb index ca2d7e7d..3d5787fd 100644 --- a/app/models/dmsf_workflow_step_action.rb +++ b/app/models/dmsf_workflow_step_action.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/dmsf_workflow_step_assignment.rb b/app/models/dmsf_workflow_step_assignment.rb index 340725b5..e8971a47 100644 --- a/app/models/dmsf_workflow_step_assignment.rb +++ b/app/models/dmsf_workflow_step_assignment.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/easy_page_modules/easy_dms/epm_dmsf_locked_documents.rb b/app/models/easy_page_modules/easy_dms/epm_dmsf_locked_documents.rb index 20e30b8a..180ed7c4 100644 --- a/app/models/easy_page_modules/easy_dms/epm_dmsf_locked_documents.rb +++ b/app/models/easy_page_modules/easy_dms/epm_dmsf_locked_documents.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/models/easy_page_modules/easy_dms/epm_dmsf_open_approvals.rb b/app/models/easy_page_modules/easy_dms/epm_dmsf_open_approvals.rb index a65e5330..425618a6 100644 --- a/app/models/easy_page_modules/easy_dms/epm_dmsf_open_approvals.rb +++ b/app/models/easy_page_modules/easy_dms/epm_dmsf_open_approvals.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/validators/dmsf_file_name_validator.rb b/app/validators/dmsf_file_name_validator.rb index 7e9b0411..697d0f09 100644 --- a/app/validators/dmsf_file_name_validator.rb +++ b/app/validators/dmsf_file_name_validator.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/validators/dmsf_url_validator.rb b/app/validators/dmsf_url_validator.rb index c1494cb2..e897c152 100644 --- a/app/validators/dmsf_url_validator.rb +++ b/app/validators/dmsf_url_validator.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/validators/dmsf_workflow_name_validator.rb b/app/validators/dmsf_workflow_name_validator.rb index 7f0cf40c..f563a173 100644 --- a/app/validators/dmsf_workflow_name_validator.rb +++ b/app/validators/dmsf_workflow_name_validator.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/_add_email.html.erb b/app/views/dmsf/_add_email.html.erb index 1f28a32f..af372982 100644 --- a/app/views/dmsf/_add_email.html.erb +++ b/app/views/dmsf/_add_email.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf/_custom_fields.html.erb b/app/views/dmsf/_custom_fields.html.erb index becebba1..27362a39 100644 --- a/app/views/dmsf/_custom_fields.html.erb +++ b/app/views/dmsf/_custom_fields.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/_dir.html.erb b/app/views/dmsf/_dir.html.erb index d554b53a..5085a21f 100644 --- a/app/views/dmsf/_dir.html.erb +++ b/app/views/dmsf/_dir.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/_dir_trash.html.erb b/app/views/dmsf/_dir_trash.html.erb index 9e49423a..add594ef 100644 --- a/app/views/dmsf/_dir_trash.html.erb +++ b/app/views/dmsf/_dir_trash.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/_dmsf_rows.erb b/app/views/dmsf/_dmsf_rows.erb index bdfd2420..9bdd2ca8 100644 --- a/app/views/dmsf/_dmsf_rows.erb +++ b/app/views/dmsf/_dmsf_rows.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf/_file.html.erb b/app/views/dmsf/_file.html.erb index 72d0c4fc..680e58e0 100644 --- a/app/views/dmsf/_file.html.erb +++ b/app/views/dmsf/_file.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/_file_trash.html.erb b/app/views/dmsf/_file_trash.html.erb index 0f120fe7..7159093b 100644 --- a/app/views/dmsf/_file_trash.html.erb +++ b/app/views/dmsf/_file_trash.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/_list_view.erb b/app/views/dmsf/_list_view.erb index b0599fd9..aca56fea 100644 --- a/app/views/dmsf/_list_view.erb +++ b/app/views/dmsf/_list_view.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/_path.html.erb b/app/views/dmsf/_path.html.erb index 53420dd9..1815f8d4 100644 --- a/app/views/dmsf/_path.html.erb +++ b/app/views/dmsf/_path.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/_tree_view.erb b/app/views/dmsf/_tree_view.erb index 19740b08..70e342e2 100644 --- a/app/views/dmsf/_tree_view.erb +++ b/app/views/dmsf/_tree_view.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/_url.html.erb b/app/views/dmsf/_url.html.erb index 5b9a7a98..aaab9270 100644 --- a/app/views/dmsf/_url.html.erb +++ b/app/views/dmsf/_url.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/_url_trash.html.erb b/app/views/dmsf/_url_trash.html.erb index 1fe04cf8..c51f96f5 100644 --- a/app/views/dmsf/_url_trash.html.erb +++ b/app/views/dmsf/_url_trash.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/add_email.js.erb b/app/views/dmsf/add_email.js.erb index 93e05385..9ebf731e 100644 --- a/app/views/dmsf/add_email.js.erb +++ b/app/views/dmsf/add_email.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/append_email.js.erb b/app/views/dmsf/append_email.js.erb index 2455cc56..d2d50d7e 100644 --- a/app/views/dmsf/append_email.js.erb +++ b/app/views/dmsf/append_email.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/autocomplete_for_user.js.erb b/app/views/dmsf/autocomplete_for_user.js.erb index 68433729..57277d95 100644 --- a/app/views/dmsf/autocomplete_for_user.js.erb +++ b/app/views/dmsf/autocomplete_for_user.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/edit.html.erb b/app/views/dmsf/edit.html.erb index 7e69ff70..519a4fb7 100644 --- a/app/views/dmsf/edit.html.erb +++ b/app/views/dmsf/edit.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/edit_root.html.erb b/app/views/dmsf/edit_root.html.erb index 69c8bb5b..eba46647 100644 --- a/app/views/dmsf/edit_root.html.erb +++ b/app/views/dmsf/edit_root.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/email_entries.html.erb b/app/views/dmsf/email_entries.html.erb index 7b4a85b1..a98e1e57 100644 --- a/app/views/dmsf/email_entries.html.erb +++ b/app/views/dmsf/email_entries.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf/show.html.erb b/app/views/dmsf/show.html.erb index 9c10ea1f..d45edc71 100644 --- a/app/views/dmsf/show.html.erb +++ b/app/views/dmsf/show.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf/trash.html.erb b/app/views/dmsf/trash.html.erb index 84f2ffac..ce840392 100644 --- a/app/views/dmsf/trash.html.erb +++ b/app/views/dmsf/trash.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_context_menus/dmsf.html.erb b/app/views/dmsf_context_menus/dmsf.html.erb index 220a04f9..fc5a60fd 100644 --- a/app/views/dmsf_context_menus/dmsf.html.erb +++ b/app/views/dmsf_context_menus/dmsf.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf_context_menus/trash.html.erb b/app/views/dmsf_context_menus/trash.html.erb index 44f01e91..858c6cca 100644 --- a/app/views/dmsf_context_menus/trash.html.erb +++ b/app/views/dmsf_context_menus/trash.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf_files/_file_new_revision.html.erb b/app/views/dmsf_files/_file_new_revision.html.erb index f264e787..640094e5 100644 --- a/app/views/dmsf_files/_file_new_revision.html.erb +++ b/app/views/dmsf_files/_file_new_revision.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_files/_link.html.erb b/app/views/dmsf_files/_link.html.erb index c0472ce8..f70582c5 100644 --- a/app/views/dmsf_files/_link.html.erb +++ b/app/views/dmsf_files/_link.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf_files/_links.html.erb b/app/views/dmsf_files/_links.html.erb index 14ef34a2..48ce2830 100644 --- a/app/views/dmsf_files/_links.html.erb +++ b/app/views/dmsf_files/_links.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf_files/_revision_access.html.erb b/app/views/dmsf_files/_revision_access.html.erb index f4a34961..446d4012 100644 --- a/app/views/dmsf_files/_revision_access.html.erb +++ b/app/views/dmsf_files/_revision_access.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_files/_thumbnails.html.erb b/app/views/dmsf_files/_thumbnails.html.erb index 4840bb56..9d7fe997 100644 --- a/app/views/dmsf_files/_thumbnails.html.erb +++ b/app/views/dmsf_files/_thumbnails.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf_files/show.html.erb b/app/views/dmsf_files/show.html.erb index ccfc3d19..e2ee93cd 100644 --- a/app/views/dmsf_files/show.html.erb +++ b/app/views/dmsf_files/show.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_files_copy/new.html.erb b/app/views/dmsf_files_copy/new.html.erb index c96c1da9..e3e3ccc2 100644 --- a/app/views/dmsf_files_copy/new.html.erb +++ b/app/views/dmsf_files_copy/new.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_folder_permissions/_new.html.erb b/app/views/dmsf_folder_permissions/_new.html.erb index c0388254..c6f4099b 100644 --- a/app/views/dmsf_folder_permissions/_new.html.erb +++ b/app/views/dmsf_folder_permissions/_new.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf_folder_permissions/append.js.erb b/app/views/dmsf_folder_permissions/append.js.erb index 4d9255d2..8b11fd1a 100644 --- a/app/views/dmsf_folder_permissions/append.js.erb +++ b/app/views/dmsf_folder_permissions/append.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_folder_permissions/autocomplete_for_user.js.erb b/app/views/dmsf_folder_permissions/autocomplete_for_user.js.erb index a43d2d5a..c4976f17 100644 --- a/app/views/dmsf_folder_permissions/autocomplete_for_user.js.erb +++ b/app/views/dmsf_folder_permissions/autocomplete_for_user.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_folder_permissions/new.js.erb b/app/views/dmsf_folder_permissions/new.js.erb index 5c302c70..68de6c5b 100644 --- a/app/views/dmsf_folder_permissions/new.js.erb +++ b/app/views/dmsf_folder_permissions/new.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_folders_copy/_form.html.erb b/app/views/dmsf_folders_copy/_form.html.erb index 806782c4..74690914 100644 --- a/app/views/dmsf_folders_copy/_form.html.erb +++ b/app/views/dmsf_folders_copy/_form.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_folders_copy/new.html.erb b/app/views/dmsf_folders_copy/new.html.erb index fbd58fd2..3dbb7808 100644 --- a/app/views/dmsf_folders_copy/new.html.erb +++ b/app/views/dmsf_folders_copy/new.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_links/_form.html.erb b/app/views/dmsf_links/_form.html.erb index 3d281f8d..a48019d5 100644 --- a/app/views/dmsf_links/_form.html.erb +++ b/app/views/dmsf_links/_form.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_links/autocomplete_for_project.js.erb b/app/views/dmsf_links/autocomplete_for_project.js.erb index 2e527478..2c30f206 100644 --- a/app/views/dmsf_links/autocomplete_for_project.js.erb +++ b/app/views/dmsf_links/autocomplete_for_project.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_links/create.js.erb b/app/views/dmsf_links/create.js.erb index dc87fb4f..0bf3ad15 100644 --- a/app/views/dmsf_links/create.js.erb +++ b/app/views/dmsf_links/create.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_links/new.html.erb b/app/views/dmsf_links/new.html.erb index cfbb9a58..aa909f0a 100644 --- a/app/views/dmsf_links/new.html.erb +++ b/app/views/dmsf_links/new.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_links/new.js.erb b/app/views/dmsf_links/new.js.erb index b062fe5c..fcdaaf65 100644 --- a/app/views/dmsf_links/new.js.erb +++ b/app/views/dmsf_links/new.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_mailer/files_deleted.html.erb b/app/views/dmsf_mailer/files_deleted.html.erb index 65e3fc53..dd2d3bef 100644 --- a/app/views/dmsf_mailer/files_deleted.html.erb +++ b/app/views/dmsf_mailer/files_deleted.html.erb @@ -2,7 +2,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_mailer/files_deleted.text.erb b/app/views/dmsf_mailer/files_deleted.text.erb index 456ad891..fe62eee3 100644 --- a/app/views/dmsf_mailer/files_deleted.text.erb +++ b/app/views/dmsf_mailer/files_deleted.text.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_mailer/files_updated.html.erb b/app/views/dmsf_mailer/files_updated.html.erb index 83337e92..33f82505 100644 --- a/app/views/dmsf_mailer/files_updated.html.erb +++ b/app/views/dmsf_mailer/files_updated.html.erb @@ -2,7 +2,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_mailer/send_documents.html.erb b/app/views/dmsf_mailer/send_documents.html.erb index 83c380cc..054ebb33 100644 --- a/app/views/dmsf_mailer/send_documents.html.erb +++ b/app/views/dmsf_mailer/send_documents.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_mailer/send_documents.text.erb b/app/views/dmsf_mailer/send_documents.text.erb index 89ee5cc8..1cc6935a 100644 --- a/app/views/dmsf_mailer/send_documents.text.erb +++ b/app/views/dmsf_mailer/send_documents.text.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_mailer/workflow_notification.html.erb b/app/views/dmsf_mailer/workflow_notification.html.erb index baea1ee3..0980c394 100644 --- a/app/views/dmsf_mailer/workflow_notification.html.erb +++ b/app/views/dmsf_mailer/workflow_notification.html.erb @@ -1,6 +1,6 @@ <%# Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_mailer/workflow_notification.text.erb b/app/views/dmsf_mailer/workflow_notification.text.erb index a4500d07..60891fac 100644 --- a/app/views/dmsf_mailer/workflow_notification.text.erb +++ b/app/views/dmsf_mailer/workflow_notification.text.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_public_urls/_new.html.erb b/app/views/dmsf_public_urls/_new.html.erb index 9485b632..d0b6b769 100644 --- a/app/views/dmsf_public_urls/_new.html.erb +++ b/app/views/dmsf_public_urls/_new.html.erb @@ -4,7 +4,7 @@ # Redmine plugin for Document Management System "Features" # # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_state/_user_pref.html.erb b/app/views/dmsf_state/_user_pref.html.erb index 6955f48f..75910580 100644 --- a/app/views/dmsf_state/_user_pref.html.erb +++ b/app/views/dmsf_state/_user_pref.html.erb @@ -2,7 +2,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_upload/_form.html.erb b/app/views/dmsf_upload/_form.html.erb index 1ec76a2f..bac951f9 100644 --- a/app/views/dmsf_upload/_form.html.erb +++ b/app/views/dmsf_upload/_form.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf_upload/_multi_upload.html.erb b/app/views/dmsf_upload/_multi_upload.html.erb index 2833425d..30212712 100644 --- a/app/views/dmsf_upload/_multi_upload.html.erb +++ b/app/views/dmsf_upload/_multi_upload.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_upload/_upload_file.html.erb b/app/views/dmsf_upload/_upload_file.html.erb index 1e84d206..68b692f1 100644 --- a/app/views/dmsf_upload/_upload_file.html.erb +++ b/app/views/dmsf_upload/_upload_file.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf_upload/_upload_file_locked.html.erb b/app/views/dmsf_upload/_upload_file_locked.html.erb index 54fc433a..84b4bad2 100644 --- a/app/views/dmsf_upload/_upload_file_locked.html.erb +++ b/app/views/dmsf_upload/_upload_file_locked.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf_upload/upload.js.erb b/app/views/dmsf_upload/upload.js.erb index ce8002e6..8a18e5aa 100644 --- a/app/views/dmsf_upload/upload.js.erb +++ b/app/views/dmsf_upload/upload.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_upload/upload_file.html.erb b/app/views/dmsf_upload/upload_file.html.erb index d33aa842..fcddd741 100644 --- a/app/views/dmsf_upload/upload_file.html.erb +++ b/app/views/dmsf_upload/upload_file.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_upload/upload_files.html.erb b/app/views/dmsf_upload/upload_files.html.erb index e52f4e7e..1430747e 100644 --- a/app/views/dmsf_upload/upload_files.html.erb +++ b/app/views/dmsf_upload/upload_files.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/_action.html.erb b/app/views/dmsf_workflows/_action.html.erb index 9129f3fa..b2448b93 100644 --- a/app/views/dmsf_workflows/_action.html.erb +++ b/app/views/dmsf_workflows/_action.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/_approval_workflow_button.html.erb b/app/views/dmsf_workflows/_approval_workflow_button.html.erb index e886465e..b8a05756 100644 --- a/app/views/dmsf_workflows/_approval_workflow_button.html.erb +++ b/app/views/dmsf_workflows/_approval_workflow_button.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/_assign.html.erb b/app/views/dmsf_workflows/_assign.html.erb index 4216cb1f..dd4bb727 100644 --- a/app/views/dmsf_workflows/_assign.html.erb +++ b/app/views/dmsf_workflows/_assign.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/_log.html.erb b/app/views/dmsf_workflows/_log.html.erb index 6c292a12..096cefbb 100644 --- a/app/views/dmsf_workflows/_log.html.erb +++ b/app/views/dmsf_workflows/_log.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/_main.html.erb b/app/views/dmsf_workflows/_main.html.erb index 640228af..bfd50631 100644 --- a/app/views/dmsf_workflows/_main.html.erb +++ b/app/views/dmsf_workflows/_main.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/_new_step_form.html.erb b/app/views/dmsf_workflows/_new_step_form.html.erb index 23467144..9a0d3735 100644 --- a/app/views/dmsf_workflows/_new_step_form.html.erb +++ b/app/views/dmsf_workflows/_new_step_form.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/_new_step_modal.html.erb b/app/views/dmsf_workflows/_new_step_modal.html.erb index faa269c9..69f022c7 100644 --- a/app/views/dmsf_workflows/_new_step_modal.html.erb +++ b/app/views/dmsf_workflows/_new_step_modal.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/_steps.html.erb b/app/views/dmsf_workflows/_steps.html.erb index bc398cc0..fe0a1367 100644 --- a/app/views/dmsf_workflows/_steps.html.erb +++ b/app/views/dmsf_workflows/_steps.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/action.js.erb b/app/views/dmsf_workflows/action.js.erb index e92331fa..7fd80d99 100644 --- a/app/views/dmsf_workflows/action.js.erb +++ b/app/views/dmsf_workflows/action.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/add_step.html.erb b/app/views/dmsf_workflows/add_step.html.erb index 34a98679..10f587c8 100644 --- a/app/views/dmsf_workflows/add_step.html.erb +++ b/app/views/dmsf_workflows/add_step.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/assign.js.erb b/app/views/dmsf_workflows/assign.js.erb index dba9611c..9ed4cb20 100644 --- a/app/views/dmsf_workflows/assign.js.erb +++ b/app/views/dmsf_workflows/assign.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/assignment.js.erb b/app/views/dmsf_workflows/assignment.js.erb index 6ec9d4cc..3504dc4e 100644 --- a/app/views/dmsf_workflows/assignment.js.erb +++ b/app/views/dmsf_workflows/assignment.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/index.html.erb b/app/views/dmsf_workflows/index.html.erb index b108f535..8928452b 100644 --- a/app/views/dmsf_workflows/index.html.erb +++ b/app/views/dmsf_workflows/index.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/log.html.erb b/app/views/dmsf_workflows/log.html.erb index 9dc82d6d..bb317897 100644 --- a/app/views/dmsf_workflows/log.html.erb +++ b/app/views/dmsf_workflows/log.html.erb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/log.js.erb b/app/views/dmsf_workflows/log.js.erb index 358c86ed..ef96e94e 100644 --- a/app/views/dmsf_workflows/log.js.erb +++ b/app/views/dmsf_workflows/log.js.erb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/new.html.erb b/app/views/dmsf_workflows/new.html.erb index 1f444144..e8e6a29c 100644 --- a/app/views/dmsf_workflows/new.html.erb +++ b/app/views/dmsf_workflows/new.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/new_step.js.erb b/app/views/dmsf_workflows/new_step.js.erb index 8c062b43..a999d9dd 100644 --- a/app/views/dmsf_workflows/new_step.js.erb +++ b/app/views/dmsf_workflows/new_step.js.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/remove_step.html.erb b/app/views/dmsf_workflows/remove_step.html.erb index 1562a854..83906a9c 100644 --- a/app/views/dmsf_workflows/remove_step.html.erb +++ b/app/views/dmsf_workflows/remove_step.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/reorder_steps.html.erb b/app/views/dmsf_workflows/reorder_steps.html.erb index 40812734..37184bfc 100644 --- a/app/views/dmsf_workflows/reorder_steps.html.erb +++ b/app/views/dmsf_workflows/reorder_steps.html.erb @@ -1,6 +1,6 @@ <%# Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/dmsf_workflows/show.html.erb b/app/views/dmsf_workflows/show.html.erb index a90de23d..afc7c9a3 100644 --- a/app/views/dmsf_workflows/show.html.erb +++ b/app/views/dmsf_workflows/show.html.erb @@ -2,7 +2,7 @@ # encoding: utf-8 # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/easy_page_modules/easy_dms/_dmsf_locked_documents_edit.html.erb b/app/views/easy_page_modules/easy_dms/_dmsf_locked_documents_edit.html.erb index 315dbe6a..44069b81 100644 --- a/app/views/easy_page_modules/easy_dms/_dmsf_locked_documents_edit.html.erb +++ b/app/views/easy_page_modules/easy_dms/_dmsf_locked_documents_edit.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/easy_page_modules/easy_dms/_dmsf_locked_documents_show.html.erb b/app/views/easy_page_modules/easy_dms/_dmsf_locked_documents_show.html.erb index a9587f5a..3dffc728 100644 --- a/app/views/easy_page_modules/easy_dms/_dmsf_locked_documents_show.html.erb +++ b/app/views/easy_page_modules/easy_dms/_dmsf_locked_documents_show.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/easy_page_modules/easy_dms/_dmsf_open_approvals_edit.html.erb b/app/views/easy_page_modules/easy_dms/_dmsf_open_approvals_edit.html.erb index 315dbe6a..44069b81 100644 --- a/app/views/easy_page_modules/easy_dms/_dmsf_open_approvals_edit.html.erb +++ b/app/views/easy_page_modules/easy_dms/_dmsf_open_approvals_edit.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/easy_page_modules/easy_dms/_dmsf_open_approvals_show.html.erb b/app/views/easy_page_modules/easy_dms/_dmsf_open_approvals_show.html.erb index 36168c5f..12ebb4e0 100644 --- a/app/views/easy_page_modules/easy_dms/_dmsf_open_approvals_show.html.erb +++ b/app/views/easy_page_modules/easy_dms/_dmsf_open_approvals_show.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/hooks/redmine_dmsf/_view_my_account.html.erb b/app/views/hooks/redmine_dmsf/_view_my_account.html.erb index c43fe103..8afeee52 100644 --- a/app/views/hooks/redmine_dmsf/_view_my_account.html.erb +++ b/app/views/hooks/redmine_dmsf/_view_my_account.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/hooks/redmine_dmsf/_view_projects_form.html.erb b/app/views/hooks/redmine_dmsf/_view_projects_form.html.erb index 46cf9ddc..142ac535 100644 --- a/app/views/hooks/redmine_dmsf/_view_projects_form.html.erb +++ b/app/views/hooks/redmine_dmsf/_view_projects_form.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/hooks/redmine_dmsf/_view_users_bulk_edit.html.erb b/app/views/hooks/redmine_dmsf/_view_users_bulk_edit.html.erb index 71505c75..2fb23f54 100644 --- a/app/views/hooks/redmine_dmsf/_view_users_bulk_edit.html.erb +++ b/app/views/hooks/redmine_dmsf/_view_users_bulk_edit.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/my/blocks/_locked_documents.html.erb b/app/views/my/blocks/_locked_documents.html.erb index 6bf1ec1c..a7ca959a 100644 --- a/app/views/my/blocks/_locked_documents.html.erb +++ b/app/views/my/blocks/_locked_documents.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/my/blocks/_open_approvals.html.erb b/app/views/my/blocks/_open_approvals.html.erb index c6351a61..1c7b40fa 100644 --- a/app/views/my/blocks/_open_approvals.html.erb +++ b/app/views/my/blocks/_open_approvals.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/search/_container.html.erb b/app/views/search/_container.html.erb index 40a35513..f7ff051d 100644 --- a/app/views/search/_container.html.erb +++ b/app/views/search/_container.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # - # Copyright © 2011-18 Karel Pičman + # Copyright © 2011-19 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 diff --git a/app/views/settings/_dmsf_columns.html.erb b/app/views/settings/_dmsf_columns.html.erb index 5afb2657..0a962738 100644 --- a/app/views/settings/_dmsf_columns.html.erb +++ b/app/views/settings/_dmsf_columns.html.erb @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/app/views/settings/_dmsf_settings.html.erb b/app/views/settings/_dmsf_settings.html.erb index 501c8750..d29ffb97 100644 --- a/app/views/settings/_dmsf_settings.html.erb +++ b/app/views/settings/_dmsf_settings.html.erb @@ -5,7 +5,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/assets/javascripts/attachments_dmsf.js b/assets/javascripts/attachments_dmsf.js index dae3741a..daee4954 100644 --- a/assets/javascripts/attachments_dmsf.js +++ b/assets/javascripts/attachments_dmsf.js @@ -2,7 +2,7 @@ * * Redmine plugin for Document Management System "Features" * - * Copyright © 2011-18 Karel Pičman + * Copyright © 2011-19 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 diff --git a/assets/javascripts/redmine_dmsf.js b/assets/javascripts/redmine_dmsf.js index e110e793..6628f0a6 100644 --- a/assets/javascripts/redmine_dmsf.js +++ b/assets/javascripts/redmine_dmsf.js @@ -2,7 +2,7 @@ * * Redmine plugin for Document Management System "Features" * -* Copyright © 2011-18 Karel Pičman +* Copyright © 2011-19 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 diff --git a/assets/stylesheets/redmine_dmsf.css b/assets/stylesheets/redmine_dmsf.css index 0c4f9203..3eb9b36d 100644 --- a/assets/stylesheets/redmine_dmsf.css +++ b/assets/stylesheets/redmine_dmsf.css @@ -2,7 +2,7 @@ * Redmine plugin for Document Management System "Features" * * Copyright © 2011 Vit Jonas -* Copyright © 2011-18 Karel Pičman +* Copyright © 2011-19 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 diff --git a/config/locales/cs.yml b/config/locales/cs.yml index c9a29d44..e6f57ade 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 Karel Pičman # # # This program is free software; you can redistribute it and/or diff --git a/config/locales/de.yml b/config/locales/de.yml index 91e9daab..52a65ec3 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -4,7 +4,7 @@ # # Copyright © 2011 Terrence Miller # Copyright © 2013 Christian Wetting -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/config/locales/en.yml b/config/locales/en.yml index 6b556592..35ed3338 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/config/locales/es.yml b/config/locales/es.yml index 744ed5fc..e8425082 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2015 Agustin Ivorra -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/config/locales/fr.yml b/config/locales/fr.yml index ad0d3ef8..f9f65187 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -5,7 +5,7 @@ # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn # Copyright © 2014 Atmis -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 76ea4a73..74632f8a 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 Karel Pičman # # # diff --git a/config/locales/it.yml b/config/locales/it.yml index aa68189b..6d8381ad 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 3c960522..f135259a 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 Karel Pičman # # # This program is free software; you can redistribute it and/or diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 964c650a..ee09dfec 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -3,7 +3,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright (C) 2011-18 Karel Pičman +# Copyright (C) 2011-19 Karel Pičman # # # This program is free software; you can redistribute it and/or diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 3f371347..a02f2de7 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright (C) 2011-18 Karel Pičman +# Copyright (C) 2011-19 Karel Pičman # # # diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 4b805690..d8267bbb 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 Karel Pičman # Polish translation created by Sebastian Białas www.bs-it.pl # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index ac08ca6e..e96d0f8d 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/config/locales/ru.yml b/config/locales/ru.yml index c76574ea..e1533747 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 Karel Pičman # # # This program is free software; you can redistribute it and/or diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 78004bb9..6a2f9601 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Zdravko Balorda -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 Karel Pičman # # # This program is free software; you can redistribute it and/or diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index ddc9b062..acbe4245 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 Karel Pičman # Copyright © 2013 Aecho Liu # # This program is free software; you can redistribute it and/or diff --git a/config/locales/zh.yml b/config/locales/zh.yml index 5b422dd5..a2fe75e7 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 Karel Pičman # # # This program is free software; you can redistribute it and/or diff --git a/config/routes.rb b/config/routes.rb index f9c4860a..385c4569 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/01_create_hierarchy.rb b/db/migrate/01_create_hierarchy.rb index 49ef8ae9..03e4e0b2 100644 --- a/db/migrate/01_create_hierarchy.rb +++ b/db/migrate/01_create_hierarchy.rb @@ -1,7 +1,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/02_dmsf_normalization.rb b/db/migrate/02_dmsf_normalization.rb index f8023026..e39588d9 100644 --- a/db/migrate/02_dmsf_normalization.rb +++ b/db/migrate/02_dmsf_normalization.rb @@ -1,7 +1,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/03_dmsf_0_8_0.rb b/db/migrate/03_dmsf_0_8_0.rb index 0f1387cb..19f07832 100644 --- a/db/migrate/03_dmsf_0_8_0.rb +++ b/db/migrate/03_dmsf_0_8_0.rb @@ -1,7 +1,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/04_dmsf_0_9_0.rb b/db/migrate/04_dmsf_0_9_0.rb index 047c0634..de1d03f1 100644 --- a/db/migrate/04_dmsf_0_9_0.rb +++ b/db/migrate/04_dmsf_0_9_0.rb @@ -1,7 +1,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/05_dmsf_0_9_0_1.rb b/db/migrate/05_dmsf_0_9_0_1.rb index af35f0af..f8981a85 100644 --- a/db/migrate/05_dmsf_0_9_0_1.rb +++ b/db/migrate/05_dmsf_0_9_0_1.rb @@ -1,7 +1,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/06_dmsf_1_2_0.rb b/db/migrate/06_dmsf_1_2_0.rb index 33424599..b9154ba2 100644 --- a/db/migrate/06_dmsf_1_2_0.rb +++ b/db/migrate/06_dmsf_1_2_0.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/07_dmsf_1_4_4.rb b/db/migrate/07_dmsf_1_4_4.rb index 48fd0af7..8d65f75c 100644 --- a/db/migrate/07_dmsf_1_4_4.rb +++ b/db/migrate/07_dmsf_1_4_4.rb @@ -1,7 +1,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20120822100401_create_dmsf_workflows.rb b/db/migrate/20120822100401_create_dmsf_workflows.rb index 3661c38f..0f516dd4 100644 --- a/db/migrate/20120822100401_create_dmsf_workflows.rb +++ b/db/migrate/20120822100401_create_dmsf_workflows.rb @@ -2,8 +2,8 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20120822100402_create_dmsf_workflow_steps.rb b/db/migrate/20120822100402_create_dmsf_workflow_steps.rb index 2dd9e0fa..bfe387b6 100644 --- a/db/migrate/20120822100402_create_dmsf_workflow_steps.rb +++ b/db/migrate/20120822100402_create_dmsf_workflow_steps.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20120822100403_create_dmsf_workflow_step_assignments.rb b/db/migrate/20120822100403_create_dmsf_workflow_step_assignments.rb index 42523cf6..c5691233 100644 --- a/db/migrate/20120822100403_create_dmsf_workflow_step_assignments.rb +++ b/db/migrate/20120822100403_create_dmsf_workflow_step_assignments.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20120822100404_create_dmsf_workflow_step_actions.rb b/db/migrate/20120822100404_create_dmsf_workflow_step_actions.rb index 7433e272..53f812a0 100644 --- a/db/migrate/20120822100404_create_dmsf_workflow_step_actions.rb +++ b/db/migrate/20120822100404_create_dmsf_workflow_step_actions.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20130819013955_update_projects.rb b/db/migrate/20130819013955_update_projects.rb index a3f07ab5..9024207d 100644 --- a/db/migrate/20130819013955_update_projects.rb +++ b/db/migrate/20130819013955_update_projects.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20131108141401_add_index_to_dmsf_files.rb b/db/migrate/20131108141401_add_index_to_dmsf_files.rb index a4ccf91c..36fac7b6 100644 --- a/db/migrate/20131108141401_add_index_to_dmsf_files.rb +++ b/db/migrate/20131108141401_add_index_to_dmsf_files.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20131108141402_add_index_to_dmsf_folders.rb b/db/migrate/20131108141402_add_index_to_dmsf_folders.rb index be1c3e29..03b7c14d 100644 --- a/db/migrate/20131108141402_add_index_to_dmsf_folders.rb +++ b/db/migrate/20131108141402_add_index_to_dmsf_folders.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20131113141401_add_index_to_dmsf_file_revision.rb b/db/migrate/20131113141401_add_index_to_dmsf_file_revision.rb index 61dfc6f5..5c815e11 100644 --- a/db/migrate/20131113141401_add_index_to_dmsf_file_revision.rb +++ b/db/migrate/20131113141401_add_index_to_dmsf_file_revision.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20131113141402_add_index_to_dmsf_lock.rb b/db/migrate/20131113141402_add_index_to_dmsf_lock.rb index ba51c200..310db5fb 100644 --- a/db/migrate/20131113141402_add_index_to_dmsf_lock.rb +++ b/db/migrate/20131113141402_add_index_to_dmsf_lock.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20131113141403_create_dmsf_links.rb b/db/migrate/20131113141403_create_dmsf_links.rb index 45d6cd56..62e98f37 100644 --- a/db/migrate/20131113141403_create_dmsf_links.rb +++ b/db/migrate/20131113141403_create_dmsf_links.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20140314132501_notifications_on.rb b/db/migrate/20140314132501_notifications_on.rb index 8f190207..fef60903 100644 --- a/db/migrate/20140314132501_notifications_on.rb +++ b/db/migrate/20140314132501_notifications_on.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20140519133201_trash_bin.rb b/db/migrate/20140519133201_trash_bin.rb index e9ce27f2..ba0aaad8 100644 --- a/db/migrate/20140519133201_trash_bin.rb +++ b/db/migrate/20140519133201_trash_bin.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20141013102501_remove_project_from_revision.rb b/db/migrate/20141013102501_remove_project_from_revision.rb index c5fdd785..c3ac23f7 100644 --- a/db/migrate/20141013102501_remove_project_from_revision.rb +++ b/db/migrate/20141013102501_remove_project_from_revision.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20141015132701_remove_folder_from_revision.rb b/db/migrate/20141015132701_remove_folder_from_revision.rb index ef30cbc4..f0b7370b 100644 --- a/db/migrate/20141015132701_remove_folder_from_revision.rb +++ b/db/migrate/20141015132701_remove_folder_from_revision.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20141205143001_remove_uniqueness_from_wf.rb b/db/migrate/20141205143001_remove_uniqueness_from_wf.rb index 18fce0be..96f73318 100644 --- a/db/migrate/20141205143001_remove_uniqueness_from_wf.rb +++ b/db/migrate/20141205143001_remove_uniqueness_from_wf.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20150120152101_notifications_nullable.rb b/db/migrate/20150120152101_notifications_nullable.rb index e0e27b81..45f7bd7a 100644 --- a/db/migrate/20150120152101_notifications_nullable.rb +++ b/db/migrate/20150120152101_notifications_nullable.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20150130052716_add_external.rb b/db/migrate/20150130052716_add_external.rb index 2fe116b6..81029635 100644 --- a/db/migrate/20150130052716_add_external.rb +++ b/db/migrate/20150130052716_add_external.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20150202010301_add_user_to_links.rb b/db/migrate/20150202010301_add_user_to_links.rb index 13fc4333..7c67fc7e 100644 --- a/db/migrate/20150202010301_add_user_to_links.rb +++ b/db/migrate/20150202010301_add_user_to_links.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20150910153701_title_not_null.rb b/db/migrate/20150910153701_title_not_null.rb index 14be804a..8b059c18 100644 --- a/db/migrate/20150910153701_title_not_null.rb +++ b/db/migrate/20150910153701_title_not_null.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20151020141801_large_files.rb b/db/migrate/20151020141801_large_files.rb index fe4442bc..8017541a 100644 --- a/db/migrate/20151020141801_large_files.rb +++ b/db/migrate/20151020141801_large_files.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20151209100001_title_format.rb b/db/migrate/20151209100001_title_format.rb index 8cd48d09..9b762cbb 100644 --- a/db/migrate/20151209100001_title_format.rb +++ b/db/migrate/20151209100001_title_format.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20160215125801_approval_workflow_status.rb b/db/migrate/20160215125801_approval_workflow_status.rb index 08c7b71d..43bfc70a 100644 --- a/db/migrate/20160215125801_approval_workflow_status.rb +++ b/db/migrate/20160215125801_approval_workflow_status.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20160217133001_status_deleted.rb b/db/migrate/20160217133001_status_deleted.rb index 2e539fb5..6042e194 100644 --- a/db/migrate/20160217133001_status_deleted.rb +++ b/db/migrate/20160217133001_status_deleted.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20160222140401_approval_workflow_std_fields.rb b/db/migrate/20160222140401_approval_workflow_std_fields.rb index fa3fdc00..43a0404d 100644 --- a/db/migrate/20160222140401_approval_workflow_std_fields.rb +++ b/db/migrate/20160222140401_approval_workflow_std_fields.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20160421150501_add_digest_to_revision.rb b/db/migrate/20160421150501_add_digest_to_revision.rb index b103c951..b1f0dc7d 100644 --- a/db/migrate/20160421150501_add_digest_to_revision.rb +++ b/db/migrate/20160421150501_add_digest_to_revision.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20161223133200_create_dmsf_public_urls.rb b/db/migrate/20161223133200_create_dmsf_public_urls.rb index cd5447c7..e4b5d1aa 100644 --- a/db/migrate/20161223133200_create_dmsf_public_urls.rb +++ b/db/migrate/20161223133200_create_dmsf_public_urls.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20170103164701_add_name_to_appoval_workflow_step.rb b/db/migrate/20170103164701_add_name_to_appoval_workflow_step.rb index c39e4a8d..81b482fb 100644 --- a/db/migrate/20170103164701_add_name_to_appoval_workflow_step.rb +++ b/db/migrate/20170103164701_add_name_to_appoval_workflow_step.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20170118142001_dmsf_file_container.rb b/db/migrate/20170118142001_dmsf_file_container.rb index 4528b643..80d7d23b 100644 --- a/db/migrate/20170118142001_dmsf_file_container.rb +++ b/db/migrate/20170118142001_dmsf_file_container.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20170204214753_add_revision_to_dmsf_lock.rb b/db/migrate/20170204214753_add_revision_to_dmsf_lock.rb index faa44ae7..a4566529 100644 --- a/db/migrate/20170204214753_add_revision_to_dmsf_lock.rb +++ b/db/migrate/20170204214753_add_revision_to_dmsf_lock.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 Karel Pičman # Copyright © 2016-17 carlolars # # This program is free software; you can redistribute it and/or diff --git a/db/migrate/20170214153223_add_dmsf_file_last_revision_id_to_dmsf_lock.rb b/db/migrate/20170214153223_add_dmsf_file_last_revision_id_to_dmsf_lock.rb index 19f64be1..0cb2c532 100644 --- a/db/migrate/20170214153223_add_dmsf_file_last_revision_id_to_dmsf_lock.rb +++ b/db/migrate/20170214153223_add_dmsf_file_last_revision_id_to_dmsf_lock.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 Karel Pičman # Copyright © 2016-17 carlolars # # This program is free software; you can redistribute it and/or diff --git a/db/migrate/20170217141601_add_dmsf_not_inheritable_to_custom_fields.rb b/db/migrate/20170217141601_add_dmsf_not_inheritable_to_custom_fields.rb index 08a8a052..fb8ec475 100644 --- a/db/migrate/20170217141601_add_dmsf_not_inheritable_to_custom_fields.rb +++ b/db/migrate/20170217141601_add_dmsf_not_inheritable_to_custom_fields.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20170323131231_dmsf_description_limit.rb b/db/migrate/20170323131231_dmsf_description_limit.rb index 9e720736..12a2eeeb 100644 --- a/db/migrate/20170323131231_dmsf_description_limit.rb +++ b/db/migrate/20170323131231_dmsf_description_limit.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20170330131901_create_dmsf_folder_permissions.rb b/db/migrate/20170330131901_create_dmsf_folder_permissions.rb index 4429bbb0..c2015467 100644 --- a/db/migrate/20170330131901_create_dmsf_folder_permissions.rb +++ b/db/migrate/20170330131901_create_dmsf_folder_permissions.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20170421101901_dmsf_file_container_rollback.rb b/db/migrate/20170421101901_dmsf_file_container_rollback.rb index 4480cac5..81d8449e 100644 --- a/db/migrate/20170421101901_dmsf_file_container_rollback.rb +++ b/db/migrate/20170421101901_dmsf_file_container_rollback.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20170422104901_migrate_documents.rb b/db/migrate/20170422104901_migrate_documents.rb index baec86be..e9ec1eaa 100644 --- a/db/migrate/20170422104901_migrate_documents.rb +++ b/db/migrate/20170422104901_migrate_documents.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20170526144701_dmsf_attachable.rb b/db/migrate/20170526144701_dmsf_attachable.rb index fd33aa7d..33729921 100644 --- a/db/migrate/20170526144701_dmsf_attachable.rb +++ b/db/migrate/20170526144701_dmsf_attachable.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20171027124101_change_revision_digest_limit_to_64.rb b/db/migrate/20171027124101_change_revision_digest_limit_to_64.rb index a4cb84f3..679221a4 100644 --- a/db/migrate/20171027124101_change_revision_digest_limit_to_64.rb +++ b/db/migrate/20171027124101_change_revision_digest_limit_to_64.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20171110155901_add_index_to_dmsf_folder.rb b/db/migrate/20171110155901_add_index_to_dmsf_folder.rb index 55dac6ce..98e74b5e 100644 --- a/db/migrate/20171110155901_add_index_to_dmsf_folder.rb +++ b/db/migrate/20171110155901_add_index_to_dmsf_folder.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20180216152501_rename_title_format.rb b/db/migrate/20180216152501_rename_title_format.rb index aa337cdd..436f35d6 100644 --- a/db/migrate/20180216152501_rename_title_format.rb +++ b/db/migrate/20180216152501_rename_title_format.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/db/migrate/20180903132101_fast_links.rb b/db/migrate/20180903132101_fast_links.rb index f0627023..39b4d541 100644 --- a/db/migrate/20180903132101_fast_links.rb +++ b/db/migrate/20180903132101_fast_links.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/extra/api/api_client.rb b/extra/api/api_client.rb index 13521ca9..1cf503d1 100644 --- a/extra/api/api_client.rb +++ b/extra/api/api_client.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/extra/api/api_client.sh b/extra/api/api_client.sh index 7881a614..809af17b 100644 --- a/extra/api/api_client.sh +++ b/extra/api/api_client.sh @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/extra/xapian_indexer.rb b/extra/xapian_indexer.rb index 5e1607f5..bd1aa0dc 100644 --- a/extra/xapian_indexer.rb +++ b/extra/xapian_indexer.rb @@ -5,7 +5,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2010 Xabier Elkano -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/init.rb b/init.rb index cf49015b..07def7a2 100644 --- a/init.rb +++ b/init.rb @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/dmsf_zip.rb b/lib/dmsf_zip.rb index 0fe1a2d9..2befcf62 100644 --- a/lib/dmsf_zip.rb +++ b/lib/dmsf_zip.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf.rb b/lib/redmine_dmsf.rb index 8ac7bfc5..8913c4f4 100644 --- a/lib/redmine_dmsf.rb +++ b/lib/redmine_dmsf.rb @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/errors/dmsf_access_error.rb b/lib/redmine_dmsf/errors/dmsf_access_error.rb index 550ebdb8..108ba6a0 100644 --- a/lib/redmine_dmsf/errors/dmsf_access_error.rb +++ b/lib/redmine_dmsf/errors/dmsf_access_error.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/errors/dmsf_content_error.rb b/lib/redmine_dmsf/errors/dmsf_content_error.rb index 2e1cea44..8cd695fd 100644 --- a/lib/redmine_dmsf/errors/dmsf_content_error.rb +++ b/lib/redmine_dmsf/errors/dmsf_content_error.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/errors/dmsf_email_max_file_error.rb b/lib/redmine_dmsf/errors/dmsf_email_max_file_error.rb index bf6460fd..d4f4113c 100644 --- a/lib/redmine_dmsf/errors/dmsf_email_max_file_error.rb +++ b/lib/redmine_dmsf/errors/dmsf_email_max_file_error.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/errors/dmsf_file_not_found_error.rb b/lib/redmine_dmsf/errors/dmsf_file_not_found_error.rb index 112adaeb..4801b3bf 100644 --- a/lib/redmine_dmsf/errors/dmsf_file_not_found_error.rb +++ b/lib/redmine_dmsf/errors/dmsf_file_not_found_error.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/errors/dmsf_lock_error.rb b/lib/redmine_dmsf/errors/dmsf_lock_error.rb index ba140072..613a6b3d 100644 --- a/lib/redmine_dmsf/errors/dmsf_lock_error.rb +++ b/lib/redmine_dmsf/errors/dmsf_lock_error.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/errors/dmsf_zip_max_file_error.rb b/lib/redmine_dmsf/errors/dmsf_zip_max_file_error.rb index 51612002..51d7e6b5 100644 --- a/lib/redmine_dmsf/errors/dmsf_zip_max_file_error.rb +++ b/lib/redmine_dmsf/errors/dmsf_zip_max_file_error.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb b/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb index 7aacb8b1..c6d38c4e 100644 --- a/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb +++ b/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/hooks/controllers/search_controller_hooks.rb b/lib/redmine_dmsf/hooks/controllers/search_controller_hooks.rb index 28af2fa0..90516b29 100644 --- a/lib/redmine_dmsf/hooks/controllers/search_controller_hooks.rb +++ b/lib/redmine_dmsf/hooks/controllers/search_controller_hooks.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/hooks/helpers/issues_helper_hooks.rb b/lib/redmine_dmsf/hooks/helpers/issues_helper_hooks.rb index 1e9b797e..d18f5455 100644 --- a/lib/redmine_dmsf/hooks/helpers/issues_helper_hooks.rb +++ b/lib/redmine_dmsf/hooks/helpers/issues_helper_hooks.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/hooks/helpers/search_helper_hooks.rb b/lib/redmine_dmsf/hooks/helpers/search_helper_hooks.rb index f942a53a..4aa9001a 100644 --- a/lib/redmine_dmsf/hooks/helpers/search_helper_hooks.rb +++ b/lib/redmine_dmsf/hooks/helpers/search_helper_hooks.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/hooks/views/base_view_hooks.rb b/lib/redmine_dmsf/hooks/views/base_view_hooks.rb index 60c20084..310d1ef0 100644 --- a/lib/redmine_dmsf/hooks/views/base_view_hooks.rb +++ b/lib/redmine_dmsf/hooks/views/base_view_hooks.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/hooks/views/custom_field_view_hooks.rb b/lib/redmine_dmsf/hooks/views/custom_field_view_hooks.rb index 3d305d12..8d5629e8 100644 --- a/lib/redmine_dmsf/hooks/views/custom_field_view_hooks.rb +++ b/lib/redmine_dmsf/hooks/views/custom_field_view_hooks.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb b/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb index f8b6dcf3..fccf907f 100644 --- a/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb +++ b/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/hooks/views/my_account_view_hooks.rb b/lib/redmine_dmsf/hooks/views/my_account_view_hooks.rb index 253b29ce..8f072405 100644 --- a/lib/redmine_dmsf/hooks/views/my_account_view_hooks.rb +++ b/lib/redmine_dmsf/hooks/views/my_account_view_hooks.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/hooks/views/search_view_hooks.rb b/lib/redmine_dmsf/hooks/views/search_view_hooks.rb index d9fb95e8..199f1842 100644 --- a/lib/redmine_dmsf/hooks/views/search_view_hooks.rb +++ b/lib/redmine_dmsf/hooks/views/search_view_hooks.rb @@ -1,6 +1,6 @@ # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/hooks/views/view_projects_form_hook.rb b/lib/redmine_dmsf/hooks/views/view_projects_form_hook.rb index fc3535ec..7abb3f23 100644 --- a/lib/redmine_dmsf/hooks/views/view_projects_form_hook.rb +++ b/lib/redmine_dmsf/hooks/views/view_projects_form_hook.rb @@ -1,6 +1,6 @@ # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/lockable.rb b/lib/redmine_dmsf/lockable.rb index 146a950f..fae03947 100644 --- a/lib/redmine_dmsf/lockable.rb +++ b/lib/redmine_dmsf/lockable.rb @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/macros.rb b/lib/redmine_dmsf/macros.rb index e93b43da..17eaf471 100644 --- a/lib/redmine_dmsf/macros.rb +++ b/lib/redmine_dmsf/macros.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/patches/attachable_patch.rb b/lib/redmine_dmsf/patches/attachable_patch.rb index a4376a63..c1f77bd3 100644 --- a/lib/redmine_dmsf/patches/attachable_patch.rb +++ b/lib/redmine_dmsf/patches/attachable_patch.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/patches/easy_crm_case_patch.rb b/lib/redmine_dmsf/patches/easy_crm_case_patch.rb index 4d4884f1..e493e1bd 100644 --- a/lib/redmine_dmsf/patches/easy_crm_case_patch.rb +++ b/lib/redmine_dmsf/patches/easy_crm_case_patch.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/patches/easy_crm_cases_controller_patch.rb b/lib/redmine_dmsf/patches/easy_crm_cases_controller_patch.rb index 86439d98..fff0365d 100644 --- a/lib/redmine_dmsf/patches/easy_crm_cases_controller_patch.rb +++ b/lib/redmine_dmsf/patches/easy_crm_cases_controller_patch.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/patches/issue_patch.rb b/lib/redmine_dmsf/patches/issue_patch.rb index e2776ae0..0a044203 100644 --- a/lib/redmine_dmsf/patches/issue_patch.rb +++ b/lib/redmine_dmsf/patches/issue_patch.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/patches/project_patch.rb b/lib/redmine_dmsf/patches/project_patch.rb index 52679710..b2a0f77c 100644 --- a/lib/redmine_dmsf/patches/project_patch.rb +++ b/lib/redmine_dmsf/patches/project_patch.rb @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/patches/projects_helper_patch.rb b/lib/redmine_dmsf/patches/projects_helper_patch.rb index 5105a784..5c1730d9 100644 --- a/lib/redmine_dmsf/patches/projects_helper_patch.rb +++ b/lib/redmine_dmsf/patches/projects_helper_patch.rb @@ -2,7 +2,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/patches/role_patch.rb b/lib/redmine_dmsf/patches/role_patch.rb index cd0ab8b4..f1544176 100644 --- a/lib/redmine_dmsf/patches/role_patch.rb +++ b/lib/redmine_dmsf/patches/role_patch.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/patches/user_patch.rb b/lib/redmine_dmsf/patches/user_patch.rb index 666c0cd4..46b8cb23 100644 --- a/lib/redmine_dmsf/patches/user_patch.rb +++ b/lib/redmine_dmsf/patches/user_patch.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/patches/user_preference_patch.rb b/lib/redmine_dmsf/patches/user_preference_patch.rb index 1447f70d..f4a4ec95 100644 --- a/lib/redmine_dmsf/patches/user_preference_patch.rb +++ b/lib/redmine_dmsf/patches/user_preference_patch.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/test/integration_test.rb b/lib/redmine_dmsf/test/integration_test.rb index 57b73e47..b933df66 100644 --- a/lib/redmine_dmsf/test/integration_test.rb +++ b/lib/redmine_dmsf/test/integration_test.rb @@ -3,7 +3,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/test/unit_test.rb b/lib/redmine_dmsf/test/unit_test.rb index 4fc84545..5d98cd48 100644 --- a/lib/redmine_dmsf/test/unit_test.rb +++ b/lib/redmine_dmsf/test/unit_test.rb @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/webdav/base_resource.rb b/lib/redmine_dmsf/webdav/base_resource.rb index 0bd8f1df..3395fbed 100644 --- a/lib/redmine_dmsf/webdav/base_resource.rb +++ b/lib/redmine_dmsf/webdav/base_resource.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/webdav/custom_middleware.rb b/lib/redmine_dmsf/webdav/custom_middleware.rb index be81c422..d4619581 100644 --- a/lib/redmine_dmsf/webdav/custom_middleware.rb +++ b/lib/redmine_dmsf/webdav/custom_middleware.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/webdav/dmsf_resource.rb b/lib/redmine_dmsf/webdav/dmsf_resource.rb index 6b456c8d..a43b9806 100644 --- a/lib/redmine_dmsf/webdav/dmsf_resource.rb +++ b/lib/redmine_dmsf/webdav/dmsf_resource.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/webdav/index_resource.rb b/lib/redmine_dmsf/webdav/index_resource.rb index 3de6e450..6883f61d 100644 --- a/lib/redmine_dmsf/webdav/index_resource.rb +++ b/lib/redmine_dmsf/webdav/index_resource.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/webdav/project_resource.rb b/lib/redmine_dmsf/webdav/project_resource.rb index 93201e1e..cf0989fa 100644 --- a/lib/redmine_dmsf/webdav/project_resource.rb +++ b/lib/redmine_dmsf/webdav/project_resource.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/redmine_dmsf/webdav/resource_proxy.rb b/lib/redmine_dmsf/webdav/resource_proxy.rb index 71ec0d14..d9ab5722 100644 --- a/lib/redmine_dmsf/webdav/resource_proxy.rb +++ b/lib/redmine_dmsf/webdav/resource_proxy.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/tasks/dmsf_alert_approvals.rake b/lib/tasks/dmsf_alert_approvals.rake index 489f4f34..1925be10 100644 --- a/lib/tasks/dmsf_alert_approvals.rake +++ b/lib/tasks/dmsf_alert_approvals.rake @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/tasks/dmsf_convert_documents.rake b/lib/tasks/dmsf_convert_documents.rake index f9f6b206..ea6b565f 100644 --- a/lib/tasks/dmsf_convert_documents.rake +++ b/lib/tasks/dmsf_convert_documents.rake @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2011 Vít Jonáš -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/tasks/dmsf_create_digests.rake b/lib/tasks/dmsf_create_digests.rake index bc55f392..95f88a15 100644 --- a/lib/tasks/dmsf_create_digests.rake +++ b/lib/tasks/dmsf_create_digests.rake @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/lib/tasks/dmsf_maintenance.rake b/lib/tasks/dmsf_maintenance.rake index 73654654..69183d35 100644 --- a/lib/tasks/dmsf_maintenance.rake +++ b/lib/tasks/dmsf_maintenance.rake @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/ci/redmine_install.sh b/test/ci/redmine_install.sh index 4d772be0..da85a5a5 100644 --- a/test/ci/redmine_install.sh +++ b/test/ci/redmine_install.sh @@ -4,7 +4,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/fixtures/custom_fields.yml b/test/fixtures/custom_fields.yml index d9cdb6d1..e8ffe537 100644 --- a/test/fixtures/custom_fields.yml +++ b/test/fixtures/custom_fields.yml @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/fixtures/custom_values.yml b/test/fixtures/custom_values.yml index d276b12e..8ec518dd 100644 --- a/test/fixtures/custom_values.yml +++ b/test/fixtures/custom_values.yml @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/dmsf_context_menus_controller_test.rb b/test/functional/dmsf_context_menus_controller_test.rb index d41e8e50..cb3e8d31 100644 --- a/test/functional/dmsf_context_menus_controller_test.rb +++ b/test/functional/dmsf_context_menus_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/dmsf_controller_test.rb b/test/functional/dmsf_controller_test.rb index bad83326..1054e8da 100644 --- a/test/functional/dmsf_controller_test.rb +++ b/test/functional/dmsf_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/dmsf_files_controller_test.rb b/test/functional/dmsf_files_controller_test.rb index 9b1ae46a..1f0c6c99 100644 --- a/test/functional/dmsf_files_controller_test.rb +++ b/test/functional/dmsf_files_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/dmsf_files_copy_controller_test.rb b/test/functional/dmsf_files_copy_controller_test.rb index 701639ad..6e270a27 100644 --- a/test/functional/dmsf_files_copy_controller_test.rb +++ b/test/functional/dmsf_files_copy_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/dmsf_folder_permissions_controller_test.rb b/test/functional/dmsf_folder_permissions_controller_test.rb index b53ef286..e54589bb 100644 --- a/test/functional/dmsf_folder_permissions_controller_test.rb +++ b/test/functional/dmsf_folder_permissions_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/dmsf_folders_copy_controller_test.rb b/test/functional/dmsf_folders_copy_controller_test.rb index 4da4c611..9fc14159 100644 --- a/test/functional/dmsf_folders_copy_controller_test.rb +++ b/test/functional/dmsf_folders_copy_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/dmsf_links_controller_test.rb b/test/functional/dmsf_links_controller_test.rb index 019cc286..43efa2f3 100644 --- a/test/functional/dmsf_links_controller_test.rb +++ b/test/functional/dmsf_links_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/dmsf_public_urls_controller_test.rb b/test/functional/dmsf_public_urls_controller_test.rb index da4845a7..ba6f07b9 100644 --- a/test/functional/dmsf_public_urls_controller_test.rb +++ b/test/functional/dmsf_public_urls_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/dmsf_state_controller_test.rb b/test/functional/dmsf_state_controller_test.rb index 1cab016e..69c42733 100644 --- a/test/functional/dmsf_state_controller_test.rb +++ b/test/functional/dmsf_state_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/dmsf_workflow_controller_test.rb b/test/functional/dmsf_workflow_controller_test.rb index a879ca40..4b526a93 100644 --- a/test/functional/dmsf_workflow_controller_test.rb +++ b/test/functional/dmsf_workflow_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index aa84cc4e..108ba90f 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/functional/my_controller_test.rb b/test/functional/my_controller_test.rb index 4abaecf9..61e07986 100644 --- a/test/functional/my_controller_test.rb +++ b/test/functional/my_controller_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/rest_api/dmsf_file_api_test.rb b/test/integration/rest_api/dmsf_file_api_test.rb index 6ee39187..b9c04428 100644 --- a/test/integration/rest_api/dmsf_file_api_test.rb +++ b/test/integration/rest_api/dmsf_file_api_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/rest_api/dmsf_folder_api_test.rb b/test/integration/rest_api/dmsf_folder_api_test.rb index 077b5b08..7dc436a5 100644 --- a/test/integration/rest_api/dmsf_folder_api_test.rb +++ b/test/integration/rest_api/dmsf_folder_api_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/rest_api/dmsf_link_api_test.rb b/test/integration/rest_api/dmsf_link_api_test.rb index 7c08d88f..b336d3a8 100644 --- a/test/integration/rest_api/dmsf_link_api_test.rb +++ b/test/integration/rest_api/dmsf_link_api_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/webdav/dmsf_webdav_custom_middleware_test.rb b/test/integration/webdav/dmsf_webdav_custom_middleware_test.rb index 25f36f35..66ee63e8 100644 --- a/test/integration/webdav/dmsf_webdav_custom_middleware_test.rb +++ b/test/integration/webdav/dmsf_webdav_custom_middleware_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/webdav/dmsf_webdav_delete_test.rb b/test/integration/webdav/dmsf_webdav_delete_test.rb index 73da5af9..f754cb99 100644 --- a/test/integration/webdav/dmsf_webdav_delete_test.rb +++ b/test/integration/webdav/dmsf_webdav_delete_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/webdav/dmsf_webdav_get_test.rb b/test/integration/webdav/dmsf_webdav_get_test.rb index d2738b5d..d422905a 100644 --- a/test/integration/webdav/dmsf_webdav_get_test.rb +++ b/test/integration/webdav/dmsf_webdav_get_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/webdav/dmsf_webdav_head_test.rb b/test/integration/webdav/dmsf_webdav_head_test.rb index d14d1b26..d7d07b82 100644 --- a/test/integration/webdav/dmsf_webdav_head_test.rb +++ b/test/integration/webdav/dmsf_webdav_head_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/webdav/dmsf_webdav_lock_test.rb b/test/integration/webdav/dmsf_webdav_lock_test.rb index bda56018..abea5540 100644 --- a/test/integration/webdav/dmsf_webdav_lock_test.rb +++ b/test/integration/webdav/dmsf_webdav_lock_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/webdav/dmsf_webdav_mkcol_test.rb b/test/integration/webdav/dmsf_webdav_mkcol_test.rb index d4a298b9..d5f9ab86 100644 --- a/test/integration/webdav/dmsf_webdav_mkcol_test.rb +++ b/test/integration/webdav/dmsf_webdav_mkcol_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/webdav/dmsf_webdav_move_test.rb b/test/integration/webdav/dmsf_webdav_move_test.rb index 4060e5d5..ba3b8d07 100644 --- a/test/integration/webdav/dmsf_webdav_move_test.rb +++ b/test/integration/webdav/dmsf_webdav_move_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/webdav/dmsf_webdav_options_test.rb b/test/integration/webdav/dmsf_webdav_options_test.rb index 38e77d62..83821894 100644 --- a/test/integration/webdav/dmsf_webdav_options_test.rb +++ b/test/integration/webdav/dmsf_webdav_options_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/webdav/dmsf_webdav_post_test.rb b/test/integration/webdav/dmsf_webdav_post_test.rb index b7ec4fa8..fc438570 100644 --- a/test/integration/webdav/dmsf_webdav_post_test.rb +++ b/test/integration/webdav/dmsf_webdav_post_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/webdav/dmsf_webdav_propfind_test.rb b/test/integration/webdav/dmsf_webdav_propfind_test.rb index 348bd355..e97c1147 100644 --- a/test/integration/webdav/dmsf_webdav_propfind_test.rb +++ b/test/integration/webdav/dmsf_webdav_propfind_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/integration/webdav/dmsf_webdav_put_test.rb b/test/integration/webdav/dmsf_webdav_put_test.rb index e57ae4fe..eff05997 100644 --- a/test/integration/webdav/dmsf_webdav_put_test.rb +++ b/test/integration/webdav/dmsf_webdav_put_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/test_helper.rb b/test/test_helper.rb index 018c6142..339ba58f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -4,7 +4,7 @@ # # Copyright © 2011 Vít Jonáš # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/attachable_patch_test.rb b/test/unit/attachable_patch_test.rb index 2bcad8ea..7fbbc718 100644 --- a/test/unit/attachable_patch_test.rb +++ b/test/unit/attachable_patch_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_file_revision_test.rb b/test/unit/dmsf_file_revision_test.rb index 98612c86..36eac40c 100644 --- a/test/unit/dmsf_file_revision_test.rb +++ b/test/unit/dmsf_file_revision_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_file_test.rb b/test/unit/dmsf_file_test.rb index 3da1f607..84abc6d8 100644 --- a/test/unit/dmsf_file_test.rb +++ b/test/unit/dmsf_file_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_folder_permission_test.rb b/test/unit/dmsf_folder_permission_test.rb index cfe9bf41..039b0305 100644 --- a/test/unit/dmsf_folder_permission_test.rb +++ b/test/unit/dmsf_folder_permission_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_folder_test.rb b/test/unit/dmsf_folder_test.rb index 0765c06d..03a76ad9 100644 --- a/test/unit/dmsf_folder_test.rb +++ b/test/unit/dmsf_folder_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_link_test.rb b/test/unit/dmsf_link_test.rb index 8e0ea792..21efb8fe 100644 --- a/test/unit/dmsf_link_test.rb +++ b/test/unit/dmsf_link_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_lock_test.rb b/test/unit/dmsf_lock_test.rb index 6759c00d..c8030d24 100644 --- a/test/unit/dmsf_lock_test.rb +++ b/test/unit/dmsf_lock_test.rb @@ -3,7 +3,7 @@ # Redmine plugin for Document Management System "Features" # # Copyright © 2012 Daniel Munn -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_mailer_test.rb b/test/unit/dmsf_mailer_test.rb index d90d55f5..0c008da4 100644 --- a/test/unit/dmsf_mailer_test.rb +++ b/test/unit/dmsf_mailer_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_public_url_test.rb b/test/unit/dmsf_public_url_test.rb index f2ad35c4..0e652793 100644 --- a/test/unit/dmsf_public_url_test.rb +++ b/test/unit/dmsf_public_url_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_workflow_step_action_test.rb b/test/unit/dmsf_workflow_step_action_test.rb index 40ff0dbf..f9dd6cb8 100644 --- a/test/unit/dmsf_workflow_step_action_test.rb +++ b/test/unit/dmsf_workflow_step_action_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_workflow_step_assignment_test.rb b/test/unit/dmsf_workflow_step_assignment_test.rb index b2dd898f..f481d95b 100644 --- a/test/unit/dmsf_workflow_step_assignment_test.rb +++ b/test/unit/dmsf_workflow_step_assignment_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_workflow_step_test.rb b/test/unit/dmsf_workflow_step_test.rb index cd0b5e36..11c9c0a8 100644 --- a/test/unit/dmsf_workflow_step_test.rb +++ b/test/unit/dmsf_workflow_step_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/dmsf_workflow_test.rb b/test/unit/dmsf_workflow_test.rb index 85273fb0..155d162a 100644 --- a/test/unit/dmsf_workflow_test.rb +++ b/test/unit/dmsf_workflow_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/issue_patch_test.rb b/test/unit/issue_patch_test.rb index 99b81d27..06f3e8ea 100644 --- a/test/unit/issue_patch_test.rb +++ b/test/unit/issue_patch_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/project_patch_test.rb b/test/unit/project_patch_test.rb index deec9162..cf962b2a 100644 --- a/test/unit/project_patch_test.rb +++ b/test/unit/project_patch_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 diff --git a/test/unit/user_patch_test.rb b/test/unit/user_patch_test.rb index e521f0fd..d7c29804 100644 --- a/test/unit/user_patch_test.rb +++ b/test/unit/user_patch_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright © 2011-18 Karel Pičman +# Copyright © 2011-19 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 From 89c1cdecf678e0bbd7714ef942defc2225dc8e0a Mon Sep 17 00:00:00 2001 From: pavel Date: Wed, 9 Jan 2019 00:10:13 +0100 Subject: [PATCH 18/53] fix email zip --- app/controllers/dmsf_controller.rb | 2 +- test/functional/dmsf_controller_test.rb | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index 13fed7be..a8b34329 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -178,7 +178,7 @@ class DmsfController < ApplicationController if params[:email][:to].strip.blank? flash[:errors] = l(:error_email_to_must_be_entered) else - DmsfMailer.deliver_send_documents(@project, params[:email]) + DmsfMailer.deliver_send_documents(@project, params[:email].permit!) File.delete(params[:email][:zipped_content]) flash[:notice] = l(:notice_email_sent, params[:email][:to]) end diff --git a/test/functional/dmsf_controller_test.rb b/test/functional/dmsf_controller_test.rb index 1054e8da..38e16448 100644 --- a/test/functional/dmsf_controller_test.rb +++ b/test/functional/dmsf_controller_test.rb @@ -257,6 +257,23 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase assert_select "input:match('value', ?)", Setting.plugin_redmine_dmsf['dmsf_documents_email_links_only'] end + def test_entries_email + @role.add_permission! :view_dmsf_files + zip_file_path = DmsfHelper.temp_dir.join(DmsfHelper.temp_filename('dmsf_email_sent_documents.zip')) + FileUtils.touch(zip_file_path) + assert File.exist?(zip_file_path) + get :entries_email, :params => {:id => @project, :email => + { + :to => 'to@test.com', :from => 'from@test.com', :subject => 'subject', :body => 'body', :expired_at => '2015-01-01', + :folders => [], :files => [@file1.id], :zipped_content => zip_file_path + } + } + assert_redirected_to dmsf_folder_path(:id => @project) + assert !File.exist?(zip_file_path) + ensure + FileUtils.rm_rf(zip_file_path) + end + def test_add_email_forbidden get :add_email, :params => {id: @project.id}, :xhr => true assert_response :forbidden From 47750f18c0ddf61b0cab3aca9afc18d6530a5e47 Mon Sep 17 00:00:00 2001 From: lpereira98 <44083899+lpereira98@users.noreply.github.com> Date: Thu, 10 Jan 2019 16:51:40 +0000 Subject: [PATCH 19/53] Update show.api.rsb --- app/views/dmsf_files/show.api.rsb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/dmsf_files/show.api.rsb b/app/views/dmsf_files/show.api.rsb index 7a5f5407..0e3f0199 100644 --- a/app/views/dmsf_files/show.api.rsb +++ b/app/views/dmsf_files/show.api.rsb @@ -12,4 +12,5 @@ api.dmsf_file do api.description @file.last_revision.description end api.content_url download_dmsf_file_url(@file) -end \ No newline at end of file + api.revisions @file.dmsf_file_revisions.visible[@revision_pages.offset, @revision_pages.per_page].each +end From 976755685c6c099e3e445cfcb7faefce6729a829 Mon Sep 17 00:00:00 2001 From: lpereira98 <44083899+lpereira98@users.noreply.github.com> Date: Thu, 10 Jan 2019 16:57:37 +0000 Subject: [PATCH 20/53] Update show.api.rsb --- app/views/dmsf_files/show.api.rsb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/views/dmsf_files/show.api.rsb b/app/views/dmsf_files/show.api.rsb index 0e3f0199..e96d57b0 100644 --- a/app/views/dmsf_files/show.api.rsb +++ b/app/views/dmsf_files/show.api.rsb @@ -4,13 +4,6 @@ api.dmsf_file do api.name @file.name api.project_id @file.project_id api.dmsf_folder_id @file.dmsf_folder_id if @file.dmsf_folder_id - if @file.last_revision - api.version "#{@file.last_revision.version}" - api.mime_type @file.last_revision.mime_type - api.digest @file.last_revision.digest - api.size @file.last_revision.size - api.description @file.last_revision.description - end api.content_url download_dmsf_file_url(@file) api.revisions @file.dmsf_file_revisions.visible[@revision_pages.offset, @revision_pages.per_page].each end From 2f77ee8688844ca5134e50b7ea55afe7e257aa48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Tue, 15 Jan 2019 17:49:11 +0100 Subject: [PATCH 21/53] #929 revision listing better + unit tests --- app/views/dmsf_files/show.api.rsb | 27 +- .../rest_api/dmsf_file_api_test.rb | 244 ++++++++++-------- 2 files changed, 167 insertions(+), 104 deletions(-) diff --git a/app/views/dmsf_files/show.api.rsb b/app/views/dmsf_files/show.api.rsb index e96d57b0..56fe4cba 100644 --- a/app/views/dmsf_files/show.api.rsb +++ b/app/views/dmsf_files/show.api.rsb @@ -5,5 +5,30 @@ api.dmsf_file do api.project_id @file.project_id api.dmsf_folder_id @file.dmsf_folder_id if @file.dmsf_folder_id api.content_url download_dmsf_file_url(@file) - api.revisions @file.dmsf_file_revisions.visible[@revision_pages.offset, @revision_pages.per_page].each + api.array :dmsf_file_revisions do + @file.dmsf_file_revisions.each do |r| + api.dmsf_file_revision do + api.id r.id + api.source_dmsf_file_revision_id r.source_dmsf_file_revision_id + api.name r.name + api.content_url view_dmsf_file_url(@file, download: r) + api.size r.size + api.mime_type r.mime_type + api.title r.title + api.description r.description + api.workflow r.workflow + api.version "#{r.major_version}.#{r.minor_version}" + api.comment r.comment + api.user_id r.user_id + api.created_at r.created_at + api.updated_at r.updated_at + api.dmsf_workflow_id r.dmsf_workflow_id + api.dmsf_workflow_assigned_by r.dmsf_workflow_assigned_by + api.dmsf_workflow_assigned_at r.dmsf_workflow_assigned_at + api.dmsf_workflow_started_by r.dmsf_workflow_started_by + api.dmsf_workflow_started_at r.dmsf_workflow_started_at + api.digest r.digest + end + end + end end diff --git a/test/integration/rest_api/dmsf_file_api_test.rb b/test/integration/rest_api/dmsf_file_api_test.rb index b9c04428..cea39cda 100644 --- a/test/integration/rest_api/dmsf_file_api_test.rb +++ b/test/integration/rest_api/dmsf_file_api_test.rb @@ -49,13 +49,13 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest Setting.plugin_redmine_dmsf['dmsf_storage_directory'] = @dmsf_storage_directory end - def test_truth - assert_kind_of User, @admin - assert_kind_of User, @jsmith - assert_kind_of DmsfFile, @file1 - assert_kind_of Role, @role - assert_kind_of Project, @project1 - end + # def test_truth + # assert_kind_of User, @admin + # assert_kind_of User, @jsmith + # assert_kind_of DmsfFile, @file1 + # assert_kind_of Role, @role + # assert_kind_of Project, @project1 + # end def test_get_document @role.add_permission! :view_dmsf_files @@ -63,118 +63,156 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest get "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}" assert_response :success assert_equal 'application/xml', @response.content_type - # + # # # 1 - # test.txt + # Test File # test.txt # 1 - # 1.0 - # text/plain - # 81dc9bdb52d04dc20036dbd8313ed055 - # 4 - # Some file :-) # http://www.example.com/dmsf/files/1/download + # + # + # 5 + # + # test5.txt + # http://www.example.com/dmsf/files/1/view?download=5 + # 4 + # text/plain + # Test File + # + # 1 + # 1.0 + # + # 1 + # 2017-04-18T12:52:28Z + # 2019-01-15T15:56:15Z + # + # + # + # + # + # + # + # + # 1 + # + # test.txt + # http://www.example.com/dmsf/files/1/view?download=1 + # 4 + # text/plain + # Test File + # Some file :-) + # 1 + # 1.0 + # + # 1 + # 2017-04-18T12:52:27Z + # 2019-01-15T15:56:15Z + # + # 1 + # + # 1 + # + # 81dc9bdb52d04dc20036dbd8313ed055 + # + # # + #puts response.body assert_select 'dmsf_file > id', text: @file1.id.to_s assert_select 'dmsf_file > title', text: @file1.title assert_select 'dmsf_file > name', text: @file1.name assert_select 'dmsf_file > project_id', text: @file1.project_id.to_s - assert_select 'dmsf_file > version', text: @file1.last_revision.version - assert_select 'dmsf_file > mime_type', text: @file1.last_revision.mime_type - assert_select 'dmsf_file > digest', text: @file1.last_revision.digest - assert_select 'dmsf_file > size', text: @file1.last_revision.size.to_s - assert_select 'dmsf_file > description', text: @file1.last_revision.description assert_select 'dmsf_file > content_url', text: "http://www.example.com/dmsf/files/#{@file1.id}/download" + assert_select 'dmsf_file > dmsf_file_revisions > dmsf_file_revision', @file1.dmsf_file_revisions.all.size #curl -v -H "Content-Type: application/octet-stream" -X GET -u ${1}:${2} http://localhost:3000/dmsf/files/41532/download > file.txt get "/dmsf/files/#{@file1.id}/download.xml?key=#{@token.value}" assert_response :success assert_equal '123', @response.body end - def test_upload_document - @role.add_permission! :file_manipulation - #curl --data-binary "@cat.gif" -H "Content-Type: application/octet-stream" -X POST -u ${1}:${2} http://localhost:3000/projects/12/dmsf/upload.xml?filename=cat.gif - post "/projects/#{@project1.id}/dmsf/upload.xml?filename=test.txt&key=#{@token.value}", :params => 'File content', :headers => {"CONTENT_TYPE" => 'application/octet-stream'} - assert_response :created - assert_equal 'application/xml', response.content_type - # - # - # 2.8bb2564936980e92ceec8a5759ec34a8 - # - xml = Hash.from_xml(response.body) - assert_kind_of Hash, xml['upload'] - ftoken = xml['upload']['token'] - assert_not_nil ftoken - #curl -v -H "Content-Type: application/xml" -X POST --data "@file.xml" -u ${1}:${2} http://localhost:3000/projects/12/dmsf/commit.xml - payload = %{ - - - - test.txt - test.txt - REST API - From API - - #{ftoken} - - } - assert_difference 'DmsfFileRevision.count', +1 do - post "/projects/#{@project1.id}/dmsf/commit.xml?key=#{@token.value}", :params => payload, :headers => {"CONTENT_TYPE" => 'application/xml'} - end - # - # - # - # 17229 - # test.txt - # - # # - assert_select 'dmsf_files > file > name', :text => 'test.txt' - assert_response :success - revision = DmsfFileRevision.order(:created_at).last - assert revision && revision.size > 0 - end - - def test_delete_file - @role.add_permission! :file_delete - # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml - delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} - assert_response :success - @file1.reload - assert_equal DmsfFile::STATUS_DELETED, @file1.deleted - assert_equal User.current, @file1.deleted_by_user - end - - def test_delete_file_no_permissions - token = Token.create!(:user => @jsmith, :action => 'api') - # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml - delete "/dmsf/files/#{@file1.id}.xml?key=#{token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} - assert_response :forbidden - end - - def test_delete_folder_commit_yes - @role.add_permission! :file_delete - # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml&commit=yes - delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}&commit=yes", :headers => {'CONTENT_TYPE' => 'application/xml'} - assert_response :success - assert_nil DmsfFile.find_by(id: @file1.id) - end - - def test_delete_file_locked - @role.add_permission! :file_delete - User.current = @admin - @file1.lock! - User.current = @jsmith - # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml - delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} - assert_response 422 - # - # - # Locked by Admin - # - assert_select 'errors > error', :text => l(:title_locked_by_user, user: @admin.name) - @file1.reload - assert_equal DmsfFile::STATUS_ACTIVE, @file1.deleted - end + # def test_upload_document + # @role.add_permission! :file_manipulation + # #curl --data-binary "@cat.gif" -H "Content-Type: application/octet-stream" -X POST -u ${1}:${2} http://localhost:3000/projects/12/dmsf/upload.xml?filename=cat.gif + # post "/projects/#{@project1.id}/dmsf/upload.xml?filename=test.txt&key=#{@token.value}", :params => 'File content', :headers => {"CONTENT_TYPE" => 'application/octet-stream'} + # assert_response :created + # assert_equal 'application/xml', response.content_type + # # + # # + # # 2.8bb2564936980e92ceec8a5759ec34a8 + # # + # xml = Hash.from_xml(response.body) + # assert_kind_of Hash, xml['upload'] + # ftoken = xml['upload']['token'] + # assert_not_nil ftoken + # #curl -v -H "Content-Type: application/xml" -X POST --data "@file.xml" -u ${1}:${2} http://localhost:3000/projects/12/dmsf/commit.xml + # payload = %{ + # + # + # + # test.txt + # test.txt + # REST API + # From API + # + # #{ftoken} + # + # } + # assert_difference 'DmsfFileRevision.count', +1 do + # post "/projects/#{@project1.id}/dmsf/commit.xml?key=#{@token.value}", :params => payload, :headers => {"CONTENT_TYPE" => 'application/xml'} + # end + # # + # # + # # + # # 17229 + # # test.txt + # # + # # # + # assert_select 'dmsf_files > file > name', :text => 'test.txt' + # assert_response :success + # revision = DmsfFileRevision.order(:created_at).last + # assert revision && revision.size > 0 + # end + # + # def test_delete_file + # @role.add_permission! :file_delete + # # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml + # delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} + # assert_response :success + # @file1.reload + # assert_equal DmsfFile::STATUS_DELETED, @file1.deleted + # assert_equal User.current, @file1.deleted_by_user + # end + # + # def test_delete_file_no_permissions + # token = Token.create!(:user => @jsmith, :action => 'api') + # # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml + # delete "/dmsf/files/#{@file1.id}.xml?key=#{token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} + # assert_response :forbidden + # end + # + # def test_delete_folder_commit_yes + # @role.add_permission! :file_delete + # # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml&commit=yes + # delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}&commit=yes", :headers => {'CONTENT_TYPE' => 'application/xml'} + # assert_response :success + # assert_nil DmsfFile.find_by(id: @file1.id) + # end + # + # def test_delete_file_locked + # @role.add_permission! :file_delete + # User.current = @admin + # @file1.lock! + # User.current = @jsmith + # # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml + # delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} + # assert_response 422 + # # + # # + # # Locked by Admin + # # + # assert_select 'errors > error', :text => l(:title_locked_by_user, user: @admin.name) + # @file1.reload + # assert_equal DmsfFile::STATUS_ACTIVE, @file1.deleted + # end end \ No newline at end of file From 1e21d7f82807030e107f9b1b6608d37c0e0b2881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Tue, 15 Jan 2019 17:50:13 +0100 Subject: [PATCH 22/53] #929 revision listing better + unit tests --- .../rest_api/dmsf_file_api_test.rb | 182 +++++++++--------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/test/integration/rest_api/dmsf_file_api_test.rb b/test/integration/rest_api/dmsf_file_api_test.rb index cea39cda..282f7aa1 100644 --- a/test/integration/rest_api/dmsf_file_api_test.rb +++ b/test/integration/rest_api/dmsf_file_api_test.rb @@ -49,13 +49,13 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest Setting.plugin_redmine_dmsf['dmsf_storage_directory'] = @dmsf_storage_directory end - # def test_truth - # assert_kind_of User, @admin - # assert_kind_of User, @jsmith - # assert_kind_of DmsfFile, @file1 - # assert_kind_of Role, @role - # assert_kind_of Project, @project1 - # end + def test_truth + assert_kind_of User, @admin + assert_kind_of User, @jsmith + assert_kind_of DmsfFile, @file1 + assert_kind_of Role, @role + assert_kind_of Project, @project1 + end def test_get_document @role.add_permission! :view_dmsf_files @@ -130,89 +130,89 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest assert_equal '123', @response.body end - # def test_upload_document - # @role.add_permission! :file_manipulation - # #curl --data-binary "@cat.gif" -H "Content-Type: application/octet-stream" -X POST -u ${1}:${2} http://localhost:3000/projects/12/dmsf/upload.xml?filename=cat.gif - # post "/projects/#{@project1.id}/dmsf/upload.xml?filename=test.txt&key=#{@token.value}", :params => 'File content', :headers => {"CONTENT_TYPE" => 'application/octet-stream'} - # assert_response :created - # assert_equal 'application/xml', response.content_type - # # - # # - # # 2.8bb2564936980e92ceec8a5759ec34a8 - # # - # xml = Hash.from_xml(response.body) - # assert_kind_of Hash, xml['upload'] - # ftoken = xml['upload']['token'] - # assert_not_nil ftoken - # #curl -v -H "Content-Type: application/xml" -X POST --data "@file.xml" -u ${1}:${2} http://localhost:3000/projects/12/dmsf/commit.xml - # payload = %{ - # - # - # - # test.txt - # test.txt - # REST API - # From API - # - # #{ftoken} - # - # } - # assert_difference 'DmsfFileRevision.count', +1 do - # post "/projects/#{@project1.id}/dmsf/commit.xml?key=#{@token.value}", :params => payload, :headers => {"CONTENT_TYPE" => 'application/xml'} - # end - # # - # # - # # - # # 17229 - # # test.txt - # # - # # # - # assert_select 'dmsf_files > file > name', :text => 'test.txt' - # assert_response :success - # revision = DmsfFileRevision.order(:created_at).last - # assert revision && revision.size > 0 - # end - # - # def test_delete_file - # @role.add_permission! :file_delete - # # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml - # delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} - # assert_response :success - # @file1.reload - # assert_equal DmsfFile::STATUS_DELETED, @file1.deleted - # assert_equal User.current, @file1.deleted_by_user - # end - # - # def test_delete_file_no_permissions - # token = Token.create!(:user => @jsmith, :action => 'api') - # # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml - # delete "/dmsf/files/#{@file1.id}.xml?key=#{token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} - # assert_response :forbidden - # end - # - # def test_delete_folder_commit_yes - # @role.add_permission! :file_delete - # # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml&commit=yes - # delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}&commit=yes", :headers => {'CONTENT_TYPE' => 'application/xml'} - # assert_response :success - # assert_nil DmsfFile.find_by(id: @file1.id) - # end - # - # def test_delete_file_locked - # @role.add_permission! :file_delete - # User.current = @admin - # @file1.lock! - # User.current = @jsmith - # # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml - # delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} - # assert_response 422 - # # - # # - # # Locked by Admin - # # - # assert_select 'errors > error', :text => l(:title_locked_by_user, user: @admin.name) - # @file1.reload - # assert_equal DmsfFile::STATUS_ACTIVE, @file1.deleted - # end + def test_upload_document + @role.add_permission! :file_manipulation + #curl --data-binary "@cat.gif" -H "Content-Type: application/octet-stream" -X POST -u ${1}:${2} http://localhost:3000/projects/12/dmsf/upload.xml?filename=cat.gif + post "/projects/#{@project1.id}/dmsf/upload.xml?filename=test.txt&key=#{@token.value}", :params => 'File content', :headers => {"CONTENT_TYPE" => 'application/octet-stream'} + assert_response :created + assert_equal 'application/xml', response.content_type + # + # + # 2.8bb2564936980e92ceec8a5759ec34a8 + # + xml = Hash.from_xml(response.body) + assert_kind_of Hash, xml['upload'] + ftoken = xml['upload']['token'] + assert_not_nil ftoken + #curl -v -H "Content-Type: application/xml" -X POST --data "@file.xml" -u ${1}:${2} http://localhost:3000/projects/12/dmsf/commit.xml + payload = %{ + + + + test.txt + test.txt + REST API + From API + + #{ftoken} + + } + assert_difference 'DmsfFileRevision.count', +1 do + post "/projects/#{@project1.id}/dmsf/commit.xml?key=#{@token.value}", :params => payload, :headers => {"CONTENT_TYPE" => 'application/xml'} + end + # + # + # + # 17229 + # test.txt + # + # # + assert_select 'dmsf_files > file > name', :text => 'test.txt' + assert_response :success + revision = DmsfFileRevision.order(:created_at).last + assert revision && revision.size > 0 + end + + def test_delete_file + @role.add_permission! :file_delete + # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml + delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} + assert_response :success + @file1.reload + assert_equal DmsfFile::STATUS_DELETED, @file1.deleted + assert_equal User.current, @file1.deleted_by_user + end + + def test_delete_file_no_permissions + token = Token.create!(:user => @jsmith, :action => 'api') + # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml + delete "/dmsf/files/#{@file1.id}.xml?key=#{token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} + assert_response :forbidden + end + + def test_delete_folder_commit_yes + @role.add_permission! :file_delete + # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml&commit=yes + delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}&commit=yes", :headers => {'CONTENT_TYPE' => 'application/xml'} + assert_response :success + assert_nil DmsfFile.find_by(id: @file1.id) + end + + def test_delete_file_locked + @role.add_permission! :file_delete + User.current = @admin + @file1.lock! + User.current = @jsmith + # curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml + delete "/dmsf/files/#{@file1.id}.xml?key=#{@token.value}", :headers => {'CONTENT_TYPE' => 'application/xml'} + assert_response 422 + # + # + # Locked by Admin + # + assert_select 'errors > error', :text => l(:title_locked_by_user, user: @admin.name) + @file1.reload + assert_equal DmsfFile::STATUS_ACTIVE, @file1.deleted + end end \ No newline at end of file From 26140d611539003af652436c28f79835649b1c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Tue, 15 Jan 2019 18:04:22 +0100 Subject: [PATCH 23/53] #950 lines_count added into the dmsft macro description --- lib/redmine_dmsf/macros.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/redmine_dmsf/macros.rb b/lib/redmine_dmsf/macros.rb index 17eaf471..ef47eb95 100644 --- a/lib/redmine_dmsf/macros.rb +++ b/lib/redmine_dmsf/macros.rb @@ -131,7 +131,7 @@ Redmine::WikiFormatting::Macros.register do # dmsft - link to the document's content preview desc "Wiki link to DMSF document's content preview:\n\n" + - "{{dmsft(file_id)}}\n\n" + + "{{dmsft(file_id, line_counts)}}\n\n" + "_file_id_ can be found in the document's details." macro :dmsft do |obj, args| raise ArgumentError if args.length < 2 # Requires file id and lines number From 2da7844c04ccb1e78e4f7f3be2fc54d47ff38378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Tue, 15 Jan 2019 18:05:15 +0100 Subject: [PATCH 24/53] #950 lines_count added into the dmsft macro description --- lib/redmine_dmsf/macros.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/redmine_dmsf/macros.rb b/lib/redmine_dmsf/macros.rb index ef47eb95..ae468709 100644 --- a/lib/redmine_dmsf/macros.rb +++ b/lib/redmine_dmsf/macros.rb @@ -131,7 +131,7 @@ Redmine::WikiFormatting::Macros.register do # dmsft - link to the document's content preview desc "Wiki link to DMSF document's content preview:\n\n" + - "{{dmsft(file_id, line_counts)}}\n\n" + + "{{dmsft(file_id, lines_count)}}\n\n" + "_file_id_ can be found in the document's details." macro :dmsft do |obj, args| raise ArgumentError if args.length < 2 # Requires file id and lines number From cc0e2ea086c3b544d65c9d4b790f49efeb064a0c Mon Sep 17 00:00:00 2001 From: mrak0s <26814959+mrak0s@users.noreply.github.com> Date: Wed, 16 Jan 2019 19:07:04 +0100 Subject: [PATCH 25/53] Update macros.rb --- lib/redmine_dmsf/macros.rb | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/redmine_dmsf/macros.rb b/lib/redmine_dmsf/macros.rb index ae468709..ec4a8376 100644 --- a/lib/redmine_dmsf/macros.rb +++ b/lib/redmine_dmsf/macros.rb @@ -53,8 +53,8 @@ Redmine::WikiFormatting::Macros.register do # dmsff - link to a folder desc "Wiki link to DMSF folder:\n\n" + - "{{dmsff(folder_id [, title])}}\n\n" + - "_folder_id_ may be missing. _folder_id_ can be found in the link for folder opening." + "{{dmsff([folder_id [, title]])}}\n\n" + + "_folder_id_ can be found in the link for folder opening. Without arguments return link to main folder 'Documents'" macro :dmsff do |obj, args| if args.length < 1 return link_to l(:link_documents), dmsf_folder_url(@project) @@ -75,7 +75,7 @@ Redmine::WikiFormatting::Macros.register do # dmsfd - link to the document's details desc "Wiki link to DMSF document details:\n\n" + - "{{dmsfd(document_id)}}\n\n" + + "{{dmsfd(document_id [, title])}}\n\n" + "_document_id_ can be found in the document's details." macro :dmsfd do |obj, args| raise ArgumentError if args.length < 1 # Requires file id @@ -130,9 +130,9 @@ Redmine::WikiFormatting::Macros.register do end # dmsft - link to the document's content preview - desc "Wiki link to DMSF document's content preview:\n\n" + + desc "Text referring to DMSF text document content:\n\n" + "{{dmsft(file_id, lines_count)}}\n\n" + - "_file_id_ can be found in the document's details." + "_file_id_ can be found in the document's details. _lines_count_ indicate quantity of lines to show." macro :dmsft do |obj, args| raise ArgumentError if args.length < 2 # Requires file id and lines number file = DmsfFile.visible.find args[0].strip @@ -146,10 +146,10 @@ Redmine::WikiFormatting::Macros.register do # dmsf_image - link to an image desc "Wiki DMSF image:\n\n" + "{{dmsf_image(file_id)}}\n" + - "{{dmsf_image(file_id, size=300)}} -- with custom title and size\n" + - "{{dmsf_image(file_id, height=300)}} -- with custom title and height (auto width)\n" + - "{{dmsf_image(file_id, width=300)}} -- with custom title and width (auto height)\n" + - "{{dmsf_image(file_id, size=640x480)}}" + "{{dmsf_image(file_id, size=300)}} -- with and size 300x300\n" + + "{{dmsf_image(file_id, height=300)}} -- with height (auto width)\n" + + "{{dmsf_image(file_id, width=300)}} -- with width (auto height)\n" + + "{{dmsf_image(file_id, size=640x480)}} -- with and size 640x480" macro :dmsf_image do |obj, args| args, options = extract_macro_options(args, :size, :width, :height, :title) file_id = args.first @@ -179,11 +179,11 @@ Redmine::WikiFormatting::Macros.register do # dmsftn - link to an image thumbnail desc "Wiki DMSF thumbnail:\n\n" + - "{{dmsftn(file_id)}}\n" + - "{{dmsftn(file_id, size=300)}} -- with custom title and size\n" + - "{{dmsftn(file_id, height=300)}} -- with custom title and height (auto width)\n" + - "{{dmsftn(file_id, width=300)}} -- with custom title and width (auto height)\n" + - "{{dmsftn(file_id, size=640x480)}}" + "{{dmsftn(file_id)}} -- with default height 200(auto width)\n" + + "{{dmsftn(file_id, size=300)}} -- with size 300x300\n" + + "{{dmsftn(file_id, height=300)}} -- with height (auto width)\n" + + "{{dmsftn(file_id, width=300)}} -- with width (auto height)\n" + + "{{dmsftn(file_id, size=640x480)}} -- with and size 640x480" macro :dmsftn do |obj, args| args, options = extract_macro_options(args, :size, :width, :height, :title) file_id = args.first @@ -217,7 +217,7 @@ Redmine::WikiFormatting::Macros.register do end # dmsfw - link to a document's approval workflow status - desc "Wiki link to DMSF document's approval workflow status:\n\n" + + desc "Text referring to DMSF document's approval workflow status:\n\n" + "{{dmsfw(file_id)}}\n\n" + "_file_id_ can be found in the document's details." macro :dmsfw do |obj, args| From 4d9fe231ae6f4bbc591a98339b4f1c97ed895834 Mon Sep 17 00:00:00 2001 From: mrak0s <26814959+mrak0s@users.noreply.github.com> Date: Thu, 17 Jan 2019 12:10:51 +0100 Subject: [PATCH 26/53] Russian translation improvement --- config/locales/ru.yml | 124 +++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/config/locales/ru.yml b/config/locales/ru.yml index e1533747..99bf9ded 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -21,8 +21,8 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ru: - dmsf: DMS # Custom fields tab title - label_dmsf_file_plural: DMS Файлы # Email subject & Search options + dmsf: СУД # Custom fields tab title + label_dmsf_file_plural: Файлы СУД # Email subject & Search options label_dmsf_file_revision_plural: Изменения документов label_dmsf_file_revision_access_plural: Доступы к документам warning_no_entries_selected: Файлы не выбраны @@ -48,11 +48,11 @@ ru: notice_file_deleted: Файл удален error_at_least_one_revision_must_be_present: По крайней мере, одна редакция должна присутствовать notice_revision_deleted: Редакция удалена - notice_revision_obsoleted: Revision obsoleted + notice_revision_obsoleted: Редакция устарела warning_one_of_files_locked: Один из файлов заблокирован notice_file_revision_created: Редакция файла создана notice_your_preferences_were_saved: Ваши настройки были сохранены - notice_your_preferences_were_not_saved: Your preferences were not saved + notice_your_preferences_were_not_saved: Ваши настройки не сохранены warning_folder_notifications_already_activated: Уведомления папки уже включены notice_folder_notifications_activated: Уведомления папки включены @@ -72,28 +72,28 @@ ru: link_title: Название link_size: Размер link_modified: Изменен - link_ver: Версия + link_ver: Редакция link_author: Автор title_check_for_zip_download_or_email: Выберите документы, которые нужно скачать или отправить их по электронной почте - title_check_for_restore_or_delete: Отметка удаления или восстановления + title_check_for_restore_or_delete: Выберите документы для удаления или восстановления title_delete: Удалить title_notifications_active_deactivate: "Уведомления включены: Отключить" title_notifications_not_active_activate: "Уведомления не включены: Включить" - title_title_version_version_download: "Скачать %{title} версию %{version}" + title_title_version_version_download: "Скачать %{title} редакции %{version}" title_locked_by_user: "Заблокировано пользователем %{user}" title_locked_by_you: Заблокировано Вами - title_waiting_for_approval: Ожидается на утверждение + title_waiting_for_approval: Ожидается утверждение title_approved: Утверждено - title_unlock_file: Разблокируйте файл, чтобы разрешить изменение его другими участниками + title_unlock_file: Разблокируйте файл, чтобы разрешить его изменение другими участниками title_lock_file: Заблокируйте файл, чтобы запретить его изменение другими участниками title_download_checked: Скачать выбранные файлы title_send_checked_by_email: Отправить выбранные файлы по электронной почте - link_user_preferences: Ваши настройки DMS проекта + link_user_preferences: Ваши настройки СУД для проекта heading_send_documents_by_email: Отправить документы по электронной почте label_email_from: От label_email_to: Кому - label_email_cc: CC + label_email_cc: Копия label_email_subject: Тема label_email_documents: Документы label_email_body: Содержание @@ -110,13 +110,13 @@ ru: select_option_deactivated: Отключено select_option_activated: Включено label_title_format: Формат заголовка - text_title_format: "Document title format for download (%t - title, %f - file, %d - date, %v - version, %i - ID, %r - - revision). Example: %t_%v" + text_title_format: "Формат названия при загрузке (%t - Название, %f - имя файла, %d - дата, %v - редакция, %i - ID, %r - + ID редакции). Пример: %t_%v" title_save_preferences: Сохранить настройки heading_revisions: Редакции title_download: Скачать title_delete_revision: Удалить редакцию - title_obsolete_revision: Obsolete revision + title_obsolete_revision: Устаревшая редакция label_created: Создан label_changed: Изменен info_changed_by_user: "%{changed} пользователем" @@ -135,7 +135,7 @@ ru: label_maximum_files_download: Максимальное количество файлов для скачивания note_maximum_number_of_files_downloaded: Ограничивает максимальное количество файлов, которое может быть скачано или отправлено по почте за один раз. 0 означает отсутствие ограничений. - label_file_storage_directory: Каталог для хранения файлов + label_file_storage_directory: Каталог хранения файлов label_index_database: Индексная база данных label_stemming_language: Язык для стемминга note_possible_values: Возможные значения @@ -156,25 +156,25 @@ ru: permission_view_dmsf_file_revision_accesses: Показывать загрзуки файлов в ленте активности permission_view_dmsf_file_revisions: Показывать изменение файлов в ленте активности permission_view_dmsf_folders: Просматривать папки - permission_user_preferences: Настройки пользователя + permission_user_preferences: Собственные настройки для проэкта permission_view_dmsf_files: Просматривать документы permission_folder_manipulation: Управление папками permission_file_manipulation: Управление файлами permission_force_file_unlock: Разблокировка любых файлов - permission_manage_workflows: Управление согласованиями + permission_manage_workflows: Управлять этапами согласования permission_file_delete: Удаление документов - permission_display_system_folders: Display system folders - permission_file_approval: File approval - permission_email_documents: Email documents + permission_display_system_folders: Просматривать скрытые папки + permission_file_approval: Назначать согласование + permission_email_documents: Отправлять документы label_file: Файл field_folder: Папка error_file_commit_require_uploaded_file: Чтобы зафиксировать файл нужно для начала его загрузить - warning_some_files_were_not_commited: "Некоторые файлы не были зафиксированы через ошибки валидации: %{files}" + warning_some_files_were_not_commited: "Некоторые файлы не были зафиксированы из-за ошибки валидации: %{files}" - error_user_has_not_right_delete_folder: Пользователь не имеет нужных прав для удаления папки + error_user_has_not_right_delete_folder: Пользователь не имеет прав для удаления папки - error_user_has_not_right_delete_file: Пользователь не имеет нужных прав для удаления файла + error_user_has_not_right_delete_file: Пользователь не имеет прав для удаления файла notice_entries_deleted: Файлы удалены warning_some_entries_were_not_deleted: "Некоторые файлы не были удалены: %{entries}" @@ -183,12 +183,12 @@ ru: title_filename_for_download: Имя файла для скачиваемого архива label_number_of_folders: Папок label_number_of_documents: Документов - error_file_storage_directory_does_not_exist: Каталог для хранения файлов не существует и не может быть создан + error_file_storage_directory_does_not_exist: Каталог хранения файлов не существует и не может быть создан error_file_can_not_be_created: Файл не может быть создан в каталоге хранения файлов error_wrong_zip_encoding: Неверная кодировка zip warning_xapian_not_available: Xapian не доступен - menu_dmsf: Документы # Project tab title + menu_dmsf: СУД # Project tab title label_physical_file_delete: Физическое удаление файла user_is_not_project_member: Вы не являетесь участником проекта heading_access_downloads_emails: Скачивание / Отправка по почте @@ -197,13 +197,13 @@ ru: label_dmsf_updated: Документ обновлен label_dmsf_downloaded: Документ скачан title_total_size_of_all_files: Общий размер всех файлов в этой папке - project_module_dmsf: DMS # Project module name + project_module_dmsf: СУД # Project module name warning_no_project_to_copy_file_to: Не выбран проект, в который нужно скопировать файл comment_copied_from: "Скопировано из %{source}" field_target_project: Целевой проект field_target_folder: Целевая папка title_copy_or_move: Копировать/Переместить - label_dmsf_folder_plural: DMS Папки # Search options + label_dmsf_folder_plural: Папки СУД # Search options comment_moved_from: "Перемещен из %{source}" error_target_folder_same: Целевая папка и проект совпадают с текущими title_copy: Копировать @@ -234,7 +234,7 @@ ru: label_webdav_strategy: "Стратегия WebDAV" note_webdav_strategy: "Позволяет администратору решить в каком режиме предоставить доступ к WebDAV для конечных - пользователей (Только для чтения или Чтение+Запись)." + пользователей (Только для Чтения или Чтение+Запись)." error_unable_delete_dmsf_workflow: Невозможно удалить процесс согласование error_empty_note: Примечание не может быть пустым @@ -259,20 +259,20 @@ ru: label_or: или label_action: Действие label_note: Примечание - title_none: Примечание + title_none: Отсутствует title_rejection: Отклонение title_delegation: Делегирование title_assignment: Назначение title_start: Запуск title_dmsf_workflow_log: Протокол процесса согласования title_assigned: Назначен - title_approval: Согласован + title_approval: Утвержден title_rejected: Отклонен - title_obsolete: Obsolete + title_obsolete: Устарел dmsf_and: AND dmsf_or: OR dmsf_new_step: Новый шаг - dmsf_new_step_or_approver: Новый шаг или Новый согласующ + dmsf_new_step_or_approver: Новый шаг или Новый согласующий message_dmsf_wokflow_note: Ваше примечание... info_revision: "r%{rev}" link_workflow: Согласование @@ -280,21 +280,21 @@ ru: text_email_subject_approved: успешно завершен text_email_subject_rejected: отклонен text_email_subject_delegated: делегирован - text_email_subject_requires_approval: ребует вашего участия + text_email_subject_requires_approval: требует Вашего рассмотрения text_email_subject_updated: обновлен text_email_subject_started: запущен text_email_finished_approved: "Процесс согласования '%{name}' документа '%{filename}' только что завершился и документ - был согласован." + был утвержден." text_email_finished_rejected: "Процесс согласования '%{name}' документа '%{filename}' только что завершился и документ был отклонен по причине '%{notice}'." text_email_finished_delegated: "Процесс согласования '%{name}' документа '%{filename}' только что был делегирован по - причине '%{notice}' и от Вас ожидается согласование." + причине '%{notice}' и и ожидает Вашего рассмотрения." text_email_finished_step: "Процесс согласования '%{name}' документа '%{filename}' только что завершил один из шагов - согласования и ожидает Вашего соглсования." + согласования и ожидает Вашего рассмотрения." text_email_finished_step_short: "Процесс согласования '%{name}' документа '%{filename}' только что завершил один из - шагов согласования." + шагов." text_email_started: "Процесс согласования '%{name}' документа '%{filename}' только что начался и ожидает Вашего - соглсования." + рассмотрения." text_email_to_proceed: Для продолжения поставьте отметку рядом с документом в text_email_to_see_history: Для просмотра истории согласования нажмите статус согласования документа в @@ -308,7 +308,7 @@ ru: label_notifications_off: Отключить уведоления field_target_file: Исходный файл title_download_entries: Скачать записи - label_external: Внешний + label_external: Внешнюю label_link_name: Наименование ссылки field_external_url: URL @@ -340,7 +340,7 @@ ru: error_resource_or_parent_locked: Невозможно выполнить блокировку - ресурс (или родительская запись) заблокированы error_parent_locked: Невозможно выполнить блокировку - родительская запись заблокирована error_resource_locked: Невозможно выполнить блокировку - ресурс заблокирован - error_lock_exclusively: Невозможно эксклюзивно заблокировать уже забловированный ресурс + error_lock_exclusively: Невозможно эксклюзивно заблокировать уже заблокированный ресурс error_unlock_parent_locked: Разблокировка не удалась - родительская запись заблокирована field_dmsf_tree_view: Навигация по папкам в виде дерева @@ -350,7 +350,7 @@ ru: open_approvals: Открытые согласования label_maximum_ajax_upload_filesize: Максимальный размер файла, загружаемого посредством AJAX - note_maximum_ajax_upload_filesize: Превышает максимальный размер файла, загружаемого посредством интерфейса AJAX, для + note_maximum_ajax_upload_filesize: Максимальный размер файла, загружаемого посредством интерфейса AJAX, для загрузки можно использовать стандартную форму Redmine. Размер указан в MB. label_classic: Обычный @@ -358,41 +358,41 @@ ru: error_maximum_upload_filecount: "Не более %{filecount} файла(ов) может быть загружено." - label_public_urls: Public URLs valid to + label_public_urls: Ссылка действительна до label_webdav: WebDAV label_full_text: Full-text search - link_extension: Ext + link_extension: Внешняя - label_webdav_ignore: Ignored files patterns - note_webdav_ignore: A regular expresion with filenames to ignore by PUT requests. + label_webdav_ignore: Паттерн игнорируемых файлов + note_webdav_ignore: Файлы попадающие под регулярное выражение не будут загружены. label_document_url: Url - label_last_revision_id: Revision + label_last_revision_id: ID редакции - label_webdav_disable_versioning: No versioning files patterns - note_webdav_disable_versioning: A regular expression that disables versioning for matching files. The default pattern - matches temporary files created by MsOffice. + label_webdav_disable_versioning: Паттерн игнорирования версионности + note_webdav_disable_versioning: Файлы попадающие под регулярное выражение не будут иметь редакций. + По умолчанию временные файлы MsOffice. - label_dmsf_keep_documents_locked: Keep documents locked - note_dmsf_keep_documents_locked: Documents will be kept locked when approved - note_global: (global) - field_dmsf_not_inheritable: Not inheritable + label_dmsf_keep_documents_locked: Оставить документы заблокированными + note_dmsf_keep_documents_locked: Документы остануться заблокированными после утверждения + note_global: (Глобальный) + field_dmsf_not_inheritable: Не наследуемый - label_webdav_use_project_names: Use project name for project folder - note_webdav_use_project_names: Use project names instead of project identifier for project folders. + label_webdav_use_project_names: Имя проэкта вместо идентификатора + note_webdav_use_project_names: Использовать имя проэкта вместо идентификатора для папки в WebDAV. - label_last_approver: Last approver + label_last_approver: Последним рассматривал - label_act_as_attachable: Act as attachable - note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues. + label_act_as_attachable: Разрешить вложения + note_dmsf_act_as_attachable: Разрешить прикреплять документы из СУД к задачам. - label_user_search_add: Search for user to add + label_user_search_add: Найти пользователя - label_dmsf_attachments: DMS Attachments - label_basic_attachments: Basic Attachments + label_dmsf_attachments: СУД вложения + label_basic_attachments: Базовые вложения - label_tmpdir: Temporary file path + label_tmpdir: Каталог временных файлов error_file_tmpdir_does_not_exist: "Temporary file path doesn't exist and can't be created" error_tmpfile_can_not_be_created: "Files can't be created in temporary file path directory" From 57575d3c74f2cd3ae09bf3b95985654d960663d5 Mon Sep 17 00:00:00 2001 From: ScratchBuild Date: Sun, 20 Jan 2019 15:38:29 +0900 Subject: [PATCH 27/53] Fix: missing "label_internal" lang strings Used in app/views/dmsf_links/_form.html.erb --- config/locales/cs.yml | 1 + config/locales/de.yml | 1 + config/locales/en.yml | 1 + config/locales/es.yml | 1 + config/locales/fr.yml | 1 + config/locales/hu.yml | 1 + config/locales/it.yml | 1 + config/locales/ja.yml | 1 + config/locales/ko.yml | 1 + config/locales/nl.yml | 1 + config/locales/pl.yml | 1 + config/locales/pt-BR.yml | 1 + config/locales/ru.yml | 1 + config/locales/sl.yml | 1 + config/locales/zh-TW.yml | 1 + config/locales/zh.yml | 1 + 16 files changed, 16 insertions(+) diff --git a/config/locales/cs.yml b/config/locales/cs.yml index e6f57ade..b7a08f25 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -309,6 +309,7 @@ cs: field_target_file: Zdrojový soubor title_download_entries: Historie stahování label_external: Externí + label_internal: Internal label_link_name: Název odkazu field_external_url: URL diff --git a/config/locales/de.yml b/config/locales/de.yml index 52a65ec3..416af57c 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -309,6 +309,7 @@ de: field_target_file: Quelldatei title_download_entries: Download entries label_external: Extern + label_internal: Internal label_link_name: Name der Verknüpfung field_external_url: URL diff --git a/config/locales/en.yml b/config/locales/en.yml index 35ed3338..f1c9a6ce 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -309,6 +309,7 @@ en: field_target_file: Source file title_download_entries: Download entries label_external: External + label_internal: Internal label_link_name: Link name field_external_url: URL diff --git a/config/locales/es.yml b/config/locales/es.yml index e8425082..b65f96b8 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -309,6 +309,7 @@ es: field_target_file: Archivo fuente title_download_entries: Entradas de descarga label_external: External + label_internal: Internal label_link_name: Nombre de enlace field_external_url: URL diff --git a/config/locales/fr.yml b/config/locales/fr.yml index f9f65187..7cb17967 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -309,6 +309,7 @@ fr: field_target_file: Fichier source title_download_entries: Historique des téléchargements label_external: Externe + label_internal: Internal label_link_name: Nom du lien field_external_url: Adresse Internet diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 74632f8a..f667901b 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -310,6 +310,7 @@ hu: field_target_file: Forrás file title_download_entries: Bejegyzések letöltése label_external: Külső + label_internal: Internal label_link_name: Link elnevezése field_external_url: URL diff --git a/config/locales/it.yml b/config/locales/it.yml index 6d8381ad..bcf1ca80 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -309,6 +309,7 @@ it: # Italian strings thx 2 Matteo Arceci! field_target_file: Scarica sorgente title_download_entries: Scarica documenti label_external: Esterno + label_internal: Internal label_link_name: Nome del collegamento field_external_url: URL diff --git a/config/locales/ja.yml b/config/locales/ja.yml index f135259a..476f11e0 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -309,6 +309,7 @@ ja: field_target_file: リンク元ファイル title_download_entries: ダウンロード記録 label_external: 外部 + label_internal: Internal label_link_name: リンク名 field_external_url: URL diff --git a/config/locales/ko.yml b/config/locales/ko.yml index ee09dfec..9e2ca321 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -309,6 +309,7 @@ ko: field_target_file: 소스 파일 title_download_entries: 다운로드 엔트리 label_external: 외부 + label_internal: Internal label_link_name: 링크 이름 field_external_url: URL diff --git a/config/locales/nl.yml b/config/locales/nl.yml index a02f2de7..7d4454cc 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -309,6 +309,7 @@ nl: field_target_file: Bronbestand title_download_entries: Download indieningen label_external: Extern + label_internal: Internal label_link_name: Link naam field_external_url: URL diff --git a/config/locales/pl.yml b/config/locales/pl.yml index d8267bbb..ed2dcad0 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -310,6 +310,7 @@ pl: field_target_file: Plik źródłowy title_download_entries: Pobrane label_external: External + label_internal: Internal label_link_name: Nazwa odnośnika field_external_url: URL diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index e96d0f8d..6ad58e5b 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -309,6 +309,7 @@ pt-BR: field_target_file: Arquivo fonte title_download_entries: Download entries label_external: External + label_internal: Internal label_link_name: Link name field_external_url: URL diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 99bf9ded..4c5d4678 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -309,6 +309,7 @@ ru: field_target_file: Исходный файл title_download_entries: Скачать записи label_external: Внешнюю + label_internal: Internal label_link_name: Наименование ссылки field_external_url: URL diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 6a2f9601..0baa95a8 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -309,6 +309,7 @@ sl: field_target_file: Source file title_download_entries: Download entries label_external: External + label_internal: Internal label_link_name: Link name field_external_url: URL diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index acbe4245..26de66b7 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -309,6 +309,7 @@ zh-TW: field_target_file: Source file title_download_entries: Download entries label_external: External + label_internal: Internal label_link_name: Link name field_external_url: URL diff --git a/config/locales/zh.yml b/config/locales/zh.yml index a2fe75e7..b8b2202d 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -310,6 +310,7 @@ zh: field_target_file: Source file title_download_entries: Download entries label_external: External + label_internal: Internal label_link_name: Link name field_external_url: URL From 8e33debc3c8262bcaaf9bee9c0f597376a599ab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Mon, 21 Jan 2019 08:00:51 +0100 Subject: [PATCH 28/53] #954 Czech localization --- config/locales/cs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/cs.yml b/config/locales/cs.yml index b7a08f25..81794e60 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -309,7 +309,7 @@ cs: field_target_file: Zdrojový soubor title_download_entries: Historie stahování label_external: Externí - label_internal: Internal + label_internal: Interní label_link_name: Název odkazu field_external_url: URL From 689b2dc7930eca92a89c839070b2e79b8e461c6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Wed, 23 Jan 2019 16:34:55 +0100 Subject: [PATCH 29/53] project_settings_tab problem --- .../patches/projects_helper_patch.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/redmine_dmsf/patches/projects_helper_patch.rb b/lib/redmine_dmsf/patches/projects_helper_patch.rb index 5c1730d9..ed7a11fa 100644 --- a/lib/redmine_dmsf/patches/projects_helper_patch.rb +++ b/lib/redmine_dmsf/patches/projects_helper_patch.rb @@ -41,10 +41,12 @@ module RedmineDmsf end end -if Redmine::Plugin.installed?(:easy_extensions) - RedmineExtensions::PatchManager.register_helper_patch 'ProjectsHelper', - 'RedmineDmsf::Patches::ProjectHelperPatch', prepend: true -else - RedmineExtensions::PatchManager.register_patch_to_be_first 'ProjectsHelper', - 'RedmineDmsf::Patches::ProjectHelperPatch', prepend: true, first: true -end \ No newline at end of file +# if Redmine::Plugin.installed?(:easy_extensions) +# RedmineExtensions::PatchManager.register_helper_patch 'ProjectsHelper', +# 'RedmineDmsf::Patches::ProjectHelperPatch', prepend: true +# else +# RedmineExtensions::PatchManager.register_patch_to_be_first 'ProjectsHelper', +# 'RedmineDmsf::Patches::ProjectHelperPatch', prepend: true, first: true +# end + +ProjectsController.send :helper, RedmineDmsf::Patches::ProjectHelperPatch \ No newline at end of file From 481edb9ae9d215d7e4387ede046c41d2e87e0489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Wed, 23 Jan 2019 17:10:50 +0100 Subject: [PATCH 30/53] #956 Non-ASCII characters in external links --- app/validators/dmsf_url_validator.rb | 6 ++++-- test/unit/dmsf_link_test.rb | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/validators/dmsf_url_validator.rb b/app/validators/dmsf_url_validator.rb index e897c152..2b2de698 100644 --- a/app/validators/dmsf_url_validator.rb +++ b/app/validators/dmsf_url_validator.rb @@ -25,12 +25,14 @@ class DmsfUrlValidator < ActiveModel::EachValidator if record.target_type == 'DmsfUrl' begin if value.present? - URI.parse value + # TODO : This prevents from entering valid URLs with non-ASCII characters sue as: 'https://www.google.com/search?q=寿司' + #URI.parse value else record.errors.add attribute, :invalid end - rescue URI::InvalidURIError + rescue URI::InvalidURIError => e record.errors.add attribute, :invalid + Rails.logger.error e.message end end end diff --git a/test/unit/dmsf_link_test.rb b/test/unit/dmsf_link_test.rb index 21efb8fe..b926046e 100644 --- a/test/unit/dmsf_link_test.rb +++ b/test/unit/dmsf_link_test.rb @@ -113,7 +113,7 @@ class DmsfLinksTest < RedmineDmsf::Test::UnitTest def test_validate_external_url @file_link.target_type = 'DmsfUrl' - @file_link.external_url = 'htt ps://abc.xyz' + @file_link.external_url = '' assert !@file_link.save, "External URL link #{@file_link.name} should have not been saved" assert_equal 1, @file_link.errors.size From 416a9e2579acca467521c3b4fb4030f5e968b8aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Wed, 23 Jan 2019 17:12:14 +0100 Subject: [PATCH 31/53] #956 Non-ASCII characters in external links --- app/validators/dmsf_url_validator.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/validators/dmsf_url_validator.rb b/app/validators/dmsf_url_validator.rb index 2b2de698..8267f739 100644 --- a/app/validators/dmsf_url_validator.rb +++ b/app/validators/dmsf_url_validator.rb @@ -25,7 +25,8 @@ class DmsfUrlValidator < ActiveModel::EachValidator if record.target_type == 'DmsfUrl' begin if value.present? - # TODO : This prevents from entering valid URLs with non-ASCII characters sue as: 'https://www.google.com/search?q=寿司' + # TODO : This prevents from entering valid URLs with non-ASCII characters such as: + # 'https://www.google.com/search?q=寿司' #URI.parse value else record.errors.add attribute, :invalid From d455b18fda5e1e7f6d640976fdabb1ad31a6e374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 24 Jan 2019 16:57:24 +0100 Subject: [PATCH 32/53] #956 Japanese links --- app/validators/dmsf_url_validator.rb | 5 ++--- app/views/dmsf/_url.html.erb | 6 +++++- app/views/dmsf_context_menus/dmsf.html.erb | 8 ++++---- test/unit/dmsf_link_test.rb | 13 +++++++++---- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/app/validators/dmsf_url_validator.rb b/app/validators/dmsf_url_validator.rb index 8267f739..c29f1f9c 100644 --- a/app/validators/dmsf_url_validator.rb +++ b/app/validators/dmsf_url_validator.rb @@ -25,9 +25,8 @@ class DmsfUrlValidator < ActiveModel::EachValidator if record.target_type == 'DmsfUrl' begin if value.present? - # TODO : This prevents from entering valid URLs with non-ASCII characters such as: - # 'https://www.google.com/search?q=寿司' - #URI.parse value + # https://www.google.com/search?q=寿司 + URI.parse value.split('?').first else record.errors.add attribute, :invalid end diff --git a/app/views/dmsf/_url.html.erb b/app/views/dmsf/_url.html.erb index aaab9270..263b15b8 100644 --- a/app/views/dmsf/_url.html.erb +++ b/app/views/dmsf/_url.html.erb @@ -34,7 +34,11 @@ :target => '_blank', :class => 'icon icon-link') %>
- <%= link.external_url %> + <% if link.external_url && link.external_url.length > 50 %> + <%= "#{link.external_url[0, 25]}...#{link.external_url[-25, 25]}" %> + <% else %> + <%= link.external_url %> + <% end %>
<%= ''.html_safe if @tree_view %> diff --git a/app/views/dmsf_context_menus/dmsf.html.erb b/app/views/dmsf_context_menus/dmsf.html.erb index fc5a60fd..f22599f5 100644 --- a/app/views/dmsf_context_menus/dmsf.html.erb +++ b/app/views/dmsf_context_menus/dmsf.html.erb @@ -23,17 +23,17 @@
  • <%= context_menu_link l(:button_download), entries_operations_dmsf_path(:id => @project, :folder_id => @folder, - :ids => params[:ids], :download_entries => true), :method => :post, :class => 'icon-download', + :ids => params[:ids], :download_entries => true), :method => :post, :class => 'icon icon-download', :id => 'dmsf-cm-download', :disabled => @disabled %>
  • <%= context_menu_link l(:field_mail), entries_operations_dmsf_path(:id => @project, :folder_id => @folder, - :ids => params[:ids], :email_entries => true), :method => :post, :class => 'icon-email', + :ids => params[:ids], :email_entries => true), :method => :post, :class => 'icon icon-email', :disabled => @disabled %>
  • <%= context_menu_link l(:button_delete), entries_operations_dmsf_path(:id => @project, :folder_id => @folder, - :ids => params[:ids], :delete_entries => true), :method => :post, :class => 'icon-del', + :ids => params[:ids], :delete_entries => true), :method => :post, :class => 'icon icon-del', :data => { :confirm => l(:text_are_you_sure) }, :id => 'dmsf-cm-delete', :disabled => @disabled %>
  • <% if @file %> @@ -45,7 +45,7 @@ <% end %> <% url << @file.name %> <% end %> - <%= context_menu_link l(:button_edit), url, :class => 'icon-edit', :disabled => url.blank? %> + <%= context_menu_link l(:button_edit), url, :class => 'icon icon-edit', :disabled => url.blank? %> <% end %>
diff --git a/test/unit/dmsf_link_test.rb b/test/unit/dmsf_link_test.rb index b926046e..e63c7576 100644 --- a/test/unit/dmsf_link_test.rb +++ b/test/unit/dmsf_link_test.rb @@ -111,13 +111,18 @@ class DmsfLinksTest < RedmineDmsf::Test::UnitTest assert_equal 1, @file_link.errors.size end - def test_validate_external_url + def test_validate_external_url_invalid @file_link.target_type = 'DmsfUrl' - @file_link.external_url = '' - assert !@file_link.save, - "External URL link #{@file_link.name} should have not been saved" + @file_link.external_url = 'htt ps://abc.xyz' + assert !@file_link.save, "External URL link #{@file_link.name} should have not been saved" assert_equal 1, @file_link.errors.size end + + def test_validate_external_url_valid + @file_link.target_type = 'DmsfUrl' + @file_link.external_url = 'https://www.google.com/search?q=寿司' + assert @file_link.save + end def test_belongs_to_project @project1.destroy From 04c1a1a8096691365fffebaa4cffa727a408e71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 24 Jan 2019 17:14:52 +0100 Subject: [PATCH 33/53] #956 Japanese links --- app/views/dmsf/_url_trash.html.erb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/views/dmsf/_url_trash.html.erb b/app/views/dmsf/_url_trash.html.erb index c51f96f5..0cace384 100644 --- a/app/views/dmsf/_url_trash.html.erb +++ b/app/views/dmsf/_url_trash.html.erb @@ -30,7 +30,13 @@ link.external_url, :target => '_blank', :class => 'icon icon-link') %> -
<%= link.external_url %>
+
+ <% if link.external_url && link.external_url.length > 50 %> + <%= "#{link.external_url[0, 25]}...#{link.external_url[-25, 25]}" %> + <% else %> + <%= link.external_url %> + <% end %> +
<% end %> <% if DmsfFolder.is_column_on?('extension') %> From 12ff703584a3abfaf61556460cd6bb73e7a1ea0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Fri, 25 Jan 2019 11:00:56 +0100 Subject: [PATCH 34/53] crete symbolic link error #959 --- app/controllers/dmsf_links_controller.rb | 4 +++- app/models/dmsf_link.rb | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/controllers/dmsf_links_controller.rb b/app/controllers/dmsf_links_controller.rb index 707d6e54..5066ea9f 100644 --- a/app/controllers/dmsf_links_controller.rb +++ b/app/controllers/dmsf_links_controller.rb @@ -112,7 +112,9 @@ class DmsfLinksController < ApplicationController if result flash[:notice] = l(:notice_successful_create) else - flash[:errors] = @dmsf_link.errors.full_messages.to_sentence + msg = @dmsf_link.errors.full_messages.to_sentence + flash[:errors] = msg + Rails.logger.error msg end else # Link to diff --git a/app/models/dmsf_link.rb b/app/models/dmsf_link.rb index d961e831..8ca299b4 100644 --- a/app/models/dmsf_link.rb +++ b/app/models/dmsf_link.rb @@ -28,7 +28,9 @@ class DmsfLink < ActiveRecord::Base belongs_to :user validates :name, presence: true, length: { maximum: 255 } - validates :project, presence: true + # There can be project_id = -1 when attaching links to an issue. The project_id is assigned later when saving the + # issue. + #validates :project, presence: true validates :external_url, length: { maximum: 255 } validates :external_url, dmsf_url: true From e7c69c61ca173b2842232c9e23e48cc09e21966b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Fri, 25 Jan 2019 16:25:20 +0100 Subject: [PATCH 35/53] crete symbolic link error #959 --- app/models/dmsf_link.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/dmsf_link.rb b/app/models/dmsf_link.rb index 3e4331df..72a62a08 100644 --- a/app/models/dmsf_link.rb +++ b/app/models/dmsf_link.rb @@ -28,7 +28,7 @@ class DmsfLink < ActiveRecord::Base belongs_to :user validates :name, presence: true, length: { maximum: 255 } - validates :project, presence: true + #validates :project, presence: true validates :external_url, length: { maximum: 255 } validates :external_url, dmsf_url: true @@ -196,4 +196,4 @@ class DmsfLink < ActiveRecord::Base csv end -end \ No newline at end of file +end From 0d34dfc2cefdfe368ff9648a71e91cc9628d94b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Wed, 30 Jan 2019 13:29:22 +0100 Subject: [PATCH 36/53] Trash icon if the trash bin is empty --- app/views/dmsf/show.html.erb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/views/dmsf/show.html.erb b/app/views/dmsf/show.html.erb index d45edc71..993fd5a2 100644 --- a/app/views/dmsf/show.html.erb +++ b/app/views/dmsf/show.html.erb @@ -68,8 +68,13 @@ :title => l(:link_create_folder), :class => 'icon icon-add') unless @locked_for_user %> <% end %> - <%= link_to_if(@trash_enabled, l(:link_trash_bin), trash_dmsf_path(@project), - :title => l(:link_trash_bin), :class => 'icon icon-del') if @trash_visible %> + <% if @trash_enabled %> + <%= link_to l(:link_trash_bin), trash_dmsf_path(@project), title: l(:link_trash_bin), class: 'icon icon-del' %> + <% else %> + + <%= l(:link_trash_bin) %> + + <% end %> <%= render(:partial => 'path', From 674fa0f74a011a038273984d66b996c6e7ed3802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 31 Jan 2019 16:14:03 +0100 Subject: [PATCH 37/53] Easy modifications --- Gemfile | 4 +++- lib/redmine_dmsf/patches/projects_helper_patch.rb | 15 ++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Gemfile b/Gemfile index e6511368..d0bce171 100644 --- a/Gemfile +++ b/Gemfile @@ -22,7 +22,6 @@ source 'https://rubygems.org' -gem 'rubyzip', '>= 1.1.3' gem 'zip-zip' gem 'simple_enum' gem 'uuidtools' @@ -31,6 +30,9 @@ gem 'dalli' # Redmine extensions unless %w(easyproject easy_gantt).any? { |plugin| Dir.exist?(File.expand_path("../../#{plugin}", __FILE__)) } gem 'redmine_extensions', '~> 0.2.5' + gem 'rubyzip', '>= 1.1.3' +else + gem 'rubyzip', '>= 1.0.0' end # Dav4Rack diff --git a/lib/redmine_dmsf/patches/projects_helper_patch.rb b/lib/redmine_dmsf/patches/projects_helper_patch.rb index ed7a11fa..9913c4a1 100644 --- a/lib/redmine_dmsf/patches/projects_helper_patch.rb +++ b/lib/redmine_dmsf/patches/projects_helper_patch.rb @@ -41,12 +41,9 @@ module RedmineDmsf end end -# if Redmine::Plugin.installed?(:easy_extensions) -# RedmineExtensions::PatchManager.register_helper_patch 'ProjectsHelper', -# 'RedmineDmsf::Patches::ProjectHelperPatch', prepend: true -# else -# RedmineExtensions::PatchManager.register_patch_to_be_first 'ProjectsHelper', -# 'RedmineDmsf::Patches::ProjectHelperPatch', prepend: true, first: true -# end - -ProjectsController.send :helper, RedmineDmsf::Patches::ProjectHelperPatch \ No newline at end of file +if Redmine::Plugin.installed?(:easy_extensions) + RedmineExtensions::PatchManager.register_helper_patch 'ProjectsHelper', + 'RedmineDmsf::Patches::ProjectHelperPatch', prepend: true +else + ProjectsController.send :helper, RedmineDmsf::Patches::ProjectHelperPatch +end \ No newline at end of file From 2340d6fdc641e9527de2cbc9bee1d60f61a3a95c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Tue, 5 Feb 2019 10:31:18 +0100 Subject: [PATCH 38/53] #folder_manipulation permission #966 --- Gemfile | 4 +--- app/controllers/dmsf_controller.rb | 1 + test/functional/dmsf_controller_test.rb | 12 ++++++++---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Gemfile b/Gemfile index d0bce171..e6511368 100644 --- a/Gemfile +++ b/Gemfile @@ -22,6 +22,7 @@ source 'https://rubygems.org' +gem 'rubyzip', '>= 1.1.3' gem 'zip-zip' gem 'simple_enum' gem 'uuidtools' @@ -30,9 +31,6 @@ gem 'dalli' # Redmine extensions unless %w(easyproject easy_gantt).any? { |plugin| Dir.exist?(File.expand_path("../../#{plugin}", __FILE__)) } gem 'redmine_extensions', '~> 0.2.5' - gem 'rubyzip', '>= 1.1.3' -else - gem 'rubyzip', '>= 1.0.0' end # Dav4Rack diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index 021391a7..b5b61056 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -493,6 +493,7 @@ class DmsfController < ApplicationController def delete_entries(selected_folders, selected_files, selected_dir_links, selected_file_links, selected_url_links, commit) # Folders selected_folders.each do |id| + raise DmsfAccessError unless User.current.allowed_to?(:folder_manipulation, @project) folder = DmsfFolder.find_by(id: id) if folder unless folder.delete commit diff --git a/test/functional/dmsf_controller_test.rb b/test/functional/dmsf_controller_test.rb index 38e16448..c4958c05 100644 --- a/test/functional/dmsf_controller_test.rb +++ b/test/functional/dmsf_controller_test.rb @@ -33,6 +33,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase @folder1 = DmsfFolder.find 1 @folder2 = DmsfFolder.find 2 @folder4 = DmsfFolder.find 4 + @folderý = DmsfFolder.find 7 @file1 = DmsfFile.find 1 @file_link2 = DmsfLink.find 4 @folder_link1 = DmsfLink.find 1 @@ -63,6 +64,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase assert_kind_of DmsfFolder, @folder1 assert_kind_of DmsfFolder, @folder2 assert_kind_of DmsfFolder, @folder4 + assert_kind_of DmsfFolder, @folder7 assert_kind_of DmsfFile, @file1 assert_kind_of DmsfLink, @file_link2 assert_kind_of DmsfLink, @folder_link1 @@ -149,16 +151,17 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase assert_response :redirect end - def test_delete_restore_entries_forbidden + def test_delete_entries_forbidden # Missing permissions get :entries_operation, :params => {:id => @project, :delete_entries => 'Delete', :ids => ["folder-#{@folder1.id}", "file-#{@file1.id}", "folder-link-#{@folder_link1.id}", "file-link-#{@file_link2.id}"]} assert_response :forbidden end - def test_delete_restore_not_empty + def test_delete_not_empty # Permissions OK but the folder is not empty @request.env['HTTP_REFERER'] = dmsf_folder_path(:id => @project.id) + @role.add_permission! :folder_manipulation @role.add_permission! :view_dmsf_files get :entries_operation, :params => {:id => @project, :delete_entries => 'Delete', :ids => ["folder-#{@folder1.id}", "file-#{@file1.id}", "folder-link-#{@folder_link1.id}", "file-link-#{@file_link2.id}"]} @@ -166,13 +169,14 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase assert_equal flash[:errors].to_s, l(:error_folder_is_not_empty) end - def test_delete_restore_entries_ok + def test_delete_entries_ok # Permissions OK @request.env['HTTP_REFERER'] = dmsf_folder_path(:id => @project.id) @role.add_permission! :view_dmsf_files + @role.add_permission! :folder_manipulation flash[:errors] = nil get :entries_operation, :params => {:id => @project, :delete_entries => 'Delete', - :ids => ["file-#{@file1.id}", "file-link-#{@file_link2.id}"]} + :ids => ["folder-#{@folder7.id}", "file-#{@file1.id}", "file-link-#{@file_link2.id}"]} assert_response :redirect assert_nil flash[:errors] end From 12ca4a16399ad4775e26e89aae09b743aadcd922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Tue, 5 Feb 2019 10:32:16 +0100 Subject: [PATCH 39/53] #folder_manipulation permission #966 --- test/functional/dmsf_controller_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/dmsf_controller_test.rb b/test/functional/dmsf_controller_test.rb index c4958c05..b9fce110 100644 --- a/test/functional/dmsf_controller_test.rb +++ b/test/functional/dmsf_controller_test.rb @@ -33,7 +33,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase @folder1 = DmsfFolder.find 1 @folder2 = DmsfFolder.find 2 @folder4 = DmsfFolder.find 4 - @folderý = DmsfFolder.find 7 + @folder7 = DmsfFolder.find 7 @file1 = DmsfFile.find 1 @file_link2 = DmsfLink.find 4 @folder_link1 = DmsfLink.find 1 From dce0356c7362f0c908827eb69aaa4b7d1b87da0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Wed, 6 Feb 2019 10:51:58 +0100 Subject: [PATCH 40/53] Fast link creation error --- app/controllers/dmsf_links_controller.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/dmsf_links_controller.rb b/app/controllers/dmsf_links_controller.rb index 4e7e4304..a857210a 100644 --- a/app/controllers/dmsf_links_controller.rb +++ b/app/controllers/dmsf_links_controller.rb @@ -121,12 +121,12 @@ class DmsfLinksController < ApplicationController if params[:dmsf_link][:target_project_id].present? @dmsf_link.project_id = params[:dmsf_link][:target_project_id] else - project_id = DmsfFolder.find_by(id: params[:dmsf_link][:target_folder_id]).pluck(:project_id).first - unless project_id + project_ids = DmsfFolder.where(id: params[:dmsf_link][:target_folder_id]).pluck(:project_id) + unless project_ids.any? render_404 return end - @dmsf_link.project_id = project_id + @dmsf_link.project_id = project_ids.first end @dmsf_link.target_project_id = params[:dmsf_link][:project_id] if params[:dmsf_link][:dmsf_file_id].present? From 13bda91dd596eb36b359ffbf458c2d595e82c903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 7 Feb 2019 11:57:33 +0100 Subject: [PATCH 41/53] PostgreSQL compatibility --- lib/redmine_dmsf/patches/easy_crm_case_patch.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/redmine_dmsf/patches/easy_crm_case_patch.rb b/lib/redmine_dmsf/patches/easy_crm_case_patch.rb index bd269b18..b23f5ed9 100644 --- a/lib/redmine_dmsf/patches/easy_crm_case_patch.rb +++ b/lib/redmine_dmsf/patches/easy_crm_case_patch.rb @@ -109,8 +109,8 @@ module RedmineDmsf 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 + folder = DmsfFolder.issystem.where(["project_id = ? AND dmsf_folder_id = ? AND title LIKE '? - %'", + prj_id, parent.id, self.id]).first if create && !folder folder = DmsfFolder.new folder.dmsf_folder_id = parent.id From faa99c56b8fc19b4d1eade2109d12750039d2a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 7 Feb 2019 12:01:56 +0100 Subject: [PATCH 42/53] PostgreSQL compatibility --- lib/redmine_dmsf/patches/easy_crm_case_patch.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/redmine_dmsf/patches/easy_crm_case_patch.rb b/lib/redmine_dmsf/patches/easy_crm_case_patch.rb index b23f5ed9..30515a2a 100644 --- a/lib/redmine_dmsf/patches/easy_crm_case_patch.rb +++ b/lib/redmine_dmsf/patches/easy_crm_case_patch.rb @@ -109,8 +109,8 @@ module RedmineDmsf parent.save end if parent - folder = DmsfFolder.issystem.where(["project_id = ? AND dmsf_folder_id = ? AND title LIKE '? - %'", - prj_id, parent.id, self.id]).first + folder = DmsfFolder.system.where(["project_id = ? AND dmsf_folder_id = ? AND title LIKE '? - %'", + self.project_id, parent.id, self.id]).first if create && !folder folder = DmsfFolder.new folder.dmsf_folder_id = parent.id From 5b3903385ae3f936a8072c8e8a8273c69605d158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 7 Feb 2019 13:25:29 +0100 Subject: [PATCH 43/53] PostgreSQL compatibility --- db/migrate/20170421101901_dmsf_file_container_rollback.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/db/migrate/20170421101901_dmsf_file_container_rollback.rb b/db/migrate/20170421101901_dmsf_file_container_rollback.rb index f6ed7f94..af209f43 100644 --- a/db/migrate/20170421101901_dmsf_file_container_rollback.rb +++ b/db/migrate/20170421101901_dmsf_file_container_rollback.rb @@ -71,7 +71,7 @@ class DmsfFileContainerRollback < ActiveRecord::Migration def down # dmsf_files file_folder_ids = DmsfFile.joins(:dmsf_folder).where(dmsf_folders: { system: true }).pluck( - 'dmsf_files.id, cast(dmsf_folders.title as decimal)') + 'dmsf_files.id, dmsf_folders.title') remove_index :dmsf_files, :project_id rename_column :dmsf_files, :project_id, :container_id # Temporarily added for the save method @@ -79,10 +79,10 @@ class DmsfFileContainerRollback < ActiveRecord::Migration add_column :dmsf_files, :container_type, :string, limit: 30, null: false, default: 'Project' DmsfFile.update_all(:container_type => 'Project') - file_folder_ids.each do |id, container_id| + file_folder_ids.each do |id, title| file = DmsfFile.find_by(id: id) - if file - file.container_id = container_id + if file && (title =~ /(^\d+) - .*/) + file.container_id = $1.to_i file.container_type = 'Issue' file.save! end From 13dd1cefbbc80d1c46d30bdac7f9c3bb64cfcdf9 Mon Sep 17 00:00:00 2001 From: pavel Date: Tue, 12 Feb 2019 17:40:16 +0100 Subject: [PATCH 44/53] uninstall fix --- db/migrate/04_dmsf_0_9_0.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/04_dmsf_0_9_0.rb b/db/migrate/04_dmsf_0_9_0.rb index 872b75ec..341ff19a 100644 --- a/db/migrate/04_dmsf_0_9_0.rb +++ b/db/migrate/04_dmsf_0_9_0.rb @@ -24,7 +24,7 @@ class Dmsf090 < ActiveRecord::Migration drop_table :dmsf_user_prefs end - def own + def down remove_column :members, :dmsf_mail_notification create_table :dmsf_user_prefs do |t| t.references :project, null: false From 3addcab7025968bb12b25be3c57e621af9297e1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 14 Feb 2019 14:27:32 +0100 Subject: [PATCH 45/53] Mailer.deliver_later doesn't work in rake tasks --- app/models/dmsf_mailer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/dmsf_mailer.rb b/app/models/dmsf_mailer.rb index e83e3353..cfef7887 100644 --- a/app/models/dmsf_mailer.rb +++ b/app/models/dmsf_mailer.rb @@ -86,7 +86,7 @@ class DmsfMailer < Mailer def self.deliver_workflow_notification(users, workflow, revision, subject_id, text1_id, text2_id, notice = nil) users.each do |user| - workflow_notification(user, workflow, revision, subject_id.to_s, text1_id.to_s, text2_id.to_s, notice).deliver_later + workflow_notification(user, workflow, revision, subject_id.to_s, text1_id.to_s, text2_id.to_s, notice).deliver_now end end From f0bf0a895d2904c0afc756d87fb244b944ceb9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Fri, 15 Feb 2019 14:16:11 +0100 Subject: [PATCH 46/53] E-mail notifications recipients are not displayes --- README.md | 6 +++--- app/controllers/dmsf_controller.rb | 4 ++-- app/controllers/dmsf_files_controller.rb | 8 ++++---- app/helpers/dmsf_upload_helper.rb | 2 +- app/models/dmsf_mailer.rb | 2 ++ 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6bd7ae25..05b6c8ee 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,12 @@ Features * Document tagging * Trash bin * Documents attachable to issues - * Compatible with Redmine 3.4.x + * Compatible with Redmine 4.0.x Dependencies ------------ - * Redmine 3.4.0 or higher + * Redmine 4.0.0 or higher ### Full-text search (optional) @@ -216,7 +216,7 @@ Before installing ensure that the Redmine instance is stopped. 1. In case of upgrade BACKUP YOUR DATABASE first 2. Put redmine_dmsf plugin directory into plugins. 3. Install dependencies: `bundle install`. -4. Initialize/Update database: `bundle exec rake redmine:plugins:migrate RAILS_ENV="production"`. +4. Initialize/Update database: `bundle exec rake redmine:plugins:migrate NAME=redmine_dmsf RAILS_ENV="production"`. 5. The access rights must be set for web server, example: `chown -R www-data:www-data plugins/redmine_dmsf`. 6. Restart the web server. 7. You should configure the plugin via Redmine interface: Administration -> Plugins -> DMSF -> Configure. diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index b5b61056..73b0f269 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -522,9 +522,9 @@ class DmsfController < ApplicationController # Activities unless deleted_files.empty? begin - DmsfMailer.deliver_files_deleted(@project, deleted_files) + recipients = DmsfMailer.deliver_files_deleted(@project, deleted_files) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] - unless recipients.empty? + if recipients.any? to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.') flash[:warning] = l(:warning_email_notifications, :to => to) diff --git a/app/controllers/dmsf_files_controller.rb b/app/controllers/dmsf_files_controller.rb index da8f4ead..c95e9f1a 100644 --- a/app/controllers/dmsf_files_controller.rb +++ b/app/controllers/dmsf_files_controller.rb @@ -173,9 +173,9 @@ class DmsfFilesController < ApplicationController @file.set_last_revision revision flash[:notice] = (flash[:notice].nil? ? '' : flash[:notice]) + l(:notice_file_revision_created) begin - DmsfMailer.deliver_files_updated(@project, [@file]) + recipients = DmsfMailer.deliver_files_updated(@project, [@file]) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] - unless recipients.empty? + if recipients.any? to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.') flash[:warning] = l(:warning_email_notifications, :to => to) @@ -203,9 +203,9 @@ class DmsfFilesController < ApplicationController flash[:notice] = l(:notice_file_deleted) unless commit begin - DmsfMailer.deliver_files_deleted(@project, [@file]) + recipients = DmsfMailer.deliver_files_deleted(@project, [@file]) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] - unless recipients.empty? + if recipients.any? to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.') flash[:warning] = l(:warning_email_notifications, :to => to) diff --git a/app/helpers/dmsf_upload_helper.rb b/app/helpers/dmsf_upload_helper.rb index b6ed1803..2ee242e6 100644 --- a/app/helpers/dmsf_upload_helper.rb +++ b/app/helpers/dmsf_upload_helper.rb @@ -142,7 +142,7 @@ module DmsfUploadHelper # Notifications if (folder && folder.notification?) || (!folder && project.dmsf_notification?) begin - DmsfMailer.deliver_files_updated(project, files) + recipients = DmsfMailer.deliver_files_updated(project, files) if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] unless recipients.empty? to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') diff --git a/app/models/dmsf_mailer.rb b/app/models/dmsf_mailer.rb index cfef7887..cf2cda02 100644 --- a/app/models/dmsf_mailer.rb +++ b/app/models/dmsf_mailer.rb @@ -30,6 +30,7 @@ class DmsfMailer < Mailer users.each do |user| files_updated(user, project, files).deliver_later end + users end def files_updated(user, project, files) @@ -49,6 +50,7 @@ class DmsfMailer < Mailer users.each do |user| files_deleted(user, project, files).deliver_later end + users end def files_deleted(user, project, files) From 3c1dfe62e40579c2487dca346c621b2fedd9120e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Mon, 18 Feb 2019 16:52:38 +0100 Subject: [PATCH 47/53] Rails 5 modules --- app/controllers/dmsf_controller.rb | 5 +- lib/dmsf_zip.rb | 81 ---------------------------- lib/redmine_dmsf/dmsf_zip.rb | 87 ++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 83 deletions(-) delete mode 100644 lib/dmsf_zip.rb create mode 100644 lib/redmine_dmsf/dmsf_zip.rb diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index 73b0f269..fa182284 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -21,6 +21,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class DmsfController < ApplicationController + include RedmineDmsf::DmsfZip before_action :find_project before_action :authorize, :except => [:expand_folder] @@ -365,7 +366,7 @@ class DmsfController < ApplicationController end def email_entries(selected_folders, selected_files) - zip = DmsfZip.new + zip = Zip.new zip_entries(zip, selected_folders, selected_files) zipped_content = DmsfHelper.temp_dir.join(DmsfHelper.temp_filename('dmsf_email_sent_documents.zip')) @@ -408,7 +409,7 @@ class DmsfController < ApplicationController end def download_entries(selected_folders, selected_files) - zip = DmsfZip.new + zip = Zip.new zip_entries(zip, selected_folders, selected_files) zip.files.each do |f| audit = DmsfFileRevisionAccess.new diff --git a/lib/dmsf_zip.rb b/lib/dmsf_zip.rb deleted file mode 100644 index 2befcf62..00000000 --- a/lib/dmsf_zip.rb +++ /dev/null @@ -1,81 +0,0 @@ -# encoding: utf-8 -# -# Redmine plugin for Document Management System "Features" -# -# Copyright © 2011 Vít Jonáš -# Copyright © 2011-19 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. - -require 'zip' - -class DmsfZip - - attr_reader :files - - def initialize - @zip_path = DmsfHelper.temp_dir.join(DmsfHelper.temp_filename('dmsf_zip.zip')) - @zip_file = Zip::OutputStream.new(@zip_path) - @files = [] - @folders = [] - end - - def finish - @zip_file.close - @zip_path - end - - def close - @zip_file.close - end - - def add_file(file, member, root_path = nil) - unless @files.include?(file) - unless file && file.last_revision && File.exist?(file.last_revision.disk_file) - raise FileNotFound - end - string_path = file.dmsf_folder.nil? ? '' : (file.dmsf_folder.dmsf_path_str + File::SEPARATOR) - string_path = string_path[(root_path.length + 1) .. string_path.length] if root_path - if member && !member.dmsf_title_format.nil? && !member.dmsf_title_format.empty? - string_path += file.formatted_name(member.dmsf_title_format) - else - string_path += file.formatted_name(Setting.plugin_redmine_dmsf['dmsf_global_title_format']) - end - zip_entry = ::Zip::Entry.new(@zip_file, string_path, nil, nil, nil, nil, nil, nil, - ::Zip::DOSTime.at(file.last_revision.updated_at)) - @zip_file.put_next_entry(zip_entry) - File.open(file.last_revision.disk_file, 'rb') do |f| - while (buffer = f.read(8192)) - @zip_file.write(buffer) - end - end - @files << file - end - end - - def add_folder(folder, member, root_path = nil) - unless @folders.include?(folder) - string_path = folder.dmsf_path_str + File::SEPARATOR - string_path = string_path[(root_path.length + 1) .. string_path.length] if root_path - zip_entry = ::Zip::Entry.new(@zip_file, string_path, nil, nil, nil, nil, nil, nil, - ::Zip::DOSTime.at(folder.modified)) - @zip_file.put_next_entry(zip_entry) - @folders << folder - folder.dmsf_folders.visible.each { |subfolder| add_folder(subfolder, member, root_path) } - folder.dmsf_files.visible.each { |file| add_file(file, member, root_path) } - end - end - -end \ No newline at end of file diff --git a/lib/redmine_dmsf/dmsf_zip.rb b/lib/redmine_dmsf/dmsf_zip.rb new file mode 100644 index 00000000..19812f1f --- /dev/null +++ b/lib/redmine_dmsf/dmsf_zip.rb @@ -0,0 +1,87 @@ +# encoding: utf-8 +# +# Redmine plugin for Document Management System "Features" +# +# Copyright © 2011 Vít Jonáš +# Copyright © 2011-19 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. + +require 'zip' + +module RedmineDmsf + module DmsfZip + + class Zip + + attr_reader :files + + def initialize + @zip_path = DmsfHelper.temp_dir.join(DmsfHelper.temp_filename('dmsf_zip.zip')) + @zip_file = ::Zip::OutputStream.new(@zip_path) + @files = [] + @folders = [] + end + + def finish + @zip_file.close + @zip_path + end + + def close + @zip_file.close + end + + def add_file(file, member, root_path = nil) + unless @files.include?(file) + unless file && file.last_revision && File.exist?(file.last_revision.disk_file) + raise FileNotFound + end + string_path = file.dmsf_folder.nil? ? '' : (file.dmsf_folder.dmsf_path_str + File::SEPARATOR) + string_path = string_path[(root_path.length + 1) .. string_path.length] if root_path + if member && !member.dmsf_title_format.nil? && !member.dmsf_title_format.empty? + string_path += file.formatted_name(member.dmsf_title_format) + else + string_path += file.formatted_name(Setting.plugin_redmine_dmsf['dmsf_global_title_format']) + end + zip_entry = ::Zip::Entry.new(@zip_file, string_path, nil, nil, nil, nil, nil, nil, + ::Zip::DOSTime.at(file.last_revision.updated_at)) + @zip_file.put_next_entry(zip_entry) + File.open(file.last_revision.disk_file, 'rb') do |f| + while (buffer = f.read(8192)) + @zip_file.write(buffer) + end + end + @files << file + end + end + + def add_folder(folder, member, root_path = nil) + unless @folders.include?(folder) + string_path = folder.dmsf_path_str + File::SEPARATOR + string_path = string_path[(root_path.length + 1) .. string_path.length] if root_path + zip_entry = ::Zip::Entry.new(@zip_file, string_path, nil, nil, nil, nil, nil, nil, + ::Zip::DOSTime.at(folder.modified)) + @zip_file.put_next_entry(zip_entry) + @folders << folder + folder.dmsf_folders.visible.each { |subfolder| add_folder(subfolder, member, root_path) } + folder.dmsf_files.visible.each { |file| add_file(file, member, root_path) } + end + end + + end + + end +end \ No newline at end of file From b84f9335c2e0dd012184609fca18e7f04125c5eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Fri, 22 Feb 2019 06:22:31 +0100 Subject: [PATCH 48/53] Quick jump search Dxxxx --- .../hooks/controllers/search_controller_hooks.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/redmine_dmsf/hooks/controllers/search_controller_hooks.rb b/lib/redmine_dmsf/hooks/controllers/search_controller_hooks.rb index 90516b29..b3457383 100644 --- a/lib/redmine_dmsf/hooks/controllers/search_controller_hooks.rb +++ b/lib/redmine_dmsf/hooks/controllers/search_controller_hooks.rb @@ -23,13 +23,14 @@ module RedmineDmsf include Redmine::Hook class ControllerSearchHook < RedmineDmsf::Hooks::Listener + include Rails.application.routes.url_helpers def controller_search_quick_jump(context={}) if context.is_a?(Hash) question = context[:question] if question.present? - if question.match(/^D(\d+)$/) && DmsfFile.visible.find_by(id: $1).exists? - return dmsf_file_path(:id => $1) + if question.match(/^D(\d+)$/) && DmsfFile.visible.where(id: $1).exists? + return dmsf_file_path(id: $1) end end end From c30629c8bcd5d88807770ae74c4544c486f43131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Fri, 22 Feb 2019 06:49:11 +0100 Subject: [PATCH 49/53] Installation problem 1.5.7 (step 4 of the guide) #576 --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 05b6c8ee..aece95f5 100644 --- a/README.md +++ b/README.md @@ -211,14 +211,20 @@ There's a patch (tested with Redmine 3.4.2) that helps you to modify all help fi Setup / Upgrade --------------- -Before installing ensure that the Redmine instance is stopped. +You can either clone the master branch or download the latest zipped version. Before installing ensure that the Redmine instance is stopped. -1. In case of upgrade BACKUP YOUR DATABASE first -2. Put redmine_dmsf plugin directory into plugins. + git clone git@github.com:danmunn/redmine_dmsf.git + + wget https://github.com/danmunn/redmine_dmsf/archive/master.zip + +1. In case of upgrade **BACKUP YOUR DATABASE, ORIGINAL PLUGIN AND THE FOLDER WITH DOCUMENTS** first!!! +2. Put redmine_dmsf plugin directory into plugins. The plugins sub-directory must be named just **redmine_dmsf**. In case + of need rename _redmine_dmsf-x.y.z_ to *redmine_dmsf*. +3. **Go to the redmine directory** `cd redmine` 3. Install dependencies: `bundle install`. 4. Initialize/Update database: `bundle exec rake redmine:plugins:migrate NAME=redmine_dmsf RAILS_ENV="production"`. 5. The access rights must be set for web server, example: `chown -R www-data:www-data plugins/redmine_dmsf`. -6. Restart the web server. +6. Restart the web server. e.g. `service apache2 restart` 7. You should configure the plugin via Redmine interface: Administration -> Plugins -> DMSF -> Configure. 8. Assign DMSF permissions to appropriate roles. 9. There are a few rake tasks: From ae56c23b39211cebc976e0fbb91aa6381c607124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Tue, 26 Feb 2019 12:23:37 +0100 Subject: [PATCH 50/53] No inheritance for folder permissions --- app/helpers/dmsf_helper.rb | 4 ++-- app/models/dmsf_folder.rb | 30 +++++++++++++++++------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/app/helpers/dmsf_helper.rb b/app/helpers/dmsf_helper.rb index 9d698cdc..c40cedf4 100644 --- a/app/helpers/dmsf_helper.rb +++ b/app/helpers/dmsf_helper.rb @@ -101,7 +101,7 @@ module DmsfHelper allowed = Setting.plugin_redmine_dmsf['dmsf_act_as_attachable'] && (project.dmsf_act_as_attachable == Project::ATTACHABLE_DMS_AND_ATTACHMENTS) && User.current.allowed_to?(:display_system_folders, project) - folders.reject{ |folder| + folders.reject do |folder| if folder.system if allowed issue_id = folder.title.to_i @@ -117,7 +117,7 @@ module DmsfHelper else false end - } + end end def self.all_children_sorted(parent, pos, ident) diff --git a/app/models/dmsf_folder.rb b/app/models/dmsf_folder.rb index e1fbbe28..016f49de 100644 --- a/app/models/dmsf_folder.rb +++ b/app/models/dmsf_folder.rb @@ -51,17 +51,19 @@ class DmsfFolder < ActiveRecord::Base def self.visible_condition(system=true) Project.allowed_to_condition(User.current, :view_dmsf_folders) do |role, user| - permissions = "#{DmsfFolderPermission.table_name}" - folders = "#{DmsfFolder.table_name}" - group_ids = user.group_ids.join(',') - group_ids = -1 if group_ids.blank? - allowed = (system && role.allowed_to?(:display_system_folders)) ? 1 : 0 - %{ - ((#{permissions}.object_id IS NULL) OR - (#{permissions}.object_id = #{role.id} AND #{permissions}.object_type = 'Role') OR - ((#{permissions}.object_id = #{user.id} OR #{permissions}.object_id IN (#{group_ids})) AND #{permissions}.object_type = 'User')) AND - (#{folders}.system = #{DmsfFolder.connection.quoted_false} OR 1 = #{allowed}) - } + if role.member? + permissions = "#{DmsfFolderPermission.table_name}" + folders = "#{DmsfFolder.table_name}" + group_ids = user.group_ids.join(',') + group_ids = -1 if group_ids.blank? + allowed = (system && role.allowed_to?(:display_system_folders)) ? 1 : 0 + %{ + ((#{permissions}.object_id IS NULL) OR + (#{permissions}.object_id = #{role.id} AND #{permissions}.object_type = 'Role') OR + ((#{permissions}.object_id = #{user.id} OR #{permissions}.object_id IN (#{group_ids})) AND #{permissions}.object_type = 'User')) AND + (#{folders}.system = #{DmsfFolder.connection.quoted_false} OR 1 = #{allowed}) + } + end end end @@ -564,7 +566,8 @@ class DmsfFolder < ActiveRecord::Base options[:checked] = folder.dmsf_folder_permissions.roles.exists?(object_id: role.id) if !options[:checked] && folder.dmsf_folder && !folder.dmsf_folder.deleted? options[:disabled] = true - permission_for_role_recursive(folder.dmsf_folder, role, options) + # TODO: No inheritance + #permission_for_role_recursive(folder.dmsf_folder, role, options) end end @@ -574,7 +577,8 @@ class DmsfFolder < ActiveRecord::Base usrs.each do |u| users << [u, disabled] end - permissions_users_recursive(folder.dmsf_folder, users, true) + # TODO: No inheritance + #permissions_users_recursive(folder.dmsf_folder, users, true) end end From 49184d11c2b8369d99f57c85a96adc57fd75ec26 Mon Sep 17 00:00:00 2001 From: lpereira98 <44083899+lpereira98@users.noreply.github.com> Date: Wed, 27 Feb 2019 12:36:45 +0000 Subject: [PATCH 51/53] Update show.api.rsb --- app/views/dmsf_files/show.api.rsb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/dmsf_files/show.api.rsb b/app/views/dmsf_files/show.api.rsb index 56fe4cba..86e77053 100644 --- a/app/views/dmsf_files/show.api.rsb +++ b/app/views/dmsf_files/show.api.rsb @@ -11,6 +11,7 @@ api.dmsf_file do api.id r.id api.source_dmsf_file_revision_id r.source_dmsf_file_revision_id api.name r.name + api.dmsf_string "{{dmsf(#{@file.id},#{@file.name},#{r.id})}}" api.content_url view_dmsf_file_url(@file, download: r) api.size r.size api.mime_type r.mime_type From 13387d7c7d5cf9e28157a86dfa0c1b2526570866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Wed, 27 Feb 2019 16:55:53 +0100 Subject: [PATCH 52/53] Disabling the original Documents module --- init.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/init.rb b/init.rb index 07def7a2..c16ed722 100644 --- a/init.rb +++ b/init.rb @@ -62,8 +62,9 @@ Redmine::Plugin.register :redmine_dmsf do 'dmsf_webdav_use_project_names' => nil } - # Uncomment to remove the original Documents from searching (replaced with DMSF) + # Uncomment to remove the original Documents from searching and project's modules (replaced with DMSF) # Redmine::Search.available_search_types.delete('documents') + # Redmine::AccessControl.available_project_modules.delete(:documents) end unless Redmine::Plugin.installed?(:easy_extensions) From b5da1eccb2447f28669e30d2e9a1178d0220e4a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Thu, 28 Feb 2019 11:51:17 +0100 Subject: [PATCH 53/53] v2.0.0 release --- CHANGELOG.md | 24 ++++++++++++++++++++++++ README.md | 2 +- dmsf_user_guide.odt | Bin 1162760 -> 1162637 bytes init.rb | 2 +- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a635aaa6..03a7c590 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,30 @@ Changelog for Redmine DMSF ========================== +2.0.0 *2019-02-28* +------------------ + + Compatibility with Redmine 4.0 + Russian localization updated + +* Bug: #976 - Can't link document to issue with column in subject +* Bug: #969 - About the DMSF folder search logic +* Bug: #966 - folder_manipulation permission +* Bug: #965 - tag column missing in the dms_file_revision_table +* Bug: #959 - crete symbolic link error +* Bug: #956 - About "External" of "Link from" +* Bug: #950 - Wrong description, missing argument for macro {{dmsft}} +* Bug: #940 - dav4rack license +* Bug: #937 - Documents upload if disk is full +* Bug: #936 - Then go to configuration an internal error #500 appear +* Bug: #935 - Upload failure for 2.0 +* Bug: #934 - problem to get reversion error +* Bug: #933 - změny v xapian_indexer +* Bug: #932 - undefined method `to_prepare' for ActionDispatch::Reloader:Class (Redmine 4.0 / Rails 5) +* Bug: #929 - Problems in revision history +* New: #928 - About Redmine 4.0.0 +* New: #576 - Installation problem 1.5.7 (step 4 of the guide) + 1.6.2 *2018-12-04* ------------------ diff --git a/README.md b/README.md index aece95f5..4e0bdc46 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Redmine DMSF Plugin =================== -The current version of Redmine DMSF is **1.6.2** [![Build Status](https://api.travis-ci.org/danmunn/redmine_dmsf.png)](https://travis-ci.org/danmunn/redmine_dmsf) +The current version of Redmine DMSF is **2.0.0** [![Build Status](https://api.travis-ci.org/danmunn/redmine_dmsf.png)](https://travis-ci.org/danmunn/redmine_dmsf) Redmine DMSF is Document Management System Features plugin for Redmine issue tracking system; It is aimed to replace current Redmine's Documents module. diff --git a/dmsf_user_guide.odt b/dmsf_user_guide.odt index 8a5553a6d8131fb43f53170641313a2ee5f81700..7e46fe8741a9b3469b6592bf9f6652493b6db8e1 100644 GIT binary patch delta 57716 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 delta 57968 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